Merge branch '2.0.x' of github.com:realm/realm-js into kneth/v1_v2-upgrade

This commit is contained in:
Kenneth Geisshirt 2017-09-23 00:18:42 +02:00
commit a717b291e8
18 changed files with 140 additions and 310 deletions

1
.gitignore vendored
View File

@ -47,6 +47,7 @@ tsconfig.json
# Tests # Tests
object-server-for-testing/ object-server-for-testing/
realm-object-server-data/
tests/realm-object-server/ tests/realm-object-server/
packager_out.txt packager_out.txt
build.log.* build.log.*

View File

@ -1,10 +1,11 @@
2.0.0 Release notes 2.0.0-rc10 Release notes (2017-9-19)
============================================================= =============================================================
### Breaking changes ### Breaking changes
* Updating core, sync, object store. * Updating core (3.2.1), sync (2.0.0-rc23 - packaged under 2.0.0-rc22), object store.
### Enhancements ### Enhancements
* Throw exception with recovery path when upgrading from 1.x to 2.x. * Throw exception with recovery path when upgrading from 1.x to 2.x.
* Add support for sorting Lists and Results on values from linked objects.
### Bug fixes ### Bug fixes
* None * None

View File

@ -1,5 +1,5 @@
PACKAGE_NAME=realm-js PACKAGE_NAME=realm-js
VERSION=2.0.0-rc6 VERSION=2.0.0-rc10
REALM_CORE_VERSION=3.1.0 REALM_CORE_VERSION=3.2.1
REALM_SYNC_VERSION=2.0.0-rc18 REALM_SYNC_VERSION=2.0.0-rc22
REALM_OBJECT_SERVER_VERSION=2.0.0-alpha.22 REALM_OBJECT_SERVER_VERSION=2.0.0-alpha.32

View File

