Advancements with postgres (#2510)

* Start DB runner from tests

* Connect GridstoreAdapter only when needed

* removes unused package

* better test errors reporting

* Adds support for __op.Delete

* Better test error reporting

* Makes sure all tests can run without crashing

* Use xdescribe to skip test suite

* Removes unused dependencies

* Let volatiles classes be created with PG on start

* Do not fail if class dont exist

* adds index.spec.js to the pg suite

* Use a new config each test to prevent side effects

* Enable EmailVerificationToken specs with pg

* Makes sure failure output is not cut

* Reduces number of ignored tests in ParseObject.spec

* Inspect reconfiguration errors

* Mark GlobalConfig is incompatible with PG

- Problem is with nested updates (param.prop = value)

* PG: Nested JSON queries and updates

- Adds support for nested json and . operator queries
- Adds debug support for PG adapter
- Adds loglevel support in helper

* Enable working specs in ParseUser

* Sets default logLevel in tests to undefined

* Adds File type support, retores purchaseValidation specs

* Adds support for updating jsonb objects

- Restores PushController tests

* Proper implementation of deleteByQuery and ORs

- Adds ParseInstallation spec to the test suite

* xit only failing tests

* Nit on ParseAPI spec

* add sorting operator

* properly bound order keys

* reverts describe_only_db behavior

* Enables passing tests

* Adds basic support for relations, upsertOneObject aliased to createObject

* progress on queries options

* Fix ACL update related problems

* Creates relation tables on class creation

* Adds Relation tests

* remove flaky tests

* use promises instead of CB

* disable flaky test

* nits

* Fixes on schema spec

- Next thing is to implemenet geopoint and files correctly

* fix failues

* Basic GeoPoint support

* Adds support for $nearSphere/$maxDistance geopoint queries

* enable passing tests

* drop tables afterEach for PG, clean up relation tables too

* Better initialization/dropTables
This commit is contained in:
Florent Vilmart
2016-08-15 16:48:39 -04:00
committed by GitHub
parent 2f1ee2186b
commit c0249283ac
42 changed files with 1447 additions and 716 deletions

View File

@@ -9,6 +9,8 @@ addons:
before_script: before_script:
- ls -al "$HOME/.mongodb/versions" - ls -al "$HOME/.mongodb/versions"
- psql -c 'create database parse_server_postgres_adapter_test_database;' -U postgres - psql -c 'create database parse_server_postgres_adapter_test_database;' -U postgres
- psql -c 'CREATE EXTENSION postgis;' -U postgres -d parse_server_postgres_adapter_test_database
- psql -c 'CREATE EXTENSION postgis_topology;' -U postgres -d parse_server_postgres_adapter_test_database
env: env:
global: global:
- COVERAGE_OPTION='./node_modules/.bin/istanbul cover' - COVERAGE_OPTION='./node_modules/.bin/istanbul cover'
@@ -26,7 +28,8 @@ branches:
cache: cache:
directories: directories:
- "$HOME/.mongodb/versions" - "$HOME/.mongodb/versions"
after_script: "./node_modules/.bin/codecov" after_script:
- bash <(curl -s https://codecov.io/bash)
deploy: deploy:
provider: npm provider: npm
email: email:

View File

@@ -19,10 +19,8 @@
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"babel-polyfill": "6.13.0", "babel-polyfill": "6.13.0",
"babel-runtime": "6.11.6",
"bcrypt-nodejs": "0.0.3", "bcrypt-nodejs": "0.0.3",
"body-parser": "1.15.2", "body-parser": "1.15.2",
"colors": "1.1.2",
"commander": "2.9.0", "commander": "2.9.0",
"deepcopy": "0.6.3", "deepcopy": "0.6.3",
"express": "4.14.0", "express": "4.14.0",
@@ -41,7 +39,6 @@
"pg-promise": "5.2.7", "pg-promise": "5.2.7",
"redis": "2.6.2", "redis": "2.6.2",
"request": "2.74.0", "request": "2.74.0",
"request-promise": "4.1.1",
"semver": "5.2.0", "semver": "5.2.0",
"tv4": "1.2.7", "tv4": "1.2.7",
"winston": "2.2.0", "winston": "2.2.0",
@@ -56,22 +53,20 @@
"babel-preset-es2015": "6.13.2", "babel-preset-es2015": "6.13.2",
"babel-preset-stage-0": "6.5.0", "babel-preset-stage-0": "6.5.0",
"babel-register": "6.11.6", "babel-register": "6.11.6",
"codecov": "1.0.1",
"cross-env": "2.0.0", "cross-env": "2.0.0",
"deep-diff": "0.3.4", "deep-diff": "0.3.4",
"gaze": "1.1.1", "gaze": "1.1.1",
"istanbul": "1.0.0-alpha.1", "istanbul": "1.0.0-alpha.1",
"jasmine": "2.4.1", "jasmine": "2.4.1",
"mongodb-runner": "3.3.2", "mongodb-runner": "3.3.2",
"nodemon": "1.10.0" "nodemon": "1.10.0",
"request-promise": "^4.1.1"
}, },
"scripts": { "scripts": {
"dev": "npm run build && node bin/dev", "dev": "npm run build && node bin/dev",
"build": "babel src/ -d lib/", "build": "babel src/ -d lib/",
"pretest": "test -z \"$PARSE_SERVER_TEST_DB\" && cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 mongodb-runner start || echo", "test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=3.2.6} MONGODB_STORAGE_ENGINE=mmapv1 NODE_ENV=test TESTING=1 babel-node $COVERAGE_OPTION ./node_modules/jasmine/bin/jasmine.js",
"test": "cross-env NODE_ENV=test TESTING=1 babel-node $COVERAGE_OPTION ./node_modules/jasmine/bin/jasmine.js",
"test:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/jasmine/bin/jasmine.js && npm run posttest", "test:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/jasmine/bin/jasmine.js && npm run posttest",
"posttest": "mongodb-runner stop",
"coverage": "cross-env COVERAGE_OPTION='./node_modules/.bin/istanbul cover' npm test", "coverage": "cross-env COVERAGE_OPTION='./node_modules/.bin/istanbul cover' npm test",
"coverage:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/babel-istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js && npm run posttest", "coverage:win": "npm run pretest && cross-env NODE_ENV=test TESTING=1 babel-node ./node_modules/babel-istanbul/lib/cli.js cover ./node_modules/jasmine/bin/jasmine.js && npm run posttest",
"start": "node ./bin/parse-server", "start": "node ./bin/parse-server",

View File

@@ -722,7 +722,7 @@ it('beforeSave should not affect fetched pointers', done => {
}); });
}); });
it_exclude_dbs(['postgres'])('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => { it('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => {
var TestObject = Parse.Object.extend('TestObject'); var TestObject = Parse.Object.extend('TestObject');
var NoBeforeSaveObject = Parse.Object.extend('NoBeforeSave'); var NoBeforeSaveObject = Parse.Object.extend('NoBeforeSave');
var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged'); var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
@@ -746,7 +746,7 @@ it('beforeSave should not affect fetched pointers', done => {
}) })
.then(object => { .then(object => {
res.success(object); res.success(object);
}); }).catch(res.error);
}); });
Parse.Cloud.define('removeme2', (req, res) => { Parse.Cloud.define('removeme2', (req, res) => {
@@ -762,7 +762,7 @@ it('beforeSave should not affect fetched pointers', done => {
}) })
.then(object => { .then(object => {
res.success(object); res.success(object);
}); }).catch(res.error);
}); });
Parse.Cloud.run('removeme') Parse.Cloud.run('removeme')
@@ -775,10 +775,13 @@ it('beforeSave should not affect fetched pointers', done => {
expect(aBeforeSaveObj.get('before')).toEqual('save'); expect(aBeforeSaveObj.get('before')).toEqual('save');
expect(aBeforeSaveObj.get('remove')).toEqual(undefined); expect(aBeforeSaveObj.get('remove')).toEqual(undefined);
done(); done();
}).catch((err) => {
jfail(err);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => { it('should fully delete objects when using `unset` with beforeSave (regression test for #1840)', done => {
var TestObject = Parse.Object.extend('TestObject'); var TestObject = Parse.Object.extend('TestObject');
var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged'); var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
@@ -802,12 +805,12 @@ it('beforeSave should not affect fetched pointers', done => {
expect(object.get('remove')).toBeUndefined(); expect(object.get('remove')).toBeUndefined();
done(); done();
}).fail((err) => { }).fail((err) => {
console.error(err); jfail(err);
done(); done();
}) });
}); });
it_exclude_dbs(['postgres'])('should not include relation op (regression test for #1606)', done => { it('should not include relation op (regression test for #1606)', done => {
var TestObject = Parse.Object.extend('TestObject'); var TestObject = Parse.Object.extend('TestObject');
var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged'); var BeforeSaveObject = Parse.Object.extend('BeforeSaveChanged');
let testObj; let testObj;
@@ -818,7 +821,7 @@ it('beforeSave should not affect fetched pointers', done => {
testObj.save().then(() => { testObj.save().then(() => {
object.relation('testsRelation').add(testObj); object.relation('testsRelation').add(testObj);
res.success(); res.success();
}) }, res.error);
}); });
let object = new BeforeSaveObject(); let object = new BeforeSaveObject();
@@ -827,7 +830,7 @@ it('beforeSave should not affect fetched pointers', done => {
expect(() => { objectAgain.relation('testsRelation') }).not.toThrow(); expect(() => { objectAgain.relation('testsRelation') }).not.toThrow();
done(); done();
}).fail((err) => { }).fail((err) => {
console.error(err); jfail(err);
done(); done();
}) })
}); });

View File

@@ -2,11 +2,11 @@
const MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions'); const MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
const request = require('request'); const request = require('request');
const MongoClient = require("mongodb").MongoClient; const Config = require('../src/Config');
describe("Email Verification Token Expiration: ", () => { describe("Email Verification Token Expiration: ", () => {
it_exclude_dbs(['postgres'])('show the invalid link page, if the user clicks on the verify email link after the email verify token expires', done => { it('show the invalid link page, if the user clicks on the verify email link after the email verify token expires', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -41,10 +41,13 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}); });
}, 1000); }, 1000);
}).catch((err) => {
jfail(err);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('emailVerified should set to false, if the user does not verify their email before the email verify token expires', done => { it('emailVerified should set to false, if the user does not verify their email before the email verify token expires', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -81,15 +84,18 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}) })
.catch((err) => { .catch((err) => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
}, 1000); }, 1000);
}).catch((err) => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('if user clicks on the email verify link before email verification token expiration then show the verify email success page', done => { it('if user clicks on the email verify link before email verification token expiration then show the verify email success page', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -119,10 +125,13 @@ describe("Email Verification Token Expiration: ", () => {
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=testEmailVerifyTokenValidity'); expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=testEmailVerifyTokenValidity');
done(); done();
}); });
}).catch((err) => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('if user clicks on the email verify link before email verification token expiration then emailVerified should be true', done => { it('if user clicks on the email verify link before email verification token expiration then emailVerified should be true', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -155,14 +164,17 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}) })
.catch((err) => { .catch((err) => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
}).catch((err) => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('if user clicks on the email verify link before email verification token expiration then user should be able to login', done => { it('if user clicks on the email verify link before email verification token expiration then user should be able to login', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -196,14 +208,17 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}) })
.catch((error) => { .catch((error) => {
fail('login should have succeeded'); jfail(error);
done(); done();
}); });
}); });
}).catch((err) => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('sets the _email_verify_token_expires_at and _email_verify_token fields after user SignUp', done => { it('sets the _email_verify_token_expires_at and _email_verify_token fields after user SignUp', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -227,14 +242,12 @@ describe("Email Verification Token Expiration: ", () => {
return user.signUp(); return user.signUp();
}) })
.then(() => { .then(() => {
const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; let config = new Config('test');
return MongoClient.connect(databaseURI); return config.database.find('_User', {username: 'sets_email_verify_token_expires_at'});
}) })
.then(database => { .then(results => {
expect(typeof database).toBe('object'); expect(results.length).toBe(1);
return database.collection('test__User').findOne({username: 'sets_email_verify_token_expires_at'}); let user = results[0];
})
.then(user => {
expect(typeof user).toBe('object'); expect(typeof user).toBe('object');
expect(user.emailVerified).toEqual(false); expect(user.emailVerified).toEqual(false);
expect(typeof user._email_verify_token).toBe('string'); expect(typeof user._email_verify_token).toBe('string');
@@ -242,12 +255,12 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}) })
.catch(error => { .catch(error => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('unsets the _email_verify_token_expires_at and _email_verify_token fields in the User class if email verification is successful', done => { it('unsets the _email_verify_token_expires_at and _email_verify_token fields in the User class if email verification is successful', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -275,12 +288,10 @@ describe("Email Verification Token Expiration: ", () => {
followRedirect: false, followRedirect: false,
}, (error, response, body) => { }, (error, response, body) => {
expect(response.statusCode).toEqual(302); expect(response.statusCode).toEqual(302);
let config = new Config('test');
const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; return config.database.find('_User', {username: 'unsets_email_verify_token_expires_at'}).then((results) => {
MongoClient.connect(databaseURI) expect(results.length).toBe(1);
.then(database => { return results[0];
expect(typeof database).toBe('object');
return database.collection('test__User').findOne({username: 'unsets_email_verify_token_expires_at'});
}) })
.then(user => { .then(user => {
expect(typeof user).toBe('object'); expect(typeof user).toBe('object');
@@ -290,18 +301,18 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}) })
.catch(error => { .catch(error => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
}) })
.catch(error => { .catch(error => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('clicking on the email verify link by an email VERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => { it('clicking on the email verify link by an email VERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -352,12 +363,12 @@ describe("Email Verification Token Expiration: ", () => {
}); });
}) })
.catch((err) => { .catch((err) => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('clicking on the email verify link by an email UNVERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => { it('clicking on the email verify link by an email UNVERIFIED user that was setup before enabling the expire email verify token should show an invalid link', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -402,14 +413,13 @@ describe("Email Verification Token Expiration: ", () => {
}); });
}) })
.catch((err) => { .catch((err) => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('setting the email on the user should set a new email verification token and new expiration date for the token when expire email verify token flag is set', done => { it('setting the email on the user should set a new email verification token and new expiration date for the token when expire email verify token flag is set', done => {
const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase';
let db; let db;
let user = new Parse.User(); let user = new Parse.User();
@@ -439,12 +449,10 @@ describe("Email Verification Token Expiration: ", () => {
return user.signUp(); return user.signUp();
}) })
.then(() => { .then(() => {
return MongoClient.connect(databaseURI); let config = new Config('test');
}) return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => {
.then(database => { return results[0];
expect(typeof database).toBe('object'); });
db = database; //save the db object for later use
return db.collection('test__User').findOne({username: 'newEmailVerifyTokenOnEmailReset'});
}) })
.then(userFromDb => { .then(userFromDb => {
expect(typeof userFromDb).toBe('object'); expect(typeof userFromDb).toBe('object');
@@ -458,8 +466,10 @@ describe("Email Verification Token Expiration: ", () => {
}); });
}) })
.then(() => { .then(() => {
// get user data after email reset and new token generation let config = new Config('test');
return db.collection('test__User').findOne({username: 'newEmailVerifyTokenOnEmailReset'}); return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => {
return results[0];
});
}) })
.then(userAfterEmailReset => { .then(userAfterEmailReset => {
expect(typeof userAfterEmailReset).toBe('object'); expect(typeof userAfterEmailReset).toBe('object');
@@ -468,12 +478,12 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}) })
.catch((err) => { .catch((err) => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('client should not see the _email_verify_token_expires_at field', done => { it('client should not see the _email_verify_token_expires_at field', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -505,10 +515,13 @@ describe("Email Verification Token Expiration: ", () => {
done(); done();
}) })
.catch(error => { .catch(error => {
fail("this should not fail"); jfail(error);
done(); done();
}); });
}).catch((err) => {
jfail(error);
done();
}); });
}); });

View File

