Merge branch 'al-sync-user-tests' of https://github.com/realm/realm-js into al-sync-user-tests

This commit is contained in:
Ari Lazier 2016-11-10 10:50:51 -08:00
commit 8bd5ee8be7
8 changed files with 287 additions and 85 deletions

View File

@ -1,37 +1,8 @@
FROM node:6
FROM ubuntu:xenial
# Make debugging quicker.
RUN apt-get update && apt-get install -y gdb vim
RUN apt-get update && \
apt-get install -y curl && \
curl -sL https://deb.nodesource.com/setup_4.x | bash - && \
apt-get install -y nodejs gcc-4.9 python build-essential
# Add non-root user.
RUN useradd -ms /bin/bash user
# Make our workspace directory and work from there.
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Get the node_modules setup before anything else.
COPY package.json .
RUN npm install
# Make sure core is downloaded.
COPY scripts/download-core.sh scripts/
RUN scripts/download-core.sh node
# Copy only what we need to build.
COPY src/ src/
# Build the Debug version of the module.
RUN src/node/build-node.sh Debug
# Copy everything else needed to run tests.
COPY lib/ lib/
COPY scripts/ scripts/
COPY tests/ tests/
# Switch to the non-root user.
RUN chown -R user .
USER user
# Default to running the Node tests
CMD ["node", "tests"]
ENV NPM_CONFIG_UNSAFE_PERM true

18
scripts/docker-test.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
# This is a wrapper script around ./scripts/test.sh which uses docker. The
# arguments are the same, as they are passed directly to test.sh.
# It can be used to locally check and debug the linux build process
# outside of CI.
set -e
./scripts/docker_build_wrapper.sh ci/realm-js:build .
exec docker run --rm \
-u $(id -u) \
-e HOME=/tmp \
-v $(pwd):/source \
-w /source \
ci/realm-js:build \
./scripts/test.sh $@

103
scripts/docker_build_wrapper.sh Executable file
View File