@ -1,7 +1,7 @@
{ {
"name": "realm", "name": "realm",
"description": "Realm is a mobile database: an alternative to SQLite and key-value stores", "description": "Realm is a mobile database: an alternative to SQLite and key-value stores",
"version": "2.0.0-rc6", "version": "2.0.0-rc10",
"license": "Apache-2.0", "license": "Apache-2.0",
"homepage": "https://realm.io", "homepage": "https://realm.io",
"keywords": [ "keywords": [
@ -85,6 +85,7 @@
"nan": "^2.3.3", "nan": "^2.3.3",
"node-fetch": "^1.6.3", "node-fetch": "^1.6.3",
"node-pre-gyp": "^0.6.36", "node-pre-gyp": "^0.6.36",
"prop-types": "^15.5.10",
"progress": "^2.0.0", "progress": "^2.0.0",
"request": "^2.78.0", "request": "^2.78.0",
"stream-counter": "^1.0.0", "stream-counter": "^1.0.0",

View File

@ -1,27 +1,25 @@
#!/bin/bash #!/bin/bash
exit 0
set -eo pipefail set -eo pipefail
[ "$(uname -s)" != "Darwin" ] && exit [ "$(uname -s)" != "Darwin" ] && exit
. dependencies.list . dependencies.list
if [ -f object-server-for-testing/node_modules/realm-object-server-developer/package.json ]; then #use existing server if same version
if grep -q "\"version\": \"$REALM_OBJECT_SERVER_VERSION\"" object-server-for-testing/node_modules/realm-object-server-developer/package.json; then if [ -f node_modules/realm-object-server/package.json ]; then
echo -e "yes\n" | object-server-for-testing/reset-server-realms.command if grep -q "\"version\": \"$REALM_OBJECT_SERVER_VERSION\"" node_modules/realm-object-server/package.json; then
# echo -e "yes\n" | object-server-for-testing/reset-server-realms.command
rm -rf realm-object-server-data
rm -rf realm-object-server
exit exit
fi fi
fi fi
object_server_bundle="realm-object-server-bundled_node_darwin-developer-$REALM_OBJECT_SERVER_VERSION.tar.gz" echo "Uninstalling old version of realm-object-server"
echo "Downloading https://static.realm.io/downloads/object-server/$object_server_bundle" npm uninstall realm-object-server
curl -f -L "https://static.realm.io/downloads/object-server/$object_server_bundle" -o "$object_server_bundle"
rm -rf object-server-for-testing
mkdir object-server-for-testing
tar -C object-server-for-testing -xf "$object_server_bundle"
rm "$object_server_bundle"
echo "enterprise:\n skip_setup: true\n" >> "object-server-for-testing/object-server/configuration.yml" echo "Installing realm-object-server version: " $REALM_OBJECT_SERVER_VERSION
# Change to a "warn" level npm install realm-object-server@$REALM_OBJECT_SERVER_VERSION
sed -i -- "s/# level: 'info'/level: 'warn'/g" object-server-for-testing/object-server/configuration.yml
touch "object-server-for-testing/object-server/do_not_open_browser"

View File

@ -2,5 +2,5 @@
set -o pipefail set -o pipefail
set -e set -e
echo $(pwd) echo "Downloading and starting ROS. Current directory: " $(pwd)
sh scripts/download-object-server.sh && sh object-server-for-testing/start-object-server.command -f && echo \"Server PID: $!\" sh scripts/download-object-server.sh && ./node_modules/.bin/ros start --data realm-object-server-data && echo \"Server PID: $!\"

View File

@ -44,21 +44,27 @@ LOGCAT_OUT="$SRCROOT/logcat_out.txt"
download_server() { download_server() {
echo "test.sh: downloading ROS"
./scripts/download-object-server.sh ./scripts/download-object-server.sh
} }
start_server() { start_server() {
echo "test.sh: starting ROS"
#disabled ROS logging #disabled ROS logging
sh ./object-server-for-testing/start-object-server.command &> /dev/null & # sh ./object-server-for-testing/start-object-server.command &> /dev/null &
#enabled ROS logging #enabled ROS logging
#sh ./object-server-for-testing/start-object-server.command & #sh ./object-server-for-testing/start-object-server.command &
./node_modules/.bin/ros start --data realm-object-server-data &
SERVER_PID=$! SERVER_PID=$!
echo ROS PID: ${SERVER_PID}
} }
stop_server() { stop_server() {
echo stopping server
if [[ ${SERVER_PID} -gt 0 ]] ; then if [[ ${SERVER_PID} -gt 0 ]] ; then
kill -9 ${SERVER_PID} echo server is running. killing it
kill -9 ${SERVER_PID} || true
fi fi
} }
@ -241,7 +247,7 @@ elif [ -x "$(command -v brew)" ] && [ -f "$(brew --prefix nvm)/nvm.sh" ]; then
# TODO: change the mac slaves to use manual nvm installation # TODO: change the mac slaves to use manual nvm installation
. "$(brew --prefix nvm)/nvm.sh" . "$(brew --prefix nvm)/nvm.sh"
fi fi
[[ "$(command -v nvm)" ]] && nvm install 6.5.0 && nvm use 6.5.0 || true [[ "$(command -v nvm)" ]] && nvm install 7.10.0 && nvm use 7.10.0 || true
# Remove cached packages # Remove cached packages
rm -rf ~/.yarn-cache/npm-realm-* rm -rf ~/.yarn-cache/npm-realm-*
@ -335,11 +341,15 @@ case "$TARGET" in
;; ;;
"node") "node")
npm run check-environment npm run check-environment
if [ "$(uname)" = 'Darwin' ]; then if [ "$(uname)" = 'Darwin' ]; then
echo "downloading server"
download_server download_server
echo "starting server"
start_server start_server
npm_tests_cmd="npm run test" npm_tests_cmd="npm run test"
npm install --build-from-source=realm --realm_enable_sync npm install --build-from-source=realm --realm_enable_sync
else else
npm_tests_cmd="npm run test" npm_tests_cmd="npm run test"
npm install --build-from-source=realm npm install --build-from-source=realm
@ -430,14 +440,6 @@ case "$TARGET" in
echo -e "enterprise:\n skip_setup: true\n" >> "tests/sync-bundle/object-server/configuration.yml" echo -e "enterprise:\n skip_setup: true\n" >> "tests/sync-bundle/object-server/configuration.yml"
touch "tests/sync-bundle/object-server/do_not_open_browser" touch "tests/sync-bundle/object-server/do_not_open_browser"
;; ;;
"object-server-integration")
echo -e "yes\n" | ./tests/sync-bundle/reset-server-realms.command
pushd "$SRCROOT/tests"
npm install
npm run test-sync-integration
popd
;;
*) *)
echo "Invalid target '${TARGET}'" echo "Invalid target '${TARGET}'"
exit 1 exit 1

