Before Connect + Before Subscribe help required (#6793)
* Before Connect + Before Subscribe #1 * Cleanup and Documentation * Add E2E tests * Bump parse to 2.15.0 Co-authored-by: Diamond Lewis <findlewis@gmail.com>
This commit is contained in:
30
package-lock.json
generated
30
package-lock.json
generated
@@ -10028,31 +10028,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"parse": {
|
"parse": {
|
||||||
"version": "2.14.0",
|
"version": "2.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/parse/-/parse-2.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/parse/-/parse-2.15.0.tgz",
|
||||||
"integrity": "sha512-S4bbF80Aom/xDk4YNkzZG1xBHYbiFQGueJWyO4DpYlajfkEs3gp0oszFDnGadTARyCgoQGxNE4Qkege/QqNETA==",
|
"integrity": "sha512-Aupg+qd6I4X5uTacpsxROg5GlhkVn2+qOHtyOhlGj/Woi75c5cPD8kn7qhhLKcVVpe2L+HoJ+yGkMdI8IjKBKA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "7.10.2",
|
"@babel/runtime": "7.10.3",
|
||||||
"@babel/runtime-corejs3": "7.10.2",
|
"@babel/runtime-corejs3": "7.10.3",
|
||||||
"crypto-js": "4.0.0",
|
"crypto-js": "4.0.0",
|
||||||
"react-native-crypto-js": "1.0.0",
|
"react-native-crypto-js": "1.0.0",
|
||||||
"uuid": "3.3.3",
|
"uuid": "3.4.0",
|
||||||
"ws": "7.3.0",
|
"ws": "7.3.0",
|
||||||
"xmlhttprequest": "1.8.0"
|
"xmlhttprequest": "1.8.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.10.2",
|
"version": "7.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.3.tgz",
|
||||||
"integrity": "sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==",
|
"integrity": "sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@babel/runtime-corejs3": {
|
"@babel/runtime-corejs3": {
|
||||||
"version": "7.10.2",
|
"version": "7.10.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.3.tgz",
|
||||||
"integrity": "sha512-+a2M/u7r15o3dV1NEizr9bRi+KUVnrs/qYxF0Z06DAPx/4VCWaz1WA7EcbE+uqGgt39lp5akWGmHsTseIkHkHg==",
|
"integrity": "sha512-HA7RPj5xvJxQl429r5Cxr2trJwOfPjKiqhCXcdQPSqO2G0RHPZpXu4fkYmBaTKCp2c/jRaMK9GB/lN+7zvvFPw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js-pure": "^3.0.0",
|
"core-js-pure": "^3.0.0",
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
@@ -10064,9 +10064,9 @@
|
|||||||
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
|
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.3.3",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
"lru-cache": "5.1.1",
|
"lru-cache": "5.1.1",
|
||||||
"mime": "2.4.6",
|
"mime": "2.4.6",
|
||||||
"mongodb": "3.5.9",
|
"mongodb": "3.5.9",
|
||||||
"parse": "2.14.0",
|
"parse": "2.15.0",
|
||||||
"pg-promise": "10.5.7",
|
"pg-promise": "10.5.7",
|
||||||
"pluralize": "8.0.0",
|
"pluralize": "8.0.0",
|
||||||
"redis": "3.0.2",
|
"redis": "3.0.2",
|
||||||
@@ -104,6 +104,7 @@
|
|||||||
"posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} mongodb-runner stop",
|
"posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} mongodb-runner stop",
|
||||||
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} TESTING=1 nyc jasmine",
|
"coverage": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} TESTING=1 nyc jasmine",
|
||||||
"start": "node ./bin/parse-server",
|
"start": "node ./bin/parse-server",
|
||||||
|
"prettier": "prettier --write {src,spec}/**/*.js",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"postinstall": "node -p 'require(\"./postinstall.js\")()'"
|
"postinstall": "node -p 'require(\"./postinstall.js\")()'"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
describe('ParseLiveQuery', function() {
|
describe('ParseLiveQuery', function () {
|
||||||
it('can subscribe to query', async done => {
|
it('can subscribe to query', async done => {
|
||||||
await reconfigureServer({
|
await reconfigureServer({
|
||||||
liveQuery: {
|
liveQuery: {
|
||||||
@@ -24,6 +24,97 @@ describe('ParseLiveQuery', function() {
|
|||||||
await object.save();
|
await object.save();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can handle beforeConnect / beforeSubscribe hooks', async done => {
|
||||||
|
await reconfigureServer({
|
||||||
|
liveQuery: {
|
||||||
|
classNames: ['TestObject'],
|
||||||
|
},
|
||||||
|
startLiveQueryServer: true,
|
||||||
|
verbose: false,
|
||||||
|
silent: true,
|
||||||
|
});
|
||||||
|
const object = new TestObject();
|
||||||
|
await object.save();
|
||||||
|
|
||||||
|
Parse.Cloud.beforeSubscribe('TestObject', req => {
|
||||||
|
expect(req.op).toBe('subscribe');
|
||||||
|
expect(req.requestId).toBe(1);
|
||||||
|
expect(req.query).toBeDefined();
|
||||||
|
expect(req.user).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
Parse.Cloud.beforeConnect(req => {
|
||||||
|
expect(req.event).toBe('connect');
|
||||||
|
expect(req.clients).toBe(0);
|
||||||
|
expect(req.subscriptions).toBe(0);
|
||||||
|
expect(req.useMasterKey).toBe(false);
|
||||||
|
expect(req.installationId).toBeDefined();
|
||||||
|
expect(req.user).toBeUndefined();
|
||||||
|
expect(req.sessionToken).toBeUndefined();
|
||||||
|
expect(req.client).toBeDefined();
|
||||||
|
});
|
||||||
|
const query = new Parse.Query(TestObject);
|
||||||
|
query.equalTo('objectId', object.id);
|
||||||
|
const subscription = await query.subscribe();
|
||||||
|
subscription.on('update', async object => {
|
||||||
|
expect(object.get('foo')).toBe('bar');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
object.set({ foo: 'bar' });
|
||||||
|
await object.save();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can handle beforeConnect error', async done => {
|
||||||
|
await reconfigureServer({
|
||||||
|
liveQuery: {
|
||||||
|
classNames: ['TestObject'],
|
||||||
|
},
|
||||||
|
startLiveQueryServer: true,
|
||||||
|
verbose: false,
|
||||||
|
silent: true,
|
||||||
|
});
|
||||||
|
const object = new TestObject();
|
||||||
|
await object.save();
|
||||||
|
|
||||||
|
Parse.Cloud.beforeConnect(() => {
|
||||||
|
throw new Error('You shall not pass!');
|
||||||
|
});
|
||||||
|
Parse.LiveQuery.on('error', error => {
|
||||||
|
expect(error).toBe('You shall not pass!');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
const query = new Parse.Query(TestObject);
|
||||||
|
query.equalTo('objectId', object.id);
|
||||||
|
await query.subscribe();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can handle beforeSubscribe error', async done => {
|
||||||
|
await reconfigureServer({
|
||||||
|
liveQuery: {
|
||||||
|
classNames: ['TestObject'],
|
||||||
|
},
|
||||||
|
startLiveQueryServer: true,
|
||||||
|
verbose: false,
|
||||||
|
silent: true,
|
||||||
|
});
|
||||||
|
const object = new TestObject();
|
||||||
|
await object.save();
|
||||||
|
|
||||||
|
Parse.Cloud.beforeSubscribe(TestObject, () => {
|
||||||
|
throw new Error('You shall not subscribe!');
|
||||||
|
});
|
||||||
|
Parse.LiveQuery.on('error', error => {
|
||||||
|
expect(error).toBe('You shall not subscribe!');
|
||||||
|
});
|
||||||
|
const query = new Parse.Query(TestObject);
|
||||||
|
query.equalTo('objectId', object.id);
|
||||||
|
const subscription = await query.subscribe();
|
||||||
|
subscription.on('error', error => {
|
||||||
|
expect(error).toBe('You shall not subscribe!');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('handle invalid websocket payload length', async done => {
|
it('handle invalid websocket payload length', async done => {
|
||||||
await reconfigureServer({
|
await reconfigureServer({
|
||||||
liveQuery: {
|
liveQuery: {
|
||||||
@@ -61,7 +152,7 @@ describe('ParseLiveQuery', function() {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async function(done) {
|
afterEach(async function (done) {
|
||||||
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
|
const client = await Parse.CoreManager.getLiveQueryController().getDefaultLiveQueryClient();
|
||||||
client.close();
|
client.close();
|
||||||
// Wait for live query client to disconnect
|
// Wait for live query client to disconnect
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ const queryHashValue = 'hash';
|
|||||||
const testUserId = 'userId';
|
const testUserId = 'userId';
|
||||||
const testClassName = 'TestObject';
|
const testClassName = 'TestObject';
|
||||||
|
|
||||||
describe('ParseLiveQueryServer', function() {
|
describe('ParseLiveQueryServer', function () {
|
||||||
beforeEach(function(done) {
|
beforeEach(function (done) {
|
||||||
// Mock ParseWebSocketServer
|
// Mock ParseWebSocketServer
|
||||||
const mockParseWebSocketServer = jasmine.createSpy('ParseWebSocketServer');
|
const mockParseWebSocketServer = jasmine.createSpy('ParseWebSocketServer');
|
||||||
jasmine.mockLibrary(
|
jasmine.mockLibrary(
|
||||||
@@ -21,7 +21,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
mockParseWebSocketServer
|
mockParseWebSocketServer
|
||||||
);
|
);
|
||||||
// Mock Client
|
// Mock Client
|
||||||
const mockClient = function(id, socket, hasMasterKey) {
|
const mockClient = function (id, socket, hasMasterKey) {
|
||||||
this.pushConnect = jasmine.createSpy('pushConnect');
|
this.pushConnect = jasmine.createSpy('pushConnect');
|
||||||
this.pushSubscribe = jasmine.createSpy('pushSubscribe');
|
this.pushSubscribe = jasmine.createSpy('pushSubscribe');
|
||||||
this.pushUnsubscribe = jasmine.createSpy('pushUnsubscribe');
|
this.pushUnsubscribe = jasmine.createSpy('pushUnsubscribe');
|
||||||
@@ -38,7 +38,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
mockClient.pushError = jasmine.createSpy('pushError');
|
mockClient.pushError = jasmine.createSpy('pushError');
|
||||||
jasmine.mockLibrary('../lib/LiveQuery/Client', 'Client', mockClient);
|
jasmine.mockLibrary('../lib/LiveQuery/Client', 'Client', mockClient);
|
||||||
// Mock Subscription
|
// Mock Subscription
|
||||||
const mockSubscriotion = function() {
|
const mockSubscriotion = function () {
|
||||||
this.addClientSubscription = jasmine.createSpy('addClientSubscription');
|
this.addClientSubscription = jasmine.createSpy('addClientSubscription');
|
||||||
this.deleteClientSubscription = jasmine.createSpy(
|
this.deleteClientSubscription = jasmine.createSpy(
|
||||||
'deleteClientSubscription'
|
'deleteClientSubscription'
|
||||||
@@ -69,13 +69,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
);
|
);
|
||||||
// Mock ParsePubSub
|
// Mock ParsePubSub
|
||||||
const mockParsePubSub = {
|
const mockParsePubSub = {
|
||||||
createPublisher: function() {
|
createPublisher: function () {
|
||||||
return {
|
return {
|
||||||
publish: jasmine.createSpy('publish'),
|
publish: jasmine.createSpy('publish'),
|
||||||
on: jasmine.createSpy('on'),
|
on: jasmine.createSpy('on'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
createSubscriber: function() {
|
createSubscriber: function () {
|
||||||
return {
|
return {
|
||||||
subscribe: jasmine.createSpy('subscribe'),
|
subscribe: jasmine.createSpy('subscribe'),
|
||||||
on: jasmine.createSpy('on'),
|
on: jasmine.createSpy('on'),
|
||||||
@@ -114,7 +114,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be initialized', function() {
|
it('can be initialized', function () {
|
||||||
const httpServer = {};
|
const httpServer = {};
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(httpServer);
|
const parseLiveQueryServer = new ParseLiveQueryServer(httpServer);
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
|
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be initialized from ParseServer', function() {
|
it('can be initialized from ParseServer', function () {
|
||||||
const httpServer = {};
|
const httpServer = {};
|
||||||
const parseLiveQueryServer = ParseServer.createLiveQueryServer(
|
const parseLiveQueryServer = ParseServer.createLiveQueryServer(
|
||||||
httpServer,
|
httpServer,
|
||||||
@@ -135,7 +135,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
|
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be initialized from ParseServer without httpServer', function(done) {
|
it('can be initialized from ParseServer without httpServer', function (done) {
|
||||||
const parseLiveQueryServer = ParseServer.createLiveQueryServer(undefined, {
|
const parseLiveQueryServer = ParseServer.createLiveQueryServer(undefined, {
|
||||||
port: 22345,
|
port: 22345,
|
||||||
});
|
});
|
||||||
@@ -147,7 +147,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe_only_db('mongo')('initialization', () => {
|
describe_only_db('mongo')('initialization', () => {
|
||||||
it('can be initialized through ParseServer without liveQueryServerOptions', function(done) {
|
it('can be initialized through ParseServer without liveQueryServerOptions', function (done) {
|
||||||
const parseServer = ParseServer.start({
|
const parseServer = ParseServer.start({
|
||||||
appId: 'hello',
|
appId: 'hello',
|
||||||
masterKey: 'world',
|
masterKey: 'world',
|
||||||
@@ -166,7 +166,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can be initialized through ParseServer with liveQueryServerOptions', function(done) {
|
it('can be initialized through ParseServer with liveQueryServerOptions', function (done) {
|
||||||
const parseServer = ParseServer.start({
|
const parseServer = ParseServer.start({
|
||||||
appId: 'hello',
|
appId: 'hello',
|
||||||
masterKey: 'world',
|
masterKey: 'world',
|
||||||
@@ -192,7 +192,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('properly passes the CLP to afterSave/afterDelete hook', function(done) {
|
it('properly passes the CLP to afterSave/afterDelete hook', function (done) {
|
||||||
function setPermissionsOnClass(className, permissions, doPut) {
|
function setPermissionsOnClass(className, permissions, doPut) {
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
let op = request.post;
|
let op = request.post;
|
||||||
@@ -285,7 +285,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle connect command', function() {
|
it('can handle connect command', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const parseWebSocket = {
|
const parseWebSocket = {
|
||||||
clientId: -1,
|
clientId: -1,
|
||||||
@@ -293,7 +293,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
parseLiveQueryServer._validateKeys = jasmine
|
parseLiveQueryServer._validateKeys = jasmine
|
||||||
.createSpy('validateKeys')
|
.createSpy('validateKeys')
|
||||||
.and.returnValue(true);
|
.and.returnValue(true);
|
||||||
parseLiveQueryServer._handleConnect(parseWebSocket, {
|
await parseLiveQueryServer._handleConnect(parseWebSocket, {
|
||||||
sessionToken: 'token',
|
sessionToken: 'token',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -307,16 +307,62 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(client.pushConnect).toHaveBeenCalled();
|
expect(client.pushConnect).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle subscribe command without clientId', function() {
|
it('basic beforeConnect rejection', async () => {
|
||||||
|
Parse.Cloud.beforeConnect(function () {
|
||||||
|
throw new Error('You shall not pass!');
|
||||||
|
});
|
||||||
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
|
const parseWebSocket = {
|
||||||
|
clientId: -1,
|
||||||
|
};
|
||||||
|
await parseLiveQueryServer._handleConnect(parseWebSocket, {
|
||||||
|
sessionToken: 'token',
|
||||||
|
});
|
||||||
|
expect(parseLiveQueryServer.clients.size).toBe(0);
|
||||||
|
const Client = require('../lib/LiveQuery/Client').Client;
|
||||||
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('basic beforeSubscribe rejection', async () => {
|
||||||
|
Parse.Cloud.beforeSubscribe('test', function () {
|
||||||
|
throw new Error('You shall not pass!');
|
||||||
|
});
|
||||||
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
|
const parseWebSocket = {
|
||||||
|
clientId: -1,
|
||||||
|
};
|
||||||
|
await parseLiveQueryServer._handleConnect(parseWebSocket, {
|
||||||
|
sessionToken: 'token',
|
||||||
|
});
|
||||||
|
const query = {
|
||||||
|
className: 'test',
|
||||||
|
where: {
|
||||||
|
key: 'value',
|
||||||
|
},
|
||||||
|
fields: ['test'],
|
||||||
|
};
|
||||||
|
const requestId = 2;
|
||||||
|
const request = {
|
||||||
|
query: query,
|
||||||
|
requestId: requestId,
|
||||||
|
sessionToken: 'sessionToken',
|
||||||
|
};
|
||||||
|
await parseLiveQueryServer._handleSubscribe(parseWebSocket, request);
|
||||||
|
expect(parseLiveQueryServer.clients.size).toBe(1);
|
||||||
|
const Client = require('../lib/LiveQuery/Client').Client;
|
||||||
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can handle subscribe command without clientId', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const incompleteParseConn = {};
|
const incompleteParseConn = {};
|
||||||
parseLiveQueryServer._handleSubscribe(incompleteParseConn, {});
|
await parseLiveQueryServer._handleSubscribe(incompleteParseConn, {});
|
||||||
|
|
||||||
const Client = require('../lib/LiveQuery/Client').Client;
|
const Client = require('../lib/LiveQuery/Client').Client;
|
||||||
expect(Client.pushError).toHaveBeenCalled();
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle subscribe command with new query', function() {
|
it('can handle subscribe command with new query', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Add mock client
|
// Add mock client
|
||||||
const clientId = 1;
|
const clientId = 1;
|
||||||
@@ -338,7 +384,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
requestId: requestId,
|
requestId: requestId,
|
||||||
sessionToken: 'sessionToken',
|
sessionToken: 'sessionToken',
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._handleSubscribe(parseWebSocket, request);
|
await parseLiveQueryServer._handleSubscribe(parseWebSocket, request);
|
||||||
|
|
||||||
// Make sure we add the subscription to the server
|
// Make sure we add the subscription to the server
|
||||||
const subscriptions = parseLiveQueryServer.subscriptions;
|
const subscriptions = parseLiveQueryServer.subscriptions;
|
||||||
@@ -363,7 +409,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(client.pushSubscribe).toHaveBeenCalledWith(requestId);
|
expect(client.pushSubscribe).toHaveBeenCalledWith(requestId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle subscribe command with existing query', function() {
|
it('can handle subscribe command with existing query', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Add two mock clients
|
// Add two mock clients
|
||||||
const clientId = 1;
|
const clientId = 1;
|
||||||
@@ -382,7 +428,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
},
|
},
|
||||||
fields: ['test'],
|
fields: ['test'],
|
||||||
};
|
};
|
||||||
addMockSubscription(
|
await addMockSubscription(
|
||||||
parseLiveQueryServer,
|
parseLiveQueryServer,
|
||||||
clientId,
|
clientId,
|
||||||
requestId,
|
requestId,
|
||||||
@@ -401,7 +447,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
fields: ['testAgain'],
|
fields: ['testAgain'],
|
||||||
};
|
};
|
||||||
const requestIdAgain = 1;
|
const requestIdAgain = 1;
|
||||||
addMockSubscription(
|
await addMockSubscription(
|
||||||
parseLiveQueryServer,
|
parseLiveQueryServer,
|
||||||
clientIdAgain,
|
clientIdAgain,
|
||||||
requestIdAgain,
|
requestIdAgain,
|
||||||
@@ -427,7 +473,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(args[1].fields).toBe(queryAgain.fields);
|
expect(args[1].fields).toBe(queryAgain.fields);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle unsubscribe command without clientId', function() {
|
it('can handle unsubscribe command without clientId', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const incompleteParseConn = {};
|
const incompleteParseConn = {};
|
||||||
parseLiveQueryServer._handleUnsubscribe(incompleteParseConn, {});
|
parseLiveQueryServer._handleUnsubscribe(incompleteParseConn, {});
|
||||||
@@ -436,7 +482,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(Client.pushError).toHaveBeenCalled();
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle unsubscribe command without not existed client', function() {
|
it('can handle unsubscribe command without not existed client', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const parseWebSocket = {
|
const parseWebSocket = {
|
||||||
clientId: 1,
|
clientId: 1,
|
||||||
@@ -447,7 +493,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(Client.pushError).toHaveBeenCalled();
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle unsubscribe command without not existed query', function() {
|
it('can handle unsubscribe command without not existed query', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Add mock client
|
// Add mock client
|
||||||
const clientId = 1;
|
const clientId = 1;
|
||||||
@@ -462,7 +508,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(Client.pushError).toHaveBeenCalled();
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle unsubscribe command', function() {
|
it('can handle unsubscribe command', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Add mock client
|
// Add mock client
|
||||||
const clientId = 1;
|
const clientId = 1;
|
||||||
@@ -472,7 +518,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
clientId: 1,
|
clientId: 1,
|
||||||
};
|
};
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
const subscription = addMockSubscription(
|
const subscription = await addMockSubscription(
|
||||||
parseLiveQueryServer,
|
parseLiveQueryServer,
|
||||||
clientId,
|
clientId,
|
||||||
requestId,
|
requestId,
|
||||||
@@ -481,7 +527,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
// Mock client.getSubscriptionInfo
|
// Mock client.getSubscriptionInfo
|
||||||
const subscriptionInfo = client.addSubscriptionInfo.calls.mostRecent()
|
const subscriptionInfo = client.addSubscriptionInfo.calls.mostRecent()
|
||||||
.args[1];
|
.args[1];
|
||||||
client.getSubscriptionInfo = function() {
|
client.getSubscriptionInfo = function () {
|
||||||
return subscriptionInfo;
|
return subscriptionInfo;
|
||||||
};
|
};
|
||||||
// Handle unsubscribe command
|
// Handle unsubscribe command
|
||||||
@@ -502,7 +548,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(subscriptions.size).toBe(0);
|
expect(subscriptions.size).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can set connect command message handler for a parseWebSocket', function() {
|
it('can set connect command message handler for a parseWebSocket', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Register mock connect/subscribe/unsubscribe handler for the server
|
// Register mock connect/subscribe/unsubscribe handler for the server
|
||||||
parseLiveQueryServer._handleConnect = jasmine.createSpy('_handleSubscribe');
|
parseLiveQueryServer._handleConnect = jasmine.createSpy('_handleSubscribe');
|
||||||
@@ -525,7 +571,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(args[0]).toBe(parseWebSocket);
|
expect(args[0]).toBe(parseWebSocket);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can set subscribe command message handler for a parseWebSocket', function() {
|
it('can set subscribe command message handler for a parseWebSocket', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Register mock connect/subscribe/unsubscribe handler for the server
|
// Register mock connect/subscribe/unsubscribe handler for the server
|
||||||
parseLiveQueryServer._handleSubscribe = jasmine.createSpy(
|
parseLiveQueryServer._handleSubscribe = jasmine.createSpy(
|
||||||
@@ -551,7 +597,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(JSON.stringify(args[1])).toBe(subscribeRequest);
|
expect(JSON.stringify(args[1])).toBe(subscribeRequest);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can set unsubscribe command message handler for a parseWebSocket', function() {
|
it('can set unsubscribe command message handler for a parseWebSocket', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Register mock connect/subscribe/unsubscribe handler for the server
|
// Register mock connect/subscribe/unsubscribe handler for the server
|
||||||
parseLiveQueryServer._handleUnsubscribe = jasmine.createSpy(
|
parseLiveQueryServer._handleUnsubscribe = jasmine.createSpy(
|
||||||
@@ -577,7 +623,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(JSON.stringify(args[1])).toBe(unsubscribeRequest);
|
expect(JSON.stringify(args[1])).toBe(unsubscribeRequest);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can set update command message handler for a parseWebSocket', function() {
|
it('can set update command message handler for a parseWebSocket', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Register mock connect/subscribe/unsubscribe handler for the server
|
// Register mock connect/subscribe/unsubscribe handler for the server
|
||||||
spyOn(parseLiveQueryServer, '_handleUpdateSubscription').and.callThrough();
|
spyOn(parseLiveQueryServer, '_handleUpdateSubscription').and.callThrough();
|
||||||
@@ -612,7 +658,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(parseLiveQueryServer._handleSubscribe).toHaveBeenCalled();
|
expect(parseLiveQueryServer._handleSubscribe).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can set missing command message handler for a parseWebSocket', function() {
|
it('can set missing command message handler for a parseWebSocket', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock parseWebsocket
|
// Make mock parseWebsocket
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
@@ -628,7 +674,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(Client.pushError).toHaveBeenCalled();
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can set unknown command message handler for a parseWebSocket', function() {
|
it('can set unknown command message handler for a parseWebSocket', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock parseWebsocket
|
// Make mock parseWebsocket
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
@@ -644,7 +690,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(Client.pushError).toHaveBeenCalled();
|
expect(Client.pushError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can set disconnect command message handler for a parseWebSocket which has not registered to the server', function() {
|
it('can set disconnect command message handler for a parseWebSocket which has not registered to the server', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const parseWebSocket = new EventEmitter();
|
const parseWebSocket = new EventEmitter();
|
||||||
@@ -657,7 +703,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
parseWebSocket.emit('disconnect');
|
parseWebSocket.emit('disconnect');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can forward event to cloud code', function() {
|
it('can forward event to cloud code', function () {
|
||||||
const cloudCodeHandler = {
|
const cloudCodeHandler = {
|
||||||
handler: () => {},
|
handler: () => {},
|
||||||
};
|
};
|
||||||
@@ -680,7 +726,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
// TODO: Test server can set disconnect command message handler for a parseWebSocket
|
// TODO: Test server can set disconnect command message handler for a parseWebSocket
|
||||||
|
|
||||||
it('has no subscription and can handle object delete command', function() {
|
it('has no subscription and can handle object delete command', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make deletedParseObject
|
// Make deletedParseObject
|
||||||
const parseObject = new Parse.Object(testClassName);
|
const parseObject = new Parse.Object(testClassName);
|
||||||
@@ -696,7 +742,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
parseLiveQueryServer._onAfterDelete(message, {});
|
parseLiveQueryServer._onAfterDelete(message, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle object delete command which does not match any subscription', function() {
|
it('can handle object delete command which does not match any subscription', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make deletedParseObject
|
// Make deletedParseObject
|
||||||
const parseObject = new Parse.Object(testClassName);
|
const parseObject = new Parse.Object(testClassName);
|
||||||
@@ -714,13 +760,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
addMockClient(parseLiveQueryServer, clientId);
|
addMockClient(parseLiveQueryServer, clientId);
|
||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
await addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
||||||
const client = parseLiveQueryServer.clients.get(clientId);
|
const client = parseLiveQueryServer.clients.get(clientId);
|
||||||
// Mock _matchesSubscription to return not matching
|
// Mock _matchesSubscription to return not matching
|
||||||
parseLiveQueryServer._matchesSubscription = function() {
|
parseLiveQueryServer._matchesSubscription = function () {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._onAfterDelete(message);
|
parseLiveQueryServer._onAfterDelete(message);
|
||||||
@@ -729,7 +775,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(client.pushDelete).not.toHaveBeenCalled();
|
expect(client.pushDelete).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle object delete command which matches some subscriptions', function(done) {
|
it('can handle object delete command which matches some subscriptions', async done => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make deletedParseObject
|
// Make deletedParseObject
|
||||||
const parseObject = new Parse.Object(testClassName);
|
const parseObject = new Parse.Object(testClassName);
|
||||||
@@ -746,26 +792,26 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
addMockClient(parseLiveQueryServer, clientId);
|
addMockClient(parseLiveQueryServer, clientId);
|
||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
await addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
||||||
const client = parseLiveQueryServer.clients.get(clientId);
|
const client = parseLiveQueryServer.clients.get(clientId);
|
||||||
// Mock _matchesSubscription to return matching
|
// Mock _matchesSubscription to return matching
|
||||||
parseLiveQueryServer._matchesSubscription = function() {
|
parseLiveQueryServer._matchesSubscription = function () {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._onAfterDelete(message);
|
parseLiveQueryServer._onAfterDelete(message);
|
||||||
|
|
||||||
// Make sure we send command to client, since _matchesACL is async, we have to
|
// Make sure we send command to client, since _matchesACL is async, we have to
|
||||||
// wait and check
|
// wait and check
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushDelete).toHaveBeenCalled();
|
expect(client.pushDelete).toHaveBeenCalled();
|
||||||
done();
|
done();
|
||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has no subscription and can handle object save command', function() {
|
it('has no subscription and can handle object save command', async () => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock request message
|
// Make mock request message
|
||||||
const message = generateMockMessage();
|
const message = generateMockMessage();
|
||||||
@@ -773,7 +819,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle object save command which does not match any subscription', function(done) {
|
it('can handle object save command which does not match any subscription', async done => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock request message
|
// Make mock request message
|
||||||
const message = generateMockMessage();
|
const message = generateMockMessage();
|
||||||
@@ -782,19 +828,19 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
const client = addMockClient(parseLiveQueryServer, clientId);
|
const client = addMockClient(parseLiveQueryServer, clientId);
|
||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
await addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
||||||
// Mock _matchesSubscription to return not matching
|
// Mock _matchesSubscription to return not matching
|
||||||
parseLiveQueryServer._matchesSubscription = function() {
|
parseLiveQueryServer._matchesSubscription = function () {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
// Trigger onAfterSave
|
// Trigger onAfterSave
|
||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
|
|
||||||
// Make sure we do not send command to client
|
// Make sure we do not send command to client
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushCreate).not.toHaveBeenCalled();
|
expect(client.pushCreate).not.toHaveBeenCalled();
|
||||||
expect(client.pushEnter).not.toHaveBeenCalled();
|
expect(client.pushEnter).not.toHaveBeenCalled();
|
||||||
expect(client.pushUpdate).not.toHaveBeenCalled();
|
expect(client.pushUpdate).not.toHaveBeenCalled();
|
||||||
@@ -804,7 +850,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle object enter command which matches some subscriptions', function(done) {
|
it('can handle object enter command which matches some subscriptions', async done => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock request message
|
// Make mock request message
|
||||||
const message = generateMockMessage(true);
|
const message = generateMockMessage(true);
|
||||||
@@ -813,25 +859,25 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
const client = addMockClient(parseLiveQueryServer, clientId);
|
const client = addMockClient(parseLiveQueryServer, clientId);
|
||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
await addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
||||||
// Mock _matchesSubscription to return matching
|
// Mock _matchesSubscription to return matching
|
||||||
// In order to mimic a enter, we need original match return false
|
// In order to mimic a enter, we need original match return false
|
||||||
// and the current match return true
|
// and the current match return true
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
parseLiveQueryServer._matchesSubscription = function(parseObject) {
|
parseLiveQueryServer._matchesSubscription = function (parseObject) {
|
||||||
if (!parseObject) {
|
if (!parseObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
counter += 1;
|
counter += 1;
|
||||||
return counter % 2 === 0;
|
return counter % 2 === 0;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
|
|
||||||
// Make sure we send enter command to client
|
// Make sure we send enter command to client
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushCreate).not.toHaveBeenCalled();
|
expect(client.pushCreate).not.toHaveBeenCalled();
|
||||||
expect(client.pushEnter).toHaveBeenCalled();
|
expect(client.pushEnter).toHaveBeenCalled();
|
||||||
expect(client.pushUpdate).not.toHaveBeenCalled();
|
expect(client.pushUpdate).not.toHaveBeenCalled();
|
||||||
@@ -841,7 +887,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle object update command which matches some subscriptions', function(done) {
|
it('can handle object update command which matches some subscriptions', async done => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock request message
|
// Make mock request message
|
||||||
const message = generateMockMessage(true);
|
const message = generateMockMessage(true);
|
||||||
@@ -850,21 +896,21 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
const client = addMockClient(parseLiveQueryServer, clientId);
|
const client = addMockClient(parseLiveQueryServer, clientId);
|
||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
await addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
||||||
// Mock _matchesSubscription to return matching
|
// Mock _matchesSubscription to return matching
|
||||||
parseLiveQueryServer._matchesSubscription = function(parseObject) {
|
parseLiveQueryServer._matchesSubscription = function (parseObject) {
|
||||||
if (!parseObject) {
|
if (!parseObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
|
|
||||||
// Make sure we send update command to client
|
// Make sure we send update command to client
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushCreate).not.toHaveBeenCalled();
|
expect(client.pushCreate).not.toHaveBeenCalled();
|
||||||
expect(client.pushEnter).not.toHaveBeenCalled();
|
expect(client.pushEnter).not.toHaveBeenCalled();
|
||||||
expect(client.pushUpdate).toHaveBeenCalled();
|
expect(client.pushUpdate).toHaveBeenCalled();
|
||||||
@@ -874,7 +920,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle object leave command which matches some subscriptions', function(done) {
|
it('can handle object leave command which matches some subscriptions', async done => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock request message
|
// Make mock request message
|
||||||
const message = generateMockMessage(true);
|
const message = generateMockMessage(true);
|
||||||
@@ -883,25 +929,25 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
const client = addMockClient(parseLiveQueryServer, clientId);
|
const client = addMockClient(parseLiveQueryServer, clientId);
|
||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
await addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
||||||
// Mock _matchesSubscription to return matching
|
// Mock _matchesSubscription to return matching
|
||||||
// In order to mimic a leave, we need original match return true
|
// In order to mimic a leave, we need original match return true
|
||||||
// and the current match return false
|
// and the current match return false
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
parseLiveQueryServer._matchesSubscription = function(parseObject) {
|
parseLiveQueryServer._matchesSubscription = function (parseObject) {
|
||||||
if (!parseObject) {
|
if (!parseObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
counter += 1;
|
counter += 1;
|
||||||
return counter % 2 !== 0;
|
return counter % 2 !== 0;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
|
|
||||||
// Make sure we send leave command to client
|
// Make sure we send leave command to client
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushCreate).not.toHaveBeenCalled();
|
expect(client.pushCreate).not.toHaveBeenCalled();
|
||||||
expect(client.pushEnter).not.toHaveBeenCalled();
|
expect(client.pushEnter).not.toHaveBeenCalled();
|
||||||
expect(client.pushUpdate).not.toHaveBeenCalled();
|
expect(client.pushUpdate).not.toHaveBeenCalled();
|
||||||
@@ -911,7 +957,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle update command with original object', function(done) {
|
it('can handle update command with original object', async done => {
|
||||||
jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client');
|
jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client');
|
||||||
const Client = require('../lib/LiveQuery/Client').Client;
|
const Client = require('../lib/LiveQuery/Client').Client;
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
@@ -930,27 +976,27 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
|
|
||||||
addMockSubscription(
|
await addMockSubscription(
|
||||||
parseLiveQueryServer,
|
parseLiveQueryServer,
|
||||||
clientId,
|
clientId,
|
||||||
requestId,
|
requestId,
|
||||||
parseWebSocket
|
parseWebSocket
|
||||||
);
|
);
|
||||||
// Mock _matchesSubscription to return matching
|
// Mock _matchesSubscription to return matching
|
||||||
parseLiveQueryServer._matchesSubscription = function(parseObject) {
|
parseLiveQueryServer._matchesSubscription = function (parseObject) {
|
||||||
if (!parseObject) {
|
if (!parseObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
|
|
||||||
// Make sure we send update command to client
|
// Make sure we send update command to client
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushUpdate).toHaveBeenCalled();
|
expect(client.pushUpdate).toHaveBeenCalled();
|
||||||
const args = parseWebSocket.send.calls.mostRecent().args;
|
const args = parseWebSocket.send.calls.mostRecent().args;
|
||||||
const toSend = JSON.parse(args[0]);
|
const toSend = JSON.parse(args[0]);
|
||||||
@@ -961,7 +1007,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle object create command which matches some subscriptions', function(done) {
|
it('can handle object create command which matches some subscriptions', async done => {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock request message
|
// Make mock request message
|
||||||
const message = generateMockMessage();
|
const message = generateMockMessage();
|
||||||
@@ -970,21 +1016,21 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
const client = addMockClient(parseLiveQueryServer, clientId);
|
const client = addMockClient(parseLiveQueryServer, clientId);
|
||||||
// Add mock subscription
|
// Add mock subscription
|
||||||
const requestId = 2;
|
const requestId = 2;
|
||||||
addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
await addMockSubscription(parseLiveQueryServer, clientId, requestId);
|
||||||
// Mock _matchesSubscription to return matching
|
// Mock _matchesSubscription to return matching
|
||||||
parseLiveQueryServer._matchesSubscription = function(parseObject) {
|
parseLiveQueryServer._matchesSubscription = function (parseObject) {
|
||||||
if (!parseObject) {
|
if (!parseObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
|
|
||||||
// Make sure we send create command to client
|
// Make sure we send create command to client
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushCreate).toHaveBeenCalled();
|
expect(client.pushCreate).toHaveBeenCalled();
|
||||||
expect(client.pushEnter).not.toHaveBeenCalled();
|
expect(client.pushEnter).not.toHaveBeenCalled();
|
||||||
expect(client.pushUpdate).not.toHaveBeenCalled();
|
expect(client.pushUpdate).not.toHaveBeenCalled();
|
||||||
@@ -994,7 +1040,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can handle create command with fields', function(done) {
|
it('can handle create command with fields', async done => {
|
||||||
jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client');
|
jasmine.restoreLibrary('../lib/LiveQuery/Client', 'Client');
|
||||||
const Client = require('../lib/LiveQuery/Client').Client;
|
const Client = require('../lib/LiveQuery/Client').Client;
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
@@ -1019,7 +1065,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
},
|
},
|
||||||
fields: ['test'],
|
fields: ['test'],
|
||||||
};
|
};
|
||||||
addMockSubscription(
|
await addMockSubscription(
|
||||||
parseLiveQueryServer,
|
parseLiveQueryServer,
|
||||||
clientId,
|
clientId,
|
||||||
requestId,
|
requestId,
|
||||||
@@ -1027,20 +1073,20 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
query
|
query
|
||||||
);
|
);
|
||||||
// Mock _matchesSubscription to return matching
|
// Mock _matchesSubscription to return matching
|
||||||
parseLiveQueryServer._matchesSubscription = function(parseObject) {
|
parseLiveQueryServer._matchesSubscription = function (parseObject) {
|
||||||
if (!parseObject) {
|
if (!parseObject) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._matchesACL = function() {
|
parseLiveQueryServer._matchesACL = function () {
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
parseLiveQueryServer._onAfterSave(message);
|
parseLiveQueryServer._onAfterSave(message);
|
||||||
|
|
||||||
// Make sure we send create command to client
|
// Make sure we send create command to client
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
expect(client.pushCreate).toHaveBeenCalled();
|
expect(client.pushCreate).toHaveBeenCalled();
|
||||||
const args = parseWebSocket.send.calls.mostRecent().args;
|
const args = parseWebSocket.send.calls.mostRecent().args;
|
||||||
const toSend = JSON.parse(args[0]);
|
const toSend = JSON.parse(args[0]);
|
||||||
@@ -1050,7 +1096,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
}, jasmine.ASYNC_TEST_WAIT_TIME);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match subscription for null or undefined parse object', function() {
|
it('can match subscription for null or undefined parse object', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock subscription
|
// Make mock subscription
|
||||||
const subscription = {
|
const subscription = {
|
||||||
@@ -1067,7 +1113,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(subscription.match).not.toHaveBeenCalled();
|
expect(subscription.match).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match subscription', function() {
|
it('can match subscription', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock subscription
|
// Make mock subscription
|
||||||
const subscription = {
|
const subscription = {
|
||||||
@@ -1082,7 +1128,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(matchesQuery).toHaveBeenCalledWith(parseObject, subscription.query);
|
expect(matchesQuery).toHaveBeenCalledWith(parseObject, subscription.query);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can inflate parse object', function() {
|
it('can inflate parse object', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
// Make mock request
|
// Make mock request
|
||||||
const objectJSON = {
|
const objectJSON = {
|
||||||
@@ -1177,20 +1223,20 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(originalObject.updatedAt).not.toBeUndefined();
|
expect(originalObject.updatedAt).not.toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match undefined ACL', function(done) {
|
it('can match undefined ACL', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const client = {};
|
const client = {};
|
||||||
const requestId = 0;
|
const requestId = 0;
|
||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(undefined, client, requestId)
|
._matchesACL(undefined, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(true);
|
expect(isMatched).toBe(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match ACL with none exist requestId', function(done) {
|
it('can match ACL with none exist requestId', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
const client = {
|
const client = {
|
||||||
@@ -1202,13 +1248,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match ACL with public read access', function(done) {
|
it('can match ACL with public read access', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setPublicReadAccess(true);
|
acl.setPublicReadAccess(true);
|
||||||
@@ -1223,13 +1269,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(true);
|
expect(isMatched).toBe(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match ACL with valid subscription sessionToken', function(done) {
|
it('can match ACL with valid subscription sessionToken', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setReadAccess(testUserId, true);
|
acl.setReadAccess(testUserId, true);
|
||||||
@@ -1244,13 +1290,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(true);
|
expect(isMatched).toBe(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match ACL with valid client sessionToken', function(done) {
|
it('can match ACL with valid client sessionToken', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setReadAccess(testUserId, true);
|
acl.setReadAccess(testUserId, true);
|
||||||
@@ -1267,13 +1313,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(true);
|
expect(isMatched).toBe(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match ACL with invalid subscription and client sessionToken', function(done) {
|
it('can match ACL with invalid subscription and client sessionToken', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setReadAccess(testUserId, true);
|
acl.setReadAccess(testUserId, true);
|
||||||
@@ -1290,13 +1336,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match ACL with subscription sessionToken checking error', function(done) {
|
it('can match ACL with subscription sessionToken checking error', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setReadAccess(testUserId, true);
|
acl.setReadAccess(testUserId, true);
|
||||||
@@ -1313,13 +1359,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can match ACL with client sessionToken checking error', function(done) {
|
it('can match ACL with client sessionToken checking error', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setReadAccess(testUserId, true);
|
acl.setReadAccess(testUserId, true);
|
||||||
@@ -1336,13 +1382,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("won't match ACL that doesn't have public read or any roles", function(done) {
|
it("won't match ACL that doesn't have public read or any roles", function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setPublicReadAccess(false);
|
acl.setPublicReadAccess(false);
|
||||||
@@ -1357,13 +1403,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("won't match non-public ACL with role when there is no user", function(done) {
|
it("won't match non-public ACL with role when there is no user", function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setPublicReadAccess(false);
|
acl.setPublicReadAccess(false);
|
||||||
@@ -1377,14 +1423,14 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("won't match ACL with role based read access set to false", function(done) {
|
it("won't match ACL with role based read access set to false", function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setPublicReadAccess(false);
|
acl.setPublicReadAccess(false);
|
||||||
@@ -1398,7 +1444,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
};
|
};
|
||||||
const requestId = 0;
|
const requestId = 0;
|
||||||
|
|
||||||
spyOn(Parse, 'Query').and.callFake(function() {
|
spyOn(Parse, 'Query').and.callFake(function () {
|
||||||
let shouldReturn = false;
|
let shouldReturn = false;
|
||||||
return {
|
return {
|
||||||
equalTo() {
|
equalTo() {
|
||||||
@@ -1427,20 +1473,20 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will match ACL with role based read access set to true', function(done) {
|
it('will match ACL with role based read access set to true', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setPublicReadAccess(false);
|
acl.setPublicReadAccess(false);
|
||||||
@@ -1454,7 +1500,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
};
|
};
|
||||||
const requestId = 0;
|
const requestId = 0;
|
||||||
|
|
||||||
spyOn(Parse, 'Query').and.callFake(function() {
|
spyOn(Parse, 'Query').and.callFake(function () {
|
||||||
let shouldReturn = false;
|
let shouldReturn = false;
|
||||||
return {
|
return {
|
||||||
equalTo() {
|
equalTo() {
|
||||||
@@ -1493,7 +1539,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(true);
|
expect(isMatched).toBe(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -1625,7 +1671,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can validate key when valid key is provided', function() {
|
it('can validate key when valid key is provided', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(
|
const parseLiveQueryServer = new ParseLiveQueryServer(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -1643,7 +1689,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can validate key when invalid key is provided', function() {
|
it('can validate key when invalid key is provided', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(
|
const parseLiveQueryServer = new ParseLiveQueryServer(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -1661,7 +1707,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).not.toBeTruthy();
|
).not.toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can validate key when key is not provided', function() {
|
it('can validate key when key is not provided', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(
|
const parseLiveQueryServer = new ParseLiveQueryServer(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -1677,7 +1723,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).not.toBeTruthy();
|
).not.toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can validate key when validKerPairs is empty', function() {
|
it('can validate key when validKerPairs is empty', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({}, {});
|
const parseLiveQueryServer = new ParseLiveQueryServer({}, {});
|
||||||
const request = {};
|
const request = {};
|
||||||
|
|
||||||
@@ -1686,7 +1732,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can validate client has master key when valid', function() {
|
it('can validate client has master key when valid', function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(
|
const parseLiveQueryServer = new ParseLiveQueryServer(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -1704,7 +1750,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can validate client doesn't have master key when invalid", function() {
|
it("can validate client doesn't have master key when invalid", function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(
|
const parseLiveQueryServer = new ParseLiveQueryServer(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -1722,7 +1768,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).not.toBeTruthy();
|
).not.toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can validate client doesn't have master key when not provided", function() {
|
it("can validate client doesn't have master key when not provided", function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer(
|
const parseLiveQueryServer = new ParseLiveQueryServer(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
@@ -1737,7 +1783,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).not.toBeTruthy();
|
).not.toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can validate client doesn't have master key when validKeyPairs is empty", function() {
|
it("can validate client doesn't have master key when validKeyPairs is empty", function () {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({}, {});
|
const parseLiveQueryServer = new ParseLiveQueryServer({}, {});
|
||||||
const request = {
|
const request = {
|
||||||
masterKey: 'test',
|
masterKey: 'test',
|
||||||
@@ -1748,7 +1794,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
).not.toBeTruthy();
|
).not.toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will match non-public ACL when client has master key', function(done) {
|
it('will match non-public ACL when client has master key', function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setPublicReadAccess(false);
|
acl.setPublicReadAccess(false);
|
||||||
@@ -1762,13 +1808,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(true);
|
expect(isMatched).toBe(true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("won't match non-public ACL when client has no master key", function(done) {
|
it("won't match non-public ACL when client has no master key", function (done) {
|
||||||
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
const parseLiveQueryServer = new ParseLiveQueryServer({});
|
||||||
const acl = new Parse.ACL();
|
const acl = new Parse.ACL();
|
||||||
acl.setPublicReadAccess(false);
|
acl.setPublicReadAccess(false);
|
||||||
@@ -1782,7 +1828,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
|
|
||||||
parseLiveQueryServer
|
parseLiveQueryServer
|
||||||
._matchesACL(acl, client, requestId)
|
._matchesACL(acl, client, requestId)
|
||||||
.then(function(isMatched) {
|
.then(function (isMatched) {
|
||||||
expect(isMatched).toBe(false);
|
expect(isMatched).toBe(false);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -1822,7 +1868,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
expect(parseLiveQueryServer.authCache.get('invalid')).not.toBe(undefined);
|
expect(parseLiveQueryServer.authCache.get('invalid')).not.toBe(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function () {
|
||||||
jasmine.restoreLibrary(
|
jasmine.restoreLibrary(
|
||||||
'../lib/LiveQuery/ParseWebSocketServer',
|
'../lib/LiveQuery/ParseWebSocketServer',
|
||||||
'ParseWebSocketServer'
|
'ParseWebSocketServer'
|
||||||
@@ -1842,7 +1888,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addMockSubscription(
|
async function addMockSubscription(
|
||||||
parseLiveQueryServer,
|
parseLiveQueryServer,
|
||||||
clientId,
|
clientId,
|
||||||
requestId,
|
requestId,
|
||||||
@@ -1870,13 +1916,13 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
requestId: requestId,
|
requestId: requestId,
|
||||||
sessionToken: 'sessionToken',
|
sessionToken: 'sessionToken',
|
||||||
};
|
};
|
||||||
parseLiveQueryServer._handleSubscribe(parseWebSocket, request);
|
await parseLiveQueryServer._handleSubscribe(parseWebSocket, request);
|
||||||
|
|
||||||
// Make mock subscription
|
// Make mock subscription
|
||||||
const subscription = parseLiveQueryServer.subscriptions
|
const subscription = parseLiveQueryServer.subscriptions
|
||||||
.get(query.className)
|
.get(query.className)
|
||||||
.get(queryHashValue);
|
.get(queryHashValue);
|
||||||
subscription.hasSubscribingClient = function() {
|
subscription.hasSubscribingClient = function () {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
subscription.className = query.className;
|
subscription.className = query.className;
|
||||||
@@ -1915,7 +1961,7 @@ describe('ParseLiveQueryServer', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('LiveQueryController', () => {
|
describe('LiveQueryController', () => {
|
||||||
it('properly passes the CLP to afterSave/afterDelete hook', function(done) {
|
it('properly passes the CLP to afterSave/afterDelete hook', function (done) {
|
||||||
function setPermissionsOnClass(className, permissions, doPut) {
|
function setPermissionsOnClass(className, permissions, doPut) {
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
let op = request.post;
|
let op = request.post;
|
||||||
|
|||||||
@@ -62,15 +62,17 @@ class Client {
|
|||||||
parseWebSocket: any,
|
parseWebSocket: any,
|
||||||
code: number,
|
code: number,
|
||||||
error: string,
|
error: string,
|
||||||
reconnect: boolean = true
|
reconnect: boolean = true,
|
||||||
|
requestId: number | void = null
|
||||||
): void {
|
): void {
|
||||||
Client.pushResponse(
|
Client.pushResponse(
|
||||||
parseWebSocket,
|
parseWebSocket,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
op: 'error',
|
op: 'error',
|
||||||
error: error,
|
error,
|
||||||
code: code,
|
code,
|
||||||
reconnect: reconnect,
|
reconnect,
|
||||||
|
requestId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import { ParsePubSub } from './ParsePubSub';
|
|||||||
import SchemaController from '../Controllers/SchemaController';
|
import SchemaController from '../Controllers/SchemaController';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { runLiveQueryEventHandlers } from '../triggers';
|
import {
|
||||||
|
runLiveQueryEventHandlers,
|
||||||
|
maybeRunConnectTrigger,
|
||||||
|
maybeRunSubscribeTrigger,
|
||||||
|
} from '../triggers';
|
||||||
import { getAuthForSessionToken, Auth } from '../Auth';
|
import { getAuthForSessionToken, Auth } from '../Auth';
|
||||||
import { getCacheController } from '../Controllers';
|
import { getCacheController } from '../Controllers';
|
||||||
import LRU from 'lru-cache';
|
import LRU from 'lru-cache';
|
||||||
@@ -574,7 +578,7 @@ class ParseLiveQueryServer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleConnect(parseWebsocket: any, request: any): any {
|
async _handleConnect(parseWebsocket: any, request: any): any {
|
||||||
if (!this._validateKeys(request, this.keyPairs)) {
|
if (!this._validateKeys(request, this.keyPairs)) {
|
||||||
Client.pushError(parseWebsocket, 4, 'Key in request is not valid');
|
Client.pushError(parseWebsocket, 4, 'Key in request is not valid');
|
||||||
logger.error('Key in request is not valid');
|
logger.error('Key in request is not valid');
|
||||||
@@ -589,19 +593,34 @@ class ParseLiveQueryServer {
|
|||||||
request.sessionToken,
|
request.sessionToken,
|
||||||
request.installationId
|
request.installationId
|
||||||
);
|
);
|
||||||
parseWebsocket.clientId = clientId;
|
try {
|
||||||
this.clients.set(parseWebsocket.clientId, client);
|
const req = {
|
||||||
logger.info(`Create new client: ${parseWebsocket.clientId}`);
|
client,
|
||||||
client.pushConnect();
|
event: 'connect',
|
||||||
runLiveQueryEventHandlers({
|
clients: this.clients.size,
|
||||||
client,
|
subscriptions: this.subscriptions.size,
|
||||||
event: 'connect',
|
sessionToken: request.sessionToken,
|
||||||
clients: this.clients.size,
|
useMasterKey: client.hasMasterKey,
|
||||||
subscriptions: this.subscriptions.size,
|
installationId: request.installationId,
|
||||||
sessionToken: request.sessionToken,
|
};
|
||||||
useMasterKey: client.hasMasterKey,
|
await maybeRunConnectTrigger('beforeConnect', req);
|
||||||
installationId: request.installationId,
|
parseWebsocket.clientId = clientId;
|
||||||
});
|
this.clients.set(parseWebsocket.clientId, client);
|
||||||
|
logger.info(`Create new client: ${parseWebsocket.clientId}`);
|
||||||
|
client.pushConnect();
|
||||||
|
runLiveQueryEventHandlers(req);
|
||||||
|
} catch (error) {
|
||||||
|
Client.pushError(
|
||||||
|
parseWebsocket,
|
||||||
|
error.code || 101,
|
||||||
|
error.message || error,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
logger.error(
|
||||||
|
`Failed running beforeConnect for session ${request.sessionToken} with:\n Error: ` +
|
||||||
|
JSON.stringify(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasMasterKey(request: any, validKeyPairs: any): boolean {
|
_hasMasterKey(request: any, validKeyPairs: any): boolean {
|
||||||
@@ -636,7 +655,7 @@ class ParseLiveQueryServer {
|
|||||||
return isValid;
|
return isValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleSubscribe(parseWebsocket: any, request: any): any {
|
async _handleSubscribe(parseWebsocket: any, request: any): any {
|
||||||
// If we can not find this client, return error to client
|
// If we can not find this client, return error to client
|
||||||
if (!Object.prototype.hasOwnProperty.call(parseWebsocket, 'clientId')) {
|
if (!Object.prototype.hasOwnProperty.call(parseWebsocket, 'clientId')) {
|
||||||
Client.pushError(
|
Client.pushError(
|
||||||
@@ -650,61 +669,77 @@ class ParseLiveQueryServer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const client = this.clients.get(parseWebsocket.clientId);
|
const client = this.clients.get(parseWebsocket.clientId);
|
||||||
|
|
||||||
// Get subscription from subscriptions, create one if necessary
|
|
||||||
const subscriptionHash = queryHash(request.query);
|
|
||||||
// Add className to subscriptions if necessary
|
|
||||||
const className = request.query.className;
|
const className = request.query.className;
|
||||||
if (!this.subscriptions.has(className)) {
|
try {
|
||||||
this.subscriptions.set(className, new Map());
|
await maybeRunSubscribeTrigger('beforeSubscribe', className, request);
|
||||||
}
|
|
||||||
const classSubscriptions = this.subscriptions.get(className);
|
// Get subscription from subscriptions, create one if necessary
|
||||||
let subscription;
|
const subscriptionHash = queryHash(request.query);
|
||||||
if (classSubscriptions.has(subscriptionHash)) {
|
// Add className to subscriptions if necessary
|
||||||
subscription = classSubscriptions.get(subscriptionHash);
|
|
||||||
} else {
|
if (!this.subscriptions.has(className)) {
|
||||||
subscription = new Subscription(
|
this.subscriptions.set(className, new Map());
|
||||||
className,
|
}
|
||||||
request.query.where,
|
const classSubscriptions = this.subscriptions.get(className);
|
||||||
subscriptionHash
|
let subscription;
|
||||||
|
if (classSubscriptions.has(subscriptionHash)) {
|
||||||
|
subscription = classSubscriptions.get(subscriptionHash);
|
||||||
|
} else {
|
||||||
|
subscription = new Subscription(
|
||||||
|
className,
|
||||||
|
request.query.where,
|
||||||
|
subscriptionHash
|
||||||
|
);
|
||||||
|
classSubscriptions.set(subscriptionHash, subscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add subscriptionInfo to client
|
||||||
|
const subscriptionInfo = {
|
||||||
|
subscription: subscription,
|
||||||
|
};
|
||||||
|
// Add selected fields, sessionToken and installationId for this subscription if necessary
|
||||||
|
if (request.query.fields) {
|
||||||
|
subscriptionInfo.fields = request.query.fields;
|
||||||
|
}
|
||||||
|
if (request.sessionToken) {
|
||||||
|
subscriptionInfo.sessionToken = request.sessionToken;
|
||||||
|
}
|
||||||
|
client.addSubscriptionInfo(request.requestId, subscriptionInfo);
|
||||||
|
|
||||||
|
// Add clientId to subscription
|
||||||
|
subscription.addClientSubscription(
|
||||||
|
parseWebsocket.clientId,
|
||||||
|
request.requestId
|
||||||
|
);
|
||||||
|
|
||||||
|
client.pushSubscribe(request.requestId);
|
||||||
|
|
||||||
|
logger.verbose(
|
||||||
|
`Create client ${parseWebsocket.clientId} new subscription: ${request.requestId}`
|
||||||
|
);
|
||||||
|
logger.verbose('Current client number: %d', this.clients.size);
|
||||||
|
runLiveQueryEventHandlers({
|
||||||
|
client,
|
||||||
|
event: 'subscribe',
|
||||||
|
clients: this.clients.size,
|
||||||
|
subscriptions: this.subscriptions.size,
|
||||||
|
sessionToken: request.sessionToken,
|
||||||
|
useMasterKey: client.hasMasterKey,
|
||||||
|
installationId: client.installationId,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
Client.pushError(
|
||||||
|
parseWebsocket,
|
||||||
|
e.code || 101,
|
||||||
|
e.message || e,
|
||||||
|
false,
|
||||||
|
request.requestId
|
||||||
|
);
|
||||||
|
logger.error(
|
||||||
|
`Failed running beforeSubscribe on ${className} for session ${request.sessionToken} with:\n Error: ` +
|
||||||
|
JSON.stringify(e)
|
||||||
);
|
);
|
||||||
classSubscriptions.set(subscriptionHash, subscription);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add subscriptionInfo to client
|
|
||||||
const subscriptionInfo = {
|
|
||||||
subscription: subscription,
|
|
||||||
};
|
|
||||||
// Add selected fields, sessionToken and installationId for this subscription if necessary
|
|
||||||
if (request.query.fields) {
|
|
||||||
subscriptionInfo.fields = request.query.fields;
|
|
||||||
}
|
|
||||||
if (request.sessionToken) {
|
|
||||||
subscriptionInfo.sessionToken = request.sessionToken;
|
|
||||||
}
|
|
||||||
client.addSubscriptionInfo(request.requestId, subscriptionInfo);
|
|
||||||
|
|
||||||
// Add clientId to subscription
|
|
||||||
subscription.addClientSubscription(
|
|
||||||
parseWebsocket.clientId,
|
|
||||||
request.requestId
|
|
||||||
);
|
|
||||||
|
|
||||||
client.pushSubscribe(request.requestId);
|
|
||||||
|
|
||||||
logger.verbose(
|
|
||||||
`Create client ${parseWebsocket.clientId} new subscription: ${request.requestId}`
|
|
||||||
);
|
|
||||||
logger.verbose('Current client number: %d', this.clients.size);
|
|
||||||
runLiveQueryEventHandlers({
|
|
||||||
client,
|
|
||||||
event: 'subscribe',
|
|
||||||
clients: this.clients.size,
|
|
||||||
subscriptions: this.subscriptions.size,
|
|
||||||
sessionToken: request.sessionToken,
|
|
||||||
useMasterKey: client.hasMasterKey,
|
|
||||||
installationId: client.installationId,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleUpdateSubscription(parseWebsocket: any, request: any): any {
|
_handleUpdateSubscription(parseWebsocket: any, request: any): any {
|
||||||
|
|||||||
@@ -453,6 +453,60 @@ ParseCloud.afterDeleteFile = function (handler) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a before live query server connect function.
|
||||||
|
*
|
||||||
|
* **Available in Cloud Code only.**
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* Parse.Cloud.beforeConnect(async (request) => {
|
||||||
|
* // code here
|
||||||
|
* })
|
||||||
|
*```
|
||||||
|
*
|
||||||
|
* @method beforeConnect
|
||||||
|
* @name Parse.Cloud.beforeConnect
|
||||||
|
* @param {Function} func The function to before connection is made. This function can be async and should take just one parameter, {@link Parse.Cloud.ConnectTriggerRequest}.
|
||||||
|
*/
|
||||||
|
ParseCloud.beforeConnect = function (handler) {
|
||||||
|
triggers.addConnectTrigger(
|
||||||
|
triggers.Types.beforeConnect,
|
||||||
|
handler,
|
||||||
|
Parse.applicationId
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a before live query subscription function.
|
||||||
|
*
|
||||||
|
* **Available in Cloud Code only.**
|
||||||
|
*
|
||||||
|
* If you want to use beforeSubscribe for a predefined class in the Parse JavaScript SDK (e.g. {@link Parse.User}), you should pass the class itself and not the String for arg1.
|
||||||
|
* ```
|
||||||
|
* Parse.Cloud.beforeSubscribe('MyCustomClass', (request) => {
|
||||||
|
* // code here
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* Parse.Cloud.beforeSubscribe(Parse.User, (request) => {
|
||||||
|
* // code here
|
||||||
|
* })
|
||||||
|
*```
|
||||||
|
*
|
||||||
|
* @method beforeSubscribe
|
||||||
|
* @name Parse.Cloud.beforeSubscribe
|
||||||
|
* @param {(String|Parse.Object)} arg1 The Parse.Object subclass to register the before subscription function for. This can instead be a String that is the className of the subclass.
|
||||||
|
* @param {Function} func The function to run before a subscription. This function can be async and should take one parameter, a {@link Parse.Cloud.TriggerRequest}.
|
||||||
|
*/
|
||||||
|
ParseCloud.beforeSubscribe = function (parseClass, handler) {
|
||||||
|
var className = getClassName(parseClass);
|
||||||
|
triggers.addTrigger(
|
||||||
|
triggers.Types.beforeSubscribe,
|
||||||
|
className,
|
||||||
|
handler,
|
||||||
|
Parse.applicationId
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
ParseCloud.onLiveQueryEvent = function (handler) {
|
ParseCloud.onLiveQueryEvent = function (handler) {
|
||||||
triggers.addLiveQueryEventHandler(handler, Parse.applicationId);
|
triggers.addLiveQueryEventHandler(handler, Parse.applicationId);
|
||||||
};
|
};
|
||||||
@@ -499,6 +553,16 @@ module.exports = ParseCloud;
|
|||||||
* @property {Object} log The current logger inside Parse Server.
|
* @property {Object} log The current logger inside Parse Server.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @interface Parse.Cloud.ConnectTriggerRequest
|
||||||
|
* @property {String} installationId If set, the installationId triggering the request.
|
||||||
|
* @property {Boolean} useMasterKey If true, means the master key was used.
|
||||||
|
* @property {Parse.User} user If set, the user that made the request.
|
||||||
|
* @property {Integer} clients The number of clients connected.
|
||||||
|
* @property {Integer} subscriptions The number of subscriptions connected.
|
||||||
|
* @property {String} sessionToken If set, the session of the user that made the request.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @interface Parse.Cloud.BeforeFindRequest
|
* @interface Parse.Cloud.BeforeFindRequest
|
||||||
* @property {String} installationId If set, the installationId triggering the request.
|
* @property {String} installationId If set, the installationId triggering the request.
|
||||||
|
|||||||
@@ -16,16 +16,19 @@ export const Types = {
|
|||||||
afterSaveFile: 'afterSaveFile',
|
afterSaveFile: 'afterSaveFile',
|
||||||
beforeDeleteFile: 'beforeDeleteFile',
|
beforeDeleteFile: 'beforeDeleteFile',
|
||||||
afterDeleteFile: 'afterDeleteFile',
|
afterDeleteFile: 'afterDeleteFile',
|
||||||
|
beforeConnect: 'beforeConnect',
|
||||||
|
beforeSubscribe: 'beforeSubscribe',
|
||||||
};
|
};
|
||||||
|
|
||||||
const FileClassName = '@File';
|
const FileClassName = '@File';
|
||||||
|
const ConnectClassName = '@Connect';
|
||||||
|
|
||||||
const baseStore = function() {
|
const baseStore = function () {
|
||||||
const Validators = {};
|
const Validators = {};
|
||||||
const Functions = {};
|
const Functions = {};
|
||||||
const Jobs = {};
|
const Jobs = {};
|
||||||
const LiveQuery = [];
|
const LiveQuery = [];
|
||||||
const Triggers = Object.keys(Types).reduce(function(base, key) {
|
const Triggers = Object.keys(Types).reduce(function (base, key) {
|
||||||
base[key] = {};
|
base[key] = {};
|
||||||
return base;
|
return base;
|
||||||
}, {});
|
}, {});
|
||||||
@@ -132,6 +135,10 @@ export function addFileTrigger(type, handler, applicationId) {
|
|||||||
add(Category.Triggers, `${type}.${FileClassName}`, handler, applicationId);
|
add(Category.Triggers, `${type}.${FileClassName}`, handler, applicationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function addConnectTrigger(type, handler, applicationId) {
|
||||||
|
add(Category.Triggers, `${type}.${ConnectClassName}`, handler, applicationId);
|
||||||
|
}
|
||||||
|
|
||||||
export function addLiveQueryEventHandler(handler, applicationId) {
|
export function addLiveQueryEventHandler(handler, applicationId) {
|
||||||
applicationId = applicationId || Parse.applicationId;
|
applicationId = applicationId || Parse.applicationId;
|
||||||
_triggerStore[applicationId] = _triggerStore[applicationId] || baseStore();
|
_triggerStore[applicationId] = _triggerStore[applicationId] || baseStore();
|
||||||
@@ -233,10 +240,12 @@ export function getRequestObject(
|
|||||||
request.original = originalParseObject;
|
request.original = originalParseObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (triggerType === Types.beforeSave ||
|
if (
|
||||||
|
triggerType === Types.beforeSave ||
|
||||||
triggerType === Types.afterSave ||
|
triggerType === Types.afterSave ||
|
||||||
triggerType === Types.beforeDelete ||
|
triggerType === Types.beforeDelete ||
|
||||||
triggerType === Types.afterDelete) {
|
triggerType === Types.afterDelete
|
||||||
|
) {
|
||||||
// Set a copy of the context on the request object.
|
// Set a copy of the context on the request object.
|
||||||
request.context = Object.assign({}, context);
|
request.context = Object.assign({}, context);
|
||||||
}
|
}
|
||||||
@@ -300,7 +309,7 @@ export function getRequestQueryObject(
|
|||||||
// Any changes made to the object in a beforeSave will be included.
|
// Any changes made to the object in a beforeSave will be included.
|
||||||
export function getResponseObject(request, resolve, reject) {
|
export function getResponseObject(request, resolve, reject) {
|
||||||
return {
|
return {
|
||||||
success: function(response) {
|
success: function (response) {
|
||||||
if (request.triggerName === Types.afterFind) {
|
if (request.triggerName === Types.afterFind) {
|
||||||
if (!response) {
|
if (!response) {
|
||||||
response = request.objects;
|
response = request.objects;
|
||||||
@@ -335,7 +344,7 @@ export function getResponseObject(request, resolve, reject) {
|
|||||||
}
|
}
|
||||||
return resolve(response);
|
return resolve(response);
|
||||||
},
|
},
|
||||||
error: function(error) {
|
error: function (error) {
|
||||||
if (error instanceof Parse.Error) {
|
if (error instanceof Parse.Error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
} else if (error instanceof Error) {
|
} else if (error instanceof Error) {
|
||||||
@@ -585,7 +594,7 @@ export function maybeRunTrigger(
|
|||||||
if (!parseObject) {
|
if (!parseObject) {
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
}
|
}
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
var trigger = getTrigger(
|
var trigger = getTrigger(
|
||||||
parseObject.className,
|
parseObject.className,
|
||||||
triggerType,
|
triggerType,
|
||||||
@@ -721,7 +730,12 @@ export function getRequestFileObject(triggerType, auth, fileObject, config) {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function maybeRunFileTrigger(triggerType, fileObject, config, auth) {
|
export async function maybeRunFileTrigger(
|
||||||
|
triggerType,
|
||||||
|
fileObject,
|
||||||
|
config,
|
||||||
|
auth
|
||||||
|
) {
|
||||||
const fileTrigger = getFileTrigger(triggerType, config.applicationId);
|
const fileTrigger = getFileTrigger(triggerType, config.applicationId);
|
||||||
if (typeof fileTrigger === 'function') {
|
if (typeof fileTrigger === 'function') {
|
||||||
try {
|
try {
|
||||||
@@ -737,8 +751,8 @@ export async function maybeRunFileTrigger(triggerType, fileObject, config, auth)
|
|||||||
'Parse.File',
|
'Parse.File',
|
||||||
{ ...fileObject.file.toJSON(), fileSize: fileObject.fileSize },
|
{ ...fileObject.file.toJSON(), fileSize: fileObject.fileSize },
|
||||||
result,
|
result,
|
||||||
auth,
|
auth
|
||||||
)
|
);
|
||||||
return result || fileObject;
|
return result || fileObject;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logTriggerErrorBeforeHook(
|
logTriggerErrorBeforeHook(
|
||||||
@@ -746,10 +760,57 @@ export async function maybeRunFileTrigger(triggerType, fileObject, config, auth)
|
|||||||
'Parse.File',
|
'Parse.File',
|
||||||
{ ...fileObject.file.toJSON(), fileSize: fileObject.fileSize },
|
{ ...fileObject.file.toJSON(), fileSize: fileObject.fileSize },
|
||||||
auth,
|
auth,
|
||||||
error,
|
error
|
||||||
);
|
);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fileObject;
|
return fileObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function maybeRunConnectTrigger(triggerType, request) {
|
||||||
|
const trigger = getTrigger(
|
||||||
|
ConnectClassName,
|
||||||
|
triggerType,
|
||||||
|
Parse.applicationId
|
||||||
|
);
|
||||||
|
if (!trigger) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
request.user = await userForSessionToken(request.sessionToken);
|
||||||
|
return trigger(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function maybeRunSubscribeTrigger(
|
||||||
|
triggerType,
|
||||||
|
className,
|
||||||
|
request
|
||||||
|
) {
|
||||||
|
const trigger = getTrigger(className, triggerType, Parse.applicationId);
|
||||||
|
if (!trigger) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parseQuery = new Parse.Query(className);
|
||||||
|
parseQuery.withJSON(request.query);
|
||||||
|
request.query = parseQuery;
|
||||||
|
request.user = await userForSessionToken(request.sessionToken);
|
||||||
|
return trigger(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function userForSessionToken(sessionToken) {
|
||||||
|
if (!sessionToken) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const q = new Parse.Query('_Session');
|
||||||
|
q.equalTo('sessionToken', sessionToken);
|
||||||
|
const session = await q.first({ useMasterKey: true });
|
||||||
|
if (!session) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const user = session.get('user');
|
||||||
|
if (!user) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await user.fetch({ useMasterKey: true });
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user