Improve single schema cache (#7214)

* Initial Commit

* fix flaky test

* temporary set ci timeout

* turn off ci check

* fix postgres tests

* fix tests

* node flaky test

* remove improvements

* Update SchemaPerformance.spec.js

* fix tests

* revert ci

* Create Singleton Object

* properly clear cache testing

* Cleanup

* remove fit

* try PushController.spec

* try push test rewrite

* try push enqueue time

* Increase test timeout

* remove pg server creation test

* xit push tests

* more xit

* remove skipped tests

* Fix conflicts

* reduce ci timeout

* fix push tests

* Revert "fix push tests"

This reverts commit 05aba62f1cbbca7d5d3e80b9444529f59407cb56.

* improve initialization

* fix flaky tests

* xit flaky test

* Update CHANGELOG.md

* enable debug logs

* Update LogsRouter.spec.js

* create initial indexes in series

* lint

* horizontal scaling documentation

* Update Changelog

* change horizontalScaling db option

* Add enableSchemaHooks option

* move enableSchemaHooks to databaseOptions
This commit is contained in:
Diamond Lewis
2021-03-16 16:05:36 -05:00
committed by GitHub
parent 32fc45d2d2
commit a02014f557
38 changed files with 673 additions and 937 deletions

View File

@@ -1,58 +0,0 @@
const auth = require('../lib/Auth');
const Config = require('../lib/Config');
const rest = require('../lib/rest');
describe('Enable single schema cache', () => {
beforeEach(done => {
reconfigureServer({
enableSingleSchemaCache: true,
schemaCacheTTL: 30000,
}).then(() => {
done();
});
});
it('can perform multiple create and query operations', done => {
let config = fakeRequestForConfig();
let nobody = auth.nobody(config);
rest
.create(config, nobody, 'Foo', { type: 1 })
.then(() => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
return rest.create(config, nobody, 'Foo', { type: 2 });
})
.then(() => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
return rest.create(config, nobody, 'Bar');
})
.then(() => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
return rest.find(config, nobody, 'Bar', { type: 1 });
})
.then(
() => {
fail('Should throw error');
done();
},
error => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
expect(error).toBeDefined();
return rest.find(config, nobody, 'Foo', { type: 1 });
}
)
.then(response => {
config = fakeRequestForConfig();
nobody = auth.nobody(config);
expect(response.results.length).toEqual(1);
done();
});
});
});
const fakeRequestForConfig = function () {
return Config.get('test');
};

View File