View File

@ -989,11 +989,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
<<<<<<< HEAD
CURRENT_PROJECT_VERSION = 2.0.0; CURRENT_PROJECT_VERSION = 2.0.0;
=======
CURRENT_PROJECT_VERSION = 1.12.0;
>>>>>>> b3ff7ada624f9fcb6d6ad6abf19e862059513857
CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh"; CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -1057,11 +1053,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
<<<<<<< HEAD
CURRENT_PROJECT_VERSION = 2.0.0; CURRENT_PROJECT_VERSION = 2.0.0;
=======
CURRENT_PROJECT_VERSION = 1.12.0;
>>>>>>> b3ff7ada624f9fcb6d6ad6abf19e862059513857
CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh"; CXX = "$(SRCROOT)/../scripts/ccache-clang++.sh";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO; ENABLE_NS_ASSERTIONS = NO;

View File

@ -248,10 +248,8 @@ void ListClass<T>::filtered(ContextType ctx, FunctionType, ObjectType this_objec
template<typename T> template<typename T>
void ListClass<T>::sorted(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { void ListClass<T>::sorted(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1, 2);
auto list = get_internal<T, ListClass<T>>(this_object); auto list = get_internal<T, ListClass<T>>(this_object);
return_value.set(ResultsClass<T>::create_sorted(ctx, *list, argc, arguments)); return_value.set(ResultsClass<T>::create_instance(ctx, list->sort(ResultsClass<T>::get_keypaths(ctx, argc, arguments))));
} }
template<typename T> template<typename T>

View File

@ -63,8 +63,7 @@ struct ResultsClass : ClassDefinition<T, realm::js::Results<T>, CollectionClass<
template<typename U> template<typename U>
static ObjectType create_filtered(ContextType, const U &, size_t, const ValueType[]); static ObjectType create_filtered(ContextType, const U &, size_t, const ValueType[]);
template<typename U> static std::vector<std::pair<std::string, bool>> get_keypaths(ContextType, size_t, const ValueType[]);
static ObjectType create_sorted(ContextType, const U &, size_t, const ValueType[]);
static void get_length(ContextType, ObjectType, ReturnValue &); static void get_length(ContextType, ObjectType, ReturnValue &);
static void get_index(ContextType, ObjectType, uint32_t, ReturnValue &); static void get_index(ContextType, ObjectType, uint32_t, ReturnValue &);
@ -132,64 +131,37 @@ typename T::Object ResultsClass<T>::create_filtered(ContextType ctx, const U &co
} }
template<typename T> template<typename T>
template<typename U> std::vector<std::pair<std::string, bool>>
typename T::Object ResultsClass<T>::create_sorted(ContextType ctx, const U &collection, size_t argc, const ValueType arguments[]) { ResultsClass<T>::get_keypaths(ContextType ctx, size_t argc, const ValueType arguments[]) {
auto const &realm = collection.get_realm(); validate_argument_count(argc, 1, 2);
auto const &object_schema = collection.get_object_schema();
std::vector<std::string> prop_names;
std::vector<bool> ascending;
size_t prop_count;
if (Value::is_array(ctx, arguments[0])) { std::vector<std::pair<std::string, bool>> sort_order;
if (argc > 0 && Value::is_array(ctx, arguments[0])) {
validate_argument_count(argc, 1, "Second argument is not allowed if passed an array of sort descriptors"); validate_argument_count(argc, 1, "Second argument is not allowed if passed an array of sort descriptors");
ObjectType js_prop_names = Value::validated_to_object(ctx, arguments[0]); ObjectType js_prop_names = Value::validated_to_object(ctx, arguments[0]);
prop_count = Object::validated_get_length(ctx, js_prop_names); size_t prop_count = Object::validated_get_length(ctx, js_prop_names);
if (!prop_count) { sort_order.reserve(prop_count);
throw std::invalid_argument("Sort descriptor array must not be empty");
}
prop_names.resize(prop_count);
ascending.resize(prop_count);
for (unsigned int i = 0; i < prop_count; i++) { for (unsigned int i = 0; i < prop_count; i++) {
ValueType value = Object::validated_get_property(ctx, js_prop_names, i); ValueType value = Object::validated_get_property(ctx, js_prop_names, i);
if (Value::is_array(ctx, value)) { if (Value::is_array(ctx, value)) {
ObjectType array = Value::to_array(ctx, value); ObjectType array = Value::to_array(ctx, value);
prop_names[i] = Object::validated_get_string(ctx, array, 0); sort_order.emplace_back(Object::validated_get_string(ctx, array, 0),
ascending[i] = !Object::validated_get_boolean(ctx, array, 1); !Object::validated_get_boolean(ctx, array, 1));
} }
else { else {
prop_names[i] = Value::validated_to_string(ctx, value); sort_order.emplace_back(Value::validated_to_string(ctx, value), true);
ascending[i] = true;
} }
} }
} }
else { else {
validate_argument_count(argc, 1, 2); sort_order.emplace_back(Value::validated_to_string(ctx, arguments[0]),
argc == 1 || !Value::to_boolean(ctx, arguments[1]));
prop_count = 1;
prop_names.push_back(Value::validated_to_string(ctx, arguments[0]));
ascending.push_back(argc == 1 ? true : !Value::to_boolean(ctx, arguments[1]));
} }
return sort_order;
std::vector<std::vector<size_t>> columns;
columns.reserve(prop_count);
for (std::string &prop_name : prop_names) {
const Property *prop = object_schema.property_for_name(prop_name);
if (!prop) {
throw std::runtime_error("Property '" + prop_name + "' does not exist on object type '" + object_schema.name + "'");
}
columns.push_back({prop->table_column});
}
auto table = realm::ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);
DescriptorOrdering ordering;
ordering.append_sort({*table, std::move(columns), std::move(ascending)});
auto results = new realm::js::Results<T>(realm, collection.get_query(), std::move(ordering));
return create_object<T, ResultsClass<T>>(ctx, results);
} }
template<typename T> template<typename T>
@ -231,10 +203,8 @@ void ResultsClass<T>::filtered(ContextType ctx, FunctionType, ObjectType this_ob
template<typename T> template<typename T>
void ResultsClass<T>::sorted(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) { void ResultsClass<T>::sorted(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 1, 2);
auto results = get_internal<T, ResultsClass<T>>(this_object); auto results = get_internal<T, ResultsClass<T>>(this_object);
return_value.set(create_sorted(ctx, *results, argc, arguments)); return_value.set(ResultsClass<T>::create_instance(ctx, results->sort(ResultsClass<T>::get_keypaths(ctx, argc, arguments))));
} }
template<typename T> template<typename T>

