1 | #!/bin/bash
|
2 |
|
3 | assert_equal() {
|
4 | local expected="${1}"
|
5 | local actual="${2}"
|
6 | if [ "$expected" != "$actual" ]; then
|
7 | echo "\nFAILED: expected ${expected}, found ${actual}"
|
8 | exit 1
|
9 | fi
|
10 | }
|
11 |
|
12 | assert_contains() {
|
13 | local expected="${1}"
|
14 | local actual="${2}"
|
15 | local return_instead_of_exit="${3}"
|
16 | if echo "$actual" | grep -qi "$expected"; then
|
17 | :
|
18 | else
|
19 | echo "\nFAILED: expected ${expected} to match ${actual}"
|
20 | if [ "$return_instead_of_exit" == true ]; then
|
21 | return 1
|
22 | else
|
23 | exit 1
|
24 | fi
|
25 | fi
|
26 | }
|
27 |
|
28 | cleanup() {
|
29 | local app="${1}"
|
30 | local extra_pid="${2}"
|
31 | echo ''
|
32 | echo 'Cleaning up...'
|
33 | heroku destroy ${app} --confirm ${app}
|
34 | cd ../..
|
35 | rm -rf tmp/${app}
|
36 |
|
37 | if [ "$CI" != "true" ]; then
|
38 | pgid=$(ps -o pgid= $$ | grep -o '[0-9]*$')
|
39 | echo "Killing processes in group $pgid..."
|
40 | kill -- -$pgid
|
41 | elif [ -n "$extra_pid" ]; then
|
42 | kill $extra_pid
|
43 | fi
|
44 | }
|
45 |
|
46 | wait_for() {
|
47 | local cmd="${1}"
|
48 | sleep 2
|
49 | attempts=0
|
50 | until $(${cmd}); do
|
51 | attempts=$((attempts+1))
|
52 | if [ $attempts -gt 10 ]; then
|
53 | echo "Too many attempts waiting for service!"
|
54 | exit 1
|
55 | fi
|
56 | sleep 2
|
57 | done
|
58 | }
|
59 |
|
60 | wait_for_dyno() {
|
61 | local dyno=${1:-web}
|
62 | echo -n "Waiting for dyno..."
|
63 | state="starting"
|
64 | while [ "up" != "$state" ]; do
|
65 | if [ "starting" != "$state" ] && [ "provisioning" != "$state" ]; then
|
66 | echo "WARNING: dyno state is \"${state}\""
|
67 | fi
|
68 | echo -n "."
|
69 | sleep 4
|
70 | state=$(heroku ps ${dyno} --json | jq .[0].state -r)
|
71 | done
|
72 | sleep 5
|
73 | echo ""
|
74 | }
|
75 |
|
76 | with_retry() {
|
77 | local cmd=${1}
|
78 | local assert_func=${2}
|
79 | local n=0
|
80 | until [ $n -ge 3 ]; do
|
81 | local output="$($cmd)"
|
82 | set +e
|
83 | $assert_func "$output"
|
84 | local result="$?"
|
85 | set -e
|
86 | [ "$result" == "0" ] && return 0
|
87 | n=$[$n+1]
|
88 | sleep 1
|
89 | echo "Retrying..."
|
90 | done
|
91 | exit 1
|
92 | }
|
93 |
|
94 | heroku plugins:link . --force
|
95 |
|
96 | set -e
|
97 |
|
98 | app="heroku-exec-test-${RANDOM}"
|
99 | echo "Preparing test app ${app}..."
|
100 |
|
101 | mkdir -p tmp
|
102 | cd tmp
|
103 | rm -rf ${app}
|
104 | mkdir ${app}
|
105 | cd ${app}
|
106 |
|
107 | file_to_copy="file-to-copy.txt"
|
108 |
|
109 | echo "Creating git repo..."
|
110 | git init
|
111 | web="ruby -rwebrick -e\"s=WEBrick::HTTPServer.new(:BindAddress => '0.0.0.0', :Port => \$PORT, :DocumentRoot => Dir.pwd); s.mount_proc('/'){|q,r| r.body='Hello'}; s.start\""
|
112 | echo "web: ${web}" > Procfile
|
113 | echo "worker: echo 'success' > ${file_to_copy}; ruby -rwebrick -e'WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd).start'" >> Procfile
|
114 |
|
115 | echo "Creating Heroku app..."
|
116 | heroku create ${app} $(if [ -n "$HEROKU_SPACE" ]; then echo "--space $HEROKU_SPACE"; else echo "--region ${HEROKU_REGION:-us}"; fi)
|
117 |
|
118 | trap "{ cleanup ${app}; }" EXIT
|
119 |
|
120 | heroku buildpacks:set https://github.com/ryandotsmith/null-buildpack
|
121 | git add Procfile
|
122 | git commit -m "first"
|
123 |
|
124 | if [ "${1}" == "staging" ] || [ "${HEROKU_EXEC_TEST_ENV}" == "staging" ]; then
|
125 | echo "=== skipping init tests"
|
126 | export HEROKU_EXEC_URL="https://heroku-exec-staging.herokuapp.com/"
|
127 | heroku buildpacks:add https://github.com/heroku/exec-buildpack#staging
|
128 | fi
|
129 |
|
130 | if [ -n "$HEROKU_SPACE" ]; then
|
131 | initOutput="$(heroku ps:exec "ls" 2>&1)"
|
132 | assert_contains "Initializing feature" "$initOutput"
|
133 | assert_contains "Adding the Heroku Exec buildpack" "$initOutput"
|
134 | assert_contains "Run the following commands to redeploy your app" "$initOutput"
|
135 | assert_contains "git push heroku master" "$initOutput"
|
136 | echo "=== test 0: success"
|
137 | else
|
138 | # TODO would be better to test that the command prompts to confirm restart
|
139 | heroku features:enable runtime-heroku-exec
|
140 | fi
|
141 |
|
142 | assert_contains "Heroku Exec is not running!" "$(heroku ps:exec --status 2>&1)"
|
143 | echo "=== test 1: success"
|
144 |
|
145 | output="$(heroku ps:exec ls 2>&1)"
|
146 | assert_contains "Establishing credentials" "$output"
|
147 | assert_contains "Could not connect to dyno!" "$output"
|
148 | echo "=== test 2: success"
|
149 |
|
150 | echo "Deploying..."
|
151 | git push heroku master
|
152 |
|
153 | wait_for_dyno "web"
|
154 |
|
155 | heroku ps:exec --ssh pwd
|
156 | assert_equal "0" "$?"
|
157 |
|
158 |
|
159 | _web_status_assert() {
|
160 | assert_contains "web.1" "$output" true && \
|
161 | assert_contains "running" "$output" true && \
|
162 | assert_contains "up" "$output" true
|
163 | return $?
|
164 | }
|
165 | with_retry "heroku ps:exec --status" "_web_status_assert"
|
166 | echo "=== test 3: success"
|
167 |
|
168 | heroku ps:scale web=0
|
169 | heroku ps:scale worker=1
|
170 |
|
171 | dyno="worker.1"
|
172 | wait_for_dyno "worker"
|
173 | echo "Dyno ${dyno} is ready!"
|
174 |
|
175 | _worker_status_assert() {
|
176 | assert_contains "$dyno" "$1" true && \
|
177 | assert_contains "running" "$1" true && \
|
178 | assert_contains "up" "$1" true
|
179 | return $?
|
180 | }
|
181 | with_retry "heroku ps:exec --status" "_worker_status_assert"
|
182 |
|
183 | heroku logs -d $dyno
|
184 |
|
185 | assert_contains "worker." "$dyno"
|
186 |
|
187 | _ps_copy_assert() {
|
188 | assert_contains "Copying ${file_to_copy} to ${file_to_copy}" "$output" true && \
|
189 | assert_contains "success" "$(cat ${file_to_copy})"
|
190 | return $?
|
191 | }
|
192 | with_retry "heroku ps:copy --dyno $dyno $file_to_copy" "_ps_copy_assert"
|
193 |
|
194 | echo "=== test 4: success"
|
195 |
|
196 | eval "heroku ps:forward --app $app --dyno $dyno 3000 &"
|
197 | trap "{ cleanup ${app} $!; }" EXIT
|
198 |
|
199 | wait_for "curl -o /dev/null -s -I -f localhost:3000"
|
200 | assert_contains "${file_to_copy}" "$(curl -s -L localhost:3000)"
|
201 | echo "=== test 5: success"
|
202 |
|
203 | assert_contains "${file_to_copy}" "$(curl --socks5 localhost:1080 -s -L 0.0.0.0:3000)"
|
204 | echo "=== test 6: success"
|
205 |
|
206 | echo ""
|
207 | echo "SUCCESS: All tests passed!"
|
208 | exit 0
|