@@ -8,7 +8,9 @@ const WinstonLoggerAdapter = require('../lib/Adapters/Logger/WinstonLoggerAdapte
const loggerController = new LoggerController(new WinstonLoggerAdapter());
describe('LogsRouter', () => {
describe_only(() => {
return process.env.PARSE_SERVER_LOG_LEVEL !== 'debug';
})('LogsRouter', () => {
it('can check valid master key of request', done => {
// Make mock request
const request = {

View File

@@ -18,6 +18,7 @@ const fakeClient = {
describe_only_db('mongo')('MongoStorageAdapter', () => {
beforeEach(done => {
new MongoStorageAdapter({ uri: databaseURI }).deleteAllClasses().then(done, fail);
Config.get(Parse.applicationId).schemaCache.clear();
});
it('auto-escapes symbols in auth information', () => {
@@ -314,6 +315,8 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
await user.signUp();
const database = Config.get(Parse.applicationId).database;
await database.adapter.dropAllIndexes('_User');
const preIndexPlan = await database.find(
'_User',
{ username: 'bugs' },
@@ -546,5 +549,33 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
});
});
describe('watch _SCHEMA', () => {
it('should change', async done => {
const adapter = new MongoStorageAdapter({
uri: databaseURI,
collectionPrefix: '',
mongoOptions: { enableSchemaHooks: true },
});
await reconfigureServer({ databaseAdapter: adapter });
expect(adapter.enableSchemaHooks).toBe(true);
spyOn(adapter, '_onchange');
const schema = {
fields: {
array: { type: 'Array' },
object: { type: 'Object' },
date: { type: 'Date' },
},
};
await adapter.createClass('Stuff', schema);
const myClassSchema = await adapter.getClass('Stuff');
expect(myClassSchema).toBeDefined();
setTimeout(() => {
expect(adapter._onchange).toHaveBeenCalled();
done();
}, 5000);
});
});
}
});

View File

@@ -30,9 +30,7 @@ describe('ParseGraphQLController', () => {
beforeEach(async () => {
if (!parseServer) {
parseServer = await global.reconfigureServer({
schemaCacheTTL: 100,
});
parseServer = await global.reconfigureServer();
databaseController = parseServer.config.databaseController;
cacheController = parseServer.config.cacheController;

View File

@@ -10,9 +10,7 @@ describe('ParseGraphQLSchema', () => {
const appId = 'test';
beforeEach(async () => {
parseServer = await global.reconfigureServer({
schemaCacheTTL: 100,
});
parseServer = await global.reconfigureServer();
databaseController = parseServer.config.databaseController;
parseGraphQLController = parseServer.config.parseGraphQLController;
parseGraphQLSchema = new ParseGraphQLSchema({
@@ -68,7 +66,7 @@ describe('ParseGraphQLSchema', () => {
const graphQLSubscriptions = parseGraphQLSchema.graphQLSubscriptions;
const newClassObject = new Parse.Object('NewClass');
await newClassObject.save();
await databaseController.schemaCache.clear();
await parseServer.config.schemaCache.clear();
await new Promise(resolve => setTimeout(resolve, 200));
await parseGraphQLSchema.load();
expect(parseClasses).not.toBe(parseGraphQLSchema.parseClasses);
@@ -426,14 +424,14 @@ describe('ParseGraphQLSchema', () => {
log: defaultLogger,
appId,
});
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const types1 = parseGraphQLSchema.graphQLTypes;
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const user = new Parse.Object('User');
await user.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const types2 = parseGraphQLSchema.graphQLTypes;
const queries2 = parseGraphQLSchema.graphQLQueries;
@@ -456,14 +454,14 @@ describe('ParseGraphQLSchema', () => {
});
const car1 = new Parse.Object('Car');
await car1.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const types1 = parseGraphQLSchema.graphQLTypes;
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const car2 = new Parse.Object('car');
await car2.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const types2 = parseGraphQLSchema.graphQLTypes;
const queries2 = parseGraphQLSchema.graphQLQueries;
@@ -486,13 +484,13 @@ describe('ParseGraphQLSchema', () => {
});
const car = new Parse.Object('Car');
await car.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const cars = new Parse.Object('cars');
await cars.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const queries2 = parseGraphQLSchema.graphQLQueries;
const mutations2 = parseGraphQLSchema.graphQLMutations;
@@ -532,7 +530,7 @@ describe('ParseGraphQLSchema', () => {
await data.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
await parseGraphQLSchema.load();
const queries1 = parseGraphQLSchema.graphQLQueries;
@@ -569,7 +567,7 @@ describe('ParseGraphQLSchema', () => {
await data.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
await parseGraphQLSchema.load();
const mutations = parseGraphQLSchema.graphQLMutations;

View File

@@ -538,7 +538,7 @@ describe('ParseGraphQLServer', () => {
const resetGraphQLCache = async () => {
await Promise.all([
parseGraphQLServer.parseGraphQLController.cacheController.graphQL.clear(),
parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(),
parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(),
]);
};
@@ -1092,7 +1092,7 @@ describe('ParseGraphQLServer', () => {
const obj = new Parse.Object('SomeClass');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createObjectInputFields = (
await apolloClient.query({
@@ -1117,7 +1117,7 @@ describe('ParseGraphQLServer', () => {
const obj = new Parse.Object('SomeClass');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createObjectPayloadFields = (
await apolloClient.query({
@@ -1142,7 +1142,7 @@ describe('ParseGraphQLServer', () => {
const obj = new Parse.Object('SomeClass');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createObjectInputFields = (
await apolloClient.query({
@@ -1167,7 +1167,7 @@ describe('ParseGraphQLServer', () => {
const obj = new Parse.Object('SomeClass');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createObjectPayloadFields = (
await apolloClient.query({
@@ -1192,7 +1192,7 @@ describe('ParseGraphQLServer', () => {
const obj = new Parse.Object('SomeClass');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createObjectInputFields = (
await apolloClient.query({
@@ -1217,7 +1217,7 @@ describe('ParseGraphQLServer', () => {
const obj = new Parse.Object('SomeClass');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createObjectPayloadFields = (
await apolloClient.query({
@@ -1339,7 +1339,7 @@ describe('ParseGraphQLServer', () => {
const resetGraphQLCache = async () => {
await Promise.all([
parseGraphQLServer.parseGraphQLController.cacheController.graphQL.clear(),
parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(),
parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(),
]);
};
@@ -3921,7 +3921,7 @@ describe('ParseGraphQLServer', () => {
obj.set('someField', 'someValue');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = (
await apolloClient.query({
@@ -3964,7 +3964,7 @@ describe('ParseGraphQLServer', () => {
obj3.set('manyRelations', [obj1, obj2]);
await obj3.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = (
await apolloClient.query({
@@ -4039,7 +4039,7 @@ describe('ParseGraphQLServer', () => {
obj1.set('country', obj4);
await obj1.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = (
await apolloClient.query({
@@ -4130,7 +4130,7 @@ describe('ParseGraphQLServer', () => {
it('should respect level permissions', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
async function getObject(className, id, headers) {
const alias = className.charAt(0).toLowerCase() + className.slice(1);
@@ -4260,7 +4260,7 @@ describe('ParseGraphQLServer', () => {
it('should support keys argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result1 = await apolloClient.query({
query: gql`
@@ -4310,7 +4310,7 @@ describe('ParseGraphQLServer', () => {
it('should support include argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result1 = await apolloClient.query({
query: gql`
@@ -4358,7 +4358,7 @@ describe('ParseGraphQLServer', () => {
it('should respect protectedFields', async done => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const className = 'GraphQLClass';
@@ -4439,7 +4439,7 @@ describe('ParseGraphQLServer', () => {
try {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const databaseAdapter = parseServer.config.databaseController.adapter;
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
@@ -4486,7 +4486,7 @@ describe('ParseGraphQLServer', () => {
it('should support readPreference argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const databaseAdapter = parseServer.config.databaseController.adapter;
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
@@ -4530,7 +4530,7 @@ describe('ParseGraphQLServer', () => {
it('should support includeReadPreference argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const databaseAdapter = parseServer.config.databaseController.adapter;
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
@@ -4585,7 +4585,7 @@ describe('ParseGraphQLServer', () => {
obj2.set('someField', 'someValue1');
await obj2.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
query: gql`
@@ -4618,7 +4618,7 @@ describe('ParseGraphQLServer', () => {
it('should respect level permissions', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
async function findObjects(className, headers) {
const graphqlClassName = pluralize(
@@ -4724,7 +4724,7 @@ describe('ParseGraphQLServer', () => {
it('should support where argument using class specific query', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
query: gql`
@@ -4776,7 +4776,7 @@ describe('ParseGraphQLServer', () => {
it('should support in pointer operator using class specific query', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
query: gql`
@@ -4816,7 +4816,7 @@ describe('ParseGraphQLServer', () => {
it('should support OR operation', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
query: gql`
@@ -4856,7 +4856,7 @@ describe('ParseGraphQLServer', () => {
obj.set('field2', 'It rocks!');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
query: gql`
@@ -4914,7 +4914,7 @@ describe('ParseGraphQLServer', () => {
city2.set('name', 'city2');
await city2.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -4970,7 +4970,7 @@ describe('ParseGraphQLServer', () => {
}
await Promise.all(promises);
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
query: gql`
@@ -5024,7 +5024,7 @@ describe('ParseGraphQLServer', () => {
}
await Promise.all(promises);
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const find = async ({ skip, after, first, before, last } = {}) => {
return await apolloClient.query({
@@ -5152,7 +5152,7 @@ describe('ParseGraphQLServer', () => {
it('should support count', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const where = {
someField: {
@@ -5207,7 +5207,7 @@ describe('ParseGraphQLServer', () => {
it('should only count', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const where = {
someField: {
@@ -5265,7 +5265,7 @@ describe('ParseGraphQLServer', () => {
}
await Promise.all(promises);
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
query: gql`
@@ -5297,7 +5297,7 @@ describe('ParseGraphQLServer', () => {
it('should support keys argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result1 = await apolloClient.query({
query: gql`
@@ -5359,7 +5359,7 @@ describe('ParseGraphQLServer', () => {
it('should support include argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const where = {
id: {
@@ -5422,7 +5422,7 @@ describe('ParseGraphQLServer', () => {
it('should read from primary by default', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const databaseAdapter = parseServer.config.databaseController.adapter;
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
@@ -5467,7 +5467,7 @@ describe('ParseGraphQLServer', () => {
it('should support readPreference argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const databaseAdapter = parseServer.config.databaseController.adapter;
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
@@ -5512,7 +5512,7 @@ describe('ParseGraphQLServer', () => {
it('should support includeReadPreference argument', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const databaseAdapter = parseServer.config.databaseController.adapter;
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
@@ -5560,7 +5560,7 @@ describe('ParseGraphQLServer', () => {
try {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const databaseAdapter = parseServer.config.databaseController.adapter;
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
@@ -5714,7 +5714,7 @@ describe('ParseGraphQLServer', () => {
customerSchema.addString('someField');
await customerSchema.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.mutate({
mutation: gql`
@@ -5757,7 +5757,7 @@ describe('ParseGraphQLServer', () => {
it('should respect level permissions', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
async function createObject(className, headers) {
const getClassName = className.charAt(0).toLowerCase() + className.slice(1);
@@ -5837,7 +5837,7 @@ describe('ParseGraphQLServer', () => {
obj.set('someField2', 'someField2Value1');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.mutate({
mutation: gql`
@@ -5880,7 +5880,7 @@ describe('ParseGraphQLServer', () => {
obj.set('someField2', 'someField2Value1');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.mutate({
mutation: gql`
@@ -5912,7 +5912,7 @@ describe('ParseGraphQLServer', () => {
it('should respect level permissions', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
async function updateObject(className, id, fields, headers) {
return await apolloClient.mutate({
@@ -6107,7 +6107,7 @@ describe('ParseGraphQLServer', () => {
it('should respect level permissions with specific class mutation', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
function updateObject(className, id, fields, headers) {
const mutationName = className.charAt(0).toLowerCase() + className.slice(1);
@@ -6327,7 +6327,7 @@ describe('ParseGraphQLServer', () => {
obj.set('someField2', 'someField2Value1');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.mutate({
mutation: gql`
@@ -6364,7 +6364,7 @@ describe('ParseGraphQLServer', () => {
it('should respect level permissions', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
function deleteObject(className, id, headers) {
const mutationName = className.charAt(0).toLowerCase() + className.slice(1);
@@ -6454,7 +6454,7 @@ describe('ParseGraphQLServer', () => {
it('should respect level permissions with specific class mutation', async () => {
await prepareData();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
function deleteObject(className, id, headers) {
const mutationName = className.charAt(0).toLowerCase() + className.slice(1);
@@ -6666,7 +6666,7 @@ describe('ParseGraphQLServer', () => {
user.set('userFoo', foo);
await user.signUp();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const session = await Parse.Session.current();
const result = await apolloClient.query({
@@ -6717,7 +6717,7 @@ describe('ParseGraphQLServer', () => {
user.set('userFoo', foo);
await user.signUp();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const session = await Parse.Session.current();
const result = await apolloClient.query({
@@ -6758,7 +6758,7 @@ describe('ParseGraphQLServer', () => {
userSchema.addPointer('aPointer', '_User');
await userSchema.update();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.mutate({
mutation: gql`
mutation SignUp($input: SignUpInput!) {
@@ -6819,7 +6819,7 @@ describe('ParseGraphQLServer', () => {
userSchema.addString('someField');
userSchema.addPointer('aPointer', '_User');
await userSchema.update();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.mutate({
mutation: gql`
mutation LogInWith($input: LogInWithInput!) {
@@ -6877,7 +6877,7 @@ describe('ParseGraphQLServer', () => {
user.set('someField', 'someValue');
await user.signUp();
await Parse.User.logOut();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.mutate({
mutation: gql`
mutation LogInUser($input: LogInInput!) {
@@ -7120,7 +7120,7 @@ describe('ParseGraphQLServer', () => {
const car = new Parse.Object('Car');
await car.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
try {
await apolloClient.query({
@@ -7418,7 +7418,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someField.type).toEqual('String');
@@ -7493,7 +7493,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createResult = await apolloClient.mutate({
mutation: gql`
@@ -7568,7 +7568,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someField.type).toEqual('Number');
@@ -7644,7 +7644,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someFieldTrue.type).toEqual('Boolean');
@@ -7734,7 +7734,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someField.type).toEqual('Date');
@@ -7827,7 +7827,7 @@ describe('ParseGraphQLServer', () => {
const role2 = new Parse.Role('aRole2', roleACL);
await role2.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const gqlUser = (
await apolloClient.query({
@@ -8013,7 +8013,7 @@ describe('ParseGraphQLServer', () => {
company2.set('name', 'imACompany2');
await company2.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8058,7 +8058,7 @@ describe('ParseGraphQLServer', () => {
country.set('company', company);
await country.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8109,7 +8109,7 @@ describe('ParseGraphQLServer', () => {
company2.set('name', 'imACompany2');
await company2.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8154,7 +8154,7 @@ describe('ParseGraphQLServer', () => {
country.set('company', company);
await country.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8201,7 +8201,7 @@ describe('ParseGraphQLServer', () => {
country.relation('companies').add(company);
await country.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8269,7 +8269,7 @@ describe('ParseGraphQLServer', () => {
country.relation('companies').add(company);
await country.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8362,7 +8362,7 @@ describe('ParseGraphQLServer', () => {
country.relation('companies').add(company1);
await country.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8421,7 +8421,7 @@ describe('ParseGraphQLServer', () => {
country.relation('companies').add(company);
await country.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const {
data: {
@@ -8489,7 +8489,7 @@ describe('ParseGraphQLServer', () => {
country.relation('companies').add([company1, company2]);
await country.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
// Without where
const {
@@ -8589,7 +8589,7 @@ describe('ParseGraphQLServer', () => {
country3.set('president', president);
await country3.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
let {
data: {
@@ -8856,7 +8856,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const body2 = new FormData();
body2.append(
@@ -9057,7 +9057,7 @@ describe('ParseGraphQLServer', () => {
},
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someObjectField.type).toEqual('Object');
@@ -9157,7 +9157,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createResult = await apolloClient.mutate({
mutation: gql`
@@ -9274,7 +9274,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someArrayField.type).toEqual('Array');
@@ -9342,7 +9342,7 @@ describe('ParseGraphQLServer', () => {
const obj = new Parse.Object('SomeClass');
await obj.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const getResult = await apolloClient.query({
query: gql`
@@ -9391,7 +9391,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const createResult = await apolloClient.mutate({
mutation: gql`
@@ -9485,7 +9485,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someField.type).toEqual('Bytes');
@@ -9576,7 +9576,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someField.type).toEqual('GeoPoint');
@@ -9735,7 +9735,7 @@ describe('ParseGraphQLServer', () => {
},
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.somePolygonField.type).toEqual('Polygon');
@@ -9830,7 +9830,7 @@ describe('ParseGraphQLServer', () => {
});
await someClass.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const schema = await new Parse.Schema('SomeClass').get();
expect(schema.fields.someField.type).toEqual('Bytes');
@@ -9930,7 +9930,7 @@ describe('ParseGraphQLServer', () => {
user.setPassword('user1');
await user.signUp();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const getResult = await apolloClient.query({
query: gql`
@@ -9954,7 +9954,7 @@ describe('ParseGraphQLServer', () => {
deviceType: 'foo',
});
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const getResult = await apolloClient.query({
query: gql`
@@ -9978,7 +9978,7 @@ describe('ParseGraphQLServer', () => {
const role = new Parse.Role('MyRole', roleACL);
await role.save();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const getResult = await apolloClient.query({
query: gql`
@@ -10002,7 +10002,7 @@ describe('ParseGraphQLServer', () => {
user.setPassword('user1');
await user.signUp();
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const session = await Parse.Session.current();
const getResult = await apolloClient.query({
@@ -10041,7 +10041,7 @@ describe('ParseGraphQLServer', () => {
{ useMasterKey: true }
);
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const getResult = await apolloClient.query({
query: gql`
@@ -10170,7 +10170,7 @@ describe('ParseGraphQLServer', () => {
await Promise.all([
parseGraphQLServer.parseGraphQLController.cacheController.graphQL.clear(),
parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear(),
parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(),
]);
await expectAsync(
@@ -10311,7 +10311,7 @@ describe('ParseGraphQLServer', () => {
it('can resolve a custom query with auto type return', async () => {
const obj = new Parse.Object('SomeClass');
await obj.save({ name: 'aname', type: 'robot' });
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
variables: { id: obj.id },
query: gql`
@@ -10334,7 +10334,7 @@ describe('ParseGraphQLServer', () => {
it('can resolve a custom extend type', async () => {
const obj = new Parse.Object('SomeClass');
await obj.save({ name: 'aname', type: 'robot' });
await parseGraphQLServer.parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
const result = await apolloClient.query({
variables: { id: obj.id },
query: gql`

View File

@@ -24,7 +24,6 @@ describe_only_db('mongo')('Parse.Query hint', () => {
});
afterEach(async () => {
await config.database.schemaCache.clear();
await TestUtils.destroyAllDataPermanently(false);
});

View File

@@ -247,6 +247,7 @@ describe('Parse.User testing', () => {
await adapter.connect();
await adapter.database.dropDatabase();
delete adapter.connectionPromise;
Config.get(Parse.applicationId).schemaCache.clear();
const user = new Parse.User();
await user.signUp({

View File

@@ -3,7 +3,7 @@ const Config = require('../lib/Config');
describe('Pointer Permissions', () => {
beforeEach(() => {
Config.get(Parse.applicationId).database.schemaCache.clear();
Config.get(Parse.applicationId).schemaCache.clear();
});
describe('using single user-pointers', () => {
@@ -2020,7 +2020,7 @@ describe('Pointer Permissions', () => {
let obj2;
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
[user1, user2] = await Promise.all([createUser('user1'), createUser('user2')]);
@@ -2442,7 +2442,7 @@ describe('Pointer Permissions', () => {
let objNobody;
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
[user1, user2, user3] = await Promise.all([
createUser('user1'),
@@ -2919,7 +2919,7 @@ describe('Pointer Permissions', () => {
let obj2;
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
[user1, user2] = await Promise.all([createUser('user1'), createUser('user2')]);
@@ -3033,7 +3033,7 @@ describe('Pointer Permissions', () => {
* Clear cache, create user and object, login user
*/
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
user1 = await createUser('user1');
user1 = await logIn(user1);

View File

@@ -26,6 +26,8 @@ describe_only_db('postgres')('PostgresStorageAdapter', () => {
it('schemaUpgrade, upgrade the database schema when schema changes', async done => {
await adapter.deleteAllClasses();
const config = Config.get('test');
config.schemaCache.clear();
await adapter.performInitialization({ VolatileClassesSchemas: [] });
const client = adapter._client;
const className = '_PushStatus';
@@ -232,13 +234,19 @@ describe_only_db('postgres')('PostgresStorageAdapter', () => {
});
it('should use index for caseInsensitive query', async () => {
await adapter.deleteAllClasses();
const config = Config.get('test');
config.schemaCache.clear();
await adapter.performInitialization({ VolatileClassesSchemas: [] });
const database = Config.get(Parse.applicationId).database;
await database.loadSchema({ clearCache: true });
const tableName = '_User';
const user = new Parse.User();
user.set('username', 'Elmer');
user.set('password', 'Fudd');
await user.signUp();
const database = Config.get(Parse.applicationId).database;
//Postgres won't take advantage of the index until it has a lot of records because sequential is faster for small db's
const client = adapter._client;
@@ -287,12 +295,19 @@ describe_only_db('postgres')('PostgresStorageAdapter', () => {
});
it('should use index for caseInsensitive query using default indexname', async () => {
await adapter.deleteAllClasses();
const config = Config.get('test');
config.schemaCache.clear();
await adapter.performInitialization({ VolatileClassesSchemas: [] });
const database = Config.get(Parse.applicationId).database;
await database.loadSchema({ clearCache: true });
const tableName = '_User';
const user = new Parse.User();
user.set('username', 'Tweety');
user.set('password', 'Bird');
await user.signUp();
const database = Config.get(Parse.applicationId).database;
const fieldToSearch = 'username';
//Create index before data is inserted
const schema = await new Parse.Schema('_User').get();
@@ -375,6 +390,45 @@ describe_only_db('postgres')('PostgresStorageAdapter', () => {
});
});
});
it('should watch _SCHEMA changes', async () => {
const enableSchemaHooks = true;
await reconfigureServer({
databaseAdapter: undefined,
databaseURI,
collectionPrefix: '',
databaseOptions: {
enableSchemaHooks,
},
});
const { database } = Config.get(Parse.applicationId);
const { adapter } = database;
expect(adapter.enableSchemaHooks).toBe(enableSchemaHooks);
spyOn(adapter, '_onchange');
enableSchemaHooks;
const otherInstance = new PostgresStorageAdapter({
uri: databaseURI,
collectionPrefix: '',
databaseOptions: { enableSchemaHooks },
});
expect(otherInstance.enableSchemaHooks).toBe(enableSchemaHooks);
otherInstance._listenToSchema();
await otherInstance.createClass('Stuff', {
className: 'Stuff',
fields: {
objectId: { type: 'String' },
createdAt: { type: 'Date' },
updatedAt: { type: 'Date' },
_rperm: { type: 'Array' },
_wperm: { type: 'Array' },
},
classLevelPermissions: undefined,
});
await new Promise(resolve => setTimeout(resolve, 500));
expect(adapter._onchange).toHaveBeenCalled();
});
});
describe_only_db('postgres')('PostgresStorageAdapter shutdown', () => {

View File

@@ -135,7 +135,7 @@ describe('ProtectedFields', function () {
describe('using the pointer-permission variant', () => {
let user1, user2;
beforeEach(async () => {
Config.get(Parse.applicationId).database.schemaCache.clear();
Config.get(Parse.applicationId).schemaCache.clear();
user1 = await Parse.User.signUp('user1', 'password');
user2 = await Parse.User.signUp('user2', 'password');
await Parse.User.logOut();
@@ -752,7 +752,7 @@ describe('ProtectedFields', function () {
let object;
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
object = new Parse.Object(className);
@@ -815,7 +815,7 @@ describe('ProtectedFields', function () {
let obj1;
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
obj1 = new Parse.Object(className);
@@ -924,7 +924,7 @@ describe('ProtectedFields', function () {
let obj2;
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
await Parse.User.logOut();
@@ -1125,7 +1125,7 @@ describe('ProtectedFields', function () {
let obj2;
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
[user1, user2] = await Promise.all([createUser('user1'), createUser('user2')]);
@@ -1477,7 +1477,7 @@ describe('ProtectedFields', function () {
* Clear cache, create user and object, login user and setup rest headers with token
*/
async function initialize() {
await Config.get(Parse.applicationId).database.schemaCache.clear();
await Config.get(Parse.applicationId).schemaCache.clear();
user1 = await createUser('user1');
user1 = await logIn(user1);

View File

@@ -7,7 +7,7 @@ const Config = require('../lib/Config');
function waitForReplication() {
return new Promise(function (resolve) {
setTimeout(resolve, 300);
setTimeout(resolve, 1000);
});
}

View File

@@ -1,5 +1,4 @@
const RedisCacheAdapter = require('../lib/Adapters/Cache/RedisCacheAdapter').default;
const Config = require('../lib/Config');
function wait(sleep) {
return new Promise(function (resolve) {
@@ -168,356 +167,3 @@ describe_only(() => {
.then(done);
});
});
describe_only(() => {
return process.env.PARSE_SERVER_TEST_CACHE === 'redis';
})('Redis Performance', function () {
let cacheAdapter;
let getSpy;
let putSpy;
let delSpy;
beforeEach(async () => {
cacheAdapter = new RedisCacheAdapter();
await reconfigureServer({
cacheAdapter,
});
await cacheAdapter.clear();
getSpy = spyOn(cacheAdapter, 'get').and.callThrough();
putSpy = spyOn(cacheAdapter, 'put').and.callThrough();
delSpy = spyOn(cacheAdapter, 'del').and.callThrough();
});
it('test new object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
expect(getSpy.calls.count()).toBe(3);
expect(putSpy.calls.count()).toBe(3);
expect(delSpy.calls.count()).toBe(1);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test new object multiple fields', async () => {
const container = new Container({
dateField: new Date(),
arrayField: [],
numberField: 1,
stringField: 'hello',
booleanField: true,
});
await container.save();
expect(getSpy.calls.count()).toBe(3);
expect(putSpy.calls.count()).toBe(3);
expect(delSpy.calls.count()).toBe(1);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test update existing fields', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
object.set('foo', 'barz');
await object.save();
expect(getSpy.calls.count()).toBe(3);
expect(putSpy.calls.count()).toBe(1);
expect(delSpy.calls.count()).toBe(2);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test saveAll / destroyAll', async () => {
const object = new TestObject();
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
const objects = [];
for (let i = 0; i < 10; i++) {
const object = new TestObject();
object.set('number', i);
objects.push(object);
}
await Parse.Object.saveAll(objects);
expect(getSpy.calls.count()).toBe(21);
expect(putSpy.calls.count()).toBe(11);
getSpy.calls.reset();
putSpy.calls.reset();
await Parse.Object.destroyAll(objects);
expect(getSpy.calls.count()).toBe(11);
expect(putSpy.calls.count()).toBe(1);
expect(delSpy.calls.count()).toBe(3);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test saveAll / destroyAll batch', async () => {
const object = new TestObject();
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
const objects = [];
for (let i = 0; i < 10; i++) {
const object = new TestObject();
object.set('number', i);
objects.push(object);
}
await Parse.Object.saveAll(objects, { batchSize: 5 });
expect(getSpy.calls.count()).toBe(22);
expect(putSpy.calls.count()).toBe(7);
getSpy.calls.reset();
putSpy.calls.reset();
await Parse.Object.destroyAll(objects, { batchSize: 5 });
expect(getSpy.calls.count()).toBe(12);
expect(putSpy.calls.count()).toBe(2);
expect(delSpy.calls.count()).toBe(5);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test add new field to existing object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
object.set('new', 'barz');
await object.save();
expect(getSpy.calls.count()).toBe(3);
expect(putSpy.calls.count()).toBe(2);
expect(delSpy.calls.count()).toBe(2);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test add multiple fields to existing object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
object.set({
dateField: new Date(),
arrayField: [],
numberField: 1,
stringField: 'hello',
booleanField: true,
});
await object.save();
expect(getSpy.calls.count()).toBe(3);
expect(putSpy.calls.count()).toBe(2);
expect(delSpy.calls.count()).toBe(2);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test user', async () => {
const user = new Parse.User();
user.setUsername('testing');
user.setPassword('testing');
await user.signUp();
expect(getSpy.calls.count()).toBe(8);
expect(putSpy.calls.count()).toBe(2);
expect(delSpy.calls.count()).toBe(1);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test allowClientCreation false', async () => {
const object = new TestObject();
await object.save();
await reconfigureServer({
cacheAdapter,
allowClientClassCreation: false,
});
await cacheAdapter.clear();
getSpy.calls.reset();
putSpy.calls.reset();
delSpy.calls.reset();
object.set('foo', 'bar');
await object.save();
expect(getSpy.calls.count()).toBe(4);
expect(putSpy.calls.count()).toBe(2);
getSpy.calls.reset();
putSpy.calls.reset();
const query = new Parse.Query(TestObject);
await query.get(object.id);
expect(getSpy.calls.count()).toBe(3);
expect(putSpy.calls.count()).toBe(1);
expect(delSpy.calls.count()).toBe(2);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test query', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
delSpy.calls.reset();
const query = new Parse.Query(TestObject);
await query.get(object.id);
expect(getSpy.calls.count()).toBe(2);
expect(putSpy.calls.count()).toBe(1);
expect(delSpy.calls.count()).toBe(1);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test query include', async () => {
const child = new TestObject();
await child.save();
const object = new TestObject();
object.set('child', child);
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
const query = new Parse.Query(TestObject);
query.include('child');
await query.get(object.id);
expect(getSpy.calls.count()).toBe(4);
expect(putSpy.calls.count()).toBe(1);
expect(delSpy.calls.count()).toBe(3);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('query relation without schema', async () => {
const child = new Parse.Object('ChildObject');
await child.save();
const parent = new Parse.Object('ParentObject');
const relation = parent.relation('child');
relation.add(child);
await parent.save();
getSpy.calls.reset();
putSpy.calls.reset();
const objects = await relation.query().find();
expect(objects.length).toBe(1);
expect(objects[0].id).toBe(child.id);
expect(getSpy.calls.count()).toBe(2);
expect(putSpy.calls.count()).toBe(1);
expect(delSpy.calls.count()).toBe(3);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test delete object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getSpy.calls.reset();
putSpy.calls.reset();
delSpy.calls.reset();
await object.destroy();
expect(getSpy.calls.count()).toBe(2);
expect(putSpy.calls.count()).toBe(1);
expect(delSpy.calls.count()).toBe(1);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(0);
});
it('test schema update class', async () => {
const container = new Container();
await container.save();
getSpy.calls.reset();
putSpy.calls.reset();
delSpy.calls.reset();
const config = Config.get('test');
const schema = await config.database.loadSchema();
await schema.reloadData();
const levelPermissions = {
find: { '*': true },
get: { '*': true },
create: { '*': true },
update: { '*': true },
delete: { '*': true },
addField: { '*': true },
protectedFields: { '*': [] },
};
await schema.updateClass(
'Container',
{
fooOne: { type: 'Number' },
fooTwo: { type: 'Array' },
fooThree: { type: 'Date' },
fooFour: { type: 'Object' },
fooFive: { type: 'Relation', targetClass: '_User' },
fooSix: { type: 'String' },
fooSeven: { type: 'Object' },
fooEight: { type: 'String' },
fooNine: { type: 'String' },
fooTeen: { type: 'Number' },
fooEleven: { type: 'String' },
fooTwelve: { type: 'String' },
fooThirteen: { type: 'String' },
fooFourteen: { type: 'String' },
fooFifteen: { type: 'String' },
fooSixteen: { type: 'String' },
fooEighteen: { type: 'String' },
fooNineteen: { type: 'String' },
},
levelPermissions,
{},
config.database
);
expect(getSpy.calls.count()).toBe(3);
expect(putSpy.calls.count()).toBe(3);
expect(delSpy.calls.count()).toBe(0);
const keys = await cacheAdapter.getAllKeys();
expect(keys.length).toBe(1);
});
});

View File

@@ -24,10 +24,6 @@ describe('SchemaController', () => {
config = Config.get('test');
});
afterEach(async () => {
await config.database.schemaCache.clear();
});
it('can validate one object', done => {
config.database
.loadSchema()
@@ -1349,17 +1345,6 @@ describe('SchemaController', () => {
.catch(done.fail);
});
it('setAllClasses return classes if cache fails', async () => {
const schema = await config.database.loadSchema();
spyOn(schema._cache, 'setAllClasses').and.callFake(() => Promise.reject('Oops!'));
const errorSpy = spyOn(console, 'error').and.callFake(() => {});
const allSchema = await schema.setAllClasses();
expect(allSchema).toBeDefined();
expect(errorSpy).toHaveBeenCalledWith('Error saving schema to cache:', 'Oops!');
});
it('should not throw on null field types', async () => {
const schema = await config.database.loadSchema();
const result = await schema.enforceFieldExists('NewClass', 'fieldName', null);

View File

@@ -1,104 +0,0 @@
const CacheController = require('../lib/Controllers/CacheController.js').default;
const InMemoryCacheAdapter = require('../lib/Adapters/Cache/InMemoryCacheAdapter').default;
const SchemaCache = require('../lib/Controllers/SchemaCache').default;
describe('SchemaCache', () => {
let cacheController;
beforeEach(() => {
const cacheAdapter = new InMemoryCacheAdapter({});
cacheController = new CacheController(cacheAdapter, 'appId');
});
it('can retrieve a single schema after all schemas stored', done => {
const schemaCache = new SchemaCache(cacheController);
const allSchemas = [
{
className: 'Class1',
},
{
className: 'Class2',
},
];
schemaCache
.setAllClasses(allSchemas)
.then(() => {
return schemaCache.getOneSchema('Class2');
})
.then(schema => {
expect(schema).not.toBeNull();
done();
});
});
it("doesn't persist cached data by default", done => {
const schemaCache = new SchemaCache(cacheController);
const schema = {
className: 'Class1',
};
schemaCache.setAllClasses([schema]).then(() => {
const anotherSchemaCache = new SchemaCache(cacheController);
return anotherSchemaCache.getOneSchema(schema.className).then(schema => {
expect(schema).toBeNull();
done();
});
});
});
it('can persist cached data', done => {
const schemaCache = new SchemaCache(cacheController, 5000, true);
const schema = {
className: 'Class1',
};
schemaCache.setAllClasses([schema]).then(() => {
const anotherSchemaCache = new SchemaCache(cacheController, 5000, true);
return anotherSchemaCache.getOneSchema(schema.className).then(schema => {
expect(schema).not.toBeNull();
done();
});
});
});
it('should not store if ttl is null', async () => {
const ttl = null;
const schemaCache = new SchemaCache(cacheController, ttl);
expect(await schemaCache.getAllClasses()).toBeNull();
expect(await schemaCache.setAllClasses()).toBeNull();
expect(await schemaCache.getOneSchema()).toBeNull();
});
it('should convert string ttl to number', async () => {
const ttl = '5000';
const schemaCache = new SchemaCache(cacheController, ttl);
expect(schemaCache.ttl).toBe(5000);
});
it('should use the SchemaCache ttl', async () => {
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const anotherCacheAdapter = new InMemoryCacheAdapter({ ttl: 2000 });
const anotherCacheController = new CacheController(anotherCacheAdapter, 'appId');
const schemaCacheTTL = 5000;
const schemaCache = new SchemaCache(anotherCacheController, schemaCacheTTL, true);
const schema = {
className: 'Class1',
};
await schemaCache.setAllClasses([schema]);
await sleep(4000);
expect(await schemaCache.getOneSchema(schema.className)).not.toBeNull();
});
it('should be expired', async () => {
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const schemaCacheTTL = 2000;
const schemaCache = new SchemaCache(cacheController, schemaCacheTTL, true);
const schema = {
className: 'Class1',
};
await schemaCache.setAllClasses([schema]);
await sleep(3000);
expect(await schemaCache.getOneSchema(schema.className)).toBeNull();
});
});

View File

@@ -0,0 +1,209 @@
const Config = require('../lib/Config');
const MongoStorageAdapter = require('../lib/Adapters/Storage/Mongo/MongoStorageAdapter').default;
const mongoURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase';
describe_only_db('mongo')('Schema Performance', function () {
let getAllSpy;
let config;
beforeEach(async () => {
config = Config.get('test');
config.schemaCache.clear();
const databaseAdapter = new MongoStorageAdapter({ uri: mongoURI });
await reconfigureServer({ databaseAdapter });
getAllSpy = spyOn(databaseAdapter, 'getAllClasses').and.callThrough();
});
it('test new object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
expect(getAllSpy.calls.count()).toBe(2);
});
it('test new object multiple fields', async () => {
const container = new Container({
dateField: new Date(),
arrayField: [],
numberField: 1,
stringField: 'hello',
booleanField: true,
});
await container.save();
expect(getAllSpy.calls.count()).toBe(2);
});
it('test update existing fields', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getAllSpy.calls.reset();
object.set('foo', 'barz');
await object.save();
expect(getAllSpy.calls.count()).toBe(0);
});
xit('test saveAll / destroyAll', async () => {
// This test can be flaky due to the nature of /batch requests
// Used for performance
const object = new TestObject();
await object.save();
getAllSpy.calls.reset();
const objects = [];
for (let i = 0; i < 10; i++) {
const object = new TestObject();
object.set('number', i);
objects.push(object);
}
await Parse.Object.saveAll(objects);
expect(getAllSpy.calls.count()).toBe(0);
getAllSpy.calls.reset();
const query = new Parse.Query(TestObject);
await query.find();
expect(getAllSpy.calls.count()).toBe(0);
getAllSpy.calls.reset();
await Parse.Object.destroyAll(objects);
expect(getAllSpy.calls.count()).toBe(0);
});
it('test add new field to existing object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getAllSpy.calls.reset();
object.set('new', 'barz');
await object.save();
expect(getAllSpy.calls.count()).toBe(1);
});
it('test add multiple fields to existing object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getAllSpy.calls.reset();
object.set({
dateField: new Date(),
arrayField: [],
numberField: 1,
stringField: 'hello',
booleanField: true,
});
await object.save();
expect(getAllSpy.calls.count()).toBe(1);
});
it('test user', async () => {
const user = new Parse.User();
user.setUsername('testing');
user.setPassword('testing');
await user.signUp();
expect(getAllSpy.calls.count()).toBe(1);
});
it('test query include', async () => {
const child = new TestObject();
await child.save();
const object = new TestObject();
object.set('child', child);
await object.save();
getAllSpy.calls.reset();
const query = new Parse.Query(TestObject);
query.include('child');
await query.get(object.id);
expect(getAllSpy.calls.count()).toBe(0);
});
it('query relation without schema', async () => {
const child = new Parse.Object('ChildObject');
await child.save();
const parent = new Parse.Object('ParentObject');
const relation = parent.relation('child');
relation.add(child);
await parent.save();
getAllSpy.calls.reset();
const objects = await relation.query().find();
expect(objects.length).toBe(1);
expect(objects[0].id).toBe(child.id);
expect(getAllSpy.calls.count()).toBe(0);
});
it('test delete object', async () => {
const object = new TestObject();
object.set('foo', 'bar');
await object.save();
getAllSpy.calls.reset();
await object.destroy();
expect(getAllSpy.calls.count()).toBe(0);
});
it('test schema update class', async () => {
const container = new Container();
await container.save();
getAllSpy.calls.reset();
const schema = await config.database.loadSchema();
await schema.reloadData();
const levelPermissions = {
find: { '*': true },
get: { '*': true },
create: { '*': true },
update: { '*': true },
delete: { '*': true },
addField: { '*': true },
protectedFields: { '*': [] },
};
await schema.updateClass(
'Container',
{
fooOne: { type: 'Number' },
fooTwo: { type: 'Array' },
fooThree: { type: 'Date' },
fooFour: { type: 'Object' },
fooFive: { type: 'Relation', targetClass: '_User' },
fooSix: { type: 'String' },
fooSeven: { type: 'Object' },
fooEight: { type: 'String' },
fooNine: { type: 'String' },
fooTeen: { type: 'Number' },
fooEleven: { type: 'String' },
fooTwelve: { type: 'String' },
fooThirteen: { type: 'String' },
fooFourteen: { type: 'String' },
fooFifteen: { type: 'String' },
fooSixteen: { type: 'String' },
fooEighteen: { type: 'String' },
fooNineteen: { type: 'String' },
},
levelPermissions,
{},
config.database
);
expect(getAllSpy.calls.count()).toBe(0);
});
});

View File

@@ -4,7 +4,9 @@ const WinstonLoggerAdapter = require('../lib/Adapters/Logger/WinstonLoggerAdapte
.WinstonLoggerAdapter;
const request = require('../lib/request');
describe('info logs', () => {
describe_only(() => {
return process.env.PARSE_SERVER_LOG_LEVEL !== 'debug';
})('info logs', () => {
it('Verify INFO logs', done => {
const winstonLoggerAdapter = new WinstonLoggerAdapter();
winstonLoggerAdapter.log('info', 'testing info logs with 1234');
@@ -85,7 +87,9 @@ describe('info logs', () => {
});
});
describe('error logs', () => {
describe_only(() => {
return process.env.PARSE_SERVER_LOG_LEVEL !== 'debug';
})('error logs', () => {
it('Verify ERROR logs', done => {
const winstonLoggerAdapter = new WinstonLoggerAdapter();
winstonLoggerAdapter.log('error', 'testing error logs');
@@ -167,7 +171,9 @@ describe('error logs', () => {
});
});
describe('verbose logs', () => {
describe_only(() => {
return process.env.PARSE_SERVER_LOG_LEVEL !== 'debug';
})('verbose logs', () => {
it('mask sensitive information in _User class', done => {
reconfigureServer({ verbose: true })
.then(() => createTestUser())

View File

@@ -2,6 +2,7 @@
const semver = require('semver');
const CurrentSpecReporter = require('./support/CurrentSpecReporter.js');
const { SpecReporter } = require('jasmine-spec-reporter');
const SchemaCache = require('../lib/Adapters/Cache/SchemaCache').default;
// Sets up a Parse API server for testing.
jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.PARSE_SERVER_TEST_TIMEOUT || 10000;
@@ -206,6 +207,7 @@ afterEach(function (done) {
}
destroyAliveConnections();
await TestUtils.destroyAllDataPermanently(true);
SchemaCache.clear();
if (didChangeConfiguration) {
await reconfigureServer();
} else {

View File

@@ -70,6 +70,8 @@ describe('server', () => {
},
}),
}).catch(() => {
const config = Config.get('test');
config.schemaCache.clear();
//Need to use rest api because saving via JS SDK results in fail() not getting called
request({
method: 'POST',

View File

@@ -145,10 +145,6 @@ describe('schemas', () => {
config = Config.get('test');
});
afterEach(async () => {
await config.database.schemaCache.clear();
});
it('requires the master key to get all schemas', done => {
request({
url: 'http://localhost:8378/1/schemas',

View File

@@ -4,12 +4,9 @@ const Parse = require('parse/node');
const className = 'AnObject';
const defaultRoleName = 'tester';
let schemaCache;
module.exports = {
/* AnObject */
className,
schemaCache,
/**
* Creates and returns new user.