View File

@ -2,92 +2,28 @@
function node_require(module) { function node_require(module) {
return require(module); return require(module);
} }
let fs = node_require("fs");
let path = node_require("path");
var Realm = node_require('realm'); var Realm = node_require('realm');
const DEFAULT_ADMIN_TOKEN_PATH = path.join(__dirname, "..", "..", "object-server-for-testing", "admin_token.base64"); const adminName = "realm-admin"
const ADMIN_TOKEN_PATH = process.env.ADMIN_TOKEN_PATH || DEFAULT_ADMIN_TOKEN_PATH; const password = '';
function getAdminToken() {
if (fs.existsSync(ADMIN_TOKEN_PATH)) {
return fs.readFileSync(ADMIN_TOKEN_PATH, 'utf-8');
} else {
throw new Error("Missing the file with an admin token: " + ADMIN_TOKEN_PATH);
}
}
function random(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const newAdminName = 'admin' + random(1, 100000);
const password = '123';
exports.createAdminUser = function () { exports.createAdminUser = function () {
let nonTokenUser, userIdentity, admin_token_user
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
Realm.Sync.User.register('http://localhost:9080', newAdminName, password, (error, user) => { Realm.Sync.User.login('http://localhost:9080', adminName, password, (error, user) => {
if (error) { if (error) {
reject(error); reject(error);
return; return;
} }
nonTokenUser = user
userIdentity = user.identity; if (!user.isAdmin) {
user.logout(); reject(adminName + " user is not an admin user on this server");
admin_token_user = Realm.Sync.User.adminUser(getAdminToken(), 'http://localhost:9080');
const config = {
sync: {
user: admin_token_user,
url: 'realm://localhost:9080/__admin',
error: err => {
reject(new Error('Error opening __admin realm error:' + err.user + ' url:' + err.url + ' state:' + err.state));
}
}
};
resolve(Realm.open(config));
});
}).then(realm => {
let pendingAdminUser = realm.objectForPrimaryKey('User', userIdentity);
realm.write(() => {
pendingAdminUser.isAdmin = true;
});
admin_token_user.logout();
}).then(() => {
return new Promise((resolve, reject) => {
let isAdminRetryCounter = 0;
let waitForServerToUpdateAdminUser = function () {
isAdminRetryCounter++;
if (isAdminRetryCounter > 10) {
reject("admin-user-helper: Create admin user timeout");
return;
}
Realm.Sync.User.login('http://localhost:9080', newAdminName, password, (error, newAdminUser) => {
if (error) {
reject(error);
return;
}
let isAdmin = newAdminUser.isAdmin;
nonTokenUser.logout();
if (!isAdmin) {
setTimeout(waitForServerToUpdateAdminUser, 500);
return;
}
resolve({
username: newAdminName,
password
});
});
} }
waitForServerToUpdateAdminUser();
resolve({
username: adminName,
password
});
}); });
}); });
} }

