711 lines
25 KiB
JavaScript
711 lines
25 KiB
JavaScript
const { DefinedSchemas } = require('../lib/SchemaMigrations/DefinedSchemas');
|
|
const Config = require('../lib/Config');
|
|
|
|
const cleanUpIndexes = schema => {
|
|
if (schema.indexes) {
|
|
delete schema.indexes._id_;
|
|
if (!Object.keys(schema.indexes).length) {
|
|
delete schema.indexes;
|
|
}
|
|
}
|
|
};
|
|
|
|
describe('DefinedSchemas', () => {
|
|
let config;
|
|
afterEach(async () => {
|
|
config = Config.get('test');
|
|
if (config) {
|
|
await config.database.adapter.deleteAllClasses();
|
|
}
|
|
});
|
|
|
|
describe('Fields', () => {
|
|
it('should keep default fields if not provided', async () => {
|
|
const server = await reconfigureServer();
|
|
// Will perform create
|
|
await new DefinedSchemas({ definitions: [{ className: 'Test' }] }, server.config).execute();
|
|
let schema = await new Parse.Schema('Test').get();
|
|
const expectedFields = {
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
ACL: { type: 'ACL' },
|
|
};
|
|
expect(schema.fields).toEqual(expectedFields);
|
|
|
|
await server.config.schemaCache.clear();
|
|
// Will perform update
|
|
await new DefinedSchemas({ definitions: [{ className: 'Test' }] }, server.config).execute();
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields).toEqual(expectedFields);
|
|
});
|
|
it('should protect default fields', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
const schemas = {
|
|
definitions: [
|
|
{
|
|
className: '_User',
|
|
fields: {
|
|
email: 'Object',
|
|
},
|
|
},
|
|
{
|
|
className: '_Role',
|
|
fields: {
|
|
users: 'Object',
|
|
},
|
|
},
|
|
{
|
|
className: '_Installation',
|
|
fields: {
|
|
installationId: 'Object',
|
|
},
|
|
},
|
|
{
|
|
className: 'Test',
|
|
fields: {
|
|
createdAt: { type: 'Object' },
|
|
objectId: { type: 'Number' },
|
|
updatedAt: { type: 'String' },
|
|
ACL: { type: 'String' },
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const expectedFields = {
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
ACL: { type: 'ACL' },
|
|
};
|
|
|
|
const expectedUserFields = {
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
ACL: { type: 'ACL' },
|
|
username: { type: 'String' },
|
|
password: { type: 'String' },
|
|
email: { type: 'String' },
|
|
emailVerified: { type: 'Boolean' },
|
|
authData: { type: 'Object' },
|
|
};
|
|
|
|
const expectedRoleFields = {
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
ACL: { type: 'ACL' },
|
|
name: { type: 'String' },
|
|
users: { type: 'Relation', targetClass: '_User' },
|
|
roles: { type: 'Relation', targetClass: '_Role' },
|
|
};
|
|
|
|
const expectedInstallationFields = {
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
ACL: { type: 'ACL' },
|
|
installationId: { type: 'String' },
|
|
deviceToken: { type: 'String' },
|
|
channels: { type: 'Array' },
|
|
deviceType: { type: 'String' },
|
|
pushType: { type: 'String' },
|
|
GCMSenderId: { type: 'String' },
|
|
timeZone: { type: 'String' },
|
|
localeIdentifier: { type: 'String' },
|
|
badge: { type: 'Number' },
|
|
appVersion: { type: 'String' },
|
|
appName: { type: 'String' },
|
|
appIdentifier: { type: 'String' },
|
|
parseVersion: { type: 'String' },
|
|
};
|
|
|
|
// Perform create
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
let schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields).toEqual(expectedFields);
|
|
|
|
let userSchema = await new Parse.Schema('_User').get();
|
|
expect(userSchema.fields).toEqual(expectedUserFields);
|
|
|
|
let roleSchema = await new Parse.Schema('_Role').get();
|
|
expect(roleSchema.fields).toEqual(expectedRoleFields);
|
|
|
|
let installationSchema = await new Parse.Schema('_Installation').get();
|
|
expect(installationSchema.fields).toEqual(expectedInstallationFields);
|
|
|
|
await server.config.schemaCache.clear();
|
|
// Perform update
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields).toEqual(expectedFields);
|
|
|
|
userSchema = await new Parse.Schema('_User').get();
|
|
expect(userSchema.fields).toEqual(expectedUserFields);
|
|
|
|
roleSchema = await new Parse.Schema('_Role').get();
|
|
expect(roleSchema.fields).toEqual(expectedRoleFields);
|
|
|
|
installationSchema = await new Parse.Schema('_Installation').get();
|
|
expect(installationSchema.fields).toEqual(expectedInstallationFields);
|
|
});
|
|
it('should create new fields', async () => {
|
|
const server = await reconfigureServer();
|
|
const fields = {
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
ACL: { type: 'ACL' },
|
|
aString: { type: 'String' },
|
|
aStringWithDefault: { type: 'String', defaultValue: 'Test' },
|
|
aStringWithRequired: { type: 'String', required: true },
|
|
aStringWithRequiredAndDefault: { type: 'String', required: true, defaultValue: 'Test' },
|
|
aBoolean: { type: 'Boolean' },
|
|
aFile: { type: 'File' },
|
|
aNumber: { type: 'Number' },
|
|
aRelation: { type: 'Relation', targetClass: '_User' },
|
|
aPointer: { type: 'Pointer', targetClass: '_Role' },
|
|
aDate: { type: 'Date' },
|
|
aGeoPoint: { type: 'GeoPoint' },
|
|
aPolygon: { type: 'Polygon' },
|
|
aArray: { type: 'Array' },
|
|
aObject: { type: 'Object' },
|
|
};
|
|
const schemas = {
|
|
definitions: [
|
|
{
|
|
className: 'Test',
|
|
fields,
|
|
},
|
|
],
|
|
};
|
|
|
|
// Create
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
let schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields).toEqual(fields);
|
|
|
|
fields.anotherObject = { type: 'Object' };
|
|
// Update
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields).toEqual(fields);
|
|
});
|
|
it('should not delete removed fields when "deleteExtraFields" is false', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
await new DefinedSchemas(
|
|
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
|
|
server.config
|
|
).execute();
|
|
|
|
let schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toBeDefined();
|
|
|
|
await new DefinedSchemas({ definitions: [{ className: 'Test' }] }, server.config).execute();
|
|
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields).toEqual({
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
aField: { type: 'String' },
|
|
ACL: { type: 'ACL' },
|
|
});
|
|
});
|
|
it('should delete removed fields when "deleteExtraFields" is true', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
await new DefinedSchemas(
|
|
{
|
|
definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }],
|
|
},
|
|
server.config
|
|
).execute();
|
|
|
|
let schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toBeDefined();
|
|
|
|
await new DefinedSchemas(
|
|
{ deleteExtraFields: true, definitions: [{ className: 'Test' }] },
|
|
server.config
|
|
).execute();
|
|
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields).toEqual({
|
|
objectId: { type: 'String' },
|
|
createdAt: { type: 'Date' },
|
|
updatedAt: { type: 'Date' },
|
|
ACL: { type: 'ACL' },
|
|
});
|
|
});
|
|
it('should re create fields with changed type when "recreateModifiedFields" is true', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
await new DefinedSchemas(
|
|
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
|
|
server.config
|
|
).execute();
|
|
|
|
let schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toEqual({ type: 'String' });
|
|
|
|
const object = new Parse.Object('Test');
|
|
await object.save({ aField: 'Hello' }, { useMasterKey: true });
|
|
|
|
await new DefinedSchemas(
|
|
{
|
|
recreateModifiedFields: true,
|
|
definitions: [{ className: 'Test', fields: { aField: { type: 'Number' } } }],
|
|
},
|
|
server.config
|
|
).execute();
|
|
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toEqual({ type: 'Number' });
|
|
|
|
await object.fetch({ useMasterKey: true });
|
|
expect(object.get('aField')).toBeUndefined();
|
|
});
|
|
it('should not re create fields with changed type when "recreateModifiedFields" is not true', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
await new DefinedSchemas(
|
|
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
|
|
server.config
|
|
).execute();
|
|
|
|
let schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toEqual({ type: 'String' });
|
|
|
|
const object = new Parse.Object('Test');
|
|
await object.save({ aField: 'Hello' }, { useMasterKey: true });
|
|
|
|
await new DefinedSchemas(
|
|
{ definitions: [{ className: 'Test', fields: { aField: { type: 'Number' } } }] },
|
|
server.config
|
|
).execute();
|
|
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toEqual({ type: 'String' });
|
|
|
|
await object.fetch({ useMasterKey: true });
|
|
expect(object.get('aField')).toBeDefined();
|
|
});
|
|
it('should just update classic fields with changed params', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
await new DefinedSchemas(
|
|
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
|
|
server.config
|
|
).execute();
|
|
|
|
let schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toEqual({ type: 'String' });
|
|
|
|
const object = new Parse.Object('Test');
|
|
await object.save({ aField: 'Hello' }, { useMasterKey: true });
|
|
|
|
await new DefinedSchemas(
|
|
{
|
|
definitions: [
|
|
{ className: 'Test', fields: { aField: { type: 'String', required: true } } },
|
|
],
|
|
},
|
|
server.config
|
|
).execute();
|
|
|
|
schema = await new Parse.Schema('Test').get();
|
|
expect(schema.fields.aField).toEqual({ type: 'String', required: true });
|
|
|
|
await object.fetch({ useMasterKey: true });
|
|
expect(object.get('aField')).toEqual('Hello');
|
|
});
|
|
});
|
|
|
|
describe('Indexes', () => {
|
|
it('should create new indexes', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
const indexes = { complex: { createdAt: 1, updatedAt: 1 } };
|
|
|
|
const schemas = {
|
|
definitions: [{ className: 'Test', fields: { aField: { type: 'String' } }, indexes }],
|
|
};
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
|
|
let schema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(schema);
|
|
expect(schema.indexes).toEqual(indexes);
|
|
|
|
indexes.complex2 = { createdAt: 1, aField: 1 };
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
schema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(schema);
|
|
expect(schema.indexes).toEqual(indexes);
|
|
});
|
|
it('should re create changed indexes', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
let indexes = { complex: { createdAt: 1, updatedAt: 1 } };
|
|
|
|
let schemas = { definitions: [{ className: 'Test', indexes }] };
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
|
|
indexes = { complex: { createdAt: 1 } };
|
|
schemas = { definitions: [{ className: 'Test', indexes }] };
|
|
|
|
// Change indexes
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
let schema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(schema);
|
|
expect(schema.indexes).toEqual(indexes);
|
|
|
|
// Update
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
schema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(schema);
|
|
expect(schema.indexes).toEqual(indexes);
|
|
});
|
|
|
|
it('should delete removed indexes', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
let indexes = { complex: { createdAt: 1, updatedAt: 1 } };
|
|
|
|
let schemas = { definitions: [{ className: 'Test', indexes }] };
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
|
|
indexes = {};
|
|
schemas = { definitions: [{ className: 'Test', indexes }] };
|
|
// Change indexes
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
let schema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(schema);
|
|
expect(schema.indexes).toBeUndefined();
|
|
|
|
// Update
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
schema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(schema);
|
|
expect(schema.indexes).toBeUndefined();
|
|
});
|
|
xit('should keep protected indexes', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
const expectedIndexes = {
|
|
username_1: { username: 1 },
|
|
case_insensitive_username: { username: 1 },
|
|
email_1: { email: 1 },
|
|
case_insensitive_email: { email: 1 },
|
|
};
|
|
const schemas = {
|
|
definitions: [
|
|
{
|
|
className: '_User',
|
|
indexes: {
|
|
case_insensitive_username: { password: true },
|
|
case_insensitive_email: { password: true },
|
|
},
|
|
},
|
|
{ className: 'Test' },
|
|
],
|
|
};
|
|
// Create
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
let userSchema = await new Parse.Schema('_User').get();
|
|
let testSchema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(userSchema);
|
|
cleanUpIndexes(testSchema);
|
|
expect(testSchema.indexes).toBeUndefined();
|
|
expect(userSchema.indexes).toEqual(expectedIndexes);
|
|
|
|
// Update
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
userSchema = await new Parse.Schema('_User').get();
|
|
testSchema = await new Parse.Schema('Test').get();
|
|
cleanUpIndexes(userSchema);
|
|
cleanUpIndexes(testSchema);
|
|
expect(testSchema.indexes).toBeUndefined();
|
|
expect(userSchema.indexes).toEqual(expectedIndexes);
|
|
});
|
|
|
|
it('should detect protected indexes for _User class', () => {
|
|
const definedSchema = new DefinedSchemas({}, {});
|
|
const protectedUserIndexes = ['_id_', 'case_insensitive_email', 'username_1', 'email_1'];
|
|
protectedUserIndexes.forEach(field => {
|
|
expect(definedSchema.isProtectedIndex('_User', field)).toEqual(true);
|
|
});
|
|
expect(definedSchema.isProtectedIndex('_User', 'test')).toEqual(false);
|
|
});
|
|
|
|
it('should detect protected indexes for _Role class', () => {
|
|
const definedSchema = new DefinedSchemas({}, {});
|
|
expect(definedSchema.isProtectedIndex('_Role', 'name_1')).toEqual(true);
|
|
expect(definedSchema.isProtectedIndex('_Role', 'test')).toEqual(false);
|
|
});
|
|
|
|
it('should detect protected indexes for _Idempotency class', () => {
|
|
const definedSchema = new DefinedSchemas({}, {});
|
|
expect(definedSchema.isProtectedIndex('_Idempotency', 'reqId_1')).toEqual(true);
|
|
expect(definedSchema.isProtectedIndex('_Idempotency', 'test')).toEqual(false);
|
|
});
|
|
|
|
it('should not detect protected indexes on user defined class', () => {
|
|
const definedSchema = new DefinedSchemas({}, {});
|
|
const protectedIndexes = [
|
|
'case_insensitive_email',
|
|
'username_1',
|
|
'email_1',
|
|
'reqId_1',
|
|
'name_1',
|
|
];
|
|
protectedIndexes.forEach(field => {
|
|
expect(definedSchema.isProtectedIndex('ExampleClass', field)).toEqual(false);
|
|
});
|
|
expect(definedSchema.isProtectedIndex('ExampleClass', '_id_')).toEqual(true);
|
|
});
|
|
});
|
|
|
|
describe('ClassLevelPermissions', () => {
|
|
it('should use default CLP', async () => {
|
|
const server = await reconfigureServer();
|
|
const schemas = { definitions: [{ className: 'Test' }] };
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
|
|
const expectedTestCLP = {
|
|
find: {},
|
|
count: {},
|
|
get: {},
|
|
create: {},
|
|
update: {},
|
|
delete: {},
|
|
addField: {},
|
|
protectedFields: {},
|
|
};
|
|
let testSchema = await new Parse.Schema('Test').get();
|
|
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
|
|
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
testSchema = await new Parse.Schema('Test').get();
|
|
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
|
|
});
|
|
it('should save CLP', async () => {
|
|
const server = await reconfigureServer();
|
|
|
|
const expectedTestCLP = {
|
|
find: {},
|
|
count: { requiresAuthentication: true },
|
|
get: { 'role:Admin': true },
|
|
create: { 'role:ARole': true, requiresAuthentication: true },
|
|
update: { requiresAuthentication: true },
|
|
delete: { requiresAuthentication: true },
|
|
addField: {},
|
|
protectedFields: { '*': ['aField'], 'role:Admin': ['anotherField'] },
|
|
};
|
|
const schemas = {
|
|
definitions: [
|
|
{
|
|
className: 'Test',
|
|
fields: { aField: { type: 'String' }, anotherField: { type: 'Object' } },
|
|
classLevelPermissions: expectedTestCLP,
|
|
},
|
|
],
|
|
};
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
|
|
let testSchema = await new Parse.Schema('Test').get();
|
|
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
|
|
|
|
expectedTestCLP.update = {};
|
|
expectedTestCLP.create = { requiresAuthentication: true };
|
|
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
testSchema = await new Parse.Schema('Test').get();
|
|
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
|
|
});
|
|
it('should force addField to empty', async () => {
|
|
const server = await reconfigureServer();
|
|
const schemas = {
|
|
definitions: [{ className: 'Test', classLevelPermissions: { addField: { '*': true } } }],
|
|
};
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
|
|
const expectedTestCLP = {
|
|
find: {},
|
|
count: {},
|
|
get: {},
|
|
create: {},
|
|
update: {},
|
|
delete: {},
|
|
addField: {},
|
|
protectedFields: {},
|
|
};
|
|
|
|
let testSchema = await new Parse.Schema('Test').get();
|
|
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
|
|
|
|
await new DefinedSchemas(schemas, server.config).execute();
|
|
testSchema = await new Parse.Schema('Test').get();
|
|
expect(testSchema.classLevelPermissions).toEqual(expectedTestCLP);
|
|
});
|
|
});
|
|
|
|
it('should not delete classes automatically', async () => {
|
|
await reconfigureServer({
|
|
schema: { definitions: [{ className: '_User' }, { className: 'Test' }] },
|
|
});
|
|
|
|
await reconfigureServer({ schema: { definitions: [{ className: '_User' }] } });
|
|
|
|
const schema = await new Parse.Schema('Test').get();
|
|
expect(schema.className).toEqual('Test');
|
|
});
|
|
|
|
it('should disable class PUT/POST endpoint when lockSchemas provided to avoid dual source of truth', async () => {
|
|
await reconfigureServer({
|
|
schema: {
|
|
lockSchemas: true,
|
|
definitions: [{ className: '_User' }, { className: 'Test' }],
|
|
},
|
|
});
|
|
|
|
const schema = await new Parse.Schema('Test').get();
|
|
expect(schema.className).toEqual('Test');
|
|
|
|
const schemas = await Parse.Schema.all();
|
|
// Role could be flaky since all system classes are not ensured
|
|
// at start up by the DefinedSchema system
|
|
expect(schemas.filter(({ className }) => className !== '_Role').length).toEqual(3);
|
|
|
|
await expectAsync(new Parse.Schema('TheNewTest').save()).toBeRejectedWithError(
|
|
'Cannot perform this operation when schemas options is used.'
|
|
);
|
|
|
|
await expectAsync(new Parse.Schema('_User').update()).toBeRejectedWithError(
|
|
'Cannot perform this operation when schemas options is used.'
|
|
);
|
|
});
|
|
it('should only enable delete class endpoint since', async () => {
|
|
await reconfigureServer({
|
|
schema: { definitions: [{ className: '_User' }, { className: 'Test' }] },
|
|
});
|
|
await reconfigureServer({ schema: { definitions: [{ className: '_User' }] } });
|
|
|
|
let schemas = await Parse.Schema.all();
|
|
expect(schemas.length).toEqual(4);
|
|
|
|
await new Parse.Schema('_User').delete();
|
|
schemas = await Parse.Schema.all();
|
|
expect(schemas.length).toEqual(3);
|
|
});
|
|
it('should run beforeMigration before execution of DefinedSchemas', async () => {
|
|
const config = {
|
|
schema: {
|
|
definitions: [{ className: '_User' }, { className: 'Test' }],
|
|
beforeMigration: async () => {},
|
|
},
|
|
};
|
|
const spy = spyOn(config.schema, 'beforeMigration');
|
|
await reconfigureServer(config);
|
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
});
|
|
it('should run afterMigration after execution of DefinedSchemas', async () => {
|
|
const config = {
|
|
schema: {
|
|
definitions: [{ className: '_User' }, { className: 'Test' }],
|
|
afterMigration: async () => {},
|
|
},
|
|
};
|
|
const spy = spyOn(config.schema, 'afterMigration');
|
|
await reconfigureServer(config);
|
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('should use logger in case of error', async () => {
|
|
const server = await reconfigureServer({ schema: { definitions: [{ className: '_User' }] } });
|
|
const error = new Error('A test error');
|
|
const logger = require('../lib/logger').logger;
|
|
spyOn(DefinedSchemas.prototype, 'wait').and.resolveTo();
|
|
spyOn(logger, 'error').and.callThrough();
|
|
spyOn(DefinedSchemas.prototype, 'createDeleteSession').and.callFake(() => {
|
|
throw error;
|
|
});
|
|
|
|
await new DefinedSchemas(
|
|
{ definitions: [{ className: 'Test', fields: { aField: { type: 'String' } } }] },
|
|
server.config
|
|
).execute();
|
|
|
|
expect(logger.error).toHaveBeenCalledWith(`Failed to run migrations: ${error.toString()}`);
|
|
});
|
|
|
|
it_id('a18bf4f2-25c8-4de3-b986-19cb1ab163b8')(it)('should perform migration in parallel without failing', async () => {
|
|
const server = await reconfigureServer();
|
|
const logger = require('../lib/logger').logger;
|
|
spyOn(logger, 'error').and.callThrough();
|
|
const migrationOptions = {
|
|
definitions: [
|
|
{
|
|
className: 'Test',
|
|
fields: { aField: { type: 'String' } },
|
|
indexes: { aField: { aField: 1 } },
|
|
classLevelPermissions: {
|
|
create: { requiresAuthentication: true },
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
// Simulate parallel deployment
|
|
await Promise.all([
|
|
new DefinedSchemas(migrationOptions, server.config).execute(),
|
|
new DefinedSchemas(migrationOptions, server.config).execute(),
|
|
new DefinedSchemas(migrationOptions, server.config).execute(),
|
|
new DefinedSchemas(migrationOptions, server.config).execute(),
|
|
new DefinedSchemas(migrationOptions, server.config).execute(),
|
|
]);
|
|
|
|
const testSchema = (await Parse.Schema.all()).find(
|
|
({ className }) => className === migrationOptions.definitions[0].className
|
|
);
|
|
|
|
expect(testSchema.indexes.aField).toEqual({ aField: 1 });
|
|
expect(testSchema.fields.aField).toEqual({ type: 'String' });
|
|
expect(testSchema.classLevelPermissions.create).toEqual({ requiresAuthentication: true });
|
|
expect(logger.error).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it('should not affect cacheAdapter', async () => {
|
|
const server = await reconfigureServer();
|
|
const logger = require('../lib/logger').logger;
|
|
spyOn(logger, 'error').and.callThrough();
|
|
const migrationOptions = {
|
|
definitions: [
|
|
{
|
|
className: 'Test',
|
|
fields: { aField: { type: 'String' } },
|
|
indexes: { aField: { aField: 1 } },
|
|
classLevelPermissions: {
|
|
create: { requiresAuthentication: true },
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const cacheAdapter = {
|
|
get: () => Promise.resolve(null),
|
|
put: () => {},
|
|
del: () => {},
|
|
clear: () => {},
|
|
connect: jasmine.createSpy('clear'),
|
|
};
|
|
server.config.cacheAdapter = cacheAdapter;
|
|
await new DefinedSchemas(migrationOptions, server.config).execute();
|
|
expect(cacheAdapter.connect).not.toHaveBeenCalled();
|
|
});
|
|
});
|