@@ -7,7 +7,7 @@ var FilesController = require('../src/Controllers/FilesController').default;
// Small additional tests to improve overall coverage // Small additional tests to improve overall coverage
describe("GridStoreAdapter",() =>{ describe_only_db('mongo')("GridStoreAdapter",() =>{
it("should properly instanciate the GridStore when deleting a file", (done) => { it("should properly instanciate the GridStore when deleting a file", (done) => {
var databaseURI = 'mongodb://localhost:27017/parse'; var databaseURI = 'mongodb://localhost:27017/parse';

View File

@@ -3,10 +3,9 @@ var Config = require('../src/Config');
var rest = require('../src/rest'); var rest = require('../src/rest');
var InstallationsRouter = require('../src/Routers/InstallationsRouter').InstallationsRouter; var InstallationsRouter = require('../src/Routers/InstallationsRouter').InstallationsRouter;
var config = new Config('test'); describe('InstallationsRouter', () => {
describe_only_db(['mongo'])('InstallationsRouter', () => {
it('uses find condition from request.body', (done) => { it('uses find condition from request.body', (done) => {
var config = new Config('test');
var androidDeviceRequest = { var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android' 'deviceType': 'android'
@@ -37,10 +36,14 @@ describe_only_db(['mongo'])('InstallationsRouter', () => {
var results = res.response.results; var results = res.response.results;
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
done(); done();
}).catch((err) => {
fail(JSON.stringify(err));
done();
}); });
}); });
it('uses find condition from request.query', (done) => { it('uses find condition from request.query', (done) => {
var config = new Config('test');
var androidDeviceRequest = { var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android' 'deviceType': 'android'
@@ -72,12 +75,14 @@ describe_only_db(['mongo'])('InstallationsRouter', () => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
done(); done();
}).catch((err) => { }).catch((err) => {
console.error(err);
fail(JSON.stringify(err)); fail(JSON.stringify(err));
done(); done();
}); });
}); });
it('query installations with limit = 0', (done) => { it('query installations with limit = 0', (done) => {
var config = new Config('test');
var androidDeviceRequest = { var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android' 'deviceType': 'android'
@@ -96,6 +101,7 @@ describe_only_db(['mongo'])('InstallationsRouter', () => {
info: {} info: {}
}; };
var config = new Config('test');
var router = new InstallationsRouter(); var router = new InstallationsRouter();
rest.create(config, auth.nobody(config), '_Installation', androidDeviceRequest) rest.create(config, auth.nobody(config), '_Installation', androidDeviceRequest)
.then(() => { .then(() => {
@@ -106,10 +112,14 @@ describe_only_db(['mongo'])('InstallationsRouter', () => {
var response = res.response; var response = res.response;
expect(response.results.length).toEqual(0); expect(response.results.length).toEqual(0);
done(); done();
}).catch((err) => {
fail(JSON.stringify(err));
done();
}); });
}); });
it('query installations with count = 1', done => { it('query installations with count = 1', done => {
var config = new Config('test');
var androidDeviceRequest = { var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android' 'deviceType': 'android'
@@ -145,6 +155,7 @@ describe_only_db(['mongo'])('InstallationsRouter', () => {
}); });
it('query installations with limit = 0 and count = 1', (done) => { it('query installations with limit = 0 and count = 1', (done) => {
var config = new Config('test');
var androidDeviceRequest = { var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc', 'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android' 'deviceType': 'android'

View File

@@ -13,8 +13,7 @@ describe('LoggerController', () => {
expect(res.length).not.toBe(0); expect(res.length).not.toBe(0);
done(); done();
}).catch((err) => { }).catch((err) => {
console.error(err); jfail(err);
fail("should not fail");
done(); done();
}) })
}).not.toThrow(); }).not.toThrow();
@@ -76,7 +75,7 @@ describe('LoggerController', () => {
expect(res.length).toBe(0); expect(res.length).toBe(0);
done(); done();
}).catch((err) => { }).catch((err) => {
console.error(err); jfail(err);
fail("should not fail"); fail("should not fail");
done(); done();
}) })

View File

@@ -217,7 +217,7 @@ describe('OAuth', function() {
return request.post(options, callback); return request.post(options, callback);
} }
it_exclude_dbs(['postgres'])("should create user with REST API", done => { it("should create user with REST API", done => {
createOAuthUser((error, response, body) => { createOAuthUser((error, response, body) => {
expect(error).toBe(null); expect(error).toBe(null);
var b = JSON.parse(body); var b = JSON.parse(body);
@@ -228,6 +228,11 @@ describe('OAuth', function() {
var q = new Parse.Query("_Session"); var q = new Parse.Query("_Session");
q.equalTo('sessionToken', sessionToken); q.equalTo('sessionToken', sessionToken);
q.first({useMasterKey: true}).then((res) => { q.first({useMasterKey: true}).then((res) => {
if (!res) {
fail('should not fail fetching the session');
done();
return;
}
expect(res.get("installationId")).toEqual('yolo'); expect(res.get("installationId")).toEqual('yolo');
done(); done();
}).fail((err) => { }).fail((err) => {
@@ -237,7 +242,7 @@ describe('OAuth', function() {
}); });
}); });
it_exclude_dbs(['postgres'])("should only create a single user with REST API", (done) => { it("should only create a single user with REST API", (done) => {
var objectId; var objectId;
createOAuthUser((error, response, body) => { createOAuthUser((error, response, body) => {
expect(error).toBe(null); expect(error).toBe(null);
@@ -257,7 +262,7 @@ describe('OAuth', function() {
}); });
}); });
it_exclude_dbs(['postgres'])("unlink and link with custom provider", (done) => { it("unlink and link with custom provider", (done) => {
var provider = getMockMyOauthProvider(); var provider = getMockMyOauthProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("myoauth", { Parse.User._logInWith("myoauth", {

View File

@@ -47,10 +47,12 @@ describe('Parse.Push', () => {
installations.push(installation); installations.push(installation);
} }
return Parse.Object.saveAll(installations); return Parse.Object.saveAll(installations);
}); }).catch((err) => {
console.error(err);
})
} }
it_exclude_dbs(['postgres'])('should properly send push', (done) => { it('should properly send push', (done) => {
return setup().then(() => { return setup().then(() => {
return Parse.Push.send({ return Parse.Push.send({
where: { where: {
@@ -64,14 +66,13 @@ describe('Parse.Push', () => {
}) })
.then(() => { .then(() => {
done(); done();
}, (err) => { }).catch((err) => {
console.error(); jfail(err);
fail('should not fail sending push')
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('should properly send push with lowercaseIncrement', (done) => { it('should properly send push with lowercaseIncrement', (done) => {
return setup().then(() => { return setup().then(() => {
return Parse.Push.send({ return Parse.Push.send({
where: { where: {
@@ -84,14 +85,13 @@ describe('Parse.Push', () => {
}, {useMasterKey: true}) }, {useMasterKey: true})
}).then(() => { }).then(() => {
done(); done();
}, (err) => { }).catch((err) => {
console.error(); jfail(err);
fail('should not fail sending push')
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('should not allow clients to query _PushStatus', done => { it('should not allow clients to query _PushStatus', done => {
setup() setup()
.then(() => Parse.Push.send({ .then(() => Parse.Push.send({
where: { where: {
@@ -113,10 +113,13 @@ describe('Parse.Push', () => {
expect(body.error).toEqual('unauthorized'); expect(body.error).toEqual('unauthorized');
done(); done();
}); });
}).catch((err) => {
jfail(err);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('should allow master key to query _PushStatus', done => { it('should allow master key to query _PushStatus', done => {
setup() setup()
.then(() => Parse.Push.send({ .then(() => Parse.Push.send({
where: { where: {
@@ -136,15 +139,22 @@ describe('Parse.Push', () => {
'X-Parse-Master-Key': 'test', 'X-Parse-Master-Key': 'test',
}, },
}, (error, response, body) => { }, (error, response, body) => {
expect(body.results.length).toEqual(1); try {
expect(body.results[0].query).toEqual('{"deviceType":"ios"}'); expect(body.results.length).toEqual(1);
expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}'); expect(body.results[0].query).toEqual('{"deviceType":"ios"}');
expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}');
} catch(e) {
jfail(e);
}
done(); done();
}); });
}).catch((err) => {
jfail(err);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('should throw error if missing push configuration', done => { it('should throw error if missing push configuration', done => {
reconfigureServer({push: null}) reconfigureServer({push: null})
.then(() => { .then(() => {
return Parse.Push.send({ return Parse.Push.send({
@@ -161,6 +171,9 @@ describe('Parse.Push', () => {
}, (err) => { }, (err) => {
expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED); expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED);
done(); done();
}).catch((err) => {
jfail(err);
done();
}); });
}); });
}); });

View File

@@ -155,7 +155,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl an object owned by one user and public delete", (done) => { it("acl an object owned by one user and public delete", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -359,7 +359,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly readable and public get", (done) => { it("acl making an object publicly readable and public get", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -407,7 +407,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly readable and public find", (done) => { it("acl making an object publicly readable and public find", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -457,7 +457,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly readable and public update", (done) => { it("acl making an object publicly readable and public update", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -504,7 +504,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly readable and public delete", (done) => { it("acl making an object publicly readable and public delete", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -548,7 +548,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly writable and public get", (done) => { it("acl making an object publicly writable and public get", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -595,7 +595,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly writable and public find", (done) => { it("acl making an object publicly writable and public find", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -642,7 +642,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly writable and public update", (done) => { it("acl making an object publicly writable and public update", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -688,7 +688,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl making an object publicly writable and public delete", (done) => { it("acl making an object publicly writable and public delete", (done) => {
// Create an object owned by Alice. // Create an object owned by Alice.
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "alice"); user.set("username", "alice");
@@ -1051,7 +1051,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl sharing with another user and public delete", (done) => { it("acl sharing with another user and public delete", (done) => {
// Sign in as Bob. // Sign in as Bob.
Parse.User.signUp("bob", "pass", null, { Parse.User.signUp("bob", "pass", null, {
success: function(bob) { success: function(bob) {
@@ -1093,7 +1093,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("acl saveAll with permissions", (done) => { it("acl saveAll with permissions", (done) => {
Parse.User.signUp("alice", "wonderland", null, { Parse.User.signUp("alice", "wonderland", null, {
success: function(alice) { success: function(alice) {
var acl = new Parse.ACL(alice); var acl = new Parse.ACL(alice);
@@ -1202,7 +1202,7 @@ describe('Parse.ACL', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('regression test #701', done => { it('regression test #701', done => {
var anonUser = { var anonUser = {
authData: { authData: {
anonymous: { anonymous: {

View File

@@ -13,6 +13,31 @@ const deepcopy = require('deepcopy');
const userSchema = SchemaController.convertSchemaToAdapterSchema({ className: '_User', fields: Object.assign({}, SchemaController.defaultColumns._Default, SchemaController.defaultColumns._User) }); const userSchema = SchemaController.convertSchemaToAdapterSchema({ className: '_User', fields: Object.assign({}, SchemaController.defaultColumns._Default, SchemaController.defaultColumns._User) });
describe_only_db('mongo')('miscellaneous', () => {
it('test rest_create_app', function(done) {
var appId;
Parse._request('POST', 'rest_create_app').then((res) => {
expect(typeof res.application_id).toEqual('string');
expect(res.master_key).toEqual('master');
appId = res.application_id;
Parse.initialize(appId, 'unused');
var obj = new Parse.Object('TestObject');
obj.set('foo', 'bar');
return obj.save();
}).then(() => {
let config = new Config(appId);
return config.database.adapter.find('TestObject', { fields: {} }, {}, {});
}).then((results) => {
expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar');
done();
}).fail(error => {
fail(JSON.stringify(error));
done();
})
});
})
describe('miscellaneous', function() { describe('miscellaneous', function() {
it('create a GameScore object', function(done) { it('create a GameScore object', function(done) {
var obj = new Parse.Object('GameScore'); var obj = new Parse.Object('GameScore');
@@ -88,7 +113,7 @@ describe('miscellaneous', function() {
.catch(done); .catch(done);
}); });
it('ensure that email is uniquely indexed', done => { it_exclude_dbs(['postgres'])('ensure that email is uniquely indexed', done => {
let numFailed = 0; let numFailed = 0;
let numCreated = 0; let numCreated = 0;
let user1 = new Parse.User(); let user1 = new Parse.User();
@@ -127,7 +152,7 @@ describe('miscellaneous', function() {
.catch(done); .catch(done);
}); });
it_exclude_dbs(['postgres'])('ensure that if people already have duplicate users, they can still sign up new users', done => { it('ensure that if people already have duplicate users, they can still sign up new users', done => {
let config = new Config('test'); let config = new Config('test');
// Remove existing data to clear out unique index // Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently() TestUtils.destroyAllDataPermanently()
@@ -347,29 +372,6 @@ describe('miscellaneous', function() {
}); });
}); });
it_exclude_dbs(['postgres'])('test rest_create_app', function(done) {
var appId;
Parse._request('POST', 'rest_create_app').then((res) => {
expect(typeof res.application_id).toEqual('string');
expect(res.master_key).toEqual('master');
appId = res.application_id;
Parse.initialize(appId, 'unused');
var obj = new Parse.Object('TestObject');
obj.set('foo', 'bar');
return obj.save();
}).then(() => {
let config = new Config(appId);
return config.database.adapter.find('TestObject', { fields: {} }, {}, {});
}).then((results) => {
expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar');
done();
}).fail(error => {
fail(JSON.stringify(error));
done();
})
});
it('object is set on create and update', done => { it('object is set on create and update', done => {
let triggerTime = 0; let triggerTime = 0;
// Register a mock beforeSave hook // Register a mock beforeSave hook
@@ -647,8 +649,7 @@ describe('miscellaneous', function() {
expect(triggerTime).toBe(2); expect(triggerTime).toBe(2);
done(); done();
}, function(error) { }, function(error) {
console.error(error); jfail(error);
fail(error);
done(); done();
}); });
}); });
@@ -695,8 +696,7 @@ describe('miscellaneous', function() {
expect(triggerTime).toBe(2); expect(triggerTime).toBe(2);
done(); done();
}, function(error) { }, function(error) {
console.error(error); jfail(error);
fail(error);
done(); done();
}); });
}); });
@@ -733,13 +733,12 @@ describe('miscellaneous', function() {
expect(triggerTime).toBe(2); expect(triggerTime).toBe(2);
done(); done();
}, error => { }, error => {
console.error(error); jfail(error);
fail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('beforeSave receives ACL', done => { it('beforeSave receives ACL', done => {
let triggerTime = 0; let triggerTime = 0;
// Register a mock beforeSave hook // Register a mock beforeSave hook
Parse.Cloud.beforeSave('GameScore', function(req, res) { Parse.Cloud.beforeSave('GameScore', function(req, res) {
@@ -773,13 +772,12 @@ describe('miscellaneous', function() {
expect(triggerTime).toBe(2); expect(triggerTime).toBe(2);
done(); done();
}, error => { }, error => {
console.error(error); jfail(error);
fail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('afterSave receives ACL', done => { it('afterSave receives ACL', done => {
let triggerTime = 0; let triggerTime = 0;
// Register a mock beforeSave hook // Register a mock beforeSave hook
Parse.Cloud.afterSave('GameScore', function(req, res) { Parse.Cloud.afterSave('GameScore', function(req, res) {
@@ -813,8 +811,7 @@ describe('miscellaneous', function() {
expect(triggerTime).toBe(2); expect(triggerTime).toBe(2);
done(); done();
}, error => { }, error => {
console.error(error); jfail(error);
fail(error);
done(); done();
}); });
}); });
@@ -840,21 +837,25 @@ describe('miscellaneous', function() {
selfThing: {"__type":"Pointer","className":"GameScore","objectId":obj.id}, selfThing: {"__type":"Pointer","className":"GameScore","objectId":obj.id},
}) })
}, (error, response, body) => { }, (error, response, body) => {
body = JSON.parse(body); try {
expect(body.a).toBeUndefined(); body = JSON.parse(body);
expect(body.c).toEqual(3); // 2+1 expect(body.a).toBeUndefined();
expect(body.d.length).toBe(2); expect(body.c).toEqual(3); // 2+1
expect(body.d.indexOf('1') > -1).toBe(true); expect(body.d.length).toBe(2);
expect(body.d.indexOf('2') > -1).toBe(true); expect(body.d.indexOf('1') > -1).toBe(true);
expect(body.e.length).toBe(2); expect(body.d.indexOf('2') > -1).toBe(true);
expect(body.e.indexOf('1') > -1).toBe(true); expect(body.e.length).toBe(2);
expect(body.e.indexOf('2') > -1).toBe(true); expect(body.e.indexOf('1') > -1).toBe(true);
expect(body.f.length).toBe(1); expect(body.e.indexOf('2') > -1).toBe(true);
expect(body.f.indexOf('1') > -1).toBe(true); expect(body.f.length).toBe(1);
// return nothing on other self expect(body.f.indexOf('1') > -1).toBe(true);
expect(body.selfThing).toBeUndefined(); // return nothing on other self
// updatedAt is always set expect(body.selfThing).toBeUndefined();
expect(body.updatedAt).not.toBeUndefined(); // updatedAt is always set
expect(body.updatedAt).not.toBeUndefined();
}catch(e) {
jfail(e);
}
done(); done();
}); });
}).fail((err) => { }).fail((err) => {
@@ -1189,7 +1190,7 @@ describe('miscellaneous', function() {
}); });
}); });
it_exclude_dbs(['postgres'])('gets relation fields', (done) => { it('gets relation fields', (done) => {
let object = new Parse.Object('AnObject'); let object = new Parse.Object('AnObject');
let relatedObject = new Parse.Object('RelatedObject'); let relatedObject = new Parse.Object('RelatedObject');
Parse.Object.saveAll([object, relatedObject]).then(() => { Parse.Object.saveAll([object, relatedObject]).then(() => {
@@ -1215,6 +1216,9 @@ describe('miscellaneous', function() {
}) })
done(); done();
}); });
}).catch((err) => {
jfail(err);
done();
}) })
}); });
@@ -1304,25 +1308,34 @@ describe('miscellaneous', function() {
it_exclude_dbs(['postgres'])('bans interior keys containing . or $', done => { it_exclude_dbs(['postgres'])('bans interior keys containing . or $', done => {
new Parse.Object('Obj').save({innerObj: {'key with a $': 'fails'}}) new Parse.Object('Obj').save({innerObj: {'key with a $': 'fails'}})
.catch(error => { .then(() => {
fail('should not succeed')
}, error => {
expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
return new Parse.Object('Obj').save({innerObj: {'key with a .': 'fails'}}); return new Parse.Object('Obj').save({innerObj: {'key with a .': 'fails'}});
}) })
.catch(error => { .then(() => {
fail('should not succeed')
}, error => {
expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with $': 'fails'}}}); return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with $': 'fails'}}});
}) })
.catch(error => { .then(() => {
fail('should not succeed')
}, error => {
expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with .': 'fails'}}}); return new Parse.Object('Obj').save({innerObj: {innerInnerObj: {'key with .': 'fails'}}});
}) })
.catch(error => { .then(() => {
fail('should not succeed')
done();
}, error => {
expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY); expect(error.code).toEqual(Parse.Error.INVALID_NESTED_KEY);
done(); done();
}) });
}); });
it_exclude_dbs(['postgres'])('does not change inner object keys named _auth_data_something', done => { it('does not change inner object keys named _auth_data_something', done => {
new Parse.Object('O').save({ innerObj: {_auth_data_facebook: 7}}) new Parse.Object('O').save({ innerObj: {_auth_data_facebook: 7}})
.then(object => new Parse.Query('O').get(object.id)) .then(object => new Parse.Query('O').get(object.id))
.then(object => { .then(object => {
@@ -1369,10 +1382,13 @@ describe('miscellaneous', function() {
geoField: [1,2], geoField: [1,2],
}); });
done(); done();
}).catch((e) => {
jfail(e);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('purge all objects in class', (done) => { it('purge all objects in class', (done) => {
let object = new Parse.Object('TestObject'); let object = new Parse.Object('TestObject');
object.set('foo', 'bar'); object.set('foo', 'bar');
let object2 = new Parse.Object('TestObject'); let object2 = new Parse.Object('TestObject');
@@ -1422,7 +1438,7 @@ describe('miscellaneous', function() {
}); });
}); });
it_exclude_dbs(['postgres'])('purge all objects in _Role also purge cache', (done) => { it('purge all objects in _Role also purge cache', (done) => {
let headers = { let headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',

View File

@@ -11,9 +11,9 @@ for (var i = 0; i < str.length; i++) {
data.push(str.charCodeAt(i)); data.push(str.charCodeAt(i));
} }
describe('Parse.File testing', () => { describe_only_db('mongo')('Parse.File testing', () => {
describe('creating files', () => { describe_only_db('mongo')('creating files', () => {
it_exclude_dbs(['postgres'])('works with Content-Type', done => { it('works with Content-Type', done => {
var headers = { var headers = {
'Content-Type': 'application/octet-stream', 'Content-Type': 'application/octet-stream',
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
@@ -37,7 +37,7 @@ describe('Parse.File testing', () => {
}); });
it_exclude_dbs(['postgres'])('works with _ContentType', done => { it('works with _ContentType', done => {
request.post({ request.post({
url: 'http://localhost:8378/1/files/file', url: 'http://localhost:8378/1/files/file',
@@ -53,15 +53,19 @@ describe('Parse.File testing', () => {
expect(b.name).toMatch(/_file.html/); expect(b.name).toMatch(/_file.html/);
expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*file.html$/); expect(b.url).toMatch(/^http:\/\/localhost:8378\/1\/files\/test\/.*file.html$/);
request.get(b.url, (error, response, body) => { request.get(b.url, (error, response, body) => {
expect(response.headers['content-type']).toMatch('^text/html'); try {
expect(error).toBe(null); expect(response.headers['content-type']).toMatch('^text/html');
expect(body).toEqual('<html></html>\n'); expect(error).toBe(null);
expect(body).toEqual('<html></html>\n');
} catch(e) {
jfail(e);
}
done(); done();
}); });
}); });
}); });
it_exclude_dbs(['postgres'])('works without Content-Type', done => { it('works without Content-Type', done => {
var headers = { var headers = {
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest' 'X-Parse-REST-API-Key': 'rest'
@@ -120,7 +124,11 @@ describe('Parse.File testing', () => {
url: b.url url: b.url
}, (error, response, body) => { }, (error, response, body) => {
expect(error).toBe(null); expect(error).toBe(null);
expect(response.statusCode).toEqual(404); try {
expect(response.statusCode).toEqual(404);
} catch(e) {
jfail(e);
}
done(); done();
}); });
}); });
@@ -128,7 +136,7 @@ describe('Parse.File testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('blocks file deletions with missing or incorrect master-key header', done => { it('blocks file deletions with missing or incorrect master-key header', done => {
var headers = { var headers = {
'Content-Type': 'image/jpeg', 'Content-Type': 'image/jpeg',
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
@@ -173,7 +181,7 @@ describe('Parse.File testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('handles other filetypes', done => { it('handles other filetypes', done => {
var headers = { var headers = {
'Content-Type': 'image/jpeg', 'Content-Type': 'image/jpeg',
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
@@ -207,10 +215,10 @@ describe('Parse.File testing', () => {
notEqual(file.name(), "hello.txt"); notEqual(file.name(), "hello.txt");
done(); done();
} }
})); }, done));
}); });
it_exclude_dbs(['postgres'])("save file in object", done => { it("save file in object", done => {
var file = new Parse.File("hello.txt", data, "text/plain"); var file = new Parse.File("hello.txt", data, "text/plain");
ok(!file.url()); ok(!file.url());
file.save(expectSuccess({ file.save(expectSuccess({
@@ -232,12 +240,12 @@ describe('Parse.File testing', () => {
} }
})); }));
} }
})); }, done));
} }
})); }, done));
}); });
it_exclude_dbs(['postgres'])("save file in object with escaped characters in filename", done => { it("save file in object with escaped characters in filename", done => {
var file = new Parse.File("hello . txt", data, "text/plain"); var file = new Parse.File("hello . txt", data, "text/plain");
ok(!file.url()); ok(!file.url());
file.save(expectSuccess({ file.save(expectSuccess({
@@ -260,9 +268,9 @@ describe('Parse.File testing', () => {
} }
})); }));
} }
})); }, done));
} }
})); }, done));
}); });
it_exclude_dbs(['postgres'])("autosave file in object", done => { it_exclude_dbs(['postgres'])("autosave file in object", done => {
@@ -282,12 +290,12 @@ describe('Parse.File testing', () => {
notEqual(file.name(), "hello.txt"); notEqual(file.name(), "hello.txt");
done(); done();
} }
})); }, done));
} }
})); }, done));
}); });
it_exclude_dbs(['postgres'])("autosave file in object in object", done => { it("autosave file in object in object", done => {
var file = new Parse.File("hello.txt", data, "text/plain"); var file = new Parse.File("hello.txt", data, "text/plain");
ok(!file.url()); ok(!file.url());
@@ -311,12 +319,12 @@ describe('Parse.File testing', () => {
notEqual(file.name(), "hello.txt"); notEqual(file.name(), "hello.txt");
done(); done();
} }
})); }, done));
} }
})); }, done));
}); });
it_exclude_dbs(['postgres'])("saving an already saved file", done => { it("saving an already saved file", done => {
var file = new Parse.File("hello.txt", data, "text/plain"); var file = new Parse.File("hello.txt", data, "text/plain");
ok(!file.url()); ok(!file.url());
file.save(expectSuccess({ file.save(expectSuccess({
@@ -332,12 +340,12 @@ describe('Parse.File testing', () => {
equal(file.name(), previousName); equal(file.name(), previousName);
done(); done();
} }
})); }, done));
} }
})); }, done));
}); });
it_exclude_dbs(['postgres'])("two saves at the same time", done => { it("two saves at the same time", done => {
var file = new Parse.File("hello.txt", data, "text/plain"); var file = new Parse.File("hello.txt", data, "text/plain");
var firstName; var firstName;
@@ -355,7 +363,7 @@ describe('Parse.File testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("file toJSON testing", done => { it("file toJSON testing", done => {
var file = new Parse.File("hello.txt", data, "text/plain"); var file = new Parse.File("hello.txt", data, "text/plain");
ok(!file.url()); ok(!file.url());
var object = new Parse.Object("TestObject"); var object = new Parse.Object("TestObject");
@@ -366,10 +374,10 @@ describe('Parse.File testing', () => {
ok(object.toJSON().file.url); ok(object.toJSON().file.url);
done(); done();
} }
})); }, done));
}); });
it_exclude_dbs(['postgres'])("content-type used with no extension", done => { it("content-type used with no extension", done => {
var headers = { var headers = {
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
@@ -384,13 +392,17 @@ describe('Parse.File testing', () => {
var b = JSON.parse(body); var b = JSON.parse(body);
expect(b.name).toMatch(/\.html$/); expect(b.name).toMatch(/\.html$/);
request.get(b.url, (error, response, body) => { request.get(b.url, (error, response, body) => {
if (!response) {
fail('response should be set');
return done();
}
expect(response.headers['content-type']).toMatch(/^text\/html/); expect(response.headers['content-type']).toMatch(/^text\/html/);
done(); done();
}); });
}); });
}); });
it_exclude_dbs(['postgres'])("filename is url encoded", done => { it("filename is url encoded", done => {
var headers = { var headers = {
'Content-Type': 'text/html', 'Content-Type': 'text/html',
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
@@ -488,6 +500,9 @@ describe('Parse.File testing', () => {
expect(fileAgain.name()).toEqual('meep'); expect(fileAgain.name()).toEqual('meep');
expect(fileAgain.url()).toEqual('http://meep.meep'); expect(fileAgain.url()).toEqual('http://meep.meep');
done(); done();
}).catch((e) => {
jfail(e);
done();
}); });
}); });
@@ -508,6 +523,9 @@ describe('Parse.File testing', () => {
'http://files.parsetfss.com/test/tfss-123.txt' 'http://files.parsetfss.com/test/tfss-123.txt'
); );
done(); done();
}).catch((e) => {
jfail(e);
done();
}); });
}); });
@@ -528,10 +546,13 @@ describe('Parse.File testing', () => {
'http://files.parse.com/test/d6e80979-a128-4c57-a167-302f874700dc-123.txt' 'http://files.parse.com/test/d6e80979-a128-4c57-a167-302f874700dc-123.txt'
); );
done(); done();
}).catch((e) => {
jfail(e);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('supports files in objects without urls', done => { it('supports files in objects without urls', done => {
var file = { var file = {
__type: 'File', __type: 'File',
name: '123.txt' name: '123.txt'
@@ -545,6 +566,9 @@ describe('Parse.File testing', () => {
let fileAgain = result.get('file'); let fileAgain = result.get('file');
expect(fileAgain.url()).toMatch(/123.txt$/); expect(fileAgain.url()).toMatch(/123.txt$/);
done(); done();
}).catch((e) => {
jfail(e);
done();
}); });
}); });
}); });

View File

@@ -4,7 +4,7 @@
var TestObject = Parse.Object.extend('TestObject'); var TestObject = Parse.Object.extend('TestObject');
describe('Parse.GeoPoint testing', () => { describe('Parse.GeoPoint testing', () => {
it_exclude_dbs(['postgres'])('geo point roundtrip', (done) => { it('geo point roundtrip', (done) => {
var point = new Parse.GeoPoint(44.0, -11.0); var point = new Parse.GeoPoint(44.0, -11.0);
var obj = new TestObject(); var obj = new TestObject();
obj.set('location', point); obj.set('location', point);
@@ -26,7 +26,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo point exception two fields', (done) => { it('geo point exception two fields', (done) => {
var point = new Parse.GeoPoint(20, 20); var point = new Parse.GeoPoint(20, 20);
var obj = new TestObject(); var obj = new TestObject();
obj.set('locationOne', point); obj.set('locationOne', point);
@@ -39,7 +39,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo line', (done) => { it('geo line', (done) => {
var line = []; var line = [];
for (var i = 0; i < 10; ++i) { for (var i = 0; i < 10; ++i) {
var obj = new TestObject(); var obj = new TestObject();
@@ -67,7 +67,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance large', (done) => { it('geo max distance large', (done) => {
var objects = []; var objects = [];
[0, 1, 2].map(function(i) { [0, 1, 2].map(function(i) {
var obj = new TestObject(); var obj = new TestObject();
@@ -86,11 +86,11 @@ describe('Parse.GeoPoint testing', () => {
done(); done();
}, (err) => { }, (err) => {
fail("Couldn't query GeoPoint"); fail("Couldn't query GeoPoint");
fail(err) jfail(err)
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance medium', (done) => { it('geo max distance medium', (done) => {
var objects = []; var objects = [];
[0, 1, 2].map(function(i) { [0, 1, 2].map(function(i) {
var obj = new TestObject(); var obj = new TestObject();
@@ -114,7 +114,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance small', (done) => { it('geo max distance small', (done) => {
var objects = []; var objects = [];
[0, 1, 2].map(function(i) { [0, 1, 2].map(function(i) {
var obj = new TestObject(); var obj = new TestObject();
@@ -153,11 +153,12 @@ describe('Parse.GeoPoint testing', () => {
Parse.Object.saveAll([sacramento, sf, honolulu], callback); Parse.Object.saveAll([sacramento, sf, honolulu], callback);
}; };
it_exclude_dbs(['postgres'])('geo max distance in km everywhere', (done) => { it('geo max distance in km everywhere', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.withinKilometers('location', sfo, 4000.0); // Honolulu is 4300 km away from SFO on a sphere ;)
query.withinKilometers('location', sfo, 4800.0);
query.find({ query.find({
success: function(results) { success: function(results) {
equal(results.length, 3); equal(results.length, 3);
@@ -167,7 +168,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance in km california', (done) => { it('geo max distance in km california', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
@@ -183,7 +184,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance in km bay area', (done) => { it('geo max distance in km bay area', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
@@ -198,7 +199,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance in km mid peninsula', (done) => { it('geo max distance in km mid peninsula', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
@@ -212,11 +213,11 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance in miles everywhere', (done) => { it('geo max distance in miles everywhere', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.withinMiles('location', sfo, 2500.0); query.withinMiles('location', sfo, 2600.0);
query.find({ query.find({
success: function(results) { success: function(results) {
equal(results.length, 3); equal(results.length, 3);
@@ -226,7 +227,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance in miles california', (done) => { it('geo max distance in miles california', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
@@ -242,11 +243,12 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance in miles bay area', (done) => { it('geo max distance in miles bay area', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.withinMiles('location', sfo, 75.0); // 100km is 62 miles...
query.withinMiles('location', sfo, 62.0);
query.find({ query.find({
success: function(results) { success: function(results) {
equal(results.length, 1); equal(results.length, 1);
@@ -257,7 +259,7 @@ describe('Parse.GeoPoint testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('geo max distance in miles mid peninsula', (done) => { it('geo max distance in miles mid peninsula', (done) => {
makeSomeGeoPoints(function(list) { makeSomeGeoPoints(function(list) {
var sfo = new Parse.GeoPoint(37.6189722, -122.3748889); var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);

View File

@@ -12,7 +12,7 @@ describe('a GlobalConfig', () => {
{ fields: {} }, { fields: {} },
{ objectId: 1 }, { objectId: 1 },
{ params: { companies: ['US', 'DK'] } } { params: { companies: ['US', 'DK'] } }
).then(done); ).then(done, done);
}); });
it_exclude_dbs(['postgres'])('can be retrieved', (done) => { it_exclude_dbs(['postgres'])('can be retrieved', (done) => {
@@ -24,8 +24,10 @@ describe('a GlobalConfig', () => {
'X-Parse-Master-Key' : 'test' 'X-Parse-Master-Key' : 'test'
} }
}, (error, response, body) => { }, (error, response, body) => {
expect(response.statusCode).toEqual(200); try {
expect(body.params.companies).toEqual(['US', 'DK']); expect(response.statusCode).toEqual(200);
expect(body.params.companies).toEqual(['US', 'DK']);
} catch(e) { jfail(e); }
done(); done();
}); });
}); });
@@ -66,10 +68,12 @@ describe('a GlobalConfig', () => {
'X-Parse-Master-Key' : 'test' 'X-Parse-Master-Key' : 'test'
} }
}, (error, response, body) => { }, (error, response, body) => {
expect(response.statusCode).toEqual(200); try {
expect(body.params.companies).toBeUndefined(); expect(response.statusCode).toEqual(200);
expect(body.params.foo).toBe('bar'); expect(body.params.companies).toBeUndefined();
expect(Object.keys(body.params).length).toBe(1); expect(body.params.foo).toBe('bar');
expect(Object.keys(body.params).length).toBe(1);
} catch(e) { jfail(e); }
done(); done();
}); });
}); });
@@ -110,6 +114,9 @@ describe('a GlobalConfig', () => {
expect(body.params).toEqual({}); expect(body.params).toEqual({});
done(); done();
}); });
}).catch((e) => {
jfail(e);
done();
}); });
}); });
}); });

View File

@@ -20,7 +20,7 @@ describe('Hooks', () => {
expect(res.constructor).toBe(Array.prototype.constructor); expect(res.constructor).toBe(Array.prototype.constructor);
done(); done();
}, (err) => { }, (err) => {
fail(err); jfail(err);
done(); done();
}); });
}); });
@@ -30,7 +30,7 @@ describe('Hooks', () => {
expect(res.constructor).toBe(Array.prototype.constructor); expect(res.constructor).toBe(Array.prototype.constructor);
done(); done();
}, (err) => { }, (err) => {
fail(err); jfail(err);
done(); done();
}); });
}); });
@@ -71,7 +71,7 @@ describe('Hooks', () => {
}) })
}) })
.catch(error => { .catch(error => {
fail(error); jfail(error);
done(); done();
}) })
}); });
@@ -95,7 +95,7 @@ describe('Hooks', () => {
// delete // delete
return Parse.Hooks.updateTrigger("MyClass","beforeDelete", "http://anotherurl"); return Parse.Hooks.updateTrigger("MyClass","beforeDelete", "http://anotherurl");
}, (err) => { }, (err) => {
fail(err); jfail(err);
done(); done();
}).then((res) => { }).then((res) => {
expect(res.className).toBe("MyClass"); expect(res.className).toBe("MyClass");
@@ -104,22 +104,26 @@ describe('Hooks', () => {
return Parse.Hooks.removeTrigger("MyClass","beforeDelete"); return Parse.Hooks.removeTrigger("MyClass","beforeDelete");
}, (err) => { }, (err) => {
fail(err); jfail(err);
done(); done();
}).then((res) => { }).then((res) => {
// Find again! but should be deleted // Find again! but should be deleted
return Parse.Hooks.getTrigger("MyClass","beforeDelete"); return Parse.Hooks.getTrigger("MyClass","beforeDelete");
}, (err) => { }, (err) => {
fail(err); jfail(err);
done(); done();
}).then(function(){ }).then(function(){
fail("should not succeed"); fail("should not succeed");
done(); done();
}, (err) => { }, (err) => {
expect(err).not.toBe(null); if (err) {
expect(err).not.toBe(undefined); expect(err).not.toBe(null);
expect(err.code).toBe(143); expect(err).not.toBe(undefined);
expect(err.message).toBe("class MyClass does not exist") expect(err.code).toBe(143);
expect(err.message).toBe("class MyClass does not exist")
} else {
fail('should have errored');
}
done(); done();
}); });
}); });
@@ -148,13 +152,15 @@ describe('Hooks', () => {
}, (err) => { }, (err) => {
expect(err).not.toBe(undefined); expect(err).not.toBe(undefined);
expect(err).not.toBe(null); expect(err).not.toBe(null);
expect(err.code).toBe(143); if (err) {
expect(err.message).toBe('function name: my_new_function already exits') expect(err.code).toBe(143);
expect(err.message).toBe('function name: my_new_function already exits')
}
return Parse.Hooks.removeFunction("my_new_function"); return Parse.Hooks.removeFunction("my_new_function");
}).then(() => { }).then(() => {
done(); done();
}, (err) => { }, (err) => {
fail(err); jfail(err);
done(); done();
}) })
}); });
@@ -167,13 +173,17 @@ describe('Hooks', () => {
}).then( () => { }).then( () => {
fail("should not be able to create the same trigger"); fail("should not be able to create the same trigger");
}, (err) => { }, (err) => {
expect(err.code).toBe(143); expect(err).not.toBe(undefined);
expect(err.message).toBe('class MyClass already has trigger beforeSave') expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(143);
expect(err.message).toBe('class MyClass already has trigger beforeSave')
}
return Parse.Hooks.removeTrigger("MyClass", "beforeSave"); return Parse.Hooks.removeTrigger("MyClass", "beforeSave");
}).then(() => { }).then(() => {
done(); done();
}, (err) => { }, (err) => {
fail(err); jfail(err);
done(); done();
}) })
}); });
@@ -182,15 +192,23 @@ describe('Hooks', () => {
Parse.Hooks.updateFunction("A_COOL_FUNCTION", "http://url.com").then( () => { Parse.Hooks.updateFunction("A_COOL_FUNCTION", "http://url.com").then( () => {
fail("Should not succeed") fail("Should not succeed")
}, (err) => { }, (err) => {
expect(err.code).toBe(143); expect(err).not.toBe(undefined);
expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined'); expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(143);
expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined');
}
return Parse.Hooks.getFunction("A_COOL_FUNCTION") return Parse.Hooks.getFunction("A_COOL_FUNCTION")
}).then( (res) => { }).then( (res) => {
fail("the function should not exist"); fail("the function should not exist");
done(); done();
}, (err) => { }, (err) => {
expect(err.code).toBe(143); expect(err).not.toBe(undefined);
expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined'); expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(143);
expect(err.message).toBe('no function named: A_COOL_FUNCTION is defined');
}
done(); done();
}); });
}); });
@@ -199,15 +217,23 @@ describe('Hooks', () => {
Parse.Hooks.updateTrigger("AClassName","beforeSave", "http://url.com").then( () => { Parse.Hooks.updateTrigger("AClassName","beforeSave", "http://url.com").then( () => {
fail("Should not succeed") fail("Should not succeed")
}, (err) => { }, (err) => {
expect(err.code).toBe(143); expect(err).not.toBe(undefined);
expect(err.message).toBe('class AClassName does not exist'); expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(143);
expect(err.message).toBe('class AClassName does not exist');
}
return Parse.Hooks.getTrigger("AClassName","beforeSave") return Parse.Hooks.getTrigger("AClassName","beforeSave")
}).then( (res) => { }).then( (res) => {
fail("the function should not exist"); fail("the function should not exist");
done(); done();
}, (err) => { }, (err) => {
expect(err.code).toBe(143); expect(err).not.toBe(undefined);
expect(err.message).toBe('class AClassName does not exist'); expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(143);
expect(err.message).toBe('class AClassName does not exist');
}
done(); done();
}); });
}); });
@@ -217,8 +243,12 @@ describe('Hooks', () => {
Parse.Hooks.createFunction("MyFunction").then( (res) => { Parse.Hooks.createFunction("MyFunction").then( (res) => {
fail(res); fail(res);
}, (err) => { }, (err) => {
expect(err.code).toBe(143); expect(err).not.toBe(undefined);
expect(err.error).toBe("invalid hook declaration"); expect(err).not.toBe(null);
if (err) {
expect(err.code).toBe(143);
expect(err.error).toBe("invalid hook declaration");
}
done(); done();
}); });
}); });
@@ -258,7 +288,7 @@ describe('Hooks', () => {
const hooksController = new HooksController(Parse.applicationId, AppCache.get('test').databaseController); const hooksController = new HooksController(Parse.applicationId, AppCache.get('test').databaseController);
return hooksController.load() return hooksController.load()
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail('Should properly create all hooks'); fail('Should properly create all hooks');
done(); done();
}).then(function() { }).then(function() {
@@ -268,7 +298,7 @@ describe('Hooks', () => {
} }
done(); done();
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail('should properly load all hooks'); fail('should properly load all hooks');
done(); done();
}) })
@@ -283,14 +313,14 @@ describe('Hooks', () => {
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunction").then(function(){ Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunction").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION") return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("Should not fail creating a function"); fail("Should not fail creating a function");
done(); done();
}).then(function(res){ }).then(function(res){
expect(res).toBe("OK!"); expect(res).toBe("OK!");
done(); done();
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("Should not fail calling a function"); fail("Should not fail calling a function");
done(); done();
}); });
@@ -305,17 +335,21 @@ describe('Hooks', () => {
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunctionError").then(function(){ Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunctionError").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION") return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("Should not fail creating a function"); fail("Should not fail creating a function");
done(); done();
}).then(function(res){ }).then(function(res){
fail("Should not succeed calling that function"); fail("Should not succeed calling that function");
done(); done();
}, (err) => { }, (err) => {
expect(err.code).toBe(141); expect(err).not.toBe(undefined);
expect(err.message.code).toEqual(1337) expect(err).not.toBe(null);
expect(err.message.error).toEqual("hacking that one!"); if (err) {
done(); expect(err.code).toBe(141);
expect(err.message.code).toEqual(1337)
expect(err.message.error).toEqual("hacking that one!");
}
done();
}); });
}); });
@@ -331,14 +365,14 @@ describe('Hooks', () => {
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKey").then(function(){ Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKey").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION") return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("Should not fail creating a function"); fail("Should not fail creating a function");
done(); done();
}).then(function(res){ }).then(function(res){
expect(res).toBe("correct key provided"); expect(res).toBe("correct key provided");
done(); done();
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("Should not fail calling a function"); fail("Should not fail calling a function");
done(); done();
}); });
@@ -358,16 +392,20 @@ describe('Hooks', () => {
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKeyAlso").then(function(){ Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKeyAlso").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION") return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("Should not fail creating a function"); fail("Should not fail creating a function");
done(); done();
}).then(function(res){ }).then(function(res){
fail("Should not succeed calling that function"); fail("Should not succeed calling that function");
done(); done();
}, (err) => { }, (err) => {
expect(err.code).toBe(141); expect(err).not.toBe(undefined);
expect(err.message).toEqual("incorrect key provided"); expect(err).not.toBe(null);
done(); if (err) {
expect(err.code).toBe(141);
expect(err.message).toEqual("incorrect key provided");
}
done();
}); });
}); });
}); });
@@ -394,7 +432,7 @@ describe('Hooks', () => {
expect(res.get("hello")).toEqual("world"); expect(res.get("hello")).toEqual("world");
done(); done();
}).fail((err) => { }).fail((err) => {
console.error(err); jfail(err);
fail("Should not fail creating a function"); fail("Should not fail creating a function");
done(); done();
}); });
@@ -451,7 +489,7 @@ describe('Hooks', () => {
expect(res.get("foo")).toEqual("bar"); expect(res.get("foo")).toEqual("bar");
done(); done();
}).fail((err) => { }).fail((err) => {
console.error(err); jfail(err);
fail("Should not fail creating a function"); fail("Should not fail creating a function");
done(); done();
}); });