@ -0,0 +1,103 @@
#!/bin/bash
# This is a wrapper script around `docker build`. It provides a mechanism
# for using cached image layers from upstream repositories as well as an
# automatic push back to the docker registry.
set -e
script_path="$(pushd "$(dirname "$0")" >/dev/null; pwd)"
src_path="$(pushd "${script_path}/.." >/dev/null; pwd)"
die() { echo "$@" 1>&2 ; exit 1; }
info() { echo "===> $*"; }
docker_build() {
declare name="$1"; shift
declare path="$1"; shift
declare args="$*"
if [ "${DOCKER_REGISTRY}" != "" ]; then
remote_name="${DOCKER_REGISTRY}/${name}"
fi
info "Building ${name} image..."
if [ "${DOCKER_REGISTRY}" != "" ]; then
docker_pull "${remote_name}" && docker tag "${remote_name}" "${name}" || true
fi
old_id=$(docker images -q "${name}")
info "Old ${name} image id: ${old_id}"
if [ "${DOCKERFILE}" != "" ]; then
docker build ${args} -t "${name}" -f "${DOCKERFILE}" "${path}" || \
die "Building ${name} image failed"
else
docker build ${args} -t "${name}" "${path}" || \
die "Building ${name} image failed"
fi
new_id=$(docker images -q "${name}")
info "New ${name} image id: ${new_id}"
if [ "${DEBUG}" ] && [ "${new_id}" != "${old_id}" ]; then
info "History for old id $old_id:"
if [ "${old_id}" != "" ]; then
docker history "$old_id"
fi
info "History for new id $new_id:"
docker history "$new_id"
fi
if [ "${DOCKER_PUSH:-0}" != "0" ] && [ "${DOCKER_REGISTRY}" != "" ]; then
docker tag "${name}" "${remote_name}"
docker_push "${remote_name}"
fi
}
# Due to https://github.com/docker/docker/issues/20316, we use
# https://github.com/tonistiigi/buildcache to generate a cache of the layer
# metadata for later builds.
my_buildcache() {
if [ "$DOCKER_REGISTRY" != "" ]; then
docker_path="/var/lib/docker"
# Stupid hack for our AWS nodes, which have docker data on another volume
if [ -d "/mnt/docker" ]; then
docker_path="/mnt/docker"
fi
docker pull "${DOCKER_REGISTRY}/ci/buildcache" >/dev/null && \
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ${docker_path}:/var/lib/docker \
"${DOCKER_REGISTRY}/ci/buildcache" "$@"
fi
}
docker_pull() {
info "Attempting to pull '$1' image from registry..."
(
tmpdir=$(mktemp -d)
docker pull "$1"
(
# In addition, pull the cached metadata and load it (buildcache)
cd "${tmpdir}" && docker pull "$1-cache" && docker save "$1-cache" | \
tar -xf - && docker load -i ./*/layer.tar
)
rm -rf "${tmpdir}"
) || true
}
docker_push() {
info "Pushing '$1' image to registry..."
docker push "$1"
# Create a cache of the layer metdata we need and push it as an image
#docker rmi $1-cache 2>/dev/null || true
my_buildcache save -g /var/lib/docker "$1" | gunzip -c | \
docker import - "$1-cache" && \
docker push "$1-cache"
}
docker_build $@

View File

@ -23,12 +23,14 @@ if [ "$1" = 'node' ]; then
PLATFORM_TAG="node-osx-"
SYNC_PLATFORM_TAG="node-cocoa-"
CORE_DOWNLOAD_FILE="realm-core-node-osx-$REALM_CORE_VERSION.tar.gz"
SYNC_DOWNLOAD_FILE="realm-sync-$SYNC_PLATFORM_TAG$REALM_SYNC_VERSION.zip"
else
PLATFORM_TAG="node-linux-"
SYNC_PLATFORM_TAG="node-cocoa-"
CORE_DOWNLOAD_FILE="realm-core-node-linux-$REALM_CORE_VERSION.tar.gz"
SYNC_DOWNLOAD_FILE=""
fi
SYNC_DOWNLOAD_FILE="realm-sync-$SYNC_PLATFORM_TAG$REALM_SYNC_VERSION.zip"
SYNC_EXTRACT="unzip"
EXTRACTED_DIR="realm-sync-node-cocoa-$REALM_SYNC_VERSION"
else
@ -115,26 +117,27 @@ else
echo "The core library seems to be up to date."
fi
if [ ! -e "vendor/$SYNC_DIR" ]; then
download_core $SYNC_DIR $REALM_SYNC_VERSION $SYNC_DOWNLOAD_FILE sync "$SYNC_EXTRACT" $EXTRACTED_DIR
elif [ -d "vendor/$SYNC_DIR" -a -d ../realm-sync -a ! -L "vendor/$SYNC_DIR" ]; then
# Allow newer versions than expected for local builds as testing
# with unreleased versions is one of the reasons to use a local build
if ! check_release_notes "vendor/$SYNC_DIR/version.txt"; then
die "Local build of sync is out of date."
if [ -n "$SYNC_DOWNLOAD_FILE" ];then
if [ ! -e "vendor/$SYNC_DIR" ]; then
download_core $SYNC_DIR $REALM_SYNC_VERSION $SYNC_DOWNLOAD_FILE sync "$SYNC_EXTRACT" $EXTRACTED_DIR
elif [ -d "vendor/$SYNC_DIR" -a -d ../realm-sync -a ! -L "vendor/$SYNC_DIR" ]; then
# Allow newer versions than expected for local builds as testing
# with unreleased versions is one of the reasons to use a local build
if ! check_release_notes "vendor/$SYNC_DIR/version.txt"; then
die "Local build of sync is out of date."
else
echo "The sync library seems to be up to date."
fi
elif [ ! -L "vendor/$SYNC_DIR" ]; then
echo "vendor/$SYNC_DIR is not a symlink. Deleting..."
rm -rf "vendor/$SYNC_DIR"
download_core $SYNC_DIR $REALM_SYNC_VERSION $SYNC_DOWNLOAD_FILE sync "$SYNC_EXTRACT" $EXTRACTED_DIR
# With a prebuilt version we only want to check the first non-empty
# line so that checking out an older commit will download the
# appropriate version of core if the already-present version is too new
elif ! grep -m 1 . "vendor/$SYNC_DIR/version.txt" | check_release_notes; then
download_core $SYNC_DIR $REALM_SYNC_VERSION $SYNC_DOWNLOAD_FILE sync "$SYNC_EXTRACT" $EXTRACTED_DIR
else
echo "The sync library seems to be up to date."
fi
elif [ ! -L "vendor/$SYNC_DIR" ]; then
echo "vendor/$SYNC_DIR is not a symlink. Deleting..."
rm -rf "vendor/$SYNC_DIR"
download_core $SYNC_DIR $REALM_SYNC_VERSION $SYNC_DOWNLOAD_FILE sync "$SYNC_EXTRACT" $EXTRACTED_DIR
# With a prebuilt version we only want to check the first non-empty
# line so that checking out an older commit will download the
# appropriate version of core if the already-present version is too new
elif ! grep -m 1 . "vendor/$SYNC_DIR/version.txt" | check_release_notes; then
download_core $SYNC_DIR $REALM_SYNC_VERSION $SYNC_DOWNLOAD_FILE sync "$SYNC_EXTRACT" $EXTRACTED_DIR
else
echo "The sync library seems to be up to date."
fi

View File

@ -185,8 +185,13 @@ case "$TARGET" in
cat tests.xml
;;
"node")
download_server
start_server
if [ "$(uname)" = 'Darwin' ]; then
download_server
start_server
npm_tests_cmd="npm run test"
else
npm_tests_cmd="npm run test-nosync"
fi
npm install --build-from-source
# Change to a temp directory.
@ -195,7 +200,7 @@ case "$TARGET" in
pushd "$SRCROOT/tests"
npm install
npm run test
eval $npm_tests_cmd
popd
stop_server
;;

View File

@ -106,10 +106,24 @@ module.exports = {
assertTrue: function(condition, errorMessage) {
if (!condition) {
throw new TestFailureError(errorMessage || 'Condition expected to be true');
throw new TestFailureError(errorMessage || `Condition ${condition} expected to be true`);
}
},
assertInstanceOf: function(object, type, errorMessage) {
if (!(object instanceof type)) {
throw new TestFailureError(errorMessage || `Object ${object} expected to be of type ${type}`);
}
},
assertType: function(value, type) {
this.assertEqual(typeof value, type, `Value ${value} expected to be of type ${type}`);
},
assertUndefined: function(value) {
this.assertEqual(value, undefined, `Value ${value} expected to be undefined`);
},
isNode: function() {
// eslint-disable-next-line no-undef
return typeof process == 'object' && Object.prototype.toString.call(process) == '[object process]';

View File

@ -31,18 +31,46 @@ function uuid() {
});
}
function assertIsUser(user, isAdmin) {
TestCase.assertType(user, 'object');
TestCase.assertType(user.token, 'string');
TestCase.assertType(user.identity, 'string');
TestCase.assertInstanceOf(user, Realm.Sync.User);
if (isAdmin !== undefined) {
TestCase.assertEqual(user.isAdmin, isAdmin);
}
}
function assertIsError(error, code) {
TestCase.assertInstanceOf(error, Error, 'The API should return an Error');
if (code) {
TestCase.assertEqual(error.code, code);
}
}
function assertIsAuthError(error, code, type) {
TestCase.assertInstanceOf(error, Realm.Sync.AuthError, 'The API should return an AuthError');
if (code) {
TestCase.assertEqual(error.code, code);
}
if (type) {
TestCase.assertEqual(error.type, type);
}
}
module.exports = {
testRegisterUser() {
var username = uuid();
return new Promise((resolve, reject) => {
Realm.Sync.User.register('http://localhost:9080', username, 'password', (error, user) => {
TestCase.assertEqual(typeof user, 'object');
TestCase.assertEqual(typeof user.token, 'string');
TestCase.assertEqual(typeof user.identity, 'string');
TestCase.assertEqual(user.isAdmin, false);
if (error) {
reject(error);
}
assertIsUser(user);
// Can we open a realm with the registered user?
var realm = new Realm({sync: {user: user, url: 'realm://localhost:9080/~/test'}});
TestCase.assertNotEqual(realm instanceof Realm);
TestCase.assertInstanceOf(realm, Realm);
resolve();
});
});
@ -52,26 +80,48 @@ module.exports = {
var username = uuid();
return new Promise((resolve, reject) => {
Realm.Sync.User.register('http://localhost:9080', username, 'password', (error, user) => {
TestCase.assertEqual(typeof user, 'object');
if (error) {
reject(error);
}
assertIsUser(user);
Realm.Sync.User.register('http://localhost:9080', username, 'password', (error, user) => {
TestCase.assertTrue(error instanceof Realm.Sync.AuthError);
TestCase.assertEqual(error.code, 613);
TestCase.assertEqual(error.type, 'https://realm.io/docs/object-server/problems/existing-account');
TestCase.assertEqual(user, undefined);
assertIsAuthError(error, 613, 'https://realm.io/docs/object-server/problems/existing-account');
TestCase.assertUndefined(user);
resolve();
});
});
});
},
testRegisterInvalidUsername() {
var username = uuid();
testRegisterMissingUsername() {
return new Promise((resolve, reject) => {
Realm.Sync.User.register('http://localhost:9080', undefined, 'password', (error, user) => {
TestCase.assertTrue(error instanceof Realm.Sync.AuthError);
TestCase.assertEqual(error.code, 602);
TestCase.assertEqual(error.type, 'https://realm.io/docs/object-server/problems/missing-parameters');
TestCase.assertEqual(user, undefined);
assertIsAuthError(error, 602, 'https://realm.io/docs/object-server/problems/missing-parameters');
TestCase.assertUndefined(user);
resolve();
});
});
},
testRegisterMissingPassword() {
var username = uuid();
return new Promise((resolve, reject) => {
Realm.Sync.User.register('http://localhost:9080', username, undefined, (error, user) => {
assertIsAuthError(error, 602, 'https://realm.io/docs/object-server/problems/missing-parameters');
TestCase.assertUndefined(user);
resolve();
});
});
},
testRegisterServerOffline() {
var username = uuid();
return new Promise((resolve, reject) => {
// Because it waits for answer this takes some time..
Realm.Sync.User.register('http://fake_host.local', username, 'password', (error, user) => {
assertIsError(error, 'ECONNRESET');
TestCase.assertUndefined(user);
resolve();
});
});
@ -80,25 +130,62 @@ module.exports = {
testLogin() {
var username = uuid();
return new Promise((resolve, reject) => {
// Create user, logout the new user, then login
Realm.Sync.User.register('http://localhost:9080', username, 'password', (error, user) => {
user.logout();
//TestCase.assertEqual(Realm.Sync.User.all.length, 0);
Realm.Sync.User.login('http://localhost:9080', username, 'password', (error, user) => {
TestCase.assertEqual(typeof user, 'object');
TestCase.assertEqual(typeof user.token, 'string');
TestCase.assertEqual(typeof user.identity, 'string');
TestCase.assertEqual(user.isAdmin, false);
assertIsUser(user);
var realm = new Realm({sync: {user: user, url: 'realm://localhost:9080/~/test'}});
TestCase.assertNotEqual(realm instanceof Realm);
//TestCase.assertEqual(Realm.Sync.User.all.length, 1);
TestCase.assertInstanceOf(realm, Realm);
resolve();
});
});
});
},
testLoginMissingUsername() {
return new Promise((resolve, reject) => {
Realm.Sync.User.login('http://localhost:9080', undefined, 'password', (error, user) => {
assertIsAuthError(error, 602, 'https://realm.io/docs/object-server/problems/missing-parameters');
TestCase.assertUndefined(user);
resolve();
});
});
},
testLoginMissingPassword() {
var username = uuid();
return new Promise((resolve, reject) => {
Realm.Sync.User.login('http://localhost:9080', username, undefined, (error, user) => {
assertIsAuthError(error, 602, 'https://realm.io/docs/object-server/problems/missing-parameters');
TestCase.assertUndefined(user);
resolve();
});
});
},
testLoginNonExistingUser() {
return new Promise((resolve, reject) => {
Realm.Sync.User.login('http://localhost:9080', 'does_not', 'exist', (error, user) => {
assertIsAuthError(error, 612, 'https://realm.io/docs/object-server/problems/unknown-account');
TestCase.assertUndefined(user);
resolve();
});
});
},
testLoginServerOffline() {
var username = uuid();
return new Promise((resolve, reject) => {
// Because it waits for answer this takes some time..
Realm.Sync.User.register('http://fake_host.local', username, 'password', (error, user) => {
assertIsError(error, 'ECONNRESET');
TestCase.assertUndefined(user);
resolve();
});
});
},
};

View File

@ -25,6 +25,7 @@ const Realm = require('realm');
const userTests = require('../js/user-tests');
describe('SyncTests', () => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
beforeEach(() => Realm.clearTestState());
afterEach(() => Realm.clearTestState());