Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ian's initial fixes #10

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,9 @@ services:
- docker

before_install:
- docker build -t mrako/wait-for .
- docker run mrako/wait-for
- docker build -t eficode/wait-for .

script:
- npm install
- ./run_tests.sh
- docker run eficode/wait-for
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ WORKDIR /app
COPY . /app
RUN npm install

CMD ./node_modules/.bin/bats wait-for.bats
# On launch, run the test suite via npm
CMD npm test
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

When using this tool, you only need to pick the `wait-for` file as part of your project.

[![Build Status](https://travis-ci.org/mrako/wait-for.svg?branch=master)](https://travis-ci.org/mrako/wait-for)
[![Build Status](https://travis-ci.org/eficode/wait-for.svg?branch=master)](https://travis-ci.org/eficode/wait-for)

## Usage

```
./wait-for host:port [-t timeout] [-- command args]
wait-for host:port [-t timeout] [-- command args]
-q | --quiet Do not output any status messages
-l | --loose Execute subcommand even if the test times out
-t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
```
Expand All @@ -21,11 +22,19 @@ To check if [eficode.com](https://eficode.com) is available:

```
$ ./wait-for www.eficode.com:80 -- echo "Eficode site is up"

Connection to www.eficode.com port 80 [tcp/http] succeeded!
Eficode site is up
```

The subcommand will be executed regardless if the service is up or not. If you wish to execute the subcommand only if the service is up, add the --strict argument. In this example, we will test port 81 on www.google.com which will fail:

```
$ ./wait-for www.google.com:81 --timeout=1 -- echo "google is up"
Operation timed out
$ ./wait-for www.google.com:81 --timeout=1 --loose -- echo "waited for google"
Operation timed out
waited for google
```

To wait for database container to become available:


Expand All @@ -48,4 +57,4 @@ services:
Ironically testing is done using [bats](https://github.com/sstephenson/bats), which on the other hand is depending on [bash](https://en.wikipedia.org/wiki/Bash_(Unix_shell)).

docker build -t wait-for .
docker run -t wait-for
docker run -t wait-for
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"name": "wait-for",
"version": "0.1.0",
"scripts": {
"test": "./node_modules/.bin/bats wait-for.bats"
"test": "./run_tests.sh"
},
"dependencies": {
"bats": "^0.4.2"
Expand Down
8 changes: 8 additions & 0 deletions run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash

# Although it would be possible to just call this directly from the Dockerfile,
# centralizing tests in this file allows both the docker container and the
# CI machine to run the same set of tests for an additional datapoint --
# which gives a better chance of turning up POSIX noncompliance

./node_modules/.bin/bats wait-for.bats
60 changes: 47 additions & 13 deletions wait-for
Original file line number Diff line number Diff line change
@@ -1,40 +1,70 @@
#!/bin/sh
#!/usr/bin/env bash

OLD_TIMEOUT=$TIMEOUT
OLD_QUIET=$QUIET
OLD_PORT=$PORT
OLD_HOST=$HOST
OLD_LOOSE=$LOOSE

TIMEOUT=15
QUIET=0
LOOSE=0

if ! which nc >/dev/null; then
echo "Netcat is not installed. This script requires netcat to work correctly."
exit 1
fi

echoerr() {
if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
}

conditionally_output() {
if [ "$QUIET" -ne 1 ]; then
"$@"
else
"$@" > /dev/null 2>&1
fi
}

usage() {
exitcode="$1"
cat << USAGE >&2
Usage:
$cmdname host:port [-t timeout] [-- command args]
$(basename $0) host:port [-t timeout] [-- command args]
-q | --quiet Do not output any status messages
-l | --loose Execute subcommand even if the test times out
-t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout
-- COMMAND ARGS Execute command with args after the test finishes
USAGE
exit "$exitcode"
}

test_connection() {
conditionally_output echo "Testing connection to $1:$2..."

# force a 1-second timeout on darwin (https://stackoverflow.com/a/20460402/2063546)
if [ -z "${OSTYPE##*darwin*}" ] ; then
conditionally_output nc -z -w 1 -G 1 "$1" "$2"
else
conditionally_output nc -z -w 1 "$1" "$2" > /dev/null 2>&1
fi
}

wait_for() {
command="$*"
local result
for i in `seq $TIMEOUT` ; do
nc -z "$HOST" "$PORT" > /dev/null 2>&1

# use a 1-second timeout, but still sleep 0.1 seconds after just to be safe
test_connection "$HOST" "$PORT"
result=$?
if [ $result -eq 0 ] ; then
if [ -n "$command" ] ; then
exec $command
fi
exit 0
fi
if [ $result -eq 0 ] ; then break ; fi
sleep 1
done
echo "Operation timed out" >&2
exit 1
[ $result -ne 0 ] && echoerr "Operation timed out"
if [ $result -eq 0 -o $LOOSE -eq 1 -a $# -gt 0 ] ; then
TIMEOUT=$OLD_TIMEOUT QUIET=$OLD_QUIET PORT=$OLD_PORT HOST=$OLD_HOST LOOSE=$OLD_LOOSE exec "$@"
fi
exit $result
}

while [ $# -gt 0 ]
Expand All @@ -49,6 +79,10 @@ do
QUIET=1
shift 1
;;
-l | --loose)
LOOSE=1
shift 1
;;
-t)
TIMEOUT="$2"
if [ "$TIMEOUT" = "" ]; then break; fi
Expand Down
27 changes: 26 additions & 1 deletion wait-for.bats
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

@test "google should be immediately found" {
run ./wait-for google.com:80 -- echo 'success'

[ "$output" = "success" ]
}

Expand All @@ -12,3 +12,28 @@
[ "$status" -ne 0 ]
[ "$output" != "success" ]
}

@test "nonexistent server should start command if loose option is specified" {
run ./wait-for -t 1 -l noserver:9999 -- echo 'passable' 2>&1

[ "$status" -eq 0 ]

[ "${lines[0]}" = "Operation timed out" ]
[ "${lines[1]}" = "passable" ]
}

@test "preserve existing environment variables" {
TIMEOUT=mytimeout
QUIET=myquiet
HOST=myhost
PORT=myport
LOOSE=myloose

run ./wait-for google.com:80 -- echo 'success'

[ "$(echo $TIMEOUT)" = 'mytimeout' ]
[ "$(echo $QUIET)" = 'myquiet' ]
[ "$(echo $HOST)" = 'myhost' ]
[ "$(echo $PORT)" = 'myport' ]
[ "$(echo $LOOSE)" = 'myloose' ]
}