View File

@@ -22,7 +22,7 @@ describe('Installations', () => {
database = config.database; database = config.database;
}); });
it_exclude_dbs(['postgres'])('creates an android installation with ids', (done) => { it('creates an android installation with ids', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var device = 'android'; var device = 'android';
var input = { var input = {
@@ -40,7 +40,7 @@ describe('Installations', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it_exclude_dbs(['postgres'])('creates an ios installation with ids', (done) => { it('creates an ios installation with ids', (done) => {
var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
var device = 'ios'; var device = 'ios';
var input = { var input = {
@@ -58,7 +58,7 @@ describe('Installations', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it_exclude_dbs(['postgres'])('creates an embedded installation with ids', (done) => { it('creates an embedded installation with ids', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var device = 'embedded'; var device = 'embedded';
var input = { var input = {
@@ -76,7 +76,7 @@ describe('Installations', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it_exclude_dbs(['postgres'])('creates an android installation with all fields', (done) => { it('creates an android installation with all fields', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var device = 'android'; var device = 'android';
var input = { var input = {
@@ -99,7 +99,7 @@ describe('Installations', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it_exclude_dbs(['postgres'])('creates an ios installation with all fields', (done) => { it('creates an ios installation with all fields', (done) => {
var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
var device = 'ios'; var device = 'ios';
var input = { var input = {
@@ -143,7 +143,7 @@ describe('Installations', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should properly queying installations with masterKey', (done) => { it('should properly queying installations with masterKey', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var device = 'android'; var device = 'android';
var input = { var input = {
@@ -197,7 +197,7 @@ describe('Installations', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('creates an object with custom fields', (done) => { it('creates an object with custom fields', (done) => {
var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
var input = { var input = {
'deviceToken': t, 'deviceToken': t,
@@ -217,7 +217,7 @@ describe('Installations', () => {
// Note: did not port test 'TestObjectIDForIdentifiers' // Note: did not port test 'TestObjectIDForIdentifiers'
it_exclude_dbs(['postgres'])('merging when installationId already exists', (done) => { it('merging when installationId already exists', (done) => {
var installId1 = '12345678-abcd-abcd-abcd-123456789abc'; var installId1 = '12345678-abcd-abcd-abcd-123456789abc';
var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
var installId2 = '12345678-abcd-abcd-abcd-123456789abd'; var installId2 = '12345678-abcd-abcd-abcd-123456789abd';
@@ -250,7 +250,7 @@ describe('Installations', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it_exclude_dbs(['postgres'])('merging when two objects both only have one id', (done) => { it('merging when two objects both only have one id', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
var input1 = { var input1 = {
@@ -290,7 +290,10 @@ describe('Installations', () => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0]['_id']).toEqual(secondObject._id); expect(results[0]['_id']).toEqual(secondObject._id);
done(); done();
}).catch((error) => { console.log(error); }); }).catch((error) => {
jfail(error);
done();
});
}); });
xit('creating multiple devices with same device token works', (done) => { xit('creating multiple devices with same device token works', (done) => {
@@ -324,7 +327,7 @@ describe('Installations', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it_exclude_dbs(['postgres'])('updating with new channels', (done) => { it('updating with new channels', (done) => {
var input = { var input = {
installationId: '12345678-abcd-abcd-abcd-123456789abc', installationId: '12345678-abcd-abcd-abcd-123456789abc',
deviceType: 'android', deviceType: 'android',
@@ -347,13 +350,12 @@ describe('Installations', () => {
expect(results[0].channels[0]).toEqual('baz'); expect(results[0].channels[0]).toEqual('baz');
done(); done();
}).catch(error => { }).catch(error => {
console.log(error); jfail(error);
fail();
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('update android fails with new installation id', (done) => { it('update android fails with new installation id', (done) => {
var installId1 = '12345678-abcd-abcd-abcd-123456789abc'; var installId1 = '12345678-abcd-abcd-abcd-123456789abc';
var installId2 = '87654321-abcd-abcd-abcd-123456789abc'; var installId2 = '87654321-abcd-abcd-abcd-123456789abc';
var input = { var input = {
@@ -376,7 +378,7 @@ describe('Installations', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('update ios fails with new deviceToken and no installationId', (done) => { it('update ios fails with new deviceToken and no installationId', (done) => {
var a = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var a = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
var b = '91433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var b = '91433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
var input = { var input = {
@@ -398,7 +400,7 @@ describe('Installations', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('update ios updates device token', (done) => { it('update ios updates device token', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var t = '11433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
var u = '91433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306'; var u = '91433856eed2f1285fb3aa11136718c1198ed5647875096952c66bf8cb976306';
@@ -424,10 +426,13 @@ describe('Installations', () => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].deviceToken).toEqual(u); expect(results[0].deviceToken).toEqual(u);
done(); done();
}); }).catch(err => {
jfail(err);
done();
})
}); });
it_exclude_dbs(['postgres'])('update fails to change deviceType', (done) => { it('update fails to change deviceType', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var input = { var input = {
'installationId': installId, 'installationId': installId,
@@ -451,7 +456,7 @@ describe('Installations', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('update android with custom field', (done) => { it('update android with custom field', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var input = { var input = {
'installationId': installId, 'installationId': installId,
@@ -475,7 +480,7 @@ describe('Installations', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('update android device token with duplicate device token', (done) => { it('update android device token with duplicate device token', (done) => {
var installId1 = '11111111-abcd-abcd-abcd-123456789abc'; var installId1 = '11111111-abcd-abcd-abcd-123456789abc';
var installId2 = '22222222-abcd-abcd-abcd-123456789abc'; var installId2 = '22222222-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
@@ -514,10 +519,13 @@ describe('Installations', () => {
// The first object should have been deleted // The first object should have been deleted
expect(results.length).toEqual(0); expect(results.length).toEqual(0);
done(); done();
}).catch((error) => { console.log(error); }); }).catch(error => {
jfail(error);
done();
});
}); });
it_exclude_dbs(['postgres'])('update ios device token with duplicate device token', (done) => { it('update ios device token with duplicate device token', (done) => {
var installId1 = '11111111-abcd-abcd-abcd-123456789abc'; var installId1 = '11111111-abcd-abcd-abcd-123456789abc';
var installId2 = '22222222-abcd-abcd-abcd-123456789abc'; var installId2 = '22222222-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
@@ -557,7 +565,10 @@ describe('Installations', () => {
// The first object should have been deleted // The first object should have been deleted
expect(results.length).toEqual(0); expect(results.length).toEqual(0);
done(); done();
}).catch((error) => { console.log(error); }); }).catch(error => {
jfail(error);
done();
});
}); });
xit('update ios device token with duplicate token different app', (done) => { xit('update ios device token with duplicate token different app', (done) => {
@@ -582,10 +593,13 @@ describe('Installations', () => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].installationId).toEqual(installId2); expect(results[0].installationId).toEqual(installId2);
done(); done();
}).catch(error => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('update ios token and channels', (done) => { it('update ios token and channels', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
var input = { var input = {
@@ -609,10 +623,13 @@ describe('Installations', () => {
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
expect(results[0].channels.length).toEqual(0); expect(results[0].channels.length).toEqual(0);
done(); done();
}).catch(error => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('update ios linking two existing objects', (done) => { it('update ios linking two existing objects', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
var input = { var input = {
@@ -644,10 +661,13 @@ describe('Installations', () => {
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
expect(results[0].deviceType).toEqual('ios'); expect(results[0].deviceType).toEqual('ios');
done(); done();
}).catch(error => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('update is linking two existing objects w/ increment', (done) => { it('update is linking two existing objects w/ increment', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
var input = { var input = {
@@ -684,10 +704,13 @@ describe('Installations', () => {
expect(results[0].deviceType).toEqual('ios'); expect(results[0].deviceType).toEqual('ios');
expect(results[0].score).toEqual(1); expect(results[0].score).toEqual(1);
done(); done();
}).catch(error => {
jfail(error);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('update is linking two existing with installation id', (done) => { it('update is linking two existing with installation id', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
var input = { var input = {
@@ -724,10 +747,13 @@ describe('Installations', () => {
expect(results[0].installationId).toEqual(installId); expect(results[0].installationId).toEqual(installId);
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
done(); done();
}).catch((error) => { console.log(error); }); }).catch(error => {
jfail(error);
done();
});
}); });
it_exclude_dbs(['postgres'])('update is linking two existing with installation id w/ op', (done) => { it('update is linking two existing with installation id w/ op', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'; var t = '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
var input = { var input = {
@@ -769,10 +795,13 @@ describe('Installations', () => {
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
expect(results[0].score).toEqual(1); expect(results[0].score).toEqual(1);
done(); done();
}).catch((error) => { console.log(error); }); }).catch(error => {
jfail(error);
done();
});
}); });
it_exclude_dbs(['postgres'])('ios merge existing same token no installation id', (done) => { it('ios merge existing same token no installation id', (done) => {
// Test creating installation when there is an existing object with the // Test creating installation when there is an existing object with the
// same device token but no installation ID. This is possible when // same device token but no installation ID. This is possible when
// developers import device tokens from another push provider; the import // developers import device tokens from another push provider; the import

View File

@@ -117,7 +117,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("relational fields", function(done) { it("relational fields", function(done) {
var item = new Item(); var item = new Item();
item.set("property", "x"); item.set("property", "x");
var container = new Container(); var container = new Container();
@@ -205,7 +205,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("createdAt doesn't change", function(done) { it("createdAt doesn't change", function(done) {
var object = new TestObject({ foo: "bar" }); var object = new TestObject({ foo: "bar" });
object.save(null, { object.save(null, {
success: function() { success: function() {
@@ -269,15 +269,21 @@ describe('Parse.Object testing', () => {
}); });
it_exclude_dbs(['postgres'])("can set null", function(done) { it_exclude_dbs(['postgres'])("can set null", function(done) {
var errored = false;
var obj = new Parse.Object("TestObject"); var obj = new Parse.Object("TestObject");
obj.set("foo", null); obj.set("foo", null);
obj.save(null, { obj.save(null, {
success: function(obj) { success: function(obj) {
equal(obj.get("foo"), null); on_db('mongo', () => {
equal(obj.get("foo"), null);
});
on_db('postgres', () => {
fail('should not succeed');
});
done(); done();
}, },
error: function(obj, error) { error: function(obj, error) {
ok(false, error.message); fail('should not fail');
done(); done();
} }
}); });
@@ -365,7 +371,7 @@ describe('Parse.Object testing', () => {
}).then(fail, err => next(0)); }).then(fail, err => next(0));
}); });
it_exclude_dbs(['postgres'])("simple field deletion", function(done) { it("simple field deletion", function(done) {
var simple = new Parse.Object("SimpleObject"); var simple = new Parse.Object("SimpleObject");
simple.save({ simple.save({
foo: "bar" foo: "bar"
@@ -439,7 +445,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("relation deletion", function(done) { it("relation deletion", function(done) {
var simple = new Parse.Object("SimpleObject"); var simple = new Parse.Object("SimpleObject");
var child = new Parse.Object("Child"); var child = new Parse.Object("Child");
simple.save({ simple.save({
@@ -578,7 +584,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("addUnique", function(done) { it("addUnique", function(done) {
var x1 = new Parse.Object('X'); var x1 = new Parse.Object('X');
x1.set('stuff', [1, 2]); x1.set('stuff', [1, 2]);
x1.save().then(() => { x1.save().then(() => {
@@ -595,12 +601,17 @@ describe('Parse.Object testing', () => {
expect(x3.get('stuff')).toEqual([1, 2, 3]); expect(x3.get('stuff')).toEqual([1, 2, 3]);
done(); done();
}, (error) => { }, (error) => {
fail(error); on_db('mongo', () => {
jfail(error);
});
on_db('postgres', () => {
expect(error.message).toEqual("Postgres does not support AddUnique operator.");
});
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])("addUnique with object", function(done) { it("addUnique with object", function(done) {
var x1 = new Parse.Object('X'); var x1 = new Parse.Object('X');
x1.set('stuff', [ 1, {'hello': 'world'}, {'foo': 'bar'}]); x1.set('stuff', [ 1, {'hello': 'world'}, {'foo': 'bar'}]);
x1.save().then(() => { x1.save().then(() => {
@@ -617,12 +628,17 @@ describe('Parse.Object testing', () => {
expect(x3.get('stuff')).toEqual([1, {'hello': 'world'}, {'foo': 'bar'}, {'bar': 'baz'}]); expect(x3.get('stuff')).toEqual([1, {'hello': 'world'}, {'foo': 'bar'}, {'bar': 'baz'}]);
done(); done();
}, (error) => { }, (error) => {
fail(error); on_db('mongo', () => {
jfail(error);
});
on_db('postgres', () => {
expect(error.message).toEqual("Postgres does not support AddUnique operator.");
});
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])("removes with object", function(done) { it("removes with object", function(done) {
var x1 = new Parse.Object('X'); var x1 = new Parse.Object('X');
x1.set('stuff', [ 1, {'hello': 'world'}, {'foo': 'bar'}]); x1.set('stuff', [ 1, {'hello': 'world'}, {'foo': 'bar'}]);
x1.save().then(() => { x1.save().then(() => {
@@ -638,7 +654,12 @@ describe('Parse.Object testing', () => {
expect(x3.get('stuff')).toEqual([1, {'foo': 'bar'}]); expect(x3.get('stuff')).toEqual([1, {'foo': 'bar'}]);
done(); done();
}, (error) => { }, (error) => {
fail(error); on_db('mongo', () => {
jfail(error);
});
on_db('postgres', () => {
expect(error.message).toEqual("Postgres does not support Remove operator.");
});
done(); done();
}); });
}); });
@@ -668,7 +689,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("dirty keys", function(done) { it("dirty keys", function(done) {
var object = new Parse.Object("TestObject"); var object = new Parse.Object("TestObject");
object.set("gogo", "good"); object.set("gogo", "good");
object.set("sito", "sexy"); object.set("sito", "sexy");
@@ -763,7 +784,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("old attribute unset then unset", function(done) { it("old attribute unset then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject"); var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject(); var obj = new TestObject();
obj.set("x", 3); obj.set("x", 3);
@@ -832,7 +853,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("old attribute unset then clear", function(done) { it("old attribute unset then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject"); var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject(); var obj = new TestObject();
obj.set("x", 3); obj.set("x", 3);
@@ -901,7 +922,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("old attribute clear then unset", function(done) { it("old attribute clear then unset", function(done) {
var TestObject = Parse.Object.extend("TestObject"); var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject(); var obj = new TestObject();
obj.set("x", 3); obj.set("x", 3);
@@ -970,7 +991,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("old attribute clear then clear", function(done) { it("old attribute clear then clear", function(done) {
var TestObject = Parse.Object.extend("TestObject"); var TestObject = Parse.Object.extend("TestObject");
var obj = new TestObject(); var obj = new TestObject();
obj.set("x", 3); obj.set("x", 3);
@@ -1039,7 +1060,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("saving children in an array", function(done) { it("saving children in an array", function(done) {
var Parent = Parse.Object.extend("Parent"); var Parent = Parse.Object.extend("Parent");
var Child = Parse.Object.extend("Child"); var Child = Parse.Object.extend("Child");
@@ -1342,7 +1363,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("fetchAll", function(done) { it("fetchAll", function(done) {
var numItems = 11; var numItems = 11;
var container = new Container(); var container = new Container();
var items = []; var items = [];
@@ -1389,7 +1410,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("fetchAll updates dates", function(done) { it("fetchAll updates dates", function(done) {
var updatedObject; var updatedObject;
var object = new TestObject(); var object = new TestObject();
object.set("x", 7); object.set("x", 7);
@@ -1409,7 +1430,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("fetchAll backbone-style callbacks", function(done) { it("fetchAll backbone-style callbacks", function(done) {
var numItems = 11; var numItems = 11;
var container = new Container(); var container = new Container();
var items = []; var items = [];
@@ -1478,7 +1499,7 @@ describe('Parse.Object testing', () => {
expectError(Parse.Error.MISSING_OBJECT_ID, done)); expectError(Parse.Error.MISSING_OBJECT_ID, done));
}); });
it_exclude_dbs(['postgres'])("fetchAll error on deleted object", function(done) { it("fetchAll error on deleted object", function(done) {
var numItems = 11; var numItems = 11;
var container = new Container(); var container = new Container();
var subContainer = new Container(); var subContainer = new Container();
@@ -1536,7 +1557,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("fetchAllIfNeeded", function(done) { it("fetchAllIfNeeded", function(done) {
var numItems = 11; var numItems = 11;
var container = new Container(); var container = new Container();
var items = []; var items = [];
@@ -1574,7 +1595,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("fetchAllIfNeeded backbone-style callbacks", function(done) { it("fetchAllIfNeeded backbone-style callbacks", function(done) {
var numItems = 11; var numItems = 11;
var container = new Container(); var container = new Container();
var items = []; var items = [];
@@ -1778,7 +1799,7 @@ describe('Parse.Object testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('dictionary fetched pointers do not lose data on fetch', (done) => { it('dictionary fetched pointers do not lose data on fetch', (done) => {
var parent = new Parse.Object('Parent'); var parent = new Parse.Object('Parent');
var dict = {}; var dict = {};
for (var i = 0; i < 5; i++) { for (var i = 0; i < 5; i++) {
@@ -1832,13 +1853,13 @@ describe('Parse.Object testing', () => {
expect(foo["_more"]["_nested"]).toEqual("key"); expect(foo["_more"]["_nested"]).toEqual("key");
done(); done();
}).fail( err => { }).fail( err => {
console.error(err); jfail(err);
fail("should not fail"); fail("should not fail");
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('should have undefined includes when object is missing', (done) => { it('should have undefined includes when object is missing', (done) => {
let obj1 = new Parse.Object("AnObject"); let obj1 = new Parse.Object("AnObject");
let obj2 = new Parse.Object("AnObject"); let obj2 = new Parse.Object("AnObject");
@@ -1852,13 +1873,19 @@ describe('Parse.Object testing', () => {
return query.find(); return query.find();
}).then((res) => { }).then((res) => {
expect(res.length).toBe(1); expect(res.length).toBe(1);
expect(res[0].get("obj")).toBe(undefined); if (res[0]) {
expect(res[0].get("obj")).toBe(undefined);
}
let query = new Parse.Query("AnObject"); let query = new Parse.Query("AnObject");
return query.find(); return query.find();
}).then((res) => { }).then((res) => {
expect(res.length).toBe(1); expect(res.length).toBe(1);
expect(res[0].get("obj")).not.toBe(undefined); if (res[0]) {
return res[0].get("obj").fetch(); expect(res[0].get("obj")).not.toBe(undefined);
return res[0].get("obj").fetch();
} else {
done();
}
}).then(() => { }).then(() => {
fail("Should not fetch a deleted object"); fail("Should not fetch a deleted object");
}, (err) => { }, (err) => {
@@ -1867,7 +1894,7 @@ describe('Parse.Object testing', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('should have undefined includes when object is missing on deeper path', (done) => { it('should have undefined includes when object is missing on deeper path', (done) => {
let obj1 = new Parse.Object("AnObject"); let obj1 = new Parse.Object("AnObject");
let obj2 = new Parse.Object("AnObject"); let obj2 = new Parse.Object("AnObject");
let obj3 = new Parse.Object("AnObject"); let obj3 = new Parse.Object("AnObject");
@@ -1884,6 +1911,9 @@ describe('Parse.Object testing', () => {
expect(res.get("obj")).not.toBe(undefined); expect(res.get("obj")).not.toBe(undefined);
expect(res.get("obj").get("obj")).toBe(undefined); expect(res.get("obj").get("obj")).toBe(undefined);
done(); done();
}); }).catch(err => {
jfail(err);
done();
})
}); });
}); });

View File

@@ -23,7 +23,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("notEqualTo with Relation is working", function(done) { it("notEqualTo with Relation is working", function(done) {
var user = new Parse.User(); var user = new Parse.User();
user.setPassword("asdf"); user.setPassword("asdf");
user.setUsername("zxcv"); user.setUsername("zxcv");
@@ -129,6 +129,9 @@ describe('Parse.Query testing', () => {
}); });
}).then(function(){ }).then(function(){
done(); done();
}).catch((err) => {
jfail(err);
done();
}) })
}); });
@@ -147,7 +150,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("containedIn object array queries", function(done) { it("containedIn object array queries", function(done) {
var messageList = []; var messageList = [];
for (var i = 0; i < 4; ++i) { for (var i = 0; i < 4; ++i) {
var message = new TestObject({}); var message = new TestObject({});
@@ -172,12 +175,12 @@ describe('Parse.Query testing', () => {
done(); done();
}, },
error: function(e) { error: function(e) {
fail(e); jfail(e);
done(); done();
} }
}); });
}, (e) => { }, (e) => {
fail(e); jfail(e);
done(); done();
}); });
}); });
@@ -198,10 +201,13 @@ describe('Parse.Query testing', () => {
done(); done();
}, },
error: function(err) { error: function(err) {
fail(err); jfail(err);
done(); done();
}, },
}); });
}).catch((err) => {
jfail(err);
done();
}); });
}); });
@@ -221,6 +227,9 @@ describe('Parse.Query testing', () => {
done(); done();
} }
}); });
}).catch((err) => {
jfail(err);
done();
}); });
}); });
@@ -273,7 +282,7 @@ describe('Parse.Query testing', () => {
done(); done();
}, },
error: function(e) { error: function(e) {
fail(e); jfail(e);
done(); done();
}, },
}); });
@@ -322,7 +331,7 @@ describe('Parse.Query testing', () => {
className: "BoxedNumber" className: "BoxedNumber"
}); });
it_exclude_dbs(['postgres'])("equalTo queries", function(done) { it("equalTo queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -339,7 +348,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("equalTo undefined", function(done) { it("equalTo undefined", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -356,7 +365,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("lessThan queries", function(done) { it("lessThan queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -373,7 +382,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("lessThanOrEqualTo queries", function(done) { it("lessThanOrEqualTo queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -391,7 +400,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("greaterThan queries", function(done) { it("greaterThan queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -409,7 +418,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("greaterThanOrEqualTo queries", function(done) { it("greaterThanOrEqualTo queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -427,7 +436,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("lessThanOrEqualTo greaterThanOrEqualTo queries", function(done) { it("lessThanOrEqualTo greaterThanOrEqualTo queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -446,7 +455,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("lessThan greaterThan queries", function(done) { it("lessThan greaterThan queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -483,7 +492,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("containedIn queries", function(done) { it("containedIn queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -501,7 +510,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("notContainedIn queries", function(done) { it("notContainedIn queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -520,7 +529,7 @@ describe('Parse.Query testing', () => {
}); });
it_exclude_dbs(['postgres'])("objectId containedIn queries", function(done) { it("objectId containedIn queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -547,7 +556,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("objectId equalTo queries", function(done) { it("objectId equalTo queries", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -570,7 +579,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("find no elements", function(done) { it("find no elements", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -691,7 +700,7 @@ describe('Parse.Query testing', () => {
className: "Container" className: "Container"
}); });
it_exclude_dbs(['postgres'])("notEqualTo object", function(done) { it("notEqualTo object", function(done) {
var item1 = new TestObject(); var item1 = new TestObject();
var item2 = new TestObject(); var item2 = new TestObject();
var container1 = new Container({item: item1}); var container1 = new Container({item: item1});
@@ -708,7 +717,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("skip", function(done) { it("skip", function(done) {
Parse.Object.saveAll([new TestObject(), new TestObject()], function() { Parse.Object.saveAll([new TestObject(), new TestObject()], function() {
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.skip(1); query.skip(1);
@@ -727,7 +736,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("skip doesn't affect count", function(done) { it("skip doesn't affect count", function(done) {
Parse.Object.saveAll([new TestObject(), new TestObject()], function() { Parse.Object.saveAll([new TestObject(), new TestObject()], function() {
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.count({ query.count({
@@ -751,7 +760,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("count", function(done) { it("count", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -769,7 +778,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by ascending number", function(done) { it("order by ascending number", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -788,11 +797,11 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by descending number", function(done) { it("order by descending number", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber), function(list) { Parse.Object.saveAll([3, 1, 2].map(makeBoxedNumber)).then( function(list) {
var query = new Parse.Query(BoxedNumber); var query = new Parse.Query(BoxedNumber);
query.descending("number"); query.descending("number");
query.find(expectSuccess({ query.find(expectSuccess({
@@ -807,13 +816,13 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by ascending number then descending string", function(done) { it("order by ascending number then descending string", function(done) {
var strings = ["a", "b", "c", "d"]; var strings = ["a", "b", "c", "d"];
var makeBoxedNumber = function(num, i) { var makeBoxedNumber = function(num, i) {
return new BoxedNumber({ number: num, string: strings[i] }); return new BoxedNumber({ number: num, string: strings[i] });
}; };
Parse.Object.saveAll( Parse.Object.saveAll(
[3, 1, 3, 2].map(makeBoxedNumber), [3, 1, 3, 2].map(makeBoxedNumber)).then(
function(list) { function(list) {
var query = new Parse.Query(BoxedNumber); var query = new Parse.Query(BoxedNumber);
query.ascending("number").addDescending("string"); query.ascending("number").addDescending("string");
@@ -834,38 +843,41 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by descending number then ascending string", function(done) { it("order by descending number then ascending string", function(done) {
var strings = ["a", "b", "c", "d"]; var strings = ["a", "b", "c", "d"];
var makeBoxedNumber = function(num, i) { var makeBoxedNumber = function(num, i) {
return new BoxedNumber({ number: num, string: strings[i] }); return new BoxedNumber({ number: num, string: strings[i] });
}; };
Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber),
function(list) { let objects = [3, 1, 3, 2].map(makeBoxedNumber);
var query = new Parse.Query(BoxedNumber); Parse.Object.saveAll(objects)
query.descending("number").addAscending("string"); .then((list) => {
query.find(expectSuccess({ var query = new Parse.Query(BoxedNumber);
success: function(results) { query.descending("number").addAscending("string");
equal(results.length, 4); return query.find();
equal(results[0].get("number"), 3); }).then((results) => {
equal(results[0].get("string"), "a"); equal(results.length, 4);
equal(results[1].get("number"), 3); equal(results[0].get("number"), 3);
equal(results[1].get("string"), "c"); equal(results[0].get("string"), "a");
equal(results[2].get("number"), 2); equal(results[1].get("number"), 3);
equal(results[2].get("string"), "d"); equal(results[1].get("string"), "c");
equal(results[3].get("number"), 1); equal(results[2].get("number"), 2);
equal(results[3].get("string"), "b"); equal(results[2].get("string"), "d");
done(); equal(results[3].get("number"), 1);
} equal(results[3].get("string"), "b");
})); done();
}); }, (err) => {
jfail(err);
done();
});
}); });
it_exclude_dbs(['postgres'])("order by descending number and string", function(done) { it("order by descending number and string", function(done) {
var strings = ["a", "b", "c", "d"]; var strings = ["a", "b", "c", "d"];
var makeBoxedNumber = function(num, i) { var makeBoxedNumber = function(num, i) {
return new BoxedNumber({ number: num, string: strings[i] }); return new BoxedNumber({ number: num, string: strings[i] });
}; };
Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
function(list) { function(list) {
var query = new Parse.Query(BoxedNumber); var query = new Parse.Query(BoxedNumber);
query.descending("number,string"); query.descending("number,string");
@@ -886,12 +898,12 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by descending number and string, with space", function(done) { it("order by descending number and string, with space", function(done) {
var strings = ["a", "b", "c", "d"]; var strings = ["a", "b", "c", "d"];
var makeBoxedNumber = function(num, i) { var makeBoxedNumber = function(num, i) {
return new BoxedNumber({ number: num, string: strings[i] }); return new BoxedNumber({ number: num, string: strings[i] });
}; };
Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
function(list) { function(list) {
var query = new Parse.Query(BoxedNumber); var query = new Parse.Query(BoxedNumber);
query.descending("number, string"); query.descending("number, string");
@@ -909,15 +921,18 @@ describe('Parse.Query testing', () => {
done(); done();
} }
})); }));
}, (err) => {
jfail(err);
done();
}); });
}); });
it_exclude_dbs(['postgres'])("order by descending number and string, with array arg", function(done) { it("order by descending number and string, with array arg", function(done) {
var strings = ["a", "b", "c", "d"]; var strings = ["a", "b", "c", "d"];
var makeBoxedNumber = function(num, i) { var makeBoxedNumber = function(num, i) {
return new BoxedNumber({ number: num, string: strings[i] }); return new BoxedNumber({ number: num, string: strings[i] });
}; };
Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
function(list) { function(list) {
var query = new Parse.Query(BoxedNumber); var query = new Parse.Query(BoxedNumber);
query.descending(["number", "string"]); query.descending(["number", "string"]);
@@ -938,12 +953,12 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by descending number and string, with multiple args", function(done) { it("order by descending number and string, with multiple args", function(done) {
var strings = ["a", "b", "c", "d"]; var strings = ["a", "b", "c", "d"];
var makeBoxedNumber = function(num, i) { var makeBoxedNumber = function(num, i) {
return new BoxedNumber({ number: num, string: strings[i] }); return new BoxedNumber({ number: num, string: strings[i] });
}; };
Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber), Parse.Object.saveAll([3, 1, 3, 2].map(makeBoxedNumber)).then(
function(list) { function(list) {
var query = new Parse.Query(BoxedNumber); var query = new Parse.Query(BoxedNumber);
query.descending("number", "string"); query.descending("number", "string");
@@ -964,7 +979,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("can't order by password", function(done) { it("can't order by password", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -996,14 +1011,14 @@ describe('Parse.Query testing', () => {
done(); done();
}, },
error: function(e) { error: function(e) {
fail(e); jfail(e);
done(); done();
}, },
}); });
}); });
}); });
it_exclude_dbs(['postgres'])("order by createdAt", function(done) { it("order by createdAt", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -1027,7 +1042,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by _updated_at", function(done) { it("order by _updated_at", function(done) {
var makeBoxedNumber = function(i) { var makeBoxedNumber = function(i) {
return new BoxedNumber({ number: i }); return new BoxedNumber({ number: i });
}; };
@@ -1056,7 +1071,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("order by updatedAt", function(done) { it("order by updatedAt", function(done) {
var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); }; var makeBoxedNumber = function(i) { return new BoxedNumber({ number: i }); };
var numbers = [3, 1, 2].map(makeBoxedNumber); var numbers = [3, 1, 2].map(makeBoxedNumber);
numbers[0].save().then(() => { numbers[0].save().then(() => {
@@ -1107,7 +1122,7 @@ describe('Parse.Query testing', () => {
}); });
} }
it_exclude_dbs(['postgres'])("time equality", function(done) { it("time equality", function(done) {
makeThreeTimeObjects().then(function(list) { makeThreeTimeObjects().then(function(list) {
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.equalTo("time", list[1].get("time")); query.equalTo("time", list[1].get("time"));
@@ -1121,7 +1136,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("time lessThan", function(done) { it("time lessThan", function(done) {
makeThreeTimeObjects().then(function(list) { makeThreeTimeObjects().then(function(list) {
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.lessThan("time", list[2].get("time")); query.lessThan("time", list[2].get("time"));
@@ -1135,7 +1150,7 @@ describe('Parse.Query testing', () => {
}); });
// This test requires Date objects to be consistently stored as a Date. // This test requires Date objects to be consistently stored as a Date.
it_exclude_dbs(['postgres'])("time createdAt", function(done) { it("time createdAt", function(done) {
makeThreeTimeObjects().then(function(list) { makeThreeTimeObjects().then(function(list) {
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.greaterThanOrEqualTo("createdAt", list[0].createdAt); query.greaterThanOrEqualTo("createdAt", list[0].createdAt);
@@ -1148,7 +1163,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("matches string", function(done) { it("matches string", function(done) {
var thing1 = new TestObject(); var thing1 = new TestObject();
thing1.set("myString", "football"); thing1.set("myString", "football");
var thing2 = new TestObject(); var thing2 = new TestObject();
@@ -1165,7 +1180,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("matches regex", function(done) { it("matches regex", function(done) {
var thing1 = new TestObject(); var thing1 = new TestObject();
thing1.set("myString", "football"); thing1.set("myString", "football");
var thing2 = new TestObject(); var thing2 = new TestObject();
@@ -1182,7 +1197,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("case insensitive regex success", function(done) { it("case insensitive regex success", function(done) {
var thing = new TestObject(); var thing = new TestObject();
thing.set("myString", "football"); thing.set("myString", "football");
Parse.Object.saveAll([thing], function() { Parse.Object.saveAll([thing], function() {
@@ -1196,7 +1211,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("regexes with invalid options fail", function(done) { it("regexes with invalid options fail", function(done) {
var query = new Parse.Query(TestObject); var query = new Parse.Query(TestObject);
query.matches("myString", "FootBall", "some invalid option"); query.matches("myString", "FootBall", "some invalid option");
query.find(expectError(Parse.Error.INVALID_QUERY, done)); query.find(expectError(Parse.Error.INVALID_QUERY, done));
@@ -1222,7 +1237,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("Regular expression constructor includes modifiers inline", function(done) { it("Regular expression constructor includes modifiers inline", function(done) {
var thing = new TestObject(); var thing = new TestObject();
thing.set("myString", "\n\nbuffer\n\nparse.COM"); thing.set("myString", "\n\nbuffer\n\nparse.COM");
Parse.Object.saveAll([thing], function() { Parse.Object.saveAll([thing], function() {
@@ -1288,7 +1303,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("exists", function(done) { it("exists", function(done) {
var objects = []; var objects = [];
for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) { for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) {
var item = new TestObject(); var item = new TestObject();
@@ -1314,7 +1329,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("doesNotExist", function(done) { it("doesNotExist", function(done) {
var objects = []; var objects = [];
for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) { for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) {
var item = new TestObject(); var item = new TestObject();
@@ -1340,7 +1355,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("exists relation", function(done) { it("exists relation", function(done) {
var objects = []; var objects = [];
for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) { for (var i of [0, 1, 2, 3, 4, 5, 6, 7, 8]) {
var container = new Container(); var container = new Container();
@@ -1354,7 +1369,7 @@ describe('Parse.Query testing', () => {
} }
objects.push(container); objects.push(container);
}; };
Parse.Object.saveAll(objects, function() { Parse.Object.saveAll(objects).then(function() {
var query = new Parse.Query(Container); var query = new Parse.Query(Container);
query.exists("x"); query.exists("x");
query.find({ query.find({
@@ -1369,7 +1384,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("doesNotExist relation", function(done) { it("doesNotExist relation", function(done) {
var objects = []; var objects = [];
for (var i of [0, 1, 2, 3, 4, 5, 6, 7]) { for (var i of [0, 1, 2, 3, 4, 5, 6, 7]) {
var container = new Container(); var container = new Container();
@@ -1398,7 +1413,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("don't include by default", function(done) { it("don't include by default", function(done) {
var child = new TestObject(); var child = new TestObject();
var parent = new Container(); var parent = new Container();
child.set("foo", "bar"); child.set("foo", "bar");
@@ -1564,7 +1579,7 @@ describe('Parse.Query testing', () => {
}) })
}); });
it('properly includes array of mixed objects', (done) => { it_exclude_dbs(['postgres'])('properly includes array of mixed objects', (done) => {
let objects = []; let objects = [];
let total = 0; let total = 0;
while(objects.length != 5) { while(objects.length != 5) {
@@ -1642,13 +1657,13 @@ describe('Parse.Query testing', () => {
expect(total).toBe(0); expect(total).toBe(0);
done() done()
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail('should not fail'); fail('should not fail');
done(); done();
}) })
}); });
it_exclude_dbs(['postgres'])('properly fetches nested pointers', (done) =>  { it('properly fetches nested pointers', (done) =>  {
let color = new Parse.Object('Color'); let color = new Parse.Object('Color');
color.set('hex','#133733'); color.set('hex','#133733');
let circle = new Parse.Object('Circle'); let circle = new Parse.Object('Circle');
@@ -1713,7 +1728,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("matches query", function(done) { it("matches query", function(done) {
var ParentObject = Parse.Object.extend("ParentObject"); var ParentObject = Parse.Object.extend("ParentObject");
var ChildObject = Parse.Object.extend("ChildObject"); var ChildObject = Parse.Object.extend("ChildObject");
var objects = []; var objects = [];
@@ -1752,7 +1767,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("select query", function(done) { it("select query", function(done) {
var RestaurantObject = Parse.Object.extend("Restaurant"); var RestaurantObject = Parse.Object.extend("Restaurant");
var PersonObject = Parse.Object.extend("Person"); var PersonObject = Parse.Object.extend("Person");
var objects = [ var objects = [
@@ -1778,7 +1793,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('$select inside $or', (done) => { it('$select inside $or', (done) => {
var Restaurant = Parse.Object.extend('Restaurant'); var Restaurant = Parse.Object.extend('Restaurant');
var Person = Parse.Object.extend('Person'); var Person = Parse.Object.extend('Person');
var objects = [ var objects = [
@@ -1802,12 +1817,12 @@ describe('Parse.Query testing', () => {
expect(results.length).toEqual(2); expect(results.length).toEqual(2);
done(); done();
}, (error) => { }, (error) => {
fail(error); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])("dontSelect query", function(done) { it("dontSelect query", function(done) {
var RestaurantObject = Parse.Object.extend("Restaurant"); var RestaurantObject = Parse.Object.extend("Restaurant");
var PersonObject = Parse.Object.extend("Person"); var PersonObject = Parse.Object.extend("Person");
var objects = [ var objects = [
@@ -1833,7 +1848,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("dontSelect query without conditions", function(done) { it("dontSelect query without conditions", function(done) {
const RestaurantObject = Parse.Object.extend("Restaurant"); const RestaurantObject = Parse.Object.extend("Restaurant");
const PersonObject = Parse.Object.extend("Person"); const PersonObject = Parse.Object.extend("Person");
const objects = [ const objects = [
@@ -1920,7 +1935,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("or queries", function(done) { it("or queries", function(done) {
var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) { var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) {
var object = new Parse.Object('BoxedNumber'); var object = new Parse.Object('BoxedNumber');
object.set('x', x); object.set('x', x);
@@ -1947,7 +1962,7 @@ describe('Parse.Query testing', () => {
}); });
// This relies on matchesQuery aka the $inQuery operator // This relies on matchesQuery aka the $inQuery operator
it_exclude_dbs(['postgres'])("or complex queries", function(done) { it("or complex queries", function(done) {
var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) { var objects = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) {
var child = new Parse.Object('Child'); var child = new Parse.Object('Child');
child.set('x', x); child.set('x', x);
@@ -1976,7 +1991,7 @@ describe('Parse.Query testing', () => {
})); }));
}); });
it_exclude_dbs(['postgres'])("async methods", function(done) { it("async methods", function(done) {
var saves = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) { var saves = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(function(x) {
var obj = new Parse.Object("TestObject"); var obj = new Parse.Object("TestObject");
obj.set("x", x + 1); obj.set("x", x + 1);
@@ -2013,7 +2028,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("query.each", function(done) { it("query.each", function(done) {
var TOTAL = 50; var TOTAL = 50;
var COUNT = 25; var COUNT = 25;
@@ -2048,7 +2063,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("query.each async", function(done) { it("query.each async", function(done) {
var TOTAL = 50; var TOTAL = 50;
var COUNT = 25; var COUNT = 25;
@@ -2249,7 +2264,7 @@ describe('Parse.Query testing', () => {
}).then(function() { }).then(function() {
done(); done();
}, function(err) { }, function(err) {
ok(false, JSON.stringify(err)); jfail(err);
done(); done();
}); });
}); });
@@ -2285,6 +2300,7 @@ describe('Parse.Query testing', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
// PG don't support creating a null column
it_exclude_dbs(['postgres'])('querying for null value', (done) => { it_exclude_dbs(['postgres'])('querying for null value', (done) => {
var obj = new Parse.Object('TestObject'); var obj = new Parse.Object('TestObject');
obj.set('aNull', null); obj.set('aNull', null);
@@ -2299,7 +2315,7 @@ describe('Parse.Query testing', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('query within dictionary', (done) => { it('query within dictionary', (done) => {
var objs = []; var objs = [];
var promises = []; var promises = [];
for (var i = 0; i < 2; i++) { for (var i = 0; i < 2; i++) {
@@ -2322,7 +2338,7 @@ describe('Parse.Query testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('supports include on the wrong key type (#2262)', function(done) { it('supports include on the wrong key type (#2262)', function(done) {
let childObject = new Parse.Object('TestChildObject'); let childObject = new Parse.Object('TestChildObject');
childObject.set('hello', 'world'); childObject.set('hello', 'world');
childObject.save().then(() => { childObject.save().then(() => {
@@ -2382,7 +2398,7 @@ describe('Parse.Query testing', () => {
}); });
// #371 // #371
it_exclude_dbs(['postgres'])('should properly interpret a query v1', (done) => { it('should properly interpret a query v1', (done) => {
var query = new Parse.Query("C1"); var query = new Parse.Query("C1");
var auxQuery = new Parse.Query("C1"); var auxQuery = new Parse.Query("C1");
query.matchesKeyInQuery("A1", "A2", auxQuery); query.matchesKeyInQuery("A1", "A2", auxQuery);
@@ -2391,13 +2407,13 @@ describe('Parse.Query testing', () => {
query.find().then((result) => { query.find().then((result) => {
done(); done();
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("should not failt"); fail("should not failt");
done(); done();
}) })
}); });
it_exclude_dbs(['postgres'])('should properly interpret a query v2', (done) => { it('should properly interpret a query v2', (done) => {
var user = new Parse.User(); var user = new Parse.User();
user.set("username", "foo"); user.set("username", "foo");
user.set("password", "bar"); user.set("password", "bar");
@@ -2426,9 +2442,8 @@ describe('Parse.Query testing', () => {
return query.find(); return query.find();
}).then((res) => { }).then((res) => {
done(); done();
done();
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("should not fail"); fail("should not fail");
done(); done();
}); });
@@ -2467,7 +2482,7 @@ describe('Parse.Query testing', () => {
} }
done(); done();
}).fail((err) => { }).fail((err) => {
console.error(err); jfail(err);
fail('should not fail'); fail('should not fail');
done(); done();
}) })
@@ -2487,7 +2502,9 @@ describe('Parse.Query testing', () => {
q2.doesNotExist('nonExistantKey2'); q2.doesNotExist('nonExistantKey2');
let orQuery = Parse.Query.or(q1, q2).find().then(results => { let orQuery = Parse.Query.or(q1, q2).find().then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].objectId).toEqual(q1.objectId); if (results.length == 1) {
expect(results[0].objectId).toEqual(q1.objectId);
}
done(); done();
}); });
}); });
@@ -2550,7 +2567,7 @@ describe('Parse.Query testing', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('properly handles nested ors', function(done) { it('properly handles nested ors', function(done) {
var objects = []; var objects = [];
while(objects.length != 4) { while(objects.length != 4) {
var obj = new Parse.Object('Object'); var obj = new Parse.Object('Object');
@@ -2571,7 +2588,7 @@ describe('Parse.Query testing', () => {
done(); done();
}).catch((error) => { }).catch((error) => {
fail('should not fail'); fail('should not fail');
console.error(error); jfail(error);
done(); done();
}) })
}); });

View File

@@ -6,7 +6,7 @@ var ChildObject = Parse.Object.extend({className: "ChildObject"});
var ParentObject = Parse.Object.extend({className: "ParentObject"}); var ParentObject = Parse.Object.extend({className: "ParentObject"});
describe('Parse.Relation testing', () => { describe('Parse.Relation testing', () => {
it_exclude_dbs(['postgres'])("simple add and remove relation", (done) => { it("simple add and remove relation", (done) => {
var child = new ChildObject(); var child = new ChildObject();
child.set("x", 2); child.set("x", 2);
var parent = new ParentObject(); var parent = new ParentObject();
@@ -41,7 +41,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("query relation without schema", (done) => { it("query relation without schema", (done) => {
var ChildObject = Parse.Object.extend("ChildObject"); var ChildObject = Parse.Object.extend("ChildObject");
var childObjects = []; var childObjects = [];
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
@@ -75,7 +75,7 @@ describe('Parse.Relation testing', () => {
})); }));
}); });
it_exclude_dbs(['postgres'])("relations are constructed right from query", (done) => { it("relations are constructed right from query", (done) => {
var ChildObject = Parse.Object.extend("ChildObject"); var ChildObject = Parse.Object.extend("ChildObject");
var childObjects = []; var childObjects = [];
@@ -121,7 +121,7 @@ describe('Parse.Relation testing', () => {
}); });
it_exclude_dbs(['postgres'])("compound add and remove relation", (done) => { it("compound add and remove relation", (done) => {
var ChildObject = Parse.Object.extend("ChildObject"); var ChildObject = Parse.Object.extend("ChildObject");
var childObjects = []; var childObjects = [];
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
@@ -164,7 +164,7 @@ describe('Parse.Relation testing', () => {
}); });
it_exclude_dbs(['postgres'])("queries with relations", (done) => { it("queries with relations", (done) => {
var ChildObject = Parse.Object.extend("ChildObject"); var ChildObject = Parse.Object.extend("ChildObject");
var childObjects = []; var childObjects = [];
@@ -202,7 +202,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("queries on relation fields", (done) => { it("queries on relation fields", (done) => {
var ChildObject = Parse.Object.extend("ChildObject"); var ChildObject = Parse.Object.extend("ChildObject");
var childObjects = []; var childObjects = [];
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
@@ -248,7 +248,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("queries on relation fields with multiple containedIn (regression test for #1271)", (done) => { it("queries on relation fields with multiple containedIn (regression test for #1271)", (done) => {
let ChildObject = Parse.Object.extend("ChildObject"); let ChildObject = Parse.Object.extend("ChildObject");
let childObjects = []; let childObjects = [];
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
@@ -334,7 +334,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("query on pointer and relation fields with equal bis", (done) => { it("query on pointer and relation fields with equal bis", (done) => {
var ChildObject = Parse.Object.extend("ChildObject"); var ChildObject = Parse.Object.extend("ChildObject");
var childObjects = []; var childObjects = [];
for (var i = 0; i < 10; i++) { for (var i = 0; i < 10; i++) {
@@ -419,7 +419,7 @@ describe('Parse.Relation testing', () => {
}); });
it_exclude_dbs(['postgres'])("Get query on relation using un-fetched parent object", (done) => { it("Get query on relation using un-fetched parent object", (done) => {
// Setup data model // Setup data model
var Wheel = Parse.Object.extend('Wheel'); var Wheel = Parse.Object.extend('Wheel');
var Car = Parse.Object.extend('Car'); var Car = Parse.Object.extend('Car');
@@ -452,7 +452,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("Find query on relation using un-fetched parent object", (done) => { it("Find query on relation using un-fetched parent object", (done) => {
// Setup data model // Setup data model
var Wheel = Parse.Object.extend('Wheel'); var Wheel = Parse.Object.extend('Wheel');
var Car = Parse.Object.extend('Car'); var Car = Parse.Object.extend('Car');
@@ -486,7 +486,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('Find objects with a related object using equalTo', (done) => { it('Find objects with a related object using equalTo', (done) => {
// Setup the objects // Setup the objects
var Card = Parse.Object.extend('Card'); var Card = Parse.Object.extend('Card');
var House = Parse.Object.extend('House'); var House = Parse.Object.extend('House');
@@ -506,7 +506,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should properly get related objects with unfetched queries', (done) => { it('should properly get related objects with unfetched queries', (done) => {
let objects = []; let objects = [];
let owners = []; let owners = [];
let allObjects = []; let allObjects = [];
@@ -575,7 +575,7 @@ describe('Parse.Relation testing', () => {
}) })
}); });
it_exclude_dbs(['postgres'])("select query", function(done) { it("select query", function(done) {
var RestaurantObject = Parse.Object.extend("Restaurant"); var RestaurantObject = Parse.Object.extend("Restaurant");
var PersonObject = Parse.Object.extend("Person"); var PersonObject = Parse.Object.extend("Person");
var OwnerObject = Parse.Object.extend('Owner'); var OwnerObject = Parse.Object.extend('Owner');
@@ -615,7 +615,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("dontSelect query", function(done) { it("dontSelect query", function(done) {
var RestaurantObject = Parse.Object.extend("Restaurant"); var RestaurantObject = Parse.Object.extend("Restaurant");
var PersonObject = Parse.Object.extend("Person"); var PersonObject = Parse.Object.extend("Person");
var OwnerObject = Parse.Object.extend('Owner'); var OwnerObject = Parse.Object.extend('Owner');
@@ -657,7 +657,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('relations are not bidirectional (regression test for #871)', done => { it('relations are not bidirectional (regression test for #871)', done => {
let PersonObject = Parse.Object.extend("Person"); let PersonObject = Parse.Object.extend("Person");
let p1 = new PersonObject(); let p1 = new PersonObject();
let p2 = new PersonObject(); let p2 = new PersonObject();
@@ -684,7 +684,7 @@ describe('Parse.Relation testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('can query roles in Cloud Code (regession test #1489)', done => { it('can query roles in Cloud Code (regession test #1489)', done => {
Parse.Cloud.define('isAdmin', (request, response) => { Parse.Cloud.define('isAdmin', (request, response) => {
let query = new Parse.Query(Parse.Role); let query = new Parse.Query(Parse.Role);
query.equalTo('name', 'admin'); query.equalTo('name', 'admin');

View File

@@ -7,7 +7,7 @@ var Auth = require("../src/Auth").Auth;
var Config = require("../src/Config"); var Config = require("../src/Config");
describe('Parse Role testing', () => { describe('Parse Role testing', () => {
it_exclude_dbs(['postgres'])('Do a bunch of basic role testing', done => { it('Do a bunch of basic role testing', done => {
var user; var user;
var role; var role;
@@ -76,7 +76,7 @@ describe('Parse Role testing', () => {
return role.save({}, { useMasterKey: true }); return role.save({}, { useMasterKey: true });
}; };
it_exclude_dbs(['postgres'])("should not recursively load the same role multiple times", (done) => { it("should not recursively load the same role multiple times", (done) => {
var rootRole = "RootRole"; var rootRole = "RootRole";
var roleNames = ["FooRole", "BarRole", "BazRole"]; var roleNames = ["FooRole", "BarRole", "BazRole"];
var allRoles = [rootRole].concat(roleNames); var allRoles = [rootRole].concat(roleNames);
@@ -142,7 +142,7 @@ describe('Parse Role testing', () => {
}); });
it_exclude_dbs(['postgres'])("should recursively load roles", (done) => { it("should recursively load roles", (done) => {
var rolesNames = ["FooRole", "BarRole", "BazRole"]; var rolesNames = ["FooRole", "BarRole", "BazRole"];
var roleIds = {}; var roleIds = {};
createTestUser().then( (user) => { createTestUser().then( (user) => {
@@ -174,7 +174,7 @@ describe('Parse Role testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("_Role object should not save without name.", (done) => { it("_Role object should not save without name.", (done) => {
var role = new Parse.Role(); var role = new Parse.Role();
role.save(null,{useMasterKey:true}) role.save(null,{useMasterKey:true})
.then((r) => { .then((r) => {
@@ -245,7 +245,7 @@ describe('Parse Role testing', () => {
}); });
it_exclude_dbs(['postgres'])('can create role and query empty users', (done)=> { it('can create role and query empty users', (done)=> {
var roleACL = new Parse.ACL(); var roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true); roleACL.setPublicReadAccess(true);
var role = new Parse.Role('subscribers', roleACL); var role = new Parse.Role('subscribers', roleACL);
@@ -265,7 +265,7 @@ describe('Parse Role testing', () => {
}); });
// Based on various scenarios described in issues #827 and #683, // Based on various scenarios described in issues #827 and #683,
it_exclude_dbs(['postgres'])('should properly handle role permissions on objects', (done) => { it('should properly handle role permissions on objects', (done) => {
var user, user2, user3; var user, user2, user3;
var role, role2, role3; var role, role2, role3;
var obj, obj2; var obj, obj2;

View File

@@ -58,7 +58,7 @@ describe('Parse.User testing', () => {
expectError(Parse.Error.OBJECT_NOT_FOUND, done)); expectError(Parse.Error.OBJECT_NOT_FOUND, done));
}, },
error: function(err) { error: function(err) {
console.error(err); jfail(err);
fail("Shit should not fail"); fail("Shit should not fail");
done(); done();
} }
@@ -88,7 +88,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should respect ACL without locking user out', (done) => { it('should respect ACL without locking user out', (done) => {
let user = new Parse.User(); let user = new Parse.User();
let ACL = new Parse.ACL(); let ACL = new Parse.ACL();
ACL.setPublicReadAccess(false); ACL.setPublicReadAccess(false);
@@ -148,10 +148,13 @@ describe('Parse.User testing', () => {
ok(fileAgain.name()); ok(fileAgain.name());
ok(fileAgain.url()); ok(fileAgain.url());
done(); done();
}).catch(err => {
jfail(err);
done();
}); });
}); });
it_exclude_dbs(['postgres'])('become sends token back', done => { it('become sends token back', done => {
let user = null; let user = null;
var sessionToken = null; var sessionToken = null;
@@ -171,7 +174,7 @@ describe('Parse.User testing', () => {
}).then(() => { }).then(() => {
done(); done();
}, error => { }, error => {
fail(error); jfail(error);
done(); done();
}); });
}); });
@@ -295,7 +298,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("cannot saveAll with non-authed user", (done) => { it("cannot saveAll with non-authed user", (done) => {
var user = new Parse.User(); var user = new Parse.User();
user.signUp({ user.signUp({
"password": "asdf", "password": "asdf",
@@ -488,7 +491,7 @@ describe('Parse.User testing', () => {
return promise._thenRunCallbacks(optionsOrCallback); return promise._thenRunCallbacks(optionsOrCallback);
} }
it_exclude_dbs(['postgres'])("contained in user array queries", (done) => { it("contained in user array queries", (done) => {
var USERS = 4; var USERS = 4;
var MESSAGES = 5; var MESSAGES = 5;
@@ -503,6 +506,11 @@ describe('Parse.User testing', () => {
signUpAll(userList, function(users) { signUpAll(userList, function(users) {
// Make a list of messages. // Make a list of messages.
if (!users || users.length != USERS) {
fail('signupAll failed');
done();
return;
}
var messageList = range(MESSAGES).map(function(i) { var messageList = range(MESSAGES).map(function(i) {
var message = new TestObject(); var message = new TestObject();
message.set("to", users[(i + 1) % USERS]); message.set("to", users[(i + 1) % USERS]);
@@ -583,7 +591,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("count users", (done) => { it("count users", (done) => {
var james = new Parse.User(); var james = new Parse.User();
james.set("username", "james"); james.set("username", "james");
james.set("password", "mypass"); james.set("password", "mypass");
@@ -711,7 +719,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("saving user after browser refresh", (done) => { it("saving user after browser refresh", (done) => {
var _ = Parse._; var _ = Parse._;
var id; var id;
@@ -859,7 +867,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("user on disk gets updated after save", (done) => { it("user on disk gets updated after save", (done) => {
var SuperUser = Parse.User.extend({ var SuperUser = Parse.User.extend({
isSuper: function() { isSuper: function() {
return true; return true;
@@ -1007,7 +1015,7 @@ describe('Parse.User testing', () => {
} }
}); });
it_exclude_dbs(['postgres'])("log in with provider", (done) => { it("log in with provider", (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1022,14 +1030,14 @@ describe('Parse.User testing', () => {
done(); done();
}, },
error: function(model, error) { error: function(model, error) {
console.error(model, error); jfail(error);
ok(false, "linking should have worked"); ok(false, "linking should have worked");
done(); done();
} }
}); });
}); });
it_exclude_dbs(['postgres'])("user authData should be available in cloudcode (#2342)", (done) => { it("user authData should be available in cloudcode (#2342)", (done) => {
Parse.Cloud.define('checkLogin', (req, res) => { Parse.Cloud.define('checkLogin', (req, res) => {
expect(req.user).not.toBeUndefined(); expect(req.user).not.toBeUndefined();
@@ -1052,14 +1060,14 @@ describe('Parse.User testing', () => {
Parse.Cloud.run('checkLogin').then(done, done); Parse.Cloud.run('checkLogin').then(done, done);
}, },
error: function(model, error) { error: function(model, error) {
console.error(model, error); jfail(error);
ok(false, "linking should have worked"); ok(false, "linking should have worked");
done(); done();
} }
}); });
}); });
it_exclude_dbs(['postgres'])("log in with provider and update token", (done) => { it("log in with provider and update token", (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token'); var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token');
var errorHandler = function(err) { var errorHandler = function(err) {
@@ -1093,7 +1101,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('returns authData when authed and logged in with provider (regression test for #1498)', done => { it('returns authData when authed and logged in with provider (regression test for #1498)', done => {
Parse.Object.enableSingleInstance(); Parse.Object.enableSingleInstance();
let provider = getMockFacebookProvider(); let provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
@@ -1128,12 +1136,12 @@ describe('Parse.User testing', () => {
}).then(() => { }).then(() => {
done(); done();
}, error => { }, error => {
fail(error); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])("log in with provider twice", (done) => { it("log in with provider twice", (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1164,14 +1172,14 @@ describe('Parse.User testing', () => {
done(); done();
}, },
error: function(model, error) { error: function(model, error) {
fail(error); jfail(error);
ok(false, "LogIn should have worked"); ok(false, "LogIn should have worked");
done(); done();
} }
}); });
}, },
error: function(model, error) { error: function(model, error) {
console.error(model, error); jfail(error);
ok(false, "LogIn should have worked"); ok(false, "LogIn should have worked");
done(); done();
} }
@@ -1208,7 +1216,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("login with provider should not call beforeSave trigger", (done) => { it("login with provider should not call beforeSave trigger", (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1232,7 +1240,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("link with provider", (done) => { it("link with provider", (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
var user = new Parse.User(); var user = new Parse.User();
@@ -1372,7 +1380,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("unlink with provider", (done) => { it("unlink with provider", (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1408,7 +1416,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("unlink and link", (done) => { it("unlink and link", (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1483,7 +1491,7 @@ describe('Parse.User testing', () => {
done(); done();
}, },
error: function(error) { error: function(error) {
console.error(error); jfail(error);
fail('SHould not fail'); fail('SHould not fail');
done(); done();
} }
@@ -1501,7 +1509,7 @@ describe('Parse.User testing', () => {
var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token'); var secondProvider = getMockFacebookProviderWithIdToken('8675309', 'jenny_valid_token');
var errorHandler = function(model, error) { var errorHandler = function(model, error) {
console.error(error); jfail(error);
fail('Should not fail'); fail('Should not fail');
done(); done();
} }
@@ -1570,7 +1578,7 @@ describe('Parse.User testing', () => {
}) })
}, },
error: function(error) { error: function(error) {
console.error(error); jfail(error);
fail('SHould not fail'); fail('SHould not fail');
done(); done();
} }
@@ -1583,7 +1591,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should fail linking with existing', (done) => { it('should fail linking with existing', (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1609,7 +1617,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should fail linking with existing', (done) => { it('should fail linking with existing', (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1635,7 +1643,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should properly error when password is missing', (done) => { it('should properly error when password is missing', (done) => {
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
Parse.User._logInWith("facebook", { Parse.User._logInWith("facebook", {
@@ -1658,7 +1666,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should have authData in beforeSave and afterSave', (done) => { it('should have authData in beforeSave and afterSave', (done) => {
Parse.Cloud.beforeSave('_User', (request, response) => { Parse.Cloud.beforeSave('_User', (request, response) => {
let authData = request.object.get('authData'); let authData = request.object.get('authData');
@@ -1721,7 +1729,7 @@ describe('Parse.User testing', () => {
})); }));
}); });
it_exclude_dbs(['postgres'])("log in with explicit facebook auth data", (done) => { it("log in with explicit facebook auth data", (done) => {
Parse.FacebookUtils.logIn({ Parse.FacebookUtils.logIn({
id: "8675309", id: "8675309",
access_token: "jenny", access_token: "jenny",
@@ -1729,7 +1737,7 @@ describe('Parse.User testing', () => {
}, expectSuccess({success: done})); }, expectSuccess({success: done}));
}); });
it_exclude_dbs(['postgres'])("log in async with explicit facebook auth data", (done) => { it("log in async with explicit facebook auth data", (done) => {
Parse.FacebookUtils.logIn({ Parse.FacebookUtils.logIn({
id: "8675309", id: "8675309",
access_token: "jenny", access_token: "jenny",
@@ -1742,7 +1750,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("link with explicit facebook auth data", (done) => { it("link with explicit facebook auth data", (done) => {
Parse.User.signUp("mask", "open sesame", null, expectSuccess({ Parse.User.signUp("mask", "open sesame", null, expectSuccess({
success: function(user) { success: function(user) {
Parse.FacebookUtils.link(user, { Parse.FacebookUtils.link(user, {
@@ -1750,14 +1758,14 @@ describe('Parse.User testing', () => {
access_token: "jenny", access_token: "jenny",
expiration_date: new Date().toJSON() expiration_date: new Date().toJSON()
}).then(done, (error) => { }).then(done, (error) => {
fail(error); jfail(error);
done(); done();
}); });
} }
})); }));
}); });
it_exclude_dbs(['postgres'])("link async with explicit facebook auth data", (done) => { it("link async with explicit facebook auth data", (done) => {
Parse.User.signUp("mask", "open sesame", null, expectSuccess({ Parse.User.signUp("mask", "open sesame", null, expectSuccess({
success: function(user) { success: function(user) {
Parse.FacebookUtils.link(user, { Parse.FacebookUtils.link(user, {
@@ -1936,7 +1944,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('unset user email', (done) => { it('unset user email', (done) => {
var user = new Parse.User(); var user = new Parse.User();
user.set('username', 'test'); user.set('username', 'test');
user.set('password', 'test'); user.set('password', 'test');
@@ -2073,10 +2081,14 @@ describe('Parse.User testing', () => {
url: 'http://localhost:8378/1/sessions' url: 'http://localhost:8378/1/sessions'
}, (error, response, body) => { }, (error, response, body) => {
expect(error).toBe(null); expect(error).toBe(null);
var b = JSON.parse(body); try {
expect(b.results.length).toEqual(1); var b = JSON.parse(body);
expect(typeof b.results[0].user).toEqual('object'); expect(b.results.length).toEqual(1);
expect(b.results[0].user.objectId).toEqual(user.id); expect(typeof b.results[0].user).toEqual('object');
expect(b.results[0].user.objectId).toEqual(user.id);
} catch(e) {
jfail(e);
}
done(); done();
}); });
}); });
@@ -2097,9 +2109,16 @@ describe('Parse.User testing', () => {
url: 'http://localhost:8378/1/sessions' url: 'http://localhost:8378/1/sessions'
}, (error, response, body) => { }, (error, response, body) => {
expect(error).toBe(null); expect(error).toBe(null);
var b = JSON.parse(body); var objId;
expect(b.results.length).toEqual(1); try {
var objId = b.results[0].objectId; var b = JSON.parse(body);
expect(b.results.length).toEqual(1);
objId = b.results[0].objectId;
} catch(e) {
jfail(e);
done();
return;
}
request.del({ request.del({
headers: { headers: {
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
@@ -2162,7 +2181,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('test parse user become', (done) => { it('test parse user become', (done) => {
var sessionToken = null; var sessionToken = null;
Parse.Promise.as().then(function() { Parse.Promise.as().then(function() {
return Parse.User.signUp("flessard", "folo",{'foo':1}); return Parse.User.signUp("flessard", "folo",{'foo':1});
@@ -2215,7 +2234,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("session expiresAt correct format", (done) => { it("session expiresAt correct format", (done) => {
Parse.User.signUp("asdf", "zxcv", null, { Parse.User.signUp("asdf", "zxcv", null, {
success: function(user) { success: function(user) {
request.get({ request.get({
@@ -2308,7 +2327,7 @@ describe('Parse.User testing', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('should cleanup null authData keys ParseUser update (regression test for #1198, #2252)', (done) => { it('should cleanup null authData keys ParseUser update (regression test for #1198, #2252)', (done) => {
Parse.Cloud.beforeSave('_User', (req, res) => { Parse.Cloud.beforeSave('_User', (req, res) => {
req.object.set('foo', 'bar'); req.object.set('foo', 'bar');
res.success(); res.success();
@@ -2390,7 +2409,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should send email when upgrading from anon', (done) => { it('should send email when upgrading from anon', (done) => {
let emailCalled = false; let emailCalled = false;
let emailOptions; let emailOptions;
@@ -2437,7 +2456,7 @@ describe('Parse.User testing', () => {
expect(emailOptions.user.get('email')).toEqual('user@email.com'); expect(emailOptions.user.get('email')).toEqual('user@email.com');
done(); done();
}).catch((err) => { }).catch((err) => {
console.error(err); jfail(err);
fail('no request should fail: ' + JSON.stringify(err)); fail('no request should fail: ' + JSON.stringify(err));
done(); done();
}); });
@@ -2484,7 +2503,7 @@ describe('Parse.User testing', () => {
}); });
it_exclude_dbs(['postgres'])('should fail to become user with expired token', (done) => { it('should fail to become user with expired token', (done) => {
let token; let token;
Parse.User.signUp("auser", "somepass", null) Parse.User.signUp("auser", "somepass", null)
.then(user => rp({ .then(user => rp({
@@ -2549,7 +2568,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should not overwrite username when unlinking facebook user (regression test for #1532)', done => { it('should not overwrite username when unlinking facebook user (regression test for #1532)', done => {
Parse.Object.disableSingleInstance(); Parse.Object.disableSingleInstance();
var provider = getMockFacebookProvider(); var provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider); Parse.User._registerAuthenticationProvider(provider);
@@ -2577,12 +2596,12 @@ describe('Parse.User testing', () => {
})) }))
.catch(error => { .catch(error => {
fail('Unexpected failure testing in unlink user test'); fail('Unexpected failure testing in unlink user test');
fail(error); jfail(error);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('should revoke sessions when converting anonymous user to "normal" user', done => { it('should revoke sessions when converting anonymous user to "normal" user', done => {
request.post({ request.post({
url: 'http://localhost:8378/1/classes/_User', url: 'http://localhost:8378/1/classes/_User',
headers: { headers: {
@@ -2618,7 +2637,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should not revoke session tokens if the server is configures to not revoke session tokens', done => { it('should not revoke session tokens if the server is configures to not revoke session tokens', done => {
reconfigureServer({ revokeSessionOnPasswordReset: false }) reconfigureServer({ revokeSessionOnPasswordReset: false })
.then(() => { .then(() => {
request.post({ request.post({
@@ -2648,7 +2667,7 @@ describe('Parse.User testing', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should not fail querying non existing relations', done => { it('should not fail querying non existing relations', done => {
let user = new Parse.User(); let user = new Parse.User();
user.set({ user.set({
username: 'hello', username: 'hello',

View File

@@ -167,13 +167,13 @@ describe('Pointer Permissions', () => {
expect(res.length).toBe(1); expect(res.length).toBe(1);
done(); done();
}).catch((err) => { }).catch((err) => {
console.error(err); jfail(err);
fail('should not fail'); fail('should not fail');
done(); done();
}) })
}); });
it_exclude_dbs(['postgres'])('should not allow creating objects', (done) => { it('should not allow creating objects', (done) => {
let config = new Config(Parse.applicationId); let config = new Config(Parse.applicationId);
let user = new Parse.User(); let user = new Parse.User();
user.set({ user.set({
@@ -465,7 +465,7 @@ describe('Pointer Permissions', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('tests CLP / Pointer Perms / ACL read (PP/ACL OK)', (done) => { it('tests CLP / Pointer Perms / ACL read (PP/ACL OK)', (done) => {
/* /*
tests: tests:
CLP: find/get open ({"*": true}) CLP: find/get open ({"*": true})
@@ -512,7 +512,7 @@ describe('Pointer Permissions', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('tests CLP / Pointer Perms / ACL read (ACL locked)', (done) => { it('tests CLP / Pointer Perms / ACL read (ACL locked)', (done) => {
/* /*
tests: tests:
CLP: find/get open ({"*": true}) CLP: find/get open ({"*": true})
@@ -557,7 +557,7 @@ describe('Pointer Permissions', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should let master key find objects', (done) => { it('should let master key find objects', (done) => {
let config = new Config(Parse.applicationId); let config = new Config(Parse.applicationId);
let user = new Parse.User(); let user = new Parse.User();
let object = new Parse.Object('AnObject'); let object = new Parse.Object('AnObject');
@@ -587,7 +587,7 @@ describe('Pointer Permissions', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('should let master key get objects', (done) => { it('should let master key get objects', (done) => {
let config = new Config(Parse.applicationId); let config = new Config(Parse.applicationId);
let user = new Parse.User(); let user = new Parse.User();
let object = new Parse.Object('AnObject'); let object = new Parse.Object('AnObject');
@@ -619,7 +619,7 @@ describe('Pointer Permissions', () => {
}); });
it_exclude_dbs(['postgres'])('should let master key update objects', (done) => { it('should let master key update objects', (done) => {
let config = new Config(Parse.applicationId); let config = new Config(Parse.applicationId);
let user = new Parse.User(); let user = new Parse.User();
let object = new Parse.Object('AnObject'); let object = new Parse.Object('AnObject');
@@ -647,7 +647,7 @@ describe('Pointer Permissions', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('should let master key delete objects', (done) => { it('should let master key delete objects', (done) => {
let config = new Config(Parse.applicationId); let config = new Config(Parse.applicationId);
let user = new Parse.User(); let user = new Parse.User();
let object = new Parse.Object('AnObject'); let object = new Parse.Object('AnObject');

View File

@@ -13,7 +13,7 @@ describe("PromiseRouter", () => {
}); });
router.routes[0].handler({}).then((result) => { router.routes[0].handler({}).then((result) => {
console.error(result); jfail(result);
fail("this should not be called"); fail("this should not be called");
done(); done();
}, (error)=> { }, (error)=> {

View File

@@ -22,9 +22,8 @@ function createProduct() {
describe("test validate_receipt endpoint", () => { describe("test validate_receipt endpoint", () => {
beforeEach( done => { beforeEach( done => {
createProduct().then(done).fail(function(err){ createProduct().then(done).fail(function(err){
console.error(err);
done(); done();
}) });
}) })
it_exclude_dbs(['postgres'])("should bypass appstore validation", (done) => { it_exclude_dbs(['postgres'])("should bypass appstore validation", (done) => {
@@ -160,7 +159,7 @@ describe("test validate_receipt endpoint", () => {
}); });
}); });
it_exclude_dbs(['postgres'])("should not create a _Product", (done) => { it("should not create a _Product", (done) => {
var product = new Parse.Object("_Product"); var product = new Parse.Object("_Product");
product.save().then(function(){ product.save().then(function(){
fail("Should not be able to save"); fail("Should not be able to save");
@@ -173,7 +172,10 @@ describe("test validate_receipt endpoint", () => {
it_exclude_dbs(['postgres'])("should be able to update a _Product", (done) => { it_exclude_dbs(['postgres'])("should be able to update a _Product", (done) => {
var query = new Parse.Query("_Product"); var query = new Parse.Query("_Product");
query.first().then(function(product){ query.first().then(function(product) {
if (!product) {
return Promise.reject(new Error('Product should be found'));
}
product.set("title", "a new title"); product.set("title", "a new title");
return product.save(); return product.save();
}).then(function(productAgain){ }).then(function(productAgain){
@@ -189,6 +191,9 @@ describe("test validate_receipt endpoint", () => {
it_exclude_dbs(['postgres'])("should not be able to remove a require key in a _Product", (done) => { it_exclude_dbs(['postgres'])("should not be able to remove a require key in a _Product", (done) => {
var query = new Parse.Query("_Product"); var query = new Parse.Query("_Product");
query.first().then(function(product){ query.first().then(function(product){
if (!product) {
return Promise.reject(new Error('Product should be found'));
}
product.unset("title"); product.unset("title");
return product.save(); return product.save();
}).then(function(productAgain){ }).then(function(productAgain){

View File

@@ -130,7 +130,7 @@ describe('PushController', () => {
done(); done();
}); });
it_exclude_dbs(['postgres'])('properly increment badges', (done) => { it('properly increment badges', (done) => {
var payload = {data:{ var payload = {data:{
alert: "Hello World!", alert: "Hello World!",
@@ -184,13 +184,13 @@ describe('PushController', () => {
}).then((result) => { }).then((result) => {
done(); done();
}, (err) => { }, (err) => {
fail("should not fail"); jfail(err);
done(); done();
}); });
}); });
it_exclude_dbs(['postgres'])('properly set badges to 1', (done) => { it('properly set badges to 1', (done) => {
var payload = {data: { var payload = {data: {
alert: "Hello World!", alert: "Hello World!",
@@ -238,7 +238,7 @@ describe('PushController', () => {
}); });
it_exclude_dbs(['postgres'])('properly creates _PushStatus', (done) => { it('properly creates _PushStatus', (done) => {
var installations = []; var installations = [];
while(installations.length != 10) { while(installations.length != 10) {
@@ -318,7 +318,7 @@ describe('PushController', () => {
}); });
it_exclude_dbs(['postgres'])('should properly report failures in _PushStatus', (done) => { it('should properly report failures in _PushStatus', (done) => {
var pushAdapter = { var pushAdapter = {
send: function(body, installations) { send: function(body, installations) {
return installations.map((installation) => { return installations.map((installation) => {
@@ -397,7 +397,7 @@ describe('PushController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should support object type for alert', (done) => { it('should support object type for alert', (done) => {
var payload = {data: { var payload = {data: {
alert: { alert: {
'loc-key': 'hello_world', 'loc-key': 'hello_world',

View File

@@ -68,7 +68,7 @@ describe('PushRouter', () => {
done(); done();
}); });
it_exclude_dbs(['postgres'])('sends a push through REST', (done) => { it('sends a push through REST', (done) => {
request.post({ request.post({
url: Parse.serverURL+"/push", url: Parse.serverURL+"/push",
json: true, json: true,

View File

@@ -11,7 +11,7 @@ var config = new Config('test');
let database = config.database; let database = config.database;
describe('rest create', () => { describe('rest create', () => {
it_exclude_dbs(['postgres'])('handles _id', done => { it('handles _id', done => {
rest.create(config, auth.nobody(config), 'Foo', {}) rest.create(config, auth.nobody(config), 'Foo', {})
.then(() => database.adapter.find('Foo', { fields: {} }, {}, {})) .then(() => database.adapter.find('Foo', { fields: {} }, {}, {}))
.then(results => { .then(results => {
@@ -23,7 +23,7 @@ describe('rest create', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('handles array, object, date', (done) => { it('handles array, object, date', (done) => {
let now = new Date(); let now = new Date();
var obj = { var obj = {
array: [1, 2, 3], array: [1, 2, 3],
@@ -77,7 +77,7 @@ describe('rest create', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('handles create on non-existent class when disabled client class creation', (done) => { it('handles create on non-existent class when disabled client class creation', (done) => {
var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); var customConfig = Object.assign({}, config, {allowClientClassCreation: false});
rest.create(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {}) rest.create(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {})
.then(() => { .then(() => {
@@ -91,7 +91,7 @@ describe('rest create', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('handles create on existent class when disabled client class creation', (done) => { it('handles create on existent class when disabled client class creation', (done) => {
var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); var customConfig = Object.assign({}, config, {allowClientClassCreation: false});
config.database.loadSchema() config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('ClientClassCreation', {})) .then(schema => schema.addClassIfNotExists('ClientClassCreation', {}))
@@ -122,7 +122,7 @@ describe('rest create', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('handles anonymous user signup', (done) => { it('handles anonymous user signup', (done) => {
var data1 = { var data1 = {
authData: { authData: {
anonymous: { anonymous: {
@@ -310,7 +310,7 @@ describe('rest create', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("test default session length", (done) => { it("test default session length", (done) => {
var user = { var user = {
username: 'asdf', username: 'asdf',
password: 'zxcv', password: 'zxcv',

View File

@@ -134,7 +134,7 @@ describe('rest query', () => {
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it_exclude_dbs(['postgres'])('query non-existent class when disabled client class creation', (done) => { it('query non-existent class when disabled client class creation', (done) => {
var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); var customConfig = Object.assign({}, config, {allowClientClassCreation: false});
rest.find(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {}) rest.find(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {})
.then(() => { .then(() => {
@@ -148,7 +148,7 @@ describe('rest query', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('query existent class when disabled client class creation', (done) => { it('query existent class when disabled client class creation', (done) => {
var customConfig = Object.assign({}, config, {allowClientClassCreation: false}); var customConfig = Object.assign({}, config, {allowClientClassCreation: false});
config.database.loadSchema() config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('ClientClassCreation', {})) .then(schema => schema.addClassIfNotExists('ClientClassCreation', {}))
@@ -201,7 +201,7 @@ describe('rest query', () => {
}); });
return Promise.all([p0, p1]); return Promise.all([p0, p1]);
}).then(done).catch((err) => { }).then(done).catch((err) => {
console.error(err); jfail(err);
fail('should not fail'); fail('should not fail');
done(); done();
}) })
@@ -221,7 +221,7 @@ describe('rest query', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('query with limit = 0 and count = 1', (done) => { it('query with limit = 0 and count = 1', (done) => {
rest.create(config, nobody, 'TestObject', {foo: 'baz'} rest.create(config, nobody, 'TestObject', {foo: 'baz'}
).then(() => { ).then(() => {
return rest.create(config, nobody, return rest.create(config, nobody,

View File

@@ -30,7 +30,7 @@ describe('SchemaController', () => {
}).then((schema) => { }).then((schema) => {
done(); done();
}, (error) => { }, (error) => {
fail(error); jfail(error);
done(); done();
}); });
}); });
@@ -41,7 +41,7 @@ describe('SchemaController', () => {
}).then((schema) => { }).then((schema) => {
done(); done();
}, (error) => { }, (error) => {
fail(error); jfail(error);
done(); done();
}); });
}); });
@@ -99,7 +99,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('class-level permissions test user', (done) => { it('class-level permissions test user', (done) => {
var user; var user;
createTestUser().then((u) => { createTestUser().then((u) => {
user = u; user = u;
@@ -124,7 +124,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('class-level permissions test get', (done) => { it('class-level permissions test get', (done) => {
var obj; var obj;
createTestUser() createTestUser()
.then(user => { .then(user => {
@@ -163,7 +163,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('can add classes without needing an object', done => { it('can add classes without needing an object', done => {
config.database.loadSchema() config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('NewClass', { .then(schema => schema.addClassIfNotExists('NewClass', {
foo: {type: 'String'} foo: {type: 'String'}
@@ -388,7 +388,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('will create classes', done => { it('will create classes', done => {
config.database.loadSchema() config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('NewClass', { .then(schema => schema.addClassIfNotExists('NewClass', {
aNumber: {type: 'Number'}, aNumber: {type: 'Number'},
@@ -436,7 +436,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('creates the default fields for non-custom classes', done => { it('creates the default fields for non-custom classes', done => {
config.database.loadSchema() config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('_Installation', { .then(schema => schema.addClassIfNotExists('_Installation', {
foo: {type: 'Number'}, foo: {type: 'Number'},
@@ -478,7 +478,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('creates non-custom classes which include relation field', done => { it('creates non-custom classes which include relation field', done => {
config.database.loadSchema() config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('_Role', {})) .then(schema => schema.addClassIfNotExists('_Role', {}))
.then(actualSchema => { .then(actualSchema => {
@@ -507,7 +507,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('creates non-custom classes which include pointer field', done => { it('creates non-custom classes which include pointer field', done => {
config.database.loadSchema() config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('_Session', {})) .then(schema => schema.addClassIfNotExists('_Session', {}))
.then(actualSchema => { .then(actualSchema => {
@@ -552,7 +552,7 @@ describe('SchemaController', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('can check if a class exists', done => { it('can check if a class exists', done => {
config.database.loadSchema() config.database.loadSchema()
.then(schema => { .then(schema => {
return schema.addClassIfNotExists('NewClass', {}) return schema.addClassIfNotExists('NewClass', {})
@@ -573,7 +573,7 @@ describe('SchemaController', () => {
}) })
.catch(error => { .catch(error => {
fail('Couldn\'t create class'); fail('Couldn\'t create class');
fail(error); jfail(error);
}); });
}) })
.catch(error => fail('Couldn\'t load schema')); .catch(error => fail('Couldn\'t load schema'));
@@ -654,7 +654,7 @@ describe('SchemaController', () => {
} }
done(); done();
}, error => { }, error => {
fail(error); jfail(error);
done(); done();
}); });
}); });
@@ -728,7 +728,7 @@ describe('SchemaController', () => {
}); });
}) })
.catch(error => { .catch(error => {
fail(error); jfail(error);
done(); done();
}); });
}); });

View File

@@ -26,7 +26,7 @@ describe('Uniqueness', function() {
}); });
}); });
it_exclude_dbs(['postgres'])('unique indexing works on pointer fields', done => { it('unique indexing works on pointer fields', done => {
let obj = new Parse.Object('UniquePointer'); let obj = new Parse.Object('UniquePointer');
obj.save({ string: 'who cares' }) obj.save({ string: 'who cares' })
.then(() => obj.save({ ptr: obj })) .then(() => obj.save({ ptr: obj }))
@@ -52,7 +52,7 @@ describe('Uniqueness', function() {
}); });
}); });
it_exclude_dbs(['postgres'])('fails when attempting to ensure uniqueness of fields that are not currently unique', done => { it('fails when attempting to ensure uniqueness of fields that are not currently unique', done => {
let o1 = new Parse.Object('UniqueFail'); let o1 = new Parse.Object('UniqueFail');
o1.set('key', 'val'); o1.set('key', 'val');
let o2 = new Parse.Object('UniqueFail'); let o2 = new Parse.Object('UniqueFail');

View File

@@ -28,7 +28,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('sends verification email if email verification is enabled', done => { it('sends verification email if email verification is enabled', done => {
var emailAdapter = { var emailAdapter = {
sendVerificationEmail: () => Promise.resolve(), sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(), sendPasswordResetEmail: () => Promise.resolve(),
@@ -97,7 +97,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('does send a validation email when updating the email', done => { it('does send a validation email when updating the email', done => {
var emailAdapter = { var emailAdapter = {
sendVerificationEmail: () => Promise.resolve(), sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(), sendPasswordResetEmail: () => Promise.resolve(),
@@ -140,7 +140,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('does send a validation email with valid verification link when updating the email', done => { it('does send a validation email with valid verification link when updating the email', done => {
var emailAdapter = { var emailAdapter = {
sendVerificationEmail: () => Promise.resolve(), sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(), sendPasswordResetEmail: () => Promise.resolve(),
@@ -238,7 +238,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('prevents user from login if email is not verified but preventLoginWithUnverifiedEmail is set to true', done => { it('prevents user from login if email is not verified but preventLoginWithUnverifiedEmail is set to true', done => {
reconfigureServer({ reconfigureServer({
appName: 'test', appName: 'test',
publicServerURL: 'http://localhost:1337/1', publicServerURL: 'http://localhost:1337/1',
@@ -271,7 +271,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', done => { it('allows user to login only after user clicks on the link to confirm email address if preventLoginWithUnverifiedEmail is set to true', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -314,20 +314,18 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
done(); done();
}); });
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("this should not fail"); fail("this should not fail");
done(); done();
}).catch((err) => }).catch((err) => {
{ jfail(err);
console.error(err);
fail(err);
done(); done();
}) })
}); });
}); });
}); });
it_exclude_dbs(['postgres'])('allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false', done => { it('allows user to login if email is not verified but preventLoginWithUnverifiedEmail is set to false', done => {
reconfigureServer({ reconfigureServer({
appName: 'test', appName: 'test',
publicServerURL: 'http://localhost:1337/1', publicServerURL: 'http://localhost:1337/1',
@@ -361,7 +359,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email', done => { it('fails if you include an emailAdapter, set a publicServerURL, but have no appName and send a password reset email', done => {
reconfigureServer({ reconfigureServer({
appName: undefined, appName: undefined,
publicServerURL: 'http://localhost:1337/1', publicServerURL: 'http://localhost:1337/1',
@@ -393,7 +391,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('fails if you include an emailAdapter, have an appName, but have no publicServerURL and send a password reset email', done => { it('fails if you include an emailAdapter, have an appName, but have no publicServerURL and send a password reset email', done => {
reconfigureServer({ reconfigureServer({
appName: undefined, appName: undefined,
emailAdapter: MockEmailAdapterWithOptions({ emailAdapter: MockEmailAdapterWithOptions({
@@ -424,7 +422,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('fails if you set a publicServerURL, have an appName, but no emailAdapter and send a password reset email', done => { it('fails if you set a publicServerURL, have an appName, but no emailAdapter and send a password reset email', done => {
reconfigureServer({ reconfigureServer({
appName: 'unused', appName: 'unused',
publicServerURL: 'http://localhost:1337/1', publicServerURL: 'http://localhost:1337/1',
@@ -452,7 +450,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('succeeds sending a password reset email if appName, publicServerURL, and email adapter are prodvided', done => { it('succeeds sending a password reset email if appName, publicServerURL, and email adapter are prodvided', done => {
reconfigureServer({ reconfigureServer({
appName: 'coolapp', appName: 'coolapp',
publicServerURL: 'http://localhost:1337/1', publicServerURL: 'http://localhost:1337/1',
@@ -515,7 +513,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('receives the app name and user in the adapter', done => { it('receives the app name and user in the adapter', done => {
var emailSent = false; var emailSent = false;
var emailAdapter = { var emailAdapter = {
sendVerificationEmail: options => { sendVerificationEmail: options => {
@@ -550,7 +548,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}) })
it_exclude_dbs(['postgres'])('when you click the link in the email it sets emailVerified to true and redirects you', done => { it('when you click the link in the email it sets emailVerified to true and redirects you', done => {
var user = new Parse.User(); var user = new Parse.User();
var sendEmailOptions; var sendEmailOptions;
var emailAdapter = { var emailAdapter = {
@@ -583,13 +581,11 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
expect(user.get('emailVerified')).toEqual(true); expect(user.get('emailVerified')).toEqual(true);
done(); done();
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("this should not fail"); fail("this should not fail");
done(); done();
}).catch((err) => }).catch((err) => {
{ jfail(err);
console.error(err);
fail(err);
done(); done();
}) })
}); });
@@ -640,7 +636,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
}); });
}); });
it_exclude_dbs(['postgres'])('does not update email verified if you use an invalid token', done => { it('does not update email verified if you use an invalid token', done => {
var user = new Parse.User(); var user = new Parse.User();
var emailAdapter = { var emailAdapter = {
sendVerificationEmail: options => { sendVerificationEmail: options => {
@@ -688,7 +684,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
followRedirect: false, followRedirect: false,
}, (error, response, body) => { }, (error, response, body) => {
if (error) { if (error) {
console.error(error); jfail(err);
fail("Failed to get the reset link"); fail("Failed to get the reset link");
return; return;
} }
@@ -713,7 +709,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
user.signUp().then(() => { user.signUp().then(() => {
Parse.User.requestPasswordReset('user@parse.com', { Parse.User.requestPasswordReset('user@parse.com', {
error: (err) => { error: (err) => {
console.error(err); jfail(err);
fail("Should not fail requesting a password"); fail("Should not fail requesting a password");
done(); done();
} }
@@ -753,7 +749,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
followRedirect: false, followRedirect: false,
}, (error, response, body) => { }, (error, response, body) => {
if (error) { if (error) {
console.error(error); jfail(error);
fail("Failed to get the reset link"); fail("Failed to get the reset link");
return; return;
} }
@@ -776,7 +772,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
followRedirect: false, followRedirect: false,
}, (error, response, body) => { }, (error, response, body) => {
if (error) { if (error) {
console.error(error); jfail(error);
fail("Failed to POST request password reset"); fail("Failed to POST request password reset");
return; return;
} }
@@ -793,7 +789,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
done(); done();
}); });
}, (err) => { }, (err) => {
console.error(err); jfail(err);
fail("should login with new password"); fail("should login with new password");
done(); done();
}); });
@@ -816,7 +812,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
user.signUp().then(() => { user.signUp().then(() => {
Parse.User.requestPasswordReset('user@parse.com', { Parse.User.requestPasswordReset('user@parse.com', {
error: (err) => { error: (err) => {
console.error(err); jfail(err);
fail("Should not fail"); fail("Should not fail");
done(); done();
} }

View File

@@ -14,24 +14,43 @@ const GridStoreAdapter = require('../src/Adapters/Files/GridStoreAdapter').GridS
const PostgresStorageAdapter = require('../src/Adapters/Storage/Postgres/PostgresStorageAdapter'); const PostgresStorageAdapter = require('../src/Adapters/Storage/Postgres/PostgresStorageAdapter');
const mongoURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase'; const mongoURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase';
const postgresURI = 'postgres://localhost:5432/parse_server_postgres_adapter_test_database';
let databaseAdapter; let databaseAdapter;
// need to bind for mocking mocha
let startDB = () => {};
let stopDB = () => {};
if (process.env.PARSE_SERVER_TEST_DB === 'postgres') { if (process.env.PARSE_SERVER_TEST_DB === 'postgres') {
var postgresURI = 'postgres://localhost:5432/parse_server_postgres_adapter_test_database';
databaseAdapter = new PostgresStorageAdapter({ databaseAdapter = new PostgresStorageAdapter({
uri: postgresURI, uri: postgresURI,
collectionPrefix: 'test_', collectionPrefix: 'test_',
}); });
} else { } else {
startDB = require('mongodb-runner/mocha/before').bind({
timeout: () => {},
slow: () => {}
});
stopDB = require('mongodb-runner/mocha/after');;
databaseAdapter = new MongoStorageAdapter({ databaseAdapter = new MongoStorageAdapter({
uri: mongoURI, uri: mongoURI,
collectionPrefix: 'test_', collectionPrefix: 'test_',
}) });
} }
var port = 8378; var port = 8378;
let gridStoreAdapter = new GridStoreAdapter(mongoURI); let gridStoreAdapter = new GridStoreAdapter(mongoURI);
let logLevel;
let silent = true;
if (process.env.VERBOSE) {
silent = false;
logLevel = 'verbose';
}
if (process.env.PARSE_SERVER_LOG_LEVEL) {
silent = false;
logLevel = process.env.PARSE_SERVER_LOG_LEVEL;
}
// Default server configuration for tests. // Default server configuration for tests.
var defaultConfiguration = { var defaultConfiguration = {
filesAdapter: gridStoreAdapter, filesAdapter: gridStoreAdapter,
@@ -45,7 +64,8 @@ var defaultConfiguration = {
webhookKey: 'hook', webhookKey: 'hook',
masterKey: 'test', masterKey: 'test',
fileKey: 'test', fileKey: 'test',
silent: !process.env.VERBOSE, silent,
logLevel,
push: { push: {
'ios': { 'ios': {
cert: 'prodCert.pem', cert: 'prodCert.pem',
@@ -65,17 +85,15 @@ var defaultConfiguration = {
let openConnections = {}; let openConnections = {};
// Set up a default API server for testing with default configuration. // Set up a default API server for testing with default configuration.
var api = new ParseServer(defaultConfiguration);
var app = express(); var app = express();
var api = new ParseServer(defaultConfiguration);
app.use('/1', api); app.use('/1', api);
var server = app.listen(port); var server = app.listen(port);
server.on('connection', connection => { server.on('connection', connection => {
let key = `${connection.remoteAddress}:${connection.remotePort}`; let key = `${connection.remoteAddress}:${connection.remotePort}`;
openConnections[key] = connection; openConnections[key] = connection;
connection.on('close', () => { delete openConnections[key] }); connection.on('close', () => { delete openConnections[key] });
}); });
// Allows testing specific configurations of Parse Server // Allows testing specific configurations of Parse Server
const reconfigureServer = changedConfiguration => { const reconfigureServer = changedConfiguration => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -111,6 +129,11 @@ Parse.serverURL = 'http://localhost:' + port + '/1';
// TODO: update tests to work in an A+ way // TODO: update tests to work in an A+ way
Parse.Promise.disableAPlusCompliant(); Parse.Promise.disableAPlusCompliant();
// 10 minutes timeout
beforeAll(startDB, 10*60*1000);
afterAll(stopDB);
beforeEach(done => { beforeEach(done => {
try { try {
Parse.User.enableUnsafeCurrentUser(); Parse.User.enableUnsafeCurrentUser();
@@ -135,7 +158,9 @@ beforeEach(done => {
Parse.serverURL = 'http://localhost:' + port + '/1'; Parse.serverURL = 'http://localhost:' + port + '/1';
done(); done();
}, error => { }, error => {
fail(JSON.stringify(error)); Parse.initialize('test', 'test', 'test');
Parse.serverURL = 'http://localhost:' + port + '/1';
// fail(JSON.stringify(error));
done(); done();
}) })
}); });
@@ -145,7 +170,9 @@ afterEach(function(done) {
if (Object.keys(openConnections).length > 0) { if (Object.keys(openConnections).length > 0) {
fail('There were open connections to the server left after the test finished'); fail('There were open connections to the server left after the test finished');
} }
done(); on_db('postgres', () => {
TestUtils.destroyAllDataPermanently().then(done, done);
}, done);
}; };
Parse.Cloud._removeAllHooks(); Parse.Cloud._removeAllHooks();
databaseAdapter.getAllClasses() databaseAdapter.getAllClasses()
@@ -216,12 +243,12 @@ function strictEqual(a, b, message) {
function notEqual(a, b, message) { function notEqual(a, b, message) {
expect(a).not.toEqual(b, message); expect(a).not.toEqual(b, message);
} }
function expectSuccess(params) { function expectSuccess(params, done) {
return { return {
success: params.success, success: params.success,
error: function(e) { error: function(e) {
console.log('got error', e);
fail('failure happened in expectSuccess'); fail('failure happened in expectSuccess');
done ? done() : null;
}, },
} }
} }
@@ -326,6 +353,9 @@ global.range = range;
global.reconfigureServer = reconfigureServer; global.reconfigureServer = reconfigureServer;
global.defaultConfiguration = defaultConfiguration; global.defaultConfiguration = defaultConfiguration;
global.mockFacebookAuthenticator = mockFacebookAuthenticator; global.mockFacebookAuthenticator = mockFacebookAuthenticator;
global.jfail = function(err) {
fail(JSON.stringify(err));
}
global.it_exclude_dbs = excluded => { global.it_exclude_dbs = excluded => {
if (excluded.includes(process.env.PARSE_SERVER_TEST_DB)) { if (excluded.includes(process.env.PARSE_SERVER_TEST_DB)) {
@@ -349,7 +379,18 @@ global.describe_only_db = db => {
} else if (!process.env.PARSE_SERVER_TEST_DB && db == 'mongo') { } else if (!process.env.PARSE_SERVER_TEST_DB && db == 'mongo') {
return describe; return describe;
} else { } else {
return () => {}; return () => {};
}
}
global.on_db = (db, callback, elseCallback) => {
if (process.env.PARSE_SERVER_TEST_DB == db) {
return callback();
} else if (!process.env.PARSE_SERVER_TEST_DB && db == 'mongo') {
return callback();
}
if (elseCallback) {
elseCallback();
} }
} }

View File

@@ -9,7 +9,7 @@ var express = require('express');
const MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter'); const MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter');
describe('server', () => { describe('server', () => {
it_exclude_dbs(['postgres'])('requires a master key and app id', done => { it('requires a master key and app id', done => {
reconfigureServer({ appId: undefined }) reconfigureServer({ appId: undefined })
.catch(error => { .catch(error => {
expect(error).toEqual('You must provide an appId!'); expect(error).toEqual('You must provide an appId!');
@@ -25,7 +25,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('support http basic authentication with masterkey', done => { it('support http basic authentication with masterkey', done => {
request.get({ request.get({
url: 'http://localhost:8378/1/classes/TestObject', url: 'http://localhost:8378/1/classes/TestObject',
headers: { headers: {
@@ -37,7 +37,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('support http basic authentication with javascriptKey', done => { it('support http basic authentication with javascriptKey', done => {
request.get({ request.get({
url: 'http://localhost:8378/1/classes/TestObject', url: 'http://localhost:8378/1/classes/TestObject',
headers: { headers: {
@@ -49,7 +49,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('fails if database is unreachable', done => { it('fails if database is unreachable', done => {
reconfigureServer({ databaseAdapter: new MongoStorageAdapter({ uri: 'mongodb://fake:fake@localhost:43605/drew3' }) }) reconfigureServer({ databaseAdapter: new MongoStorageAdapter({ uri: 'mongodb://fake:fake@localhost:43605/drew3' }) })
.catch(() => { .catch(() => {
//Need to use rest api because saving via JS SDK results in fail() not getting called //Need to use rest api because saving via JS SDK results in fail() not getting called
@@ -70,7 +70,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('can load email adapter via object', done => { it('can load email adapter via object', done => {
reconfigureServer({ reconfigureServer({
appName: 'unused', appName: 'unused',
verifyUserEmails: true, verifyUserEmails: true,
@@ -83,7 +83,7 @@ describe('server', () => {
}).then(done, fail); }).then(done, fail);
}); });
it_exclude_dbs(['postgres'])('can load email adapter via class', done => { it('can load email adapter via class', done => {
reconfigureServer({ reconfigureServer({
appName: 'unused', appName: 'unused',
verifyUserEmails: true, verifyUserEmails: true,
@@ -99,7 +99,7 @@ describe('server', () => {
}).then(done, fail); }).then(done, fail);
}); });
it_exclude_dbs(['postgres'])('can load email adapter via module name', done => { it('can load email adapter via module name', done => {
reconfigureServer({ reconfigureServer({
appName: 'unused', appName: 'unused',
verifyUserEmails: true, verifyUserEmails: true,
@@ -115,7 +115,7 @@ describe('server', () => {
}).then(done, fail); }).then(done, fail);
}); });
it_exclude_dbs(['postgres'])('can load email adapter via only module name', done => { it('can load email adapter via only module name', done => {
reconfigureServer({ reconfigureServer({
appName: 'unused', appName: 'unused',
verifyUserEmails: true, verifyUserEmails: true,
@@ -128,7 +128,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('throws if you initialize email adapter incorrecly', done => { it('throws if you initialize email adapter incorrecly', done => {
reconfigureServer({ reconfigureServer({
appName: 'unused', appName: 'unused',
verifyUserEmails: true, verifyUserEmails: true,
@@ -146,7 +146,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('can report the server version', done => { it('can report the server version', done => {
request.get({ request.get({
url: 'http://localhost:8378/1/serverInfo', url: 'http://localhost:8378/1/serverInfo',
headers: { headers: {
@@ -160,7 +160,7 @@ describe('server', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('can create a parse-server v1', done => { it('can create a parse-server v1', done => {
var parseServer = new ParseServer.default(Object.assign({}, var parseServer = new ParseServer.default(Object.assign({},
defaultConfiguration, { defaultConfiguration, {
appId: "aTestApp", appId: "aTestApp",
@@ -191,7 +191,7 @@ describe('server', () => {
); );
}); });
it_exclude_dbs(['postgres'])('can create a parse-server v2', done => { it('can create a parse-server v2', done => {
let objId; let objId;
let server let server
let parseServer = ParseServer.ParseServer(Object.assign({}, let parseServer = ParseServer.ParseServer(Object.assign({},
@@ -221,13 +221,17 @@ describe('server', () => {
}) })
.catch(error => { .catch(error => {
fail(JSON.stringify(error)) fail(JSON.stringify(error))
done(); if (server) {
server.close(done);
} else {
done();
}
}); });
}} }}
)); ));
}); });
it_exclude_dbs(['postgres'])('has createLiveQueryServer', done => { it('has createLiveQueryServer', done => {
// original implementation through the factory // original implementation through the factory
expect(typeof ParseServer.ParseServer.createLiveQueryServer).toEqual('function'); expect(typeof ParseServer.ParseServer.createLiveQueryServer).toEqual('function');
// For import calls // For import calls
@@ -235,7 +239,7 @@ describe('server', () => {
done(); done();
}); });
it_exclude_dbs(['postgres'])('exposes correct adapters', done => { it('exposes correct adapters', done => {
expect(ParseServer.S3Adapter).toThrow(); expect(ParseServer.S3Adapter).toThrow();
expect(ParseServer.GCSAdapter).toThrow('GCSAdapter is not provided by parse-server anymore; please install parse-server-gcs-adapter'); expect(ParseServer.GCSAdapter).toThrow('GCSAdapter is not provided by parse-server anymore; please install parse-server-gcs-adapter');
expect(ParseServer.FileSystemAdapter).toThrow(); expect(ParseServer.FileSystemAdapter).toThrow();
@@ -243,7 +247,7 @@ describe('server', () => {
done(); done();
}); });
it_exclude_dbs(['postgres'])('properly gives publicServerURL when set', done => { it('properly gives publicServerURL when set', done => {
reconfigureServer({ publicServerURL: 'https://myserver.com/1' }) reconfigureServer({ publicServerURL: 'https://myserver.com/1' })
.then(() => { .then(() => {
var config = new Config('test', 'http://localhost:8378/1'); var config = new Config('test', 'http://localhost:8378/1');
@@ -252,7 +256,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('properly removes trailing slash in mount', done => { it('properly removes trailing slash in mount', done => {
reconfigureServer({}) reconfigureServer({})
.then(() => { .then(() => {
var config = new Config('test', 'http://localhost:8378/1/'); var config = new Config('test', 'http://localhost:8378/1/');
@@ -261,7 +265,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should throw when getting invalid mount', done => { it('should throw when getting invalid mount', done => {
reconfigureServer({ publicServerURL: 'blabla:/some' }) reconfigureServer({ publicServerURL: 'blabla:/some' })
.catch(error => { .catch(error => {
expect(error).toEqual('publicServerURL should be a valid HTTPS URL starting with https://') expect(error).toEqual('publicServerURL should be a valid HTTPS URL starting with https://')
@@ -269,7 +273,7 @@ describe('server', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('fails if the session length is not a number', done => { it('fails if the session length is not a number', done => {
reconfigureServer({ sessionLength: 'test' }) reconfigureServer({ sessionLength: 'test' })
.catch(error => { .catch(error => {
expect(error).toEqual('Session length must be a valid number.'); expect(error).toEqual('Session length must be a valid number.');
@@ -277,7 +281,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('fails if the session length is less than or equal to 0', done => { it('fails if the session length is less than or equal to 0', done => {
reconfigureServer({ sessionLength: '-33' }) reconfigureServer({ sessionLength: '-33' })
.catch(error => { .catch(error => {
expect(error).toEqual('Session length must be a value greater than 0.'); expect(error).toEqual('Session length must be a value greater than 0.');
@@ -289,7 +293,7 @@ describe('server', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('ignores the session length when expireInactiveSessions set to false', (done) => { it('ignores the session length when expireInactiveSessions set to false', (done) => {
reconfigureServer({ reconfigureServer({
sessionLength: '-33', sessionLength: '-33',
expireInactiveSessions: false expireInactiveSessions: false
@@ -301,7 +305,7 @@ describe('server', () => {
.then(done); .then(done);
}) })
it_exclude_dbs(['postgres'])('fails if you try to set revokeSessionOnPasswordReset to non-boolean', done => { it('fails if you try to set revokeSessionOnPasswordReset to non-boolean', done => {
reconfigureServer({ revokeSessionOnPasswordReset: 'non-bool' }) reconfigureServer({ revokeSessionOnPasswordReset: 'non-bool' })
.catch(done); .catch(done);
}); });

View File

@@ -159,7 +159,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('creates _User schema when server starts', done => { it('creates _User schema when server starts', done => {
request.get({ request.get({
url: 'http://localhost:8378/1/schemas', url: 'http://localhost:8378/1/schemas',
json: true, json: true,
@@ -317,7 +317,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('responds with all fields when you create a class', done => { it('responds with all fields when you create a class', done => {
request.post({ request.post({
url: 'http://localhost:8378/1/schemas', url: 'http://localhost:8378/1/schemas',
headers: masterKeyHeaders, headers: masterKeyHeaders,
@@ -346,7 +346,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('responds with all fields when getting incomplete schema', done => { it('responds with all fields when getting incomplete schema', done => {
config.database.loadSchema() config.database.loadSchema()
.then(schemaController => schemaController.addClassIfNotExists('_Installation', {}, defaultClassLevelPermissions)) .then(schemaController => schemaController.addClassIfNotExists('_Installation', {}, defaultClassLevelPermissions))
.then(() => { .then(() => {
@@ -387,7 +387,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('lets you specify class name in both places', done => { it('lets you specify class name in both places', done => {
request.post({ request.post({
url: 'http://localhost:8378/1/schemas/NewClass', url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders, headers: masterKeyHeaders,
@@ -600,7 +600,7 @@ describe('schemas', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('lets you add fields', done => { it('lets you add fields', done => {
request.post({ request.post({
url: 'http://localhost:8378/1/schemas/NewClass', url: 'http://localhost:8378/1/schemas/NewClass',
headers: masterKeyHeaders, headers: masterKeyHeaders,
@@ -650,7 +650,7 @@ describe('schemas', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('lets you add fields to system schema', done => { it('lets you add fields to system schema', done => {
request.post({ request.post({
url: 'http://localhost:8378/1/schemas/_User', url: 'http://localhost:8378/1/schemas/_User',
headers: masterKeyHeaders, headers: masterKeyHeaders,
@@ -963,7 +963,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('should set/get schema permissions', done => { it('should set/get schema permissions', done => {
request.post({ request.post({
url: 'http://localhost:8378/1/schemas/AClass', url: 'http://localhost:8378/1/schemas/AClass',
headers: masterKeyHeaders, headers: masterKeyHeaders,
@@ -1245,7 +1245,7 @@ describe('schemas', () => {
}); });
} }
it_exclude_dbs(['postgres'])('validate CLP 1', done => { it('validate CLP 1', done => {
let user = new Parse.User(); let user = new Parse.User();
user.setUsername('user'); user.setUsername('user');
user.setPassword('user'); user.setPassword('user');
@@ -1294,7 +1294,7 @@ describe('schemas', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('validate CLP 2', done => { it('validate CLP 2', done => {
let user = new Parse.User(); let user = new Parse.User();
user.setUsername('user'); user.setUsername('user');
user.setPassword('user'); user.setPassword('user');
@@ -1417,7 +1417,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('validate CLP 4', done => { it('validate CLP 4', done => {
let user = new Parse.User(); let user = new Parse.User();
user.setUsername('user'); user.setUsername('user');
user.setPassword('user'); user.setPassword('user');
@@ -1485,7 +1485,7 @@ describe('schemas', () => {
}) })
}); });
it_exclude_dbs(['postgres'])('validate CLP 5', done => { it('validate CLP 5', done => {
let user = new Parse.User(); let user = new Parse.User();
user.setUsername('user'); user.setUsername('user');
user.setPassword('user'); user.setPassword('user');
@@ -1567,7 +1567,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])('can login when addFields is false (issue #1355)', (done) => { it('can login when addFields is false (issue #1355)', (done) => {
setPermissionsOnClass('_User', { setPermissionsOnClass('_User', {
'create': {'*': true}, 'create': {'*': true},
'addField': {} 'addField': {}
@@ -1599,7 +1599,7 @@ describe('schemas', () => {
}); });
}); });
it_exclude_dbs(['postgres'])("regression test for #1991", done => { it("regression test for #1991", done => {
let user = new Parse.User(); let user = new Parse.User();
user.setUsername('user'); user.setUsername('user');
user.setPassword('user'); user.setPassword('user');
@@ -1630,7 +1630,7 @@ describe('schemas', () => {
done(); done();
}).catch((err) => { }).catch((err) => {
fail('should not fail'); fail('should not fail');
console.error(err); jfail(err);
done(); done();
}); });
}); });

View File

@@ -17,7 +17,6 @@ export class GridStoreAdapter extends FilesAdapter {
constructor(mongoDatabaseURI = defaults.DefaultMongoURI) { constructor(mongoDatabaseURI = defaults.DefaultMongoURI) {
super(); super();
this._databaseURI = mongoDatabaseURI; this._databaseURI = mongoDatabaseURI;
this._connect();
} }
_connect() { _connect() {

View File

@@ -363,6 +363,10 @@ export class MongoStorageAdapter {
return this._adaptiveCollection(className) return this._adaptiveCollection(className)
.then(collection => collection.count(transformWhere(className, query, schema))); .then(collection => collection.count(transformWhere(className, query, schema)));
} }
performInitialization() {
return Promise.resolve();
}
} }
export default MongoStorageAdapter; export default MongoStorageAdapter;

View File

@@ -714,10 +714,13 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
restObject._hashed_password = mongoObject[key]; restObject._hashed_password = mongoObject[key];
break; break;
case '_acl': case '_acl':
break;
case '_email_verify_token': case '_email_verify_token':
case '_perishable_token': case '_perishable_token':
case '_tombstone': case '_tombstone':
case '_email_verify_token_expires_at': case '_email_verify_token_expires_at':
// Those keys will be deleted if needed in the DB Controller
restObject[key] = mongoObject[key];
break; break;
case '_session_token': case '_session_token':
restObject['sessionToken'] = mongoObject[key]; restObject['sessionToken'] = mongoObject[key];

View File

@@ -4,15 +4,25 @@ const PostgresRelationDoesNotExistError = '42P01';
const PostgresDuplicateRelationError = '42P07'; const PostgresDuplicateRelationError = '42P07';
const PostgresDuplicateColumnError = '42701'; const PostgresDuplicateColumnError = '42701';
const PostgresUniqueIndexViolationError = '23505'; const PostgresUniqueIndexViolationError = '23505';
const logger = require('../../../logger');
const debug = function(){
let args = [...arguments];
args = ['PG: '+arguments[0]].concat(args.slice(1, args.length));
let log = logger.getLogger();
log.debug.apply(log, args);
}
const parseTypeToPostgresType = type => { const parseTypeToPostgresType = type => {
switch (type.type) { switch (type.type) {
case 'String': return 'text'; case 'String': return 'text';
case 'Date': return 'timestamp'; case 'Date': return 'timestamp with time zone';
case 'Object': return 'jsonb'; case 'Object': return 'jsonb';
case 'File': return 'jsonb';
case 'Boolean': return 'boolean'; case 'Boolean': return 'boolean';
case 'Pointer': return 'char(10)'; case 'Pointer': return 'char(10)';
case 'Number': return 'double precision'; case 'Number': return 'double precision';
case 'GeoPoint': return 'point';
case 'Array': case 'Array':
if (type.contents && type.contents.type === 'String') { if (type.contents && type.contents.type === 'String') {
return 'text[]'; return 'text[]';
@@ -23,25 +33,144 @@ const parseTypeToPostgresType = type => {
} }
}; };
const ParseToPosgresComparator = {
'$gt': '>',
'$lt': '<',
'$gte': '>=',
'$lte': '<='
}
const toPostgresValue = value => {
if (typeof value === 'object') {
if (value.__type === 'Date') {
return value.iso;
}
}
return value;
}
const transformValue = value => {
if (value.__type == 'Pointer') {
return value.objectId;
}
return value;
}
// Duplicate from then mongo adapter...
const emptyCLPS = Object.freeze({
find: {},
get: {},
create: {},
update: {},
delete: {},
addField: {},
});
const defaultCLPS = Object.freeze({
find: {'*': true},
get: {'*': true},
create: {'*': true},
update: {'*': true},
delete: {'*': true},
addField: {'*': true},
});
const toParseSchema = (schema) => {
if (schema.className === '_User') {
delete schema.fields._hashed_password;
}
if (schema.fields) {
delete schema.fields._wperm;
delete schema.fields._rperm;
}
let clps = defaultCLPS;
if (schema.classLevelPermissions) {
clps = {...emptyCLPS, ...schema.classLevelPermissions};
}
return {
className: schema.className,
fields: schema.fields,
classLevelPermissions: clps,
};
}
const toPostgresSchema = (schema) => {
if (!schema) {
return schema;
}
schema.fields = schema.fields || {};
schema.fields._wperm = {type: 'Array', contents: {type: 'String'}}
schema.fields._rperm = {type: 'Array', contents: {type: 'String'}}
if (schema.className === '_User') {
schema.fields._hashed_password = {type: 'String'};
}
return schema;
}
const buildWhereClause = ({ schema, query, index }) => { const buildWhereClause = ({ schema, query, index }) => {
let patterns = []; let patterns = [];
let values = []; let values = [];
let sorts = [];
schema = toPostgresSchema(schema);
for (let fieldName in query) { for (let fieldName in query) {
let initialPatternsLength = patterns.length;
let fieldValue = query[fieldName]; let fieldValue = query[fieldName];
if (typeof fieldValue === 'string') { if (fieldName.indexOf('.') >= 0) {
let components = fieldName.split('.').map((cmpt, index) => {
if (index == 0) {
return `"${cmpt}"`;
}
return `'${cmpt}'`; 
});
let name = components.slice(0, components.length-1).join('->');
name+='->>'+components[components.length-1];
patterns.push(`${name} = '${fieldValue}'`);
} else if (typeof fieldValue === 'string') {
patterns.push(`$${index}:name = $${index + 1}`); patterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue); values.push(fieldName, fieldValue);
index += 2; index += 2;
} else if (fieldValue.$ne) { } else if (typeof fieldValue === 'boolean') {
patterns.push(`$${index}:name <> $${index + 1}`); patterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue.$ne); values.push(fieldName, fieldValue);
index += 2;
} else if (typeof fieldValue === 'number') {
patterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue);
index += 2; index += 2;
} else if (fieldName === '$or') { } else if (fieldName === '$or') {
fieldValue.map(subQuery => buildWhereClause({ schema, query: subQuery, index })).forEach(result => { let clauses = [];
patterns.push(result.pattern); let clauseValues = [];
values.push(...result.values); fieldValue.forEach((subQuery, idx) =>  {
let clause = buildWhereClause({ schema, query: subQuery, index });
clauses.push(clause.pattern);
clauseValues.push(...clause.values);
index += clause.values.length;
}); });
} else if (Array.isArray(fieldValue.$in) && schema.fields[fieldName].type === 'Array') { patterns.push(`(${clauses.join(' OR ')})`);
values.push(...clauseValues);
}
if (fieldValue.$ne) {
if (fieldValue.$ne === null) {
patterns.push(`$${index}:name <> $${index + 1}`);
} else {
// if not null, we need to manually exclude null
patterns.push(`($${index}:name <> $${index + 1} OR $${index}:name IS NULL)`);
}
// TODO: support arrays
values.push(fieldName, fieldValue.$ne);
index += 2;
}
if (fieldValue.$eq) {
patterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue.$eq);
index += 2;
}
const isInOrNin = Array.isArray(fieldValue.$in) || Array.isArray(fieldValue.$nin);
if (Array.isArray(fieldValue.$in) && schema.fields[fieldName].type === 'Array') {
let inPatterns = []; let inPatterns = [];
let allowNull = false; let allowNull = false;
values.push(fieldName); values.push(fieldName);
@@ -59,24 +188,93 @@ const buildWhereClause = ({ schema, query, index }) => {
patterns.push(`$${index}:name && ARRAY[${inPatterns.join(',')}]`); patterns.push(`$${index}:name && ARRAY[${inPatterns.join(',')}]`);
} }
index = index + 1 + inPatterns.length; index = index + 1 + inPatterns.length;
} else if (Array.isArray(fieldValue.$in) && schema.fields[fieldName].type === 'String') { } else if (isInOrNin) {
let inPatterns = []; var createConstraint = (baseArray, notIn) => {
if (baseArray.length > 0) {
let inPatterns = [];
values.push(fieldName);
baseArray.forEach((listElem, listIndex) => {
values.push(listElem);
inPatterns.push(`$${index + 1 + listIndex}`);
});
let not = notIn ? 'NOT' : '';
patterns.push(`$${index}:name ${not} IN (${inPatterns.join(',')})`);
index = index + 1 + inPatterns.length;
} else if (!notIn) {
values.push(fieldName);
patterns.push(`$${index}:name IS NULL`);
index = index + 1;
}
}
if (fieldValue.$in) {
createConstraint(fieldValue.$in, false);
}
if (fieldValue.$nin) {
createConstraint(fieldValue.$nin, true);
}
}
if (typeof fieldValue.$exists !== 'undefined') {
if (fieldValue.$exists) {
patterns.push(`$${index}:name IS NOT NULL`);
} else {
patterns.push(`$${index}:name IS NULL`);
}
values.push(fieldName); values.push(fieldName);
fieldValue.$in.forEach((listElem, listIndex) => { index += 1;
values.push(listElem); }
inPatterns.push(`$${index + 1 + listIndex}`);
}); if (fieldValue.$nearSphere) {
patterns.push(`$${index}:name IN (${inPatterns.join(',')})`); let point = fieldValue.$nearSphere;
index = index + 1 + inPatterns.length; let distance = fieldValue.$maxDistance;
} else if (fieldValue.__type === 'Pointer') { let distanceInKM = distance*6371*1000;
patterns.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index+1}, $${index+2})::geometry) <= $${index+3}`);
sorts.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index+1}, $${index+2})::geometry) ASC`)
values.push(fieldName, point.latitude, point.longitude, distanceInKM);
index += 4;
}
if (fieldValue.$regex) {
let regex = fieldValue.$regex;
let operator = '~';
let opts = fieldValue.$options;
if (opts) {
if (opts.indexOf('i') >= 0) {
operator = '~*';
}
}
patterns.push(`$${index}:name ${operator} $${index+1}`);
values.push(fieldName, regex);
index += 2;
}
if (fieldValue.__type === 'Pointer') {
patterns.push(`$${index}:name = $${index + 1}`); patterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue.objectId); values.push(fieldName, fieldValue.objectId);
index += 2; index += 2;
} else { }
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support this query type yet`);
if (fieldValue.__type === 'Date') {
patterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue.iso);
index += 2;
}
Object.keys(ParseToPosgresComparator).forEach(cmp => {
if (fieldValue[cmp]) {
let pgComparator = ParseToPosgresComparator[cmp];
patterns.push(`$${index}:name ${pgComparator} $${index + 1}`);
values.push(fieldName, toPostgresValue(fieldValue[cmp]));
index += 2;
}
});
if (initialPatternsLength === patterns.length) {
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support this query type yet ${JSON.stringify(fieldValue)}`);
} }
} }
return { pattern: patterns.join(' AND '), values }; values = values.map(transformValue);
return { pattern: patterns.join(' AND '), values, sorts };
} }
export class PostgresStorageAdapter { export class PostgresStorageAdapter {
@@ -95,7 +293,7 @@ export class PostgresStorageAdapter {
_ensureSchemaCollectionExists() { _ensureSchemaCollectionExists() {
return this._client.none('CREATE TABLE "_SCHEMA" ( "className" varChar(120), "schema" jsonb, "isParseClass" bool, PRIMARY KEY ("className") )') return this._client.none('CREATE TABLE "_SCHEMA" ( "className" varChar(120), "schema" jsonb, "isParseClass" bool, PRIMARY KEY ("className") )')
.catch(error => { .catch(error => {
if (error.code === PostgresDuplicateRelationError) { if (error.code === PostgresDuplicateRelationError || error.code === PostgresUniqueIndexViolationError) {
// Table already exists, must have been created by a different request. Ignore error. // Table already exists, must have been created by a different request. Ignore error.
} else { } else {
throw error; throw error;
@@ -108,42 +306,80 @@ export class PostgresStorageAdapter {
} }
setClassLevelPermissions(className, CLPs) { setClassLevelPermissions(className, CLPs) {
return notImplemented(); return this._ensureSchemaCollectionExists().then(() => {
const values = [className, 'schema', 'classLevelPermissions', CLPs]
return this._client.none(`UPDATE "_SCHEMA" SET $2:name = json_object_set_key($2:name, $3::text, $4::jsonb) WHERE "className"=$1 `, values);
}).catch((err) => {
console.error("ERR!!!", err);
return Promise.reject(err);
})
} }
createClass(className, schema) { createClass(className, schema) {
return this.createTable(className, schema)
.then(() => this._client.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($<className>, $<schema>, true)', { className, schema }))
.then(() => {
return toParseSchema(schema)
});
}
// Just create a table, do not insert in schema
createTable(className, schema) {
debug('createTable', className, schema);
let valuesArray = []; let valuesArray = [];
let patternsArray = []; let patternsArray = [];
Object.keys(schema.fields).forEach((fieldName, index) => { let fields = Object.assign({}, schema.fields);
valuesArray.push(fieldName); if (className === '_User') {
let parseType = schema.fields[fieldName]; fields._email_verify_token_expires_at = {type: 'Date'};
fields._email_verify_token = {type: 'String'};
}
let index = 2;
let relations = [];
Object.keys(fields).forEach((fieldName) => {
let parseType = fields[fieldName];
// Skip when it's a relation
// We'll create the tables later
if (parseType.type == 'Relation') {
relations.push(fieldName)
return;
}
if (['_rperm', '_wperm'].includes(fieldName)) { if (['_rperm', '_wperm'].includes(fieldName)) {
parseType.contents = { type: 'String' }; parseType.contents = { type: 'String' };
} }
valuesArray.push(fieldName);
valuesArray.push(parseTypeToPostgresType(parseType)); valuesArray.push(parseTypeToPostgresType(parseType));
patternsArray.push(`$${index * 2 + 2}:name $${index * 2 + 3}:raw`); patternsArray.push(`$${index}:name $${index+1}:raw`);
index = index+2;
}); });
const qs = `CREATE TABLE $1:name (${patternsArray.join(',')}, PRIMARY KEY ("objectId"))`;
const values = [className, ...valuesArray];
return this._ensureSchemaCollectionExists() return this._ensureSchemaCollectionExists()
.then(() => this._client.none(`CREATE TABLE $1:name (${patternsArray.join(',')})`, [className, ...valuesArray])) .then(() => this._client.none(qs, values))
.catch(error => { .catch(error => {
if (error.code === PostgresDuplicateRelationError) { if (error.code === PostgresDuplicateRelationError) {
// Table already exists, must have been created by a different request. Ignore error. // Table already exists, must have been created by a different request. Ignore error.
} else { } else {
throw error; throw error;
} }
}) }).then(() => {
.then(() => this._client.none('INSERT INTO "_SCHEMA" ("className", "schema", "isParseClass") VALUES ($<className>, $<schema>, true)', { className, schema })) // Create the relation tables
.then(() => schema); return Promise.all(relations.map((fieldName) => {
return this._client.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`})
}));
});
} }
addFieldIfNotExists(className, fieldName, type) { addFieldIfNotExists(className, fieldName, type) {
// TODO: Must be revised for invalid logic... // TODO: Must be revised for invalid logic...
debug('addFieldIfNotExists', {className, fieldName, type});
return this._client.tx("addFieldIfNotExists", t=> { return this._client.tx("addFieldIfNotExists", t=> {
return t.none('ALTER TABLE $<className:name> ADD COLUMN $<fieldName:name> $<postgresType:raw>', { let promise = Promise.resolve();
className, if (type.type !== 'Relation') {
fieldName, promise = t.none('ALTER TABLE $<className:name> ADD COLUMN $<fieldName:name> $<postgresType:raw>', {
postgresType: parseTypeToPostgresType(type) className,
}) fieldName,
postgresType: parseTypeToPostgresType(type)
})
.catch(error => { .catch(error => {
if (error.code === PostgresRelationDoesNotExistError) { if (error.code === PostgresRelationDoesNotExistError) {
return this.createClass(className, {fields: {[fieldName]: type}}) return this.createClass(className, {fields: {[fieldName]: type}})
@@ -154,18 +390,22 @@ export class PostgresStorageAdapter {
throw error; throw error;
} }
}) })
.then(() => t.any('SELECT "schema" FROM "_SCHEMA" WHERE "className" = $<className>', {className})) } else {
.then(result => { promise = t.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`})
if (fieldName in result[0].schema) { }
throw "Attempted to add a field that already exists"; return promise.then(() => {
} else { return t.any('SELECT "schema" FROM "_SCHEMA" WHERE "className" = $<className>', {className});
result[0].schema.fields[fieldName] = type; }).then(result => {
return t.none( if (fieldName in result[0].schema) {
'UPDATE "_SCHEMA" SET "schema"=$<schema> WHERE "className"=$<className>', throw "Attempted to add a field that already exists";
{schema: result[0].schema, className} } else {
); result[0].schema.fields[fieldName] = type;
} return t.none(
}) 'UPDATE "_SCHEMA" SET "schema"=$<schema> WHERE "className"=$<className>',
{schema: result[0].schema, className}
);
}
});
}); });
} }
@@ -177,10 +417,20 @@ export class PostgresStorageAdapter {
// Delete all data known to this adapter. Used for testing. // Delete all data known to this adapter. Used for testing.
deleteAllClasses() { deleteAllClasses() {
return this._client.any('SELECT "className" FROM "_SCHEMA"') let now = new Date().getTime();
debug('deleteAllClasses');
return this._client.any('SELECT * FROM "_SCHEMA"')
.then(results => { .then(results => {
const classes = ['_SCHEMA', ...results.map(result => result.className)]; let joins = results.reduce((list, schema) => {
return this._client.tx(t=>t.batch(classes.map(className=>t.none('DROP TABLE $<className:name>', { className })))); Object.keys(schema.schema.fields).forEach((field) => {
if (schema.schema.fields[field].type === 'Relation') {
list.push(`_Join:${field}:${schema.className}`);
}
})
return list;
}, []);
const classes = ['_SCHEMA','_PushStatus','_Hooks','_GlobalConfig', ...results.map(result => result.className), ...joins];
return this._client.tx(t=>t.batch(classes.map(className=>t.none('DROP TABLE IF EXISTS $<className:name>', { className }))));
}, error => { }, error => {
if (error.code === PostgresRelationDoesNotExistError) { if (error.code === PostgresRelationDoesNotExistError) {
// No _SCHEMA collection. Don't delete anything. // No _SCHEMA collection. Don't delete anything.
@@ -188,7 +438,9 @@ export class PostgresStorageAdapter {
} else { } else {
throw error; throw error;
} }
}) }).then(() => {
debug(`deleteAllClasses done in ${new Date().getTime() - now}`);
});
} }
// Remove the column and all the data. For Relations, the _Join collection is handled // Remove the column and all the data. For Relations, the _Join collection is handled
@@ -213,7 +465,8 @@ export class PostgresStorageAdapter {
// rejection reason are TBD. // rejection reason are TBD.
getAllClasses() { getAllClasses() {
return this._ensureSchemaCollectionExists() return this._ensureSchemaCollectionExists()
.then(() => this._client.map('SELECT * FROM "_SCHEMA"', null, row => ({ className: row.className, ...row.schema }))); .then(() => this._client.map('SELECT * FROM "_SCHEMA"', null, row => ({ className: row.className, ...row.schema })))
.then(res => res.map(toParseSchema))
} }
// Return a promise for the schema with the given name, in Parse format. If // Return a promise for the schema with the given name, in Parse format. If
@@ -227,15 +480,37 @@ export class PostgresStorageAdapter {
} else { } else {
throw undefined; throw undefined;
} }
}); }).then(toParseSchema);
} }
// TODO: remove the mongo format dependency in the return value // TODO: remove the mongo format dependency in the return value
createObject(className, schema, object) { createObject(className, schema, object) {
debug('createObject', className, object);
let columnsArray = []; let columnsArray = [];
let newFieldsArray = [];
let valuesArray = []; let valuesArray = [];
schema = toPostgresSchema(schema);
let geoPoints = {};
Object.keys(object).forEach(fieldName => { Object.keys(object).forEach(fieldName => {
var authDataMatch = fieldName.match(/^_auth_data_([a-zA-Z0-9_]+)$/);
if (authDataMatch) {
var provider = authDataMatch[1];
object['authData'] = object['authData'] || {};
object['authData'][provider] = object[fieldName];
delete object[fieldName];
fieldName = 'authData';
}
columnsArray.push(fieldName); columnsArray.push(fieldName);
if (!schema.fields[fieldName] && className === '_User') {
if (fieldName == '_email_verify_token') {
valuesArray.push(object[fieldName]);
}
if (fieldName == '_email_verify_token_expires_at') {
valuesArray.push(object[fieldName].iso);
}
return;
}
switch (schema.fields[fieldName].type) { switch (schema.fields[fieldName].type) {
case 'Date': case 'Date':
valuesArray.push(object[fieldName].iso); valuesArray.push(object[fieldName].iso);
@@ -249,29 +524,42 @@ export class PostgresStorageAdapter {
} else { } else {
valuesArray.push(JSON.stringify(object[fieldName])); valuesArray.push(JSON.stringify(object[fieldName]));
} }
break; break;
case 'Object': case 'Object':
valuesArray.push(object[fieldName]);
break;
case 'String': case 'String':
valuesArray.push(object[fieldName]);
break;
case 'Number': case 'Number':
case 'Boolean':
case 'File':
valuesArray.push(object[fieldName]); valuesArray.push(object[fieldName]);
break; break;
case 'Boolean': case 'GeoPoint':
valuesArray.push(object[fieldName]); // pop the point and process later
geoPoints[fieldName] = object[fieldName];
columnsArray.pop();
break; break;
default: default:
throw `Type ${schema.fields[fieldName].type} not supported yet`; throw `Type ${schema.fields[fieldName].type} not supported yet`;
break; break;
} }
}); });
columnsArray = columnsArray.concat(Object.keys(geoPoints));
let initialValues = valuesArray.map((val, index) => `$${index + 2 + columnsArray.length}${(['_rperm','_wperm'].includes(columnsArray[index])) ? '::text[]' : ''}`);
let geoPointsInjects = Object.keys(geoPoints).map((key, idx) => {
let value = geoPoints[key];
valuesArray.push(value.latitude, value.longitude);
let l = valuesArray.length + columnsArray.length;
return `POINT($${l}, $${l+1})`;
});
let columnsPattern = columnsArray.map((col, index) => `$${index + 2}:name`).join(','); let columnsPattern = columnsArray.map((col, index) => `$${index + 2}:name`).join(',');
let valuesPattern = valuesArray.map((val, index) => `$${index + 2 + columnsArray.length}${(['_rperm','_wperm'].includes(columnsArray[index])) ? '::text[]' : ''}`).join(','); let valuesPattern = initialValues.concat(geoPointsInjects).join(',')
let qs = `INSERT INTO $1:name (${columnsPattern}) VALUES (${valuesPattern})` let qs = `INSERT INTO $1:name (${columnsPattern}) VALUES (${valuesPattern})`
let values = [className, ...columnsArray, ...valuesArray] let values = [className, ...columnsArray, ...valuesArray]
return this._client.none(qs, values) debug(qs, values);
return this._client.any(qs, values)
.then(() => ({ ops: [object] })) .then(() => ({ ops: [object] }))
.catch(error => { .catch(error => {
if (error.code === PostgresUniqueIndexViolationError) { if (error.code === PostgresUniqueIndexViolationError) {
@@ -286,7 +574,17 @@ export class PostgresStorageAdapter {
// If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined. // If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined.
// If there is some other error, reject with INTERNAL_SERVER_ERROR. // If there is some other error, reject with INTERNAL_SERVER_ERROR.
deleteObjectsByQuery(className, schema, query) { deleteObjectsByQuery(className, schema, query) {
return this._client.one(`WITH deleted AS (DELETE FROM $<className:name> RETURNING *) SELECT count(*) FROM deleted`, { className }, a => +a.count) debug('deleteObjectsByQuery', className, query);
let values = [className];
let index = 2;
let where = buildWhereClause({ schema, index, query })
values.push(...where.values);
if (Object.keys(query).length == 0) {
where.pattern = 'TRUE';
}
let qs = `WITH deleted AS (DELETE FROM $1:name WHERE ${where.pattern} RETURNING *) SELECT count(*) FROM deleted`;
debug(qs, values);
return this._client.one(qs, values , a => +a.count)
.then(count => { .then(count => {
if (count === 0) { if (count === 0) {
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'); throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
@@ -298,19 +596,30 @@ export class PostgresStorageAdapter {
// Apply the update to all objects that match the given Parse Query. // Apply the update to all objects that match the given Parse Query.
updateObjectsByQuery(className, schema, query, update) { updateObjectsByQuery(className, schema, query, update) {
return notImplemented(); debug('updateObjectsByQuery', className, query, update);
return this.findOneAndUpdate(className, schema, query, update);
} }
// Return value not currently well specified. // Return value not currently well specified.
findOneAndUpdate(className, schema, query, update) { findOneAndUpdate(className, schema, query, update) {
debug('findOneAndUpdate', className, query, update);
let conditionPatterns = []; let conditionPatterns = [];
let updatePatterns = []; let updatePatterns = [];
let values = [className] let values = [className]
let index = 2; let index = 2;
schema = toPostgresSchema(schema);
for (let fieldName in update) { for (let fieldName in update) {
let fieldValue = update[fieldName]; let fieldValue = update[fieldName];
if (fieldValue.__op === 'Increment') { var authDataMatch = fieldName.match(/^_auth_data_([a-zA-Z0-9_]+)$/);
if (authDataMatch) {
var provider = authDataMatch[1];
let value = update[fieldName];
delete update[fieldName];
fieldName = 'authData';
updatePatterns.push(`$${index}:name = json_object_set_key($${index}:name, $${index+1}::text, $${index+2}::jsonb)`);
values.push(fieldName, provider, value);
index += 3;
} else if (fieldValue.__op === 'Increment') {
updatePatterns.push(`$${index}:name = COALESCE($${index}:name, 0) + $${index + 1}`); updatePatterns.push(`$${index}:name = COALESCE($${index}:name, 0) + $${index + 1}`);
values.push(fieldName, fieldValue.amount); values.push(fieldName, fieldValue.amount);
index += 2; index += 2;
@@ -318,23 +627,61 @@ export class PostgresStorageAdapter {
updatePatterns.push(`$${index}:name = COALESCE($${index}:name, '[]'::jsonb) || $${index + 1}`); updatePatterns.push(`$${index}:name = COALESCE($${index}:name, '[]'::jsonb) || $${index + 1}`);
values.push(fieldName, fieldValue.objects); values.push(fieldName, fieldValue.objects);
index += 2; index += 2;
} else if (fieldValue.__op === 'Delete') {
updatePatterns.push(`$${index}:name = $${index + 1}`)
values.push(fieldName, null);
index += 2;
} else if (fieldValue.__op === 'Remove') { } else if (fieldValue.__op === 'Remove') {
return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Postgres does not support Remove operator.')); return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Postgres does not support Remove operator.'));
} else if (fieldValue.__op === 'AddUnique') { } else if (fieldValue.__op === 'AddUnique') {
return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Postgres does not support AddUnique operator')); return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Postgres does not support AddUnique operator.'));
} else if (fieldName === 'updatedAt') { //TODO: stop special casing this. It should check for __type === 'Date' and use .iso } else if (fieldName === 'updatedAt') { //TODO: stop special casing this. It should check for __type === 'Date' and use .iso
updatePatterns.push(`$${index}:name = $${index + 1}`) updatePatterns.push(`$${index}:name = $${index + 1}`)
values.push(fieldName, new Date(fieldValue)); values.push(fieldName, fieldValue);
index += 2; index += 2;
} else if (typeof fieldValue === 'string') { } else if (typeof fieldValue === 'string') {
updatePatterns.push(`$${index}:name = $${index + 1}`); updatePatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue); values.push(fieldName, fieldValue);
index += 2; index += 2;
} else if (typeof fieldValue === 'boolean') {
updatePatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue);
index += 2;
} else if (fieldValue.__type === 'Pointer') { } else if (fieldValue.__type === 'Pointer') {
updatePatterns.push(`$${index}:name = $${index + 1}`); updatePatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue.objectId); values.push(fieldName, fieldValue.objectId);
index += 2; index += 2;
} else if (fieldValue.__type === 'Date') {
updatePatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, toPostgresValue(fieldValue));
index += 2;
} else if (fieldValue.__type === 'GeoPoint') {
updatePatterns.push(`$${index}:name = POINT($${index + 1}, $${index + 2})`);
values.push(fieldName, fieldValue.latitude, fieldValue.longitude);
index += 3;
} else if (typeof fieldValue === 'number') {
updatePatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue);
index += 2;
} else if (typeof fieldValue === 'object'
&& schema.fields[fieldName]
&& schema.fields[fieldName].type == 'Object') {
updatePatterns.push(`$${index}:name = $${index + 1}`);
values.push(fieldName, fieldValue);
index += 2;
} else if (Array.isArray(fieldValue)
&& schema.fields[fieldName]
&& schema.fields[fieldName].type == 'Array') {
let expectedType = parseTypeToPostgresType(schema.fields[fieldName]);
if (expectedType === 'text[]') {
updatePatterns.push(`$${index}:name = $${index + 1}::text[]`);
} else {
updatePatterns.push(`$${index}:name = array_to_json($${index + 1}::text[])::jsonb`);
}
values.push(fieldName, fieldValue);
index += 2;
} else { } else {
debug('Not supported update', fieldName, fieldValue);
return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support update ${JSON.stringify(fieldValue)} yet`)); return Promise.reject(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `Postgres doesn't support update ${JSON.stringify(fieldValue)} yet`));
} }
} }
@@ -343,31 +690,83 @@ export class PostgresStorageAdapter {
values.push(...where.values); values.push(...where.values);
let qs = `UPDATE $1:name SET ${updatePatterns.join(',')} WHERE ${where.pattern} RETURNING *`; let qs = `UPDATE $1:name SET ${updatePatterns.join(',')} WHERE ${where.pattern} RETURNING *`;
return this._client.any(qs, values) debug('update: ', qs, values);
return this._client.any(qs, values)
.then(val => val[0]); // TODO: This is unsafe, verification is needed, or a different query method; .then(val => val[0]); // TODO: This is unsafe, verification is needed, or a different query method;
} }
// Hopefully, we can get rid of this. It's only used for config and hooks. // Hopefully, we can get rid of this. It's only used for config and hooks.
upsertOneObject(className, schema, query, update) { upsertOneObject(className, schema, query, update) {
return notImplemented(); debug('upsertOneObject', {className, query, update});
return this.createObject(className, schema, update).catch((err) => {
// ignore duplicate value errors as it's upsert
if (err.code == Parse.Error.DUPLICATE_VALUE) {
return;
}
throw err;
});
} }
find(className, schema, query, { skip, limit, sort }) { find(className, schema, query, { skip, limit, sort }) {
debug('find', className, query, {skip, limit, sort});
const hasLimit = limit !== undefined;
const hasSkip = skip !== undefined;
let values = [className]; let values = [className];
let where = buildWhereClause({ schema, query, index: 2 }) let where = buildWhereClause({ schema, query, index: 2 })
values.push(...where.values); values.push(...where.values);
const wherePattern = where.pattern.length > 0 ? `WHERE ${where.pattern}` : ''; const wherePattern = where.pattern.length > 0 ? `WHERE ${where.pattern}` : '';
const limitPattern = limit !== undefined ? `LIMIT $${values.length + 1}` : ''; const limitPattern = hasLimit ? `LIMIT $${values.length + 1}` : '';
if (hasLimit) {
const qs = `SELECT * FROM $1:name ${wherePattern} ${limitPattern}`;
if (limit !== undefined) {
values.push(limit); values.push(limit);
} }
const skipPattern = hasSkip ? `OFFSET $${values.length+1}` : '';
if (hasSkip) {
values.push(skip);
}
let sortPattern = '';
if (sort) {
let sorting = Object.keys(sort).map((key) => {
// Using $idx pattern gives: non-integer constant in ORDER BY
if (sort[key] === 1) {
return `"${key}" ASC`;
}
return `"${key}" DESC`;
}).join(',');
sortPattern = sort !== undefined && Object.keys(sort).length > 0 ? `ORDER BY ${sorting}` : '';
}
if (where.sorts && Object.keys(where.sorts).length > 0) {
sortPattern = `ORDER BY ${where.sorts.join(',')}`;
}
const qs = `SELECT * FROM $1:name ${wherePattern} ${sortPattern} ${limitPattern} ${skipPattern}`;
debug(qs, values);
return this._client.any(qs, values) return this._client.any(qs, values)
.catch((err) => {
// Query on non existing table, don't crash
if (err.code === PostgresRelationDoesNotExistError) {
return [];
}
return Promise.reject(err);
})
.then(results => results.map(object => { .then(results => results.map(object => {
Object.keys(schema.fields).filter(field => schema.fields[field].type === 'Pointer').forEach(fieldName => { Object.keys(schema.fields).forEach(fieldName => {
object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass }; if (schema.fields[fieldName].type === 'Pointer' && object[fieldName]) {
object[fieldName] = { objectId: object[fieldName], __type: 'Pointer', className: schema.fields[fieldName].targetClass };
}
if (schema.fields[fieldName].type === 'Relation') {
object[fieldName] = {
__type: "Relation",
className: schema.fields[fieldName].targetClass
}
}
if (object[fieldName] && schema.fields[fieldName].type === 'GeoPoint') {
object[fieldName] = {
latitude: object[fieldName].x,
longitude: object[fieldName].y
}
}
}); });
//TODO: remove this reliance on the mongo format. DB adapter shouldn't know there is a difference between created at and any other date field. //TODO: remove this reliance on the mongo format. DB adapter shouldn't know there is a difference between created at and any other date field.
if (object.createdAt) { if (object.createdAt) {
@@ -393,7 +792,7 @@ export class PostgresStorageAdapter {
} }
return object; return object;
})) }));
} }
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't // Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
@@ -411,6 +810,9 @@ export class PostgresStorageAdapter {
.catch(error => { .catch(error => {
if (error.code === PostgresDuplicateRelationError && error.message.includes(constraintName)) { if (error.code === PostgresDuplicateRelationError && error.message.includes(constraintName)) {
// Index already exists. Ignore error. // Index already exists. Ignore error.
} else if (error.code === PostgresUniqueIndexViolationError && error.message.includes(constraintName)) {
// Cast the error into the proper parse error
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'A duplicate value for a field with unique values was provided');
} else { } else {
throw error; throw error;
} }
@@ -427,11 +829,46 @@ export class PostgresStorageAdapter {
const qs = `SELECT count(*) FROM $1:name ${wherePattern}`; const qs = `SELECT count(*) FROM $1:name ${wherePattern}`;
return this._client.one(qs, values, a => +a.count); return this._client.one(qs, values, a => +a.count);
} }
performInitialization({ VolatileClassesSchemas }) {
let now = new Date().getTime();
debug('performInitialization');
let promises = VolatileClassesSchemas.map((schema) => {
return this.createTable(schema.className, schema);
});
return Promise.all(promises).then(() => {
return this._client.any(json_object_set_key).catch((err) => {
console.error(err);
})
}).then(() => {
debug(`initialzationDone in ${new Date().getTime() - now}`);
})
}
} }
function notImplemented() { function notImplemented() {
return Promise.reject(new Error('Not implemented yet.')); return Promise.reject(new Error('Not implemented yet.'));
} }
// Function to set a key on a nested JSON document
const json_object_set_key = 'CREATE OR REPLACE FUNCTION "json_object_set_key"(\
"json" jsonb,\
"key_to_set" TEXT,\
"value_to_set" anyelement\
)\
RETURNS jsonb \
LANGUAGE sql \
IMMUTABLE \
STRICT \
AS $function$\
SELECT concat(\'{\', string_agg(to_json("key") || \':\' || "value", \',\'), \'}\')::jsonb\
FROM (SELECT *\
FROM jsonb_each("json")\
WHERE "key" <> "key_to_set"\
UNION ALL\
SELECT "key_to_set", to_json("value_to_set")::jsonb) AS "fields"\
$function$;'
export default PostgresStorageAdapter; export default PostgresStorageAdapter;
module.exports = PostgresStorageAdapter; // Required for tests module.exports = PostgresStorageAdapter; // Required for tests

View File

@@ -159,12 +159,18 @@ const filterSensitiveData = (isMaster, aclGroup, className, object) => {
delete object.sessionToken; delete object.sessionToken;
if (isMaster || (aclGroup.indexOf(object.objectId) > -1)) { if (isMaster) {
return object; return object;
} }
delete object._email_verify_token;
delete object._perishable_token;
delete object._tombstone;
delete object._email_verify_token_expires_at;
if ((aclGroup.indexOf(object.objectId) > -1)) {
return object;
}
delete object.authData; delete object.authData;
return object; return object;
}; };
@@ -204,7 +210,7 @@ DatabaseController.prototype.update = function(className, query, update, {
query = addWriteACL(query, acl); query = addWriteACL(query, acl);
} }
validateQuery(query); validateQuery(query);
return schemaController.getOneSchema(className) return schemaController.getOneSchema(className, true)
.catch(error => { .catch(error => {
// If the schema doesn't exist, pretend it exists with no fields. This behaviour // If the schema doesn't exist, pretend it exists with no fields. This behaviour
// will likely need revisiting. // will likely need revisiting.
@@ -899,7 +905,10 @@ DatabaseController.prototype.performInitizalization = function() {
logger.warn('Unable to ensure uniqueness for user email addresses: ', error); logger.warn('Unable to ensure uniqueness for user email addresses: ', error);
return Promise.reject(error); return Promise.reject(error);
}); });
return Promise.all([usernameUniqueness, emailUniqueness]);
// Create tables for volatile classes
let adapterInit = this.adapter.performInitialization({ VolatileClassesSchemas: SchemaController.VolatileClassesSchemas });
return Promise.all([usernameUniqueness, emailUniqueness, adapterInit]);
} }
function joinTableName(className, key) { function joinTableName(className, key) {

View File

@@ -76,7 +76,7 @@ const defaultColumns = Object.freeze({
"pushTime": {type:'String'}, "pushTime": {type:'String'},
"source": {type:'String'}, // rest or webui "source": {type:'String'}, // rest or webui
"query": {type:'String'}, // the stringified JSON query "query": {type:'String'}, // the stringified JSON query
"payload": {type:'Object'}, // the JSON payload, "payload": {type:'String'}, // the stringified JSON payload,
"title": {type:'String'}, "title": {type:'String'},
"expiry": {type:'Number'}, "expiry": {type:'Number'},
"status": {type:'String'}, "status": {type:'String'},
@@ -256,7 +256,15 @@ const injectDefaultSchema = ({className, fields, classLevelPermissions}) => ({
...fields, ...fields,
}, },
classLevelPermissions, classLevelPermissions,
}) });
const VolatileClassesSchemas = volatileClasses.map((className) => {
return convertSchemaToAdapterSchema(injectDefaultSchema({
className,
fields: {},
classLevelPermissions: {}
}));
});
const dbTypeMatchesObjectType = (dbType, objectType) => { const dbTypeMatchesObjectType = (dbType, objectType) => {
if (dbType.type !== objectType.type) return false; if (dbType.type !== objectType.type) return false;
@@ -900,4 +908,5 @@ export {
systemClasses, systemClasses,
defaultColumns, defaultColumns,
convertSchemaToAdapterSchema, convertSchemaToAdapterSchema,
VolatileClassesSchemas,
}; };

View File

@@ -4,7 +4,6 @@ import { ParseServer } from '../index';
import definitions from './cli-definitions'; import definitions from './cli-definitions';
import program from './utils/commander'; import program from './utils/commander';
import { mergeWithOptions } from './utils/commander'; import { mergeWithOptions } from './utils/commander';
import colors from 'colors';
program.loadDefinitions(definitions); program.loadDefinitions(definitions);
@@ -44,7 +43,7 @@ if (!options.serverURL) {
if (!options.appId || !options.masterKey || !options.serverURL) { if (!options.appId || !options.masterKey || !options.serverURL) {
program.outputHelp(); program.outputHelp();
console.error(""); console.error("");
console.error(colors.red("ERROR: appId and masterKey are required")); console.error('\u001b[31mERROR: appId and masterKey are required\u001b[0m');
console.error(""); console.error("");
process.exit(1); process.exit(1);
} }

View File

@@ -48,12 +48,13 @@ export default function pushStatusHandler(config) {
// lockdown! // lockdown!
ACL: {} ACL: {}
} }
lastPromise = Promise.resolve().then(() => {
lastPromise = database.create(PUSH_STATUS_COLLECTION, object).then(() => { return database.create(PUSH_STATUS_COLLECTION, object).then(() => {
pushStatus = { pushStatus = {
objectId objectId
}; };
return Promise.resolve(pushStatus); return Promise.resolve(pushStatus);
});
}); });
return lastPromise; return lastPromise;
} }