Skip to content

Docker cross test infrastructure #297

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

Merged
merged 20 commits into from
Mar 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e6fff3a
testing: add ci scripts to aid testing on more architectures/versions
posborne Mar 6, 2016
6ffe725
testing: configure linker via .cargo/config
posborne Mar 7, 2016
b5a9227
testing: add documentation covering the basics
posborne Mar 7, 2016
22b1820
testing: switch to posborne/rust-cross
posborne Mar 7, 2016
3f2b70a
testing: allow the docker image to be overriden
posborne Mar 7, 2016
806e0a7
testing: remove `set -x` from ci/run.sh
posborne Mar 7, 2016
d95f4d5
testing: disable some targets and continue running on failure
posborne Mar 7, 2016
b5b7042
testing: fix test exeuction paths with move to docker container
posborne Mar 7, 2016
5ddd8b2
testing: disable thread parallelization in docker testing
posborne Mar 7, 2016
14e2f76
testing: export CC based on .cargo/config contents
posborne Mar 7, 2016
b69558c
testing: fix gcc/linker paths for several targets
posborne Mar 13, 2016
cd3fdaf
testing: move to new posborne/rust-cross images
posborne Mar 13, 2016
6ad81d1
testing: first shot at testing with travis for arm, mips, android, ...
posborne Mar 13, 2016
3b7b15d
testing: docker tests now work on travis
posborne Mar 13, 2016
ef8f643
libc: revert change to libc version
posborne Mar 14, 2016
02af925
testing: move echo statement within docker run script
posborne Mar 14, 2016
5eb1fa6
testing: use default linker for appropriate platforms
posborne Mar 14, 2016
4e245f4
testing: update documentation related to testing
posborne Mar 14, 2016
72f6754
testing: explicitly check TRAVIS_OS_NAME is osx
posborne Mar 14, 2016
d1311ff
testing: ensure run.sh is executing in docker container
posborne Mar 14, 2016
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
64 changes: 42 additions & 22 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,37 +1,57 @@
---
sudo: false
language: rust
sudo: required
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really wish they'd let this be set per matrix entry... we're going to be slower to schedule because of this.

/me is planning to spend time on https://github.com/kamalmarhubi/containy-thing this week because of this silliness

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. It is annoying -- I removed some combos from the matrix to make overall build time somewhat reasonable, but that is a tradeoff and we could, for instance, miss a failure on some intermediate rust version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was more a comment than anything else. It's been on my mind.

dist: trusty
services:
- docker

rust:
- 1.1.0 # Oldest supported version
- 1.2.0
- 1.3.0
- 1.4.0
- 1.5.0
- stable
- beta
- nightly

# Failures on nightly shouldn't fail the overall build.
matrix:
allow_failures:
- rust: nightly
script:
- bash ci/run-travis.sh

env:
- ARCH=x86_64

os:
- linux
- osx

env:
- RUST_TEST_THREADS=1 ARCH=x86_64
- RUST_TEST_THREADS=1 ARCH=i686

script:
- curl -sSL https://raw.githubusercontent.com/carllerche/travis-rust-matrix/master/test | RUST_TEST_THREADS=1 bash
- cargo doc --no-deps

addons:
apt:
packages:
- gcc-multilib
# Failures on nightly shouldn't fail the overall build.
matrix:
fast_finish: true
include:
- os: linux
env: ARCH=i686
rust: stable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this deploy the docs somewhere? Or just build them?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deployment is done later on and should be unchanged.

- os: osx
env: ARCH=i686
rust: stable
- os: linux
env: TARGET=aarch64-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:arm
rust: 1.7.0
- os: linux
env: TARGET=arm-unknown-linux-gnueabihf DOCKER_IMAGE=posborne/rust-cross:arm
rust: 1.7.0
- os: linux
env: TARGET=mips-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
rust: 1.7.0
- os: linux
env: TARGET=mipsel-unknwon-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
rust: 1.7.0
- os: linux
env: TARGET=arm-linux-androideabi DOCKER_IMAGE=posborne/rust-cross:android
rust: 1.7.0
allow_failures:
- rust: nightly
- env: TARGET=aarch64-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:arm
- env: TARGET=arm-unknown-linux-gnueabihf DOCKER_IMAGE=posborne/rust-cross:arm
- env: TARGET=mips-unknown-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
- env: TARGET=mipsel-unknwon-linux-gnu DOCKER_IMAGE=posborne/rust-cross:mips
- env: TARGET=arm-linux-androideabi DOCKER_IMAGE=posborne/rust-cross:android

# Deploy documentation to S3 for specific branches. At some
# point, it would be nice to also support building docs for
Expand Down
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ environment. We also have [continuous integration set up on
Travis-CI][travis-ci], which might find some issues on other platforms. The CI
will run once you open a pull request.

[travis-ci]: https://travis-ci.org/nix-rust/nix
There is also infrastructure for running tests for other targets
locally. More information is available in the [CI Readme][ci-readme].

[travis-ci]: https://travis-ci.org/nix-rust/nix
[ci-readme]: ci/README.md

## Homu, the bot who merges all the PRs

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ To use `nix`, first add this to your `Cargo.toml`:

```toml
[dependencies]
nix = "*"
nix = "0.5.0"
```

Then, add this to your crate root:
Expand Down
48 changes: 48 additions & 0 deletions ci/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
Test Infrastructure
===================

The ci directory contains scripts that aid in the testing of nix both
in our continuous integration environment (Travis CI) but also for
developers working locally.

Nix interfaces very directly with the underlying platform (usually via
libc) and changes need to be tested on a large number of platforms to
avoid problems.

Running Tests For Host Architecture
-----------------------------------

Running the tests for one's host architecture can be done by simply
doing the following:

$ cargo test

Running Tests Against All Architectures/Versions
------------------------------------------------

Testing for other architectures is more involved. Currently,
developers may run tests against several architectures and versions of
rust by running the `ci/run-all.sh` script. This scripts requires
that docker be set up. This will take some time:

$ ci/run-all.sh

The list of versions and architectures tested by this can be
determined by looking at the contents of the script. The docker image
used is [posborne/rust-cross][posborne/rust-cross].

[posborne/rust-cross]: https://github.com/rust-embedded/docker-rust-cross

Running Test for Specific Architectures/Versions
------------------------------------------------

Suppose we have a failing test with Rust 1.7 on the raspberry pi. In
that case, we can run the following:

$ DOCKER_IMAGE=posborne/rust-cross:arm \
RUST_VERSION=1.7.0 \
RUST_TARGET=arm-unknown-linux-gnueabihf ci/run-docker.sh

Currently, the docker images only support Rust 1.7. To get a better
idea of combinations that might work, look at the contents of the
[travis configuration](../.travis.yml) or [run-all.sh](run-all.sh).
18 changes: 18 additions & 0 deletions ci/cargo-config
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Configuration of which linkers to call on Travis for various architectures
[target.arm-linux-androideabi]
linker = "arm-linux-androideabi-gcc"

[target.arm-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc-4.7"

[target.mips-unknown-linux-gnu]
linker = "mips-linux-gnu-gcc-5"

[target.mipsel-unknown-linux-gnu]
linker = "mipsel-linux-gnu-gcc-5"

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc-4.8"

[target.powerpc-unknown-linux-gnu]
linker = "powerpc-linux-gnu-gcc-4.8"
28 changes: 28 additions & 0 deletions ci/run-all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash
#
# Build nix and all tests for as many versions and platforms as can be
# managed. This requires docker.
#

set -e

BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
RUN_DOCKER="${BASE_DIR}/ci/run-docker.sh"

export RUST_VERSION=1.7.0

export DOCKER_IMAGE=posborne/rust-cross:base
RUST_TARGET=x86_64-unknown-linux-gnu ${RUN_DOCKER}
RUST_TARGET=x86_64-unknown-linux-musl ${RUN_DOCKER}

export DOCKER_IMAGE=posborne/rust-cross:arm
RUST_TARGET=aarch64-unknown-linux-gnu ${RUN_DOCKER}
RUST_TARGET=arm-linux-gnueabi test_nix ${RUN_DOCKER}
RUST_TARGET=arm-linux-gnueabihf test_nix ${RUN_DOCKER}

export DOCKER_IMAGE=posborne/rust-cross:mips
RUST_TARGET=mips-unknown-linux-gnu test_nix ${RUN_DOCKER}
RUST_TARGET=mipsel-unknown-linux-gnu test_nix ${RUN_DOCKER}

export DOCKER_IMAGE=posborne/rust-cross:android ${RUN_DOCKER}
RUST_TARGET=arm-linux-androideabi test_nix ${RUN_DOCKER}
15 changes: 15 additions & 0 deletions ci/run-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash
#
# Run the nix tests in a docker container. This script expects the following
# environment variables to be set:
# - DOCKER_IMAGE : Docker image to use for testing (e.g. posborne/rust-cross:arm)
# - RUST_VERSION : Rust Version to test against (e.g. 1.7.0)
# - RUST_TARGET : Target Triple to test

BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

docker run -i -t \
-v ${BASE_DIR}:/source \
-e CARGO_TARGET_DIR=/build \
${DOCKER_IMAGE} \
/source/ci/run.sh ${RUST_VERSION} ${RUST_TARGET}
47 changes: 47 additions & 0 deletions ci/run-travis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash
#
# Entry point for all travis builds, this will set up the Travis environment by
# downloading any dependencies. It will then execute the `run.sh` script to
# build and execute all tests.
#
# Much of this script was liberally stolen from rust-lang/libc
#
# Key variables that may be set from Travis:
# - TRAVIS_RUST_VERSION: 1.1.0 ... stable/nightly/beta
# - TRAVIS_OS_NAME: linux/osx
# - DOCKER_IMAGE: posborne/rust-cross:arm
# - TARGET: e.g. arm-unknown-linux-gnueabihf

set -ex

BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

if [ "$TRAVIS_OS_NAME" = "linux" ]; then
OS=unknown-linux-gnu
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
OS=apple-darwin
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you make this an elif, or the whole thing a case and abort if it's neither linux nor darwin?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. This bit was taken from libc, but I agree that it is probably better to be a bit more strict: https://github.com/rust-lang/libc/blob/master/ci/run-travis.sh#L11

else
echo "Unexpected TRAVIS_OS_NAME: $TRAVIS_OS_NAME"
exit 1
fi

export HOST=$ARCH-$OS
if [ "$TARGET" = "" ]; then
TARGET=$HOST
fi

if [ "$TARGET" = "i686-unknown-linux-gnu" ]; then
sudo apt-get -y update
sudo apt-get install -y gcc-multilib
fi

if [ "$DOCKER_IMAGE" = "" ]; then
export RUST_TEST_THREADS=1
curl -sSL "https://raw.githubusercontent.com/carllerche/travis-rust-matrix/master/test" | bash
cargo doc --no-deps
else
export RUST_VERSION=${TRAVIS_RUST_VERSION}
export RUST_TARGET=${TARGET}
export DOCKER_IMAGE=${DOCKER_IMAGE}
${BASE_DIR}/ci/run-docker.sh
fi
135 changes: 135 additions & 0 deletions ci/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
#!/bin/bash

# Builds and runs tests for a particular target passed as an argument to this
# script.

set -e

# This should only be run in a docker container, so verify that
if [ ! -f /.dockerinit ]; then
echo "run.sh should only be executed in a docker container"
echo "and that does not appear to be the case. Maybe you meant"
echo "to execute the tests via run-all.sh or run-docker.sh."
echo ""
echo "For more instructions, please refer to ci/README.md"
exit 1
fi

BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
MANIFEST_PATH="${BASE_DIR}/Cargo.toml"
BUILD_DIR="."

VERSION="$1"
TARGET="$2"

export RUST_TEST_THREADS=1

#
# Tell cargo what linker to use and whatever else is required
#
configure_cargo() {
mkdir -p .cargo
cp -b "${BASE_DIR}/ci/cargo-config" .cargo/config
}

#
# We need to export CC for the tests to build properly (some C code is
# compiled) to work. We already tell Cargo about the compiler in the
# cargo config, so we just parse that info out of the cargo config
#
cc_for_target() {
awk "/\[target\.${TARGET}\]/{getline; print}" .cargo/config |
cut -d '=' -f2 | \
tr -d '"' | tr -d ' '
}

cross_compile_tests() {
case "$TARGET" in
*-apple-ios)
cargo test --no-run --manifest-path="${MANIFEST_PATH}" --target "$TARGET" -- \
-C link-args=-mios-simulator-version-min=7.0
;;

*)
cargo test --no-run --verbose \
--manifest-path="${MANIFEST_PATH}" \
--target "$TARGET"
;;
esac
}

