0
0
mirror of https://github.com/tj/n.git synced 2024-11-21 18:48:57 +01:00

Add test folder and tests

This commit is contained in:
John Gee 2019-05-04 19:45:53 +12:00
parent 6fc267147a
commit af1f7fe75e
18 changed files with 519 additions and 1 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.DS_Store
node_modules
test/proxy~~.dump

11
package-lock.json generated
View File

@ -1,5 +1,14 @@
{ {
"name": "n", "name": "n",
"version": "3.0.3-0", "version": "3.0.3-0",
"lockfileVersion": 1 "lockfileVersion": 1,
"requires": true,
"dependencies": {
"bats": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/bats/-/bats-1.1.0.tgz",
"integrity": "sha512-1pA29OhDByrUtAXX+nmqZxgRgx2y8PvuZzbLJVjd2dpEDVDvz0MjcBMdmIPNq5lC+tG53G+RbeRsbIlv3vw7tg==",
"dev": true
}
}
} }

View File

@ -42,6 +42,12 @@
"type": "git", "type": "git",
"url": "git://github.com/tj/n.git" "url": "git://github.com/tj/n.git"
}, },
"scripts": {
"test": "test/bin/run-all-tests"
},
"devDependencies": {
"bats": "^1.1.0"
},
"preferGlobal": true, "preferGlobal": true,
"os": [ "os": [
"!win32" "!win32"

47
test/bin/proxy-build Executable file
View File

@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Unoffical bash safe mode
set -euo pipefail
BIN_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
waitproxy() {
while ! nc -z localhost 8080 ; do sleep 1 ; done
}
if nc -z localhost 8080; then
echo "Error: port 8080 already in use. Is mitmdump already running?"
pgrep -f -l mitmdump
exit 2
fi
echo "Launching proxy..."
mitmdump -w proxy~~.dump &> /dev/null &
mitm_process="$!"
echo "Waiting for proxy..."
waitproxy
echo "Recording downloads..."
source tests/shared-functions.bash
unset_n_env
setup_tmp_prefix
install_dummy_node
# Hack curl to avoid certificate issues with proxy
readonly CURL_HOME="$(dirname "${BIN_DIRECTORY}")/config"
export CURL_HOME
# Go through proxy so it can record traffic, http for taobao redirects
http_proxy="$(hostname):8080"
export http_proxy
https_proxy="$(hostname):8080"
export https_proxy
# native
tests/install-reference-versions.bash
# linux
docker-compose run ubuntu-curl /mnt/tests/install-reference-versions.bash
rm -rf "${TMP_PREFIX_DIR}"
echo "Stopping proxy"
kill "${mitm_process}"

12
test/bin/proxy-run Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
BIN_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
echo ""
echo "To make use of proxy server:"
echo " export https_proxy=\"$(hostname):8080\""
echo " export http_proxy=\"$(hostname):8080\""
echo " export CURL_HOME=$(dirname "${BIN_DIRECTORY}")/config"
echo ""
echo "Launching proxy server..."
mitmdump --server-replay-nopop --server-replay proxy~~.dump

14
test/bin/run-all-tests Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
BIN_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
services=( ubuntu-curl ubuntu-wget )
cd "$(dirname "${BIN_DIRECTORY}")" || exit 2
for service in "${services[@]}" ; do
echo "${service}"
docker-compose run --rm "${service}" "bats" "/mnt/tests"
echo ""
done
uname -s
../node_modules/.bin/bats tests

2
test/config/.curlrc Normal file
View File

@ -0,0 +1,2 @@
# Allow use of mitm proxy
--insecure

20
test/docker-base.yml Normal file
View File

@ -0,0 +1,20 @@
version: '2'
# Define base service to specify the mounts and environment variables
services:
testbed:
volumes:
# make locally installed bats available in container (based on bats/install.sh)
- ../node_modules/bats/bin/bats:/usr/local/bin/bats
- ../node_modules/bats/libexec/bats-core:/usr/local/libexec/bats-core
- ../node_modules/bats/man/bats.1:/usr/local/share/man/man1"
- ../node_modules/bats/man/bats.7:/usr/local/share/man/man7"
# the bats tests
- ./tests:/mnt/tests
# the n script
- ../bin/n:/usr/local/bin/n
# override curl settings to allow insecure connection in case using proxy
- ./config/.curlrc:/root/.curlrc
environment:
# pass through proxy settings to allow caching proxy
- http_proxy
- https_proxy

16
test/docker-compose.yml Normal file
View File

@ -0,0 +1,16 @@
version: '2'
services:
ubuntu-curl:
extends:
file: ./docker-base.yml
service: testbed
build:
context: dockerfiles
dockerfile: Dockerfile-ubuntu-curl
ubuntu-wget:
extends:
file: ./docker-base.yml
service: testbed
build:
context: dockerfiles
dockerfile: Dockerfile-ubuntu-wget

View File

@ -0,0 +1,9 @@
FROM ubuntu:latest
# curl
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD ["/bin/bash"]

View File

@ -0,0 +1,9 @@
FROM ubuntu:latest
# wget
RUN apt-get update \
&& apt-get install -y wget \
&& rm -rf /var/lib/apt/lists/*
CMD ["/bin/bash"]

70
test/tests.md Normal file
View File

@ -0,0 +1,70 @@
# n-test
Prototype and develop a set of automated tests for `n`.
## Setup
Optional proxy using mitmproxy:
# using homebrew (Mac) to install mitmproxy
brew install mitmproxy
## Running Tests
Run all the tests across a range of containers and on the host system:
npm run test
Run all the tests on a single system:
cd test
npx bats tests
docker-compose run ubuntu-curl bats /mnt/tests
Run single test on a single system::
cd test
npx bats tests/install-contents.bats
docker-compose run ubuntu-curl bats /mnt/tests/install-contents.bats
## Proxy
To speed up running tests multiple times, you can optionally run a caching proxy for the node downloads. The curl settings are modified
to allow an insecure connection through the mitm proxy.
cd test
bin/proxy-build
bin/proxy-run
# follow the instructions for configuring environment variables for using proxy, then run tests
`node` versions added to proxy cache (and used in tests):
* v4.9.1
* lts
* latest
## Docker Tips
Using `docker-compose` in addition to `docker` for convenient mounting of `n` script and the tests into the container. Changes to the tests or to `n` itself are reflected immediately without needing to rebuild the containers.
`bats` is being mounted directly out of `node_modules` into the container as a manual install based on its own install script. This is a bit of a hack, but avoids needing to install `git` or `npm` for a full remote install of `bats`, and means everything on the same version of `bats`.
The containers each have:
* either curl or wget (or both) installed
Using `docker-compose` to run the container adds:
* specified `n` script mounted to `/usr/local/bin/n`
* `test/tests` mounted to `/mnt/tests`
* `node_modules/bats` provides `/usr/local/bin/bats` et al
* `.curlrc` with `--insecure` to allow use of proxy
So for example:
cd test
docker-compose run ubuntu-curl
# in container
n --version
bats /mnt/tests

View File

@ -0,0 +1,43 @@
#!/usr/bin/env bats
load shared-functions
function setup() {
unset_n_env
}
# Test that files get installed to expected locations
# https://github.com/tj/n/issues/246
@test "install: contents" {
readonly TARGET_VERSION="4.9.1"
setup_tmp_prefix
[ ! -d "${N_PREFIX}/n/versions" ]
[ ! -d "${N_PREFIX}/bin" ]
[ ! -d "${N_PREFIX}/include" ]
[ ! -d "${N_PREFIX}/lib" ]
[ ! -d "${N_PREFIX}/shared" ]
install_dummy_node
n ${TARGET_VERSION}
# Cached version
[ -d "${N_PREFIX}/n/versions/node/${TARGET_VERSION}" ]
# node and npm
[ -f "${N_PREFIX}/bin/node" ]
[ -f "${N_PREFIX}/bin/npm" ]
# Installed something into each of other key folders
[ -d "${N_PREFIX}/include/node" ]
[ -d "${N_PREFIX}/lib/node_modules" ]
[ -d "${N_PREFIX}/share/doc/node" ]
# Did not install files from top level of tarball
[ ! -f "${N_PREFIX}/README.md" ]
run node --version
[ "${output}" = "v${TARGET_VERSION}" ]
rm -rf "${TMP_PREFIX_DIR}"
}

View File

@ -0,0 +1,37 @@
#!/usr/bin/env bats
load shared-functions
function setup() {
unset_n_env
setup_tmp_prefix
install_dummy_node
}
function teardown() {
rm -rf "${TMP_PREFIX_DIR}"
}
@test "n --download 4.9.1" {
n --download 4.9.1
[ -d "${N_PREFIX}/n/versions/node/4.9.1" ]
# Remember, we installed a dumy node so do have a bin/node
[ ! -f "${N_PREFIX}/bin/npm" ]
[ ! -d "${N_PREFIX}/include" ]
[ ! -d "${N_PREFIX}/lib" ]
[ ! -d "${N_PREFIX}/shared" ]
}
@test "n --quiet 4.9.1" {
# just checking option is allowed, not testing functionality
n --quiet 4.9.1
run node --version
[ "${output}" = "v4.9.1" ]
}
# ToDo: --arch

View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# These are the versions installed and hence cached by proxy-build.
# Run commands we want to cache downloads for
# Get index into cache for lookups of expected versions.
curl --location --fail https://nodejs.org/dist/index.tab &> /dev/null
# Using 4.9.1 as a well known old version (which is no longer getting updated so does not change)
n --download 4
n --download lts
n --download latest

View File

@ -0,0 +1,76 @@
#!/usr/bin/env bats
load shared-functions
function setup() {
unset_n_env
setup_tmp_prefix
install_dummy_node
}
function teardown() {
rm -rf "${TMP_PREFIX_DIR}"
}
# Explicit version
@test "n 4.9.1" {
n 4.9.1
run node --version
[ "${output}" = "v4.9.1" ]
}
# Explicit version, optional leading v
@test "n v4.9.1" {
n v4.9.1
run node --version
[ "${output}" = "v4.9.1" ]
}
# Partial version
@test "n 4" {
n 4
run node --version
[ "${output}" = "v4.9.1" ]
}
# Partial version, optional leading v
@test "n v4" {
n v4
run node --version
[ "${output}" = "v4.9.1" ]
}
# Partial version
@test "n 4.9" {
n 4.9
run node --version
[ "${output}" = "v4.9.1" ]
}
@test "n lts" {
n lts
run node --version
[ "${output}" = "$(display_remote_version lts)" ]
}
@test "n stable" {
n stable
run node --version
[ "${output}" = "$(display_remote_version lts)" ]
}
@test "n latest" {
n latest
run node --version
[ "${output}" = "$(display_remote_version latest)" ]
}

28
test/tests/lookup.bats Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/env bats
load shared-functions
function setup() {
unset_n_env
}
@test "n --lts" {
run n --lts
[ "${status}" -eq 0 ]
local expected_version
expected_version="$(display_remote_version lts)"
expected_version="${expected_version#v}"
[ "${output}" = "${expected_version}" ]
}
@test "n --latest" {
run n --latest
[ "${status}" -eq 0 ]
local expected_version
expected_version="$(display_remote_version latest)"
expected_version="${expected_version#v}"
[ "${output}" = "${expected_version}" ]
}

View File

@ -0,0 +1,104 @@
#!/usr/bin/env bash
# unset the n environment variables so tests running from known state.
# Globals:
# lots
function unset_n_env(){
unset N_PREFIX
# Undocumented [sic]
unset NODE_MIRROR
# Documented under "custom source", but PROJECT and HTTP implemented as independent
unset PROJECT_NAME
unset PROJECT_URL
unset PROJECT_VERSION_CHECK
unset HTTP_USER
unset HTTP_PASSWORD
}
# Create a dummy version of node so `n install` will always activate (and not be affected by possible system version of node).
function install_dummy_node() {
local prefix="${N_PREFIX-/usr/local}"
mkdir -p "${prefix}/bin"
echo "echo vDummy" > "${prefix}/bin/node"
chmod a+x "${prefix}/bin/node"
}
# Create temporary dir and configure n to use it.
# Globals:
# TMP_PREFIX_DIR
# N_PREFIX
# PATH
function setup_tmp_prefix() {
TMP_PREFIX_DIR="$(mktemp -d)"
[ -d "${TMP_PREFIX_DIR}" ] || exit 2
# return a safer variable to `rm -rf` later than N_PREFIX
export TMP_PREFIX_DIR
export N_PREFIX="${TMP_PREFIX_DIR}"
export PATH="${N_PREFIX}/bin:${PATH}"
}
# Display relevant file name (third field of index.tab) for current platform.
# Based on code from nvm rather than n for independent approach. Simplified for just common platforms initially.
# See list on https://github.com/nodejs/nodejs-dist-indexer
function display_compatible_file_field() {
local os="unexpected"
case "$(uname -a)" in
Linux\ *) os="linux" ;;
Darwin\ *) os="osx" ;;
esac
local arch="unexpected"
local uname_m
uname_m="$(uname -m)"
case "${uname_m}" in
x86_64 | amd64) arch="x64" ;;
i*86) arch="x86" ;;
aarch64) arch="arm64" ;;
*) arch="${uname_m}" ;;
esac
echo "${os}-${arch}"
}
# display_remote_version <version>
# Limited support for using index.tab to resolve version into a number.
# Return version number, including leading v.
function display_remote_version() {
# ToDo: support NODE_MIRROR
local fetch
if command -v curl &> /dev/null; then
fetch="curl --silent --location --fail"
else
# insecure to match current n implementation
fetch="wget -q -O- --no-check-certificate"
fi
local match='xxx'
if [[ "$1" = "lts" ]]; then
match='[^-]$'
elif [[ "$1" = "latest" ]]; then
match='.'
fi
# Using awk rather than head so do not close pipe early on curl
# (Add display_compatible_file_field when n does similar check!)
${fetch} "https://nodejs.org/dist/index.tab" \
| tail -n +2 \
| grep -E "${match}" \
| awk "NR==1" \
| cut -f -1
}