Unique indexes (#1971)

* Add unique indexing

* Add unique indexing for username/email

* WIP

* Finish unique indexes

* Notes on how to upgrade to 2.3.0 safely

* index on unique-indexes: c454180 Revert "Log objects rather than JSON stringified objects (#1922)"

* reconfigure username/email tests

* Start dealing with test shittyness

* Remove tests for files that we are removing

* most tests passing

* fix failing test

* Make specific server config for tests async

* Fix more tests

* fix more tests

* Fix another test

* fix more tests

* Fix email validation

* move some stuff around

* Destroy server to ensure all connections are gone

* Fix broken cloud code

* Save callback to variable

* no need to delete non existant cloud

* undo

* Fix all tests where connections are left open after server closes.

* Fix issues caused by missing gridstore adapter

* Update guide for 2.3.0 and fix final tests

* use strict

* don't use features that won't work in node 4

* Fix syntax error

* Fix typos

* Add duplicate finding command

* Update 2.3.0.md
This commit is contained in:
Drew
2016-06-10 20:27:21 -07:00
committed by GitHub
parent 6415a35433
commit 7e868b2dcc
37 changed files with 1727 additions and 1517 deletions

View File

@@ -3,9 +3,14 @@
'use strict';
var DatabaseAdapter = require('../src/DatabaseAdapter');
const MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter');
var request = require('request');
const Parse = require("parse/node");
let Config = require('../src/Config');
let defaultColumns = require('../src/Controllers/SchemaController').defaultColumns;
var TestUtils = require('../src/index').TestUtils;
const requiredUserFields = { fields: Object.assign({}, defaultColumns._Default, defaultColumns._User) };
describe('miscellaneous', function() {
it('create a GameScore object', function(done) {
@@ -45,14 +50,172 @@ describe('miscellaneous', function() {
});
});
it('fail to create a duplicate username', function(done) {
createTestUser(function(data) {
createTestUser(function(data) {
fail('Should not have been able to save duplicate username.');
}, function(error) {
expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
it('fail to create a duplicate username', done => {
let numCreated = 0;
let numFailed = 0;
let p1 = createTestUser();
p1.then(user => {
numCreated++;
expect(numCreated).toEqual(1);
})
.catch(error => {
numFailed++;
expect(numFailed).toEqual(1);
expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
});
let p2 = createTestUser();
p2.then(user => {
numCreated++;
expect(numCreated).toEqual(1);
})
.catch(error => {
numFailed++;
expect(numFailed).toEqual(1);
expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
});
Parse.Promise.when([p1, p2])
.then(() => {
fail('one of the users should not have been created');
done();
})
.catch(done);
});
it('ensure that email is uniquely indexed', done => {
let numCreated = 0;
let numFailed = 0;
let user1 = new Parse.User();
user1.setPassword('asdf');
user1.setUsername('u1');
user1.setEmail('dupe@dupe.dupe');
let p1 = user1.signUp();
p1.then(user => {
numCreated++;
expect(numCreated).toEqual(1);
}, error => {
numFailed++;
expect(numFailed).toEqual(1);
expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
});
let user2 = new Parse.User();
user2.setPassword('asdf');
user2.setUsername('u2');
user2.setEmail('dupe@dupe.dupe');
let p2 = user2.signUp();
p2.then(user => {
numCreated++;
expect(numCreated).toEqual(1);
}, error => {
numFailed++;
expect(numFailed).toEqual(1);
expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
});
Parse.Promise.when([p1, p2])
.then(() => {
fail('one of the users should not have been created');
done();
})
.catch(done);
});
it('ensure that if people already have duplicate users, they can still sign up new users', done => {
reconfigureServer({})
// Remove existing data to clear out unique index
.then(TestUtils.destroyAllDataPermanently)
.then(() => {
let adapter = new MongoStorageAdapter({
uri: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase',
collectionPrefix: 'test_',
});
adapter.createObject('_User', { objectId: 'x', username: 'u' }, requiredUserFields)
.then(() => adapter.createObject('_User', { objectId: 'y', username: 'u' }, requiredUserFields))
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('zxcv');
return user.signUp();
})
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('u');
user.signUp()
.catch(error => {
expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
done();
});
})
.catch(error => {
fail(JSON.stringify(error));
done();
});
}, () => {
fail('destroyAllDataPermanently failed')
done();
});
});
it('ensure that if people already have duplicate emails, they can still sign up new users', done => {
reconfigureServer({})
// Wipe out existing database with unique index so we can create a duplicate user
.then(TestUtils.destroyAllDataPermanently)
.then(() => {
let adapter = new MongoStorageAdapter({
uri: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase',
collectionPrefix: 'test_',
});
adapter.createObject('_User', { objectId: 'x', email: 'a@b.c' }, requiredUserFields)
.then(() => adapter.createObject('_User', { objectId: 'y', email: 'a@b.c' }, requiredUserFields))
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('qqq');
user.setEmail('unique@unique.unique');
return user.signUp();
})
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('www');
user.setEmail('a@b.c');
user.signUp()
.catch(error => {
expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
done();
});
})
.catch(error => {
fail(JSON.stringify(error));
done();
});
});
});
it('ensure that if you try to sign up a user with a unique username and email, but duplicates in some other field that has a uniqueness constraint, you get a regular duplicate value error', done => {
let config = new Config('test');
config.database.adapter.ensureUniqueness('_User', ['randomField'], requiredUserFields)
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('1');
user.setEmail('1@b.c');
user.set('randomField', 'a');
return user.signUp()
})
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('2');
user.setEmail('2@b.c');
user.set('randomField', 'a');
return user.signUp()
})
.catch(error => {
expect(error.code).toEqual(Parse.Error.DUPLICATE_VALUE);
done();
});
});
@@ -89,8 +252,8 @@ describe('miscellaneous', function() {
return Parse.User.logIn('test', 'moon-y');
}).then((user) => {
expect(user.get('foo')).toEqual(2);
Parse.User.logOut();
done();
Parse.User.logOut()
.then(done);
}, (error) => {
fail(error);
done();
@@ -202,14 +365,14 @@ describe('miscellaneous', function() {
obj.set('foo', 'bar');
return obj.save();
}).then(() => {
var db = DatabaseAdapter.getDatabaseConnection(appId, 'test_');
return db.adapter.find('TestObject', {}, { fields: {} }, {});
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(err => {
fail(err);
}).fail(error => {
fail(JSON.stringify(error));
done();
})
});
@@ -1119,27 +1282,6 @@ describe('miscellaneous', function() {
});
});
it('fail when create duplicate value in unique field', (done) => {
let obj = new Parse.Object('UniqueField');
obj.set('unique', 'value');
obj.save().then(() => {
expect(obj.id).not.toBeUndefined();
let config = new Config('test');
return config.database.adapter.adaptiveCollection('UniqueField')
}).then(collection => {
return collection._mongoCollection.createIndex({ 'unique': 1 }, { unique: true })
}).then(() => {
let obj = new Parse.Object('UniqueField');
obj.set('unique', 'value');
return obj.save()
}).then(() => {
return Promise.reject();
}, error => {
expect(error.code === Parse.Error.DUPLICATE_VALUE);
done();
});
});
it('doesnt convert interior keys of objects that use special names', done => {
let obj = new Parse.Object('Obj');
obj.set('val', { createdAt: 'a', updatedAt: 1 });