# This is a hack as we cannot currently
# ask cargo what test files it generated:
# https://github.com/rust-lang/cargo/issues/1924
find_binaries() {
target_base_dir="${BUILD_DIR}/${TARGET}/debug"

# find [[test]] sections and print the first line and
# hack it to what we want from there. Also "nix" for
# tests that are implicitly prsent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: present

for test_base in $( awk '/\[\[test\]\]/{getline; print}' "${MANIFEST_PATH}" | \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you might be able to use cargo read-manifest and JSON processing here instead of fake-parsing the manifest

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you get jq installed, then this works:

$ for bin in $(cargo read-manifest | jq '.targets[].name'); do echo $bin; done
"rustfmt"
"cargo-fmt"
"rustfmt"
"system"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh I didn't actually read the linked bug. That is silly an annoying.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may still be possible to collect them up by doing $bin{-,}* or something like that

cut -d '=' -f2 | \
tr -d '"' | \
tr '-' '_' | \
tr -d ' '; echo "nix" ); do
for path in ${target_base_dir}/${test_base}-* ; do
echo "${path} "
done
done
}

test_binary() {
binary=$1

case "$TARGET" in
arm-linux-gnueabi-gcc)
qemu-arm -L /usr/arm-linux-gnueabihf "$binary"
;;

arm-unknown-linux-gnueabihf)
qemu-arm -L /usr/arm-linux-gnueabihf "$binary"
;;

mips-unknown-linux-gnu)
qemu-mips -L /usr/mips-linux-gnu "$binary"
;;

aarch64-unknown-linux-gnu)
qemu-aarch64 -L /usr/aarch64-linux-gnu "$binary"
;;

*-rumprun-netbsd)
rumprun-bake hw_virtio /tmp/nix-test.img "${binary}"
qemu-system-x86_64 -nographic -vga none -m 64 \
-kernel /tmp/nix-test.img 2>&1 | tee /tmp/out &
sleep 5
grep "^PASSED .* tests" /tmp/out
;;

*)
echo "Running binary: ${binary}"
${binary}
;;
esac
}

echo "======================================================="
echo "TESTING VERSION: ${VERSION}, TARGET: ${TARGET}"
echo "======================================================="

configure_cargo
export CC="$(cc_for_target)"
if [ "${CC}" = "" ]; then
unset CC
fi

# select the proper version
multirust override ${VERSION}

# build the tests
cross_compile_tests

# and run the tests
for bin in $(find_binaries); do
test_binary "${bin}"
done