Refactor pushStatusHandler to use Parse instead of direct access (#4173)
* Refactors pushStatusHandler to use HTTP interface so we can bind CloudCode hooks * Handle correctly nested dot atomic operations * Better handling of restricted class names, add support for afterSave _PushStatus * Adds simple testing for afterSave(PushStatus) * Reverts jobStatusHandler * Addresses fixes * adds delays to all methods
This commit is contained in:
@@ -1627,4 +1627,19 @@ describe('afterFind hooks', () => {
|
||||
})
|
||||
.then(() => done());
|
||||
});
|
||||
|
||||
it('should validate triggers correctly', () => {
|
||||
expect(() => {
|
||||
Parse.Cloud.beforeSave('_Session', () => {});
|
||||
}).toThrow('Triggers are not supported for _Session class.');
|
||||
expect(() => {
|
||||
Parse.Cloud.afterSave('_Session', () => {});
|
||||
}).toThrow('Triggers are not supported for _Session class.');
|
||||
expect(() => {
|
||||
Parse.Cloud.beforeSave('_PushStatus', () => {});
|
||||
}).toThrow('Only afterSave is allowed on _PushStatus');
|
||||
expect(() => {
|
||||
Parse.Cloud.afterSave('_PushStatus', () => {});
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -127,6 +127,7 @@ describe('Parse.Push', () => {
|
||||
alert: 'Hello world!'
|
||||
}
|
||||
}, {useMasterKey: true}))
|
||||
.then(() => delayPromise(500))
|
||||
.then(() => {
|
||||
request.get({
|
||||
url: 'http://localhost:8378/1/classes/_PushStatus',
|
||||
@@ -155,6 +156,7 @@ describe('Parse.Push', () => {
|
||||
alert: 'Hello world!'
|
||||
}
|
||||
}, {useMasterKey: true}))
|
||||
.then(() => delayPromise(500)) // put a delay as we keep writing
|
||||
.then(() => {
|
||||
request.get({
|
||||
url: 'http://localhost:8378/1/classes/_PushStatus',
|
||||
|
||||
@@ -388,6 +388,11 @@ describe('PushController', () => {
|
||||
});
|
||||
|
||||
it('properly creates _PushStatus', (done) => {
|
||||
const pushStatusAfterSave = {
|
||||
handler: function() {}
|
||||
};
|
||||
const spy = spyOn(pushStatusAfterSave, 'handler').and.callThrough();
|
||||
Parse.Cloud.afterSave('_PushStatus', pushStatusAfterSave.handler);
|
||||
var installations = [];
|
||||
while(installations.length != 10) {
|
||||
const installation = new Parse.Object("_Installation");
|
||||
@@ -466,8 +471,36 @@ describe('PushController', () => {
|
||||
return query.find();
|
||||
}).catch((error) => {
|
||||
expect(error.code).toBe(119);
|
||||
done();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
function getPushStatus(callIndex) {
|
||||
return spy.calls.all()[callIndex].args[0].object;
|
||||
}
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.calls.count()).toBe(4);
|
||||
const allCalls = spy.calls.all();
|
||||
allCalls.forEach((call) => {
|
||||
expect(call.args.length).toBe(2);
|
||||
const object = call.args[0].object;
|
||||
expect(object instanceof Parse.Object).toBe(true);
|
||||
});
|
||||
expect(getPushStatus(0).get('status')).toBe('pending');
|
||||
expect(getPushStatus(1).get('status')).toBe('running');
|
||||
expect(getPushStatus(1).get('numSent')).toBe(0);
|
||||
expect(getPushStatus(2).get('status')).toBe('running');
|
||||
expect(getPushStatus(2).get('numSent')).toBe(10);
|
||||
expect(getPushStatus(2).get('numFailed')).toBe(5);
|
||||
// Those are updated from a nested . operation, this would
|
||||
// not render correctly before
|
||||
expect(getPushStatus(2).get('failedPerType')).toEqual({
|
||||
android: 5
|
||||
});
|
||||
expect(getPushStatus(2).get('sentPerType')).toEqual({
|
||||
ios: 10
|
||||
});
|
||||
expect(getPushStatus(3).get('status')).toBe('succeeded');
|
||||
})
|
||||
.then(done).catch(done.fail);
|
||||
});
|
||||
|
||||
it('should properly report failures in _PushStatus', (done) => {
|
||||
@@ -710,7 +743,7 @@ describe('PushController', () => {
|
||||
}).then(() => {
|
||||
return Parse.Object.saveAll(installations).then(() => {
|
||||
return pushController.sendPush(payload, {}, config, auth);
|
||||
});
|
||||
}).then(() => new Promise(resolve => setTimeout(resolve, 300)));
|
||||
}).then(() => {
|
||||
const query = new Parse.Query('_PushStatus');
|
||||
return query.find({useMasterKey: true}).then((results) => {
|
||||
@@ -776,20 +809,15 @@ describe('PushController', () => {
|
||||
var config = new Config(Parse.applicationId);
|
||||
return Parse.Object.saveAll(installations).then(() => {
|
||||
return pushController.sendPush(payload, {}, config, auth);
|
||||
}).then(() => new Promise(resolve => setTimeout(resolve, 100)));
|
||||
}).then(() => new Promise(resolve => setTimeout(resolve, 300)));
|
||||
}).then(() => {
|
||||
const query = new Parse.Query('_PushStatus');
|
||||
return query.find({useMasterKey: true}).then((results) => {
|
||||
expect(results.length).toBe(1);
|
||||
const pushStatus = results[0];
|
||||
expect(pushStatus.get('status')).toBe('scheduled');
|
||||
done();
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
fail('should not fail');
|
||||
done();
|
||||
});
|
||||
}).then(done).catch(done.err);
|
||||
});
|
||||
|
||||
it('should not enqueue push when device token is not set', (done) => {
|
||||
|
||||
@@ -165,7 +165,7 @@ describe('PushWorker', () => {
|
||||
const spy = spyOn(config.database, "update").and.callFake(() => {
|
||||
return Promise.resolve();
|
||||
});
|
||||
handler.trackSent([
|
||||
const toAwait = handler.trackSent([
|
||||
{
|
||||
transmitted: false,
|
||||
device: {
|
||||
@@ -239,13 +239,13 @@ describe('PushWorker', () => {
|
||||
expect(lastCall.args[2]).toEqual({
|
||||
deviceToken: { '__op': "Delete" }
|
||||
});
|
||||
done();
|
||||
toAwait.then(done).catch(done);
|
||||
});
|
||||
|
||||
it('tracks push status per UTC offsets', (done) => {
|
||||
const config = new Config('test');
|
||||
const handler = pushStatusHandler(config, 'ABCDEF1234');
|
||||
const spy = spyOn(config.database, "update").and.callThrough();
|
||||
const handler = pushStatusHandler(config);
|
||||
const spy = spyOn(Parse, "_request").and.callThrough();
|
||||
const UTCOffset = 1;
|
||||
handler.setInitial().then(() => {
|
||||
return handler.trackSent([
|
||||
@@ -266,14 +266,9 @@ describe('PushWorker', () => {
|
||||
], UTCOffset)
|
||||
}).then(() => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.calls.count()).toBe(1);
|
||||
const lastCall = spy.calls.mostRecent();
|
||||
expect(lastCall.args[0]).toBe('_PushStatus');
|
||||
const updatePayload = lastCall.args[2];
|
||||
expect(updatePayload.updatedAt instanceof Date).toBeTruthy();
|
||||
// remove the updatedAt as not testable
|
||||
delete updatePayload.updatedAt;
|
||||
|
||||
expect(lastCall.args[0]).toBe('PUT');
|
||||
expect(lastCall.args[1]).toBe(`classes/_PushStatus/${handler.objectId}`);
|
||||
expect(lastCall.args[2]).toEqual({
|
||||
numSent: { __op: 'Increment', amount: 1 },
|
||||
numFailed: { __op: 'Increment', amount: 1 },
|
||||
@@ -284,7 +279,7 @@ describe('PushWorker', () => {
|
||||
count: { __op: 'Increment', amount: -2 },
|
||||
});
|
||||
const query = new Parse.Query('_PushStatus');
|
||||
return query.get('ABCDEF1234', { useMasterKey: true });
|
||||
return query.get(handler.objectId, { useMasterKey: true });
|
||||
}).then((pushStatus) => {
|
||||
const sentPerUTCOffset = pushStatus.get('sentPerUTCOffset');
|
||||
expect(sentPerUTCOffset['1']).toBe(1);
|
||||
@@ -315,7 +310,7 @@ describe('PushWorker', () => {
|
||||
], UTCOffset)
|
||||
}).then(() => {
|
||||
const query = new Parse.Query('_PushStatus');
|
||||
return query.get('ABCDEF1234', { useMasterKey: true });
|
||||
return query.get(handler.objectId, { useMasterKey: true });
|
||||
}).then((pushStatus) => {
|
||||
const sentPerUTCOffset = pushStatus.get('sentPerUTCOffset');
|
||||
expect(sentPerUTCOffset['1']).toBe(3);
|
||||
@@ -330,7 +325,7 @@ describe('PushWorker', () => {
|
||||
spyOn(config.database, "create").and.callFake(() => {
|
||||
return Promise.resolve();
|
||||
});
|
||||
const spy = spyOn(config.database, "update").and.callFake(() => {
|
||||
const spy = spyOn(Parse, "_request").and.callFake(() => {
|
||||
return Promise.resolve();
|
||||
});
|
||||
const UTCOffset = -6;
|
||||
@@ -353,14 +348,8 @@ describe('PushWorker', () => {
|
||||
},
|
||||
], UTCOffset).then(() => {
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.calls.count()).toBe(1);
|
||||
const lastCall = spy.calls.mostRecent();
|
||||
expect(lastCall.args[0]).toBe('_PushStatus');
|
||||
const updatePayload = lastCall.args[2];
|
||||
expect(updatePayload.updatedAt instanceof Date).toBeTruthy();
|
||||
// remove the updatedAt as not testable
|
||||
delete updatePayload.updatedAt;
|
||||
|
||||
expect(lastCall.args[1]).toBe(`classes/_PushStatus/${handler.objectId}`);
|
||||
expect(lastCall.args[2]).toEqual({
|
||||
numSent: { __op: 'Increment', amount: 1 },
|
||||
numFailed: { __op: 'Increment', amount: 1 },
|
||||
|
||||
Reference in New Issue
Block a user