View File

@ -71,7 +71,7 @@ module.exports = {
}, },
}; };
if (Realm.Sync) { if (global.enableSyncTests) {
module.exports.testEncryptionWithSync = function() { module.exports.testEncryptionWithSync = function() {
new Realm({ new Realm({
encryptionKey: new Int8Array(64), encryptionKey: new Int8Array(64),

View File

@ -18,7 +18,10 @@
'use strict'; 'use strict';
var Realm = require('realm'); const Realm = require('realm');
// FIXME: sync testing needs to be updated for ROS 2.0
global.enableSyncTests = Realm.Sync && false;
var TESTS = { var TESTS = {
ListTests: require('./list-tests'), ListTests: require('./list-tests'),
@ -37,14 +40,15 @@ if (!(typeof process === 'object' && process.platform === 'win32')) {
} }
// If sync is enabled, run the sync tests // If sync is enabled, run the sync tests
if (Realm.Sync) { if (global.enableSyncTests) {
TESTS.UserTests = require('./user-tests'); TESTS.UserTests = require('./user-tests');
TESTS.SessionTests = require('./session-tests'); TESTS.SessionTests = require('./session-tests');
// FIXME: Permission tests currently fail in chrome debugging mode. // FIXME: Permission tests currently fail in chrome debugging mode.
if (typeof navigator === 'undefined' || if (typeof navigator === 'undefined' ||
!/Chrome/.test(navigator.userAgent)) { // eslint-disable-line no-undef !/Chrome/.test(navigator.userAgent)) { // eslint-disable-line no-undef
TESTS.PermissionTests = require('./permission-tests');
TESTS.PermissionTests = require('./permission-tests');
} }
} }
@ -53,7 +57,7 @@ function node_require(module) { return require(module); }
// If on node, run the async tests // If on node, run the async tests
const isNodeProcess = typeof process === 'object' && process + '' === '[object process]'; const isNodeProcess = typeof process === 'object' && process + '' === '[object process]';
if (isNodeProcess) { if (isNodeProcess) {
//TESTS.AsyncTests = node_require('./async-tests'); TESTS.AsyncTests = node_require('./async-tests');
} }
var SPECIAL_METHODS = { var SPECIAL_METHODS = {
@ -82,7 +86,7 @@ exports.registerTests = function(tests) {
}; };
exports.prepare = function(done) { exports.prepare = function(done) {
if (!Realm.Sync || !isNodeProcess || global.testAdminUserInfo) { if (!global.enableSyncTests || !isNodeProcess || global.testAdminUserInfo) {
done(); done();
return; return;
} }

View File

@ -511,32 +511,46 @@ module.exports = {
}, },
testListSorted: function() { testListSorted: function() {
var realm = new Realm({schema: [schemas.PersonObject, schemas.PersonList]}); const schema = [
var list; {name: 'Target', properties: {value: 'int'}},
{name: 'Mid', properties: {value: 'int', link: 'Target'}},
{name: 'List', properties: {list: {type: 'list', objectType: 'Mid'}}},
];
const realm = new Realm({schema: schema});
realm.write(function() { let list;
var object = realm.create('PersonList', {list: [ realm.write(() => {
{name: 'Ari', age: 10}, list = realm.create('List', {list: [
{name: 'Tim', age: 11}, {value: 3, link: {value: 1}},
{name: 'Bjarne', age: 12}, {value: 1, link: {value: 3}},
{name: 'Alex', age: 12, married: true} {value: 2, link: {value: 2}},
]}).list;
realm.create('List', {list: [
{value: 4, link: {value: 4}},
]}); ]});
realm.create('PersonObject', {name: 'NotInList', age: 10});
list = object.list;
}); });
var names = function(results) { const values = (results) => results.map((o) => o.value);
return results.map(function(object) {
return object.name;
});
};
var objects = list.sorted('name', true); TestCase.assertThrows(() => list.sorted());
TestCase.assertArraysEqual(names(objects), ['Tim', 'Bjarne', 'Ari', 'Alex']); TestCase.assertThrows(() => list.sorted('nonexistent property'));
TestCase.assertThrows(() => list.sorted('link'));
objects = list.sorted(['age', 'name']); TestCase.assertArraysEqual(values(list.sorted([])), [3, 1, 2]);
TestCase.assertArraysEqual(names(objects), ['Ari', 'Tim', 'Alex', 'Bjarne']);
TestCase.assertArraysEqual(values(list.sorted('value')), [1, 2, 3]);
TestCase.assertArraysEqual(values(list.sorted('value', false)), [1, 2, 3]);
TestCase.assertArraysEqual(values(list.sorted('value', true)), [3, 2, 1]);
TestCase.assertArraysEqual(values(list.sorted(['value'])), [1, 2, 3]);
TestCase.assertArraysEqual(values(list.sorted([['value', false]])), [1, 2, 3]);
TestCase.assertArraysEqual(values(list.sorted([['value', true]])), [3, 2, 1]);
TestCase.assertArraysEqual(values(list.sorted('link.value')), [3, 2, 1]);
TestCase.assertArraysEqual(values(list.sorted('link.value', false)), [3, 2, 1]);
TestCase.assertArraysEqual(values(list.sorted('link.value', true)), [1, 2, 3]);
TestCase.assertArraysEqual(values(list.sorted(['link.value'])), [3, 2, 1]);
TestCase.assertArraysEqual(values(list.sorted([['link.value', false]])), [3, 2, 1]);
TestCase.assertArraysEqual(values(list.sorted([['link.value', true]])), [1, 2, 3]);
}, },
testArrayMethods: function() { testArrayMethods: function() {

View File

@ -206,6 +206,9 @@ module.exports = {
}); });
}; };
objects = objects.sorted([]);
TestCase.assertArraysEqual(primaries(objects), [2, 3, 1, 4, 0]);
objects = objects.sorted('primaryCol'); objects = objects.sorted('primaryCol');
TestCase.assertArraysEqual(primaries(objects), [0, 1, 2, 3, 4]); TestCase.assertArraysEqual(primaries(objects), [0, 1, 2, 3, 4]);
@ -242,9 +245,6 @@ module.exports = {
TestCase.assertThrows(function() { TestCase.assertThrows(function() {
objects.sorted([1]); objects.sorted([1]);
}); });
TestCase.assertThrows(function() {
objects.sorted([]);
});
TestCase.assertThrows(function() { TestCase.assertThrows(function() {
objects.sorted('fish'); objects.sorted('fish');
}); });

View File

@ -55,13 +55,13 @@ function assertIsError(error, message) {
} }
} }
function assertIsAuthError(error, code, type) { function assertIsAuthError(error, code, title) {
TestCase.assertInstanceOf(error, Realm.Sync.AuthError, 'The API should return an AuthError'); TestCase.assertInstanceOf(error, Realm.Sync.AuthError, 'The API should return an AuthError');
if (code) { if (code) {
TestCase.assertEqual(error.code, code); TestCase.assertEqual(error.code, code);
} }
if (type) { if (title) {
TestCase.assertEqual(error.type, type); TestCase.assertEqual(error.title, title);
} }
} }
@ -123,13 +123,20 @@ module.exports = {
testRegisterExistingUser() { testRegisterExistingUser() {
var username = uuid(); var username = uuid();
return callbackTest((callback) => Realm.Sync.User.register('http://localhost:9080', username, 'password', callback), (error, user) => { return new Promise((resolve, reject) => {
failOnError(error);
assertIsUser(user);
Realm.Sync.User.register('http://localhost:9080', username, 'password', (error, user) => { Realm.Sync.User.register('http://localhost:9080', username, 'password', (error, user) => {
assertIsAuthError(error, 611, 'https://realm.io/docs/object-server/problems/invalid-credentials'); failOnError(error);
TestCase.assertUndefined(user); assertIsUser(user);
Realm.Sync.User.register('http://localhost:9080', username, 'password', (error, user) => {
try {
assertIsAuthError(error, 613, "The account cannot be registered as it exists already.");
TestCase.assertUndefined(user);
resolve();
} catch(e) {
reject(e);
}
});
}); });
}); });
}, },
@ -202,7 +209,7 @@ module.exports = {
testLoginNonExistingUser() { testLoginNonExistingUser() {
return callbackTest((callback) => Realm.Sync.User.login('http://localhost:9080', 'does_not', 'exist', callback), (error, user) => { return callbackTest((callback) => Realm.Sync.User.login('http://localhost:9080', 'does_not', 'exist', callback), (error, user) => {
assertIsAuthError(error, 611, 'https://realm.io/docs/object-server/problems/invalid-credentials'); assertIsAuthError(error, 611, "The provided credentials are invalid.");
TestCase.assertUndefined(user); TestCase.assertUndefined(user);
}); });
}, },
@ -359,7 +366,12 @@ module.exports = {
reject("Retrieving not existing account should fail"); reject("Retrieving not existing account should fail");
}) })
.catch(e => { .catch(e => {
TestCase.assertEqual(e.code, 404); try {
TestCase.assertEqual(e.code, 404);
}
catch (e) {
reject(e);
}
resolve() resolve()
}); });
}) })

View File

@ -15,7 +15,7 @@
}, },
"scripts": { "scripts": {
"check-typescript" : "tsc --noEmit --alwaysStrict ./../lib/index.d.ts", "check-typescript" : "tsc --noEmit --alwaysStrict ./../lib/index.d.ts",
"test": "npm run check-typescript && jasmine spec/unit_tests.js", "js-tests" : "jasmine spec/unit_tests.js",
"test-sync-integration": "npm run check-typescript && jasmine spec/sync_integration_tests.js" "test": "npm run check-typescript && npm run js-tests"
} }
} }

View File

@ -1,99 +0,0 @@
"use strict";
const spawn = require("child_process").spawn;
const readline = require("readline");
const fs = require("fs");
const Realm = require("realm");
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
describe('Sync Integration', () => {
beforeEach(function(done) {
this.objectServer = spawn("sync-bundle/start-object-server.command");
this.objectServer.once("close", (code) => {
if (typeof code === "number" && code != 0) {
console.error(`Object Server exited with code ${code}`);
process.exit(-1);
}
});
this.rl = readline.createInterface({ input: this.objectServer.stdout });
this.rl.on("line", (line) => {
var match;
if ((match = line.match(/Connection\[1\]: Session\[1\]: Received: BIND\(server_path='\/(.+)',/))) {
var adminUser = Realm.Sync.User.adminUser(fs.readFileSync("sync-bundle/admin_token.base64", "utf-8"));
this.adminRealmPath = match[1];
this.adminRealm = new Realm({
path: "__admin.realm",
sync: {
user: adminUser,
url: `realm://127.0.0.1:9080/${this.adminRealmPath}`
},
schema: [
{
name: "RealmFile",
properties: {
id: 'string',
path: 'string'
}
}
]
});
done();
}
});
});
afterEach(function(done) {
this.rl.close();
this.objectServer.kill('SIGKILL');
this.adminRealm.close();
let reset = spawn("sync-bundle/reset-server-realms.command");
reset.once("close", done);
reset.stdin.write("yes\n");
Realm.clearTestState();
});
it("should work", function(done) {
Realm.Sync.User.create('http://127.0.0.1:9080/', 'foo', 'bar', function(error) {
if (error) {
fail(error);
return;
}
Realm.Sync.User.login('http://127.0.0.1:9080/', 'foo', 'bar', function(error, user) {
if (error) {
fail(error);
return;
}
var _realm = new Realm({
syncConfig: {
identity: user.identity,
url: 'realm://127.0.0.1:9080/~/demo/realm1'
},
schema: [
{
name: 'IntObject',
properties: {
int: 'int'
}
}
]
});
});
});
var realms = this.adminRealm.objects("RealmFile");
realms.addListener((sender, changeset) => {
if (changeset.insertions.length === 1) {
expect(realms[changeset.insertions[0]].path).toMatch(/demo\/realm1$/);
done();
}
});
});
});