Fix Parse.Push flaky tests (#7263)

* Fix Push Notification Flaky Tests

* handle all tests
This commit is contained in:
Diamond Lewis
2021-03-12 17:50:13 -06:00
committed by GitHub
parent 687f4b7cf2
commit 8b0e8cd02c
2 changed files with 598 additions and 1056 deletions

View File

@@ -2,14 +2,56 @@
const request = require('../lib/request'); const request = require('../lib/request');
const delayPromise = delay => { const pushCompleted = async pushId => {
return new Promise(resolve => { let result = await Parse.Push.getPushStatus(pushId);
setTimeout(resolve, delay); while (!(result && result.get('status') === 'succeeded')) {
}); result = await Parse.Push.getPushStatus(pushId);
}
}; };
describe('Parse.Push', () => { const successfulAny = function (body, installations) {
const setup = function () { const promises = installations.map(device => {
return Promise.resolve({
transmitted: true,
device: device,
});
});
return Promise.all(promises);
};
const provideInstallations = function (num) {
if (!num) {
num = 2;
}
const installations = [];
while (installations.length !== num) {
// add Android installations
const installation = new Parse.Object('_Installation');
installation.set('installationId', 'installation_' + installations.length);
installation.set('deviceToken', 'device_token_' + installations.length);
installation.set('deviceType', 'android');
installations.push(installation);
}
return installations;
};
const losingAdapter = {
send: function (body, installations) {
// simulate having lost an installation before this was called
// thus invalidating our 'count' in _PushStatus
installations.pop();
return successfulAny(body, installations);
},
getValidPushTypes: function () {
return ['android'];
},
};
const setup = function () {
const sendToInstallationSpy = jasmine.createSpy(); const sendToInstallationSpy = jasmine.createSpy();
const pushAdapter = { const pushAdapter = {
@@ -62,19 +104,13 @@ describe('Parse.Push', () => {
return { return {
sendToInstallationSpy, sendToInstallationSpy,
}; };
})
.catch(err => {
console.error(err);
throw err;
}); });
}; };
it('should properly send push', done => { describe('Parse.Push', () => {
return setup() it('should properly send push', async () => {
.then(({ sendToInstallationSpy }) => { const { sendToInstallationSpy } = await setup();
return Parse.Push.send( const pushStatusId = await Parse.Push.send({
{
where: { where: {
deviceType: 'ios', deviceType: 'ios',
}, },
@@ -82,30 +118,14 @@ describe('Parse.Push', () => {
badge: 'Increment', badge: 'Increment',
alert: 'Hello world!', alert: 'Hello world!',
}, },
}, });
{ useMasterKey: true } await pushCompleted(pushStatusId);
)
.then(() => {
return delayPromise(500);
})
.then(() => {
expect(sendToInstallationSpy.calls.count()).toEqual(10); expect(sendToInstallationSpy.calls.count()).toEqual(10);
}); });
})
.then(() => {
done();
})
.catch(err => {
jfail(err);
done();
});
});
it('should properly send push with lowercaseIncrement', done => { it('should properly send push with lowercaseIncrement', async () => {
return setup() await setup();
.then(() => { const pushStatusId = await Parse.Push.send({
return Parse.Push.send(
{
where: { where: {
deviceType: 'ios', deviceType: 'ios',
}, },
@@ -113,27 +133,13 @@ describe('Parse.Push', () => {
badge: 'increment', badge: 'increment',
alert: 'Hello world!', alert: 'Hello world!',
}, },
},
{ useMasterKey: true }
);
})
.then(() => {
return delayPromise(500);
})
.then(() => {
done();
})
.catch(err => {
jfail(err);
done();
}); });
await pushCompleted(pushStatusId);
}); });
it('should not allow clients to query _PushStatus', done => { it('should not allow clients to query _PushStatus', async () => {
setup() await setup();
.then(() => const pushStatusId = await Parse.Push.send({
Parse.Push.send(
{
where: { where: {
deviceType: 'ios', deviceType: 'ios',
}, },
@@ -141,34 +147,25 @@ describe('Parse.Push', () => {
badge: 'increment', badge: 'increment',
alert: 'Hello world!', alert: 'Hello world!',
}, },
}, });
{ useMasterKey: true } await pushCompleted(pushStatusId);
) try {
) await request({
.then(() => delayPromise(500))
.then(() => {
request({
url: 'http://localhost:8378/1/classes/_PushStatus', url: 'http://localhost:8378/1/classes/_PushStatus',
json: true, json: true,
headers: { headers: {
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
}, },
}).then(fail, response => { });
fail();
} catch (response) {
expect(response.data.error).toEqual('unauthorized'); expect(response.data.error).toEqual('unauthorized');
done(); }
});
})
.catch(err => {
jfail(err);
done();
});
}); });
it('should allow master key to query _PushStatus', done => { it('should allow master key to query _PushStatus', async () => {
setup() await setup();
.then(() => const pushStatusId = await Parse.Push.send({
Parse.Push.send(
{
where: { where: {
deviceType: 'ios', deviceType: 'ios',
}, },
@@ -176,42 +173,26 @@ describe('Parse.Push', () => {
badge: 'increment', badge: 'increment',
alert: 'Hello world!', alert: 'Hello world!',
}, },
}, });
{ useMasterKey: true } await pushCompleted(pushStatusId);
) const response = await request({
)
.then(() => delayPromise(500)) // put a delay as we keep writing
.then(() => {
request({
url: 'http://localhost:8378/1/classes/_PushStatus', url: 'http://localhost:8378/1/classes/_PushStatus',
json: true, json: true,
headers: { headers: {
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key': 'test', 'X-Parse-Master-Key': 'test',
}, },
}).then(response => { });
const body = response.data; const body = response.data;
try {
expect(body.results.length).toEqual(1); expect(body.results.length).toEqual(1);
expect(body.results[0].query).toEqual('{"deviceType":"ios"}'); expect(body.results[0].query).toEqual('{"deviceType":"ios"}');
expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}'); expect(body.results[0].payload).toEqual('{"badge":"increment","alert":"Hello world!"}');
} catch (e) {
jfail(e);
}
done();
});
})
.catch(err => {
jfail(err);
done();
});
}); });
it('should throw error if missing push configuration', done => { it('should throw error if missing push configuration', async () => {
reconfigureServer({ push: null }) await reconfigureServer({ push: null });
.then(() => { try {
return Parse.Push.send( await Parse.Push.send({
{
where: { where: {
deviceType: 'ios', deviceType: 'ios',
}, },
@@ -219,110 +200,32 @@ describe('Parse.Push', () => {
badge: 'increment', badge: 'increment',
alert: 'Hello world!', alert: 'Hello world!',
}, },
}, });
{ useMasterKey: true } fail();
); } catch (err) {
})
.then(
() => {
fail('should not succeed');
},
err => {
expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED); expect(err.code).toEqual(Parse.Error.PUSH_MISCONFIGURED);
done();
} }
)
.catch(err => {
jfail(err);
done();
}); });
});
const successfulAny = function (body, installations) {
const promises = installations.map(device => {
return Promise.resolve({
transmitted: true,
device: device,
});
});
return Promise.all(promises);
};
const provideInstallations = function (num) {
if (!num) {
num = 2;
}
const installations = [];
while (installations.length !== num) {
// add Android installations
const installation = new Parse.Object('_Installation');
installation.set('installationId', 'installation_' + installations.length);
installation.set('deviceToken', 'device_token_' + installations.length);
installation.set('deviceType', 'android');
installations.push(installation);
}
return installations;
};
const losingAdapter = {
send: function (body, installations) {
// simulate having lost an installation before this was called
// thus invalidating our 'count' in _PushStatus
installations.pop();
return successfulAny(body, installations);
},
getValidPushTypes: function () {
return ['android'];
},
};
/** /**
* Verifies that _PushStatus cannot get stuck in a 'running' state * Verifies that _PushStatus cannot get stuck in a 'running' state
* Simulates a simple push where 1 installation is removed between _PushStatus * Simulates a simple push where 1 installation is removed between _PushStatus
* count being set and the pushes being sent * count being set and the pushes being sent
*/ */
it("does not get stuck with _PushStatus 'running' on 1 installation lost", done => { it("does not get stuck with _PushStatus 'running' on 1 installation lost", async () => {
reconfigureServer({ await reconfigureServer({
push: { adapter: losingAdapter }, push: { adapter: losingAdapter },
}) });
.then(() => { await Parse.Object.saveAll(provideInstallations());
return Parse.Object.saveAll(provideInstallations()); const pushStatusId = await Parse.Push.send({
})
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' }, data: { alert: 'We fixed our status!' },
where: { deviceType: 'android' }, where: { deviceType: 'android' },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await pushCompleted(pushStatusId);
.then(() => { const result = await Parse.Push.getPushStatus(pushStatusId);
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded'); expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(1); expect(result.get('numSent')).toEqual(1);
expect(result.get('count')).toEqual(undefined); expect(result.get('count')).toEqual(undefined);
done();
});
}); });
/** /**
@@ -330,7 +233,7 @@ describe('Parse.Push', () => {
* Simulates a simple push where 1 installation is added between _PushStatus * Simulates a simple push where 1 installation is added between _PushStatus
* count being set and the pushes being sent * count being set and the pushes being sent
*/ */
it("does not get stuck with _PushStatus 'running' on 1 installation added", done => { it("does not get stuck with _PushStatus 'running' on 1 installation added", async () => {
const installations = provideInstallations(); const installations = provideInstallations();
// add 1 iOS installation which we will omit & add later on // add 1 iOS installation which we will omit & add later on
@@ -340,14 +243,13 @@ describe('Parse.Push', () => {
iOSInstallation.set('deviceType', 'ios'); iOSInstallation.set('deviceType', 'ios');
installations.push(iOSInstallation); installations.push(iOSInstallation);
reconfigureServer({ await reconfigureServer({
push: { push: {
adapter: { adapter: {
send: function (body, installations) { send: function (body, installations) {
// simulate having added an installation before this was called // simulate having added an installation before this was called
// thus invalidating our 'count' in _PushStatus // thus invalidating our 'count' in _PushStatus
installations.push(iOSInstallation); installations.push(iOSInstallation);
return successfulAny(body, installations); return successfulAny(body, installations);
}, },
getValidPushTypes: function () { getValidPushTypes: function () {
@@ -355,41 +257,17 @@ describe('Parse.Push', () => {
}, },
}, },
}, },
}) });
.then(() => { await Parse.Object.saveAll(installations);
return Parse.Object.saveAll(installations); const pushStatusId = await Parse.Push.send({
})
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' }, data: { alert: 'We fixed our status!' },
where: { deviceType: { $ne: 'random' } }, where: { deviceType: { $ne: 'random' } },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await pushCompleted(pushStatusId);
.then(() => { const result = await Parse.Push.getPushStatus(pushStatusId);
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded'); expect(result.get('status')).toEqual('succeeded');
expect(result.get('numSent')).toEqual(3); expect(result.get('numSent')).toEqual(3);
expect(result.get('count')).toEqual(undefined); expect(result.get('count')).toEqual(undefined);
done();
});
}); });
/** /**
@@ -397,48 +275,24 @@ describe('Parse.Push', () => {
* Simulates an extended push, where some installations may be removed, * Simulates an extended push, where some installations may be removed,
* resulting in a non-zero count * resulting in a non-zero count
*/ */
it("does not get stuck with _PushStatus 'running' on many installations removed", done => { it("does not get stuck with _PushStatus 'running' on many installations removed", async () => {
const devices = 1000; const devices = 1000;
const installations = provideInstallations(devices); const installations = provideInstallations(devices);
reconfigureServer({ await reconfigureServer({
push: { adapter: losingAdapter }, push: { adapter: losingAdapter },
}) });
.then(() => { await Parse.Object.saveAll(installations);
return Parse.Object.saveAll(installations); const pushStatusId = await Parse.Push.send({
})
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' }, data: { alert: 'We fixed our status!' },
where: { deviceType: 'android' }, where: { deviceType: 'android' },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await pushCompleted(pushStatusId);
.then(() => { const result = await Parse.Push.getPushStatus(pushStatusId);
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded'); expect(result.get('status')).toEqual('succeeded');
// expect # less than # of batches used, assuming each batch is 100 pushes // expect # less than # of batches used, assuming each batch is 100 pushes
expect(result.get('numSent')).toEqual(devices - devices / 100); expect(result.get('numSent')).toEqual(devices - devices / 100);
expect(result.get('count')).toEqual(undefined); expect(result.get('count')).toEqual(undefined);
done();
});
}); });
/** /**
@@ -446,13 +300,12 @@ describe('Parse.Push', () => {
* Simulates an extended push, where some installations may be added, * Simulates an extended push, where some installations may be added,
* resulting in a non-zero count * resulting in a non-zero count
*/ */
it("does not get stuck with _PushStatus 'running' on many installations added", done => { it("does not get stuck with _PushStatus 'running' on many installations added", async () => {
const devices = 1000; const devices = 1000;
const installations = provideInstallations(devices); const installations = provideInstallations(devices);
// add 1 iOS installation which we will omit & add later on // add 1 iOS installation which we will omit & add later on
const iOSInstallations = []; const iOSInstallations = [];
while (iOSInstallations.length !== devices / 100) { while (iOSInstallations.length !== devices / 100) {
const iOSInstallation = new Parse.Object('_Installation'); const iOSInstallation = new Parse.Object('_Installation');
iOSInstallation.set('installationId', 'installation_' + installations.length); iOSInstallation.set('installationId', 'installation_' + installations.length);
@@ -461,15 +314,13 @@ describe('Parse.Push', () => {
installations.push(iOSInstallation); installations.push(iOSInstallation);
iOSInstallations.push(iOSInstallation); iOSInstallations.push(iOSInstallation);
} }
await reconfigureServer({
reconfigureServer({
push: { push: {
adapter: { adapter: {
send: function (body, installations) { send: function (body, installations) {
// simulate having added an installation before this was called // simulate having added an installation before this was called
// thus invalidating our 'count' in _PushStatus // thus invalidating our 'count' in _PushStatus
installations.push(iOSInstallations.pop()); installations.push(iOSInstallations.pop());
return successfulAny(body, installations); return successfulAny(body, installations);
}, },
getValidPushTypes: function () { getValidPushTypes: function () {
@@ -477,41 +328,18 @@ describe('Parse.Push', () => {
}, },
}, },
}, },
}) });
.then(() => { await Parse.Object.saveAll(installations);
return Parse.Object.saveAll(installations);
}) const pushStatusId = await Parse.Push.send({
.then(() => {
return Parse.Push.send(
{
data: { alert: 'We fixed our status!' }, data: { alert: 'We fixed our status!' },
where: { deviceType: { $ne: 'random' } }, where: { deviceType: { $ne: 'random' } },
},
{ useMasterKey: true }
);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await pushCompleted(pushStatusId);
.then(() => { const result = await Parse.Push.getPushStatus(pushStatusId);
// query for push status
const query = new Parse.Query('_PushStatus');
return query.find({ useMasterKey: true });
})
.then(results => {
// verify status is NOT broken
expect(results.length).toBe(1);
const result = results[0];
expect(result.get('status')).toEqual('succeeded'); expect(result.get('status')).toEqual('succeeded');
// expect # less than # of batches used, assuming each batch is 100 pushes // expect # less than # of batches used, assuming each batch is 100 pushes
expect(result.get('numSent')).toEqual(devices + devices / 100); expect(result.get('numSent')).toEqual(devices + devices / 100);
expect(result.get('count')).toEqual(undefined); expect(result.get('count')).toEqual(undefined);
done();
});
}); });
}); });

View File

@@ -26,6 +26,20 @@ const successfulIOS = function (body, installations) {
return Promise.all(promises); return Promise.all(promises);
}; };
const pushCompleted = async pushId => {
let result = await Parse.Push.getPushStatus(pushId);
while (!(result && result.get('status') === 'succeeded')) {
result = await Parse.Push.getPushStatus(pushId);
}
};
const sendPush = (body, where, config, auth, now) => {
const pushController = new PushController();
return new Promise((resolve, reject) => {
pushController.sendPush(body, where, config, auth, resolve, now).catch(reject);
});
};
describe('PushController', () => { describe('PushController', () => {
it('can validate device type when no device type is set', done => { it('can validate device type when no device type is set', done => {
// Make query condition // Make query condition
@@ -151,7 +165,7 @@ describe('PushController', () => {
done(); done();
}); });
it('properly increment badges', done => { it('properly increment badges', async () => {
const pushAdapter = { const pushAdapter = {
send: function (body, installations) { send: function (body, installations) {
const badge = body.data.badge; const badge = body.data.badge;
@@ -195,55 +209,28 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
await reconfigureServer({
const pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(() => {
return pushController.sendPush(payload, {}, config, auth);
})
.then(() => {
// Wait so the push is completed.
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await Parse.Object.saveAll(installations);
.then(() => { const pushStatusId = await sendPush(payload, {}, config, auth);
await pushCompleted(pushStatusId);
// Check we actually sent 15 pushes. // Check we actually sent 15 pushes.
const query = new Parse.Query('_PushStatus'); const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
return query.find({ useMasterKey: true });
})
.then(results => {
expect(results.length).toBe(1);
const pushStatus = results[0];
expect(pushStatus.get('numSent')).toBe(15); expect(pushStatus.get('numSent')).toBe(15);
})
.then(() => {
// Check that the installations were actually updated. // Check that the installations were actually updated.
const query = new Parse.Query('_Installation'); const query = new Parse.Query('_Installation');
return query.find({ useMasterKey: true }); const results = await query.find({ useMasterKey: true });
})
.then(results => {
expect(results.length).toBe(15); expect(results.length).toBe(15);
for (let i = 0; i < 15; i++) { for (let i = 0; i < 15; i++) {
const installation = results[i]; const installation = results[i];
expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 1); expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 1);
} }
done();
})
.catch(err => {
jfail(err);
done();
});
}); });
it('properly increment badges by more than 1', done => { it('properly increment badges by more than 1', async () => {
const pushAdapter = { const pushAdapter = {
send: function (body, installations) { send: function (body, installations) {
const badge = body.data.badge; const badge = body.data.badge;
@@ -287,55 +274,25 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
await reconfigureServer({
const pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(() => {
return pushController.sendPush(payload, {}, config, auth);
})
.then(() => {
// Wait so the push is completed.
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await Parse.Object.saveAll(installations);
.then(() => { const pushStatusId = await sendPush(payload, {}, config, auth);
// Check we actually sent 15 pushes. await pushCompleted(pushStatusId);
const query = new Parse.Query('_PushStatus'); const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
return query.find({ useMasterKey: true });
})
.then(results => {
expect(results.length).toBe(1);
const pushStatus = results[0];
expect(pushStatus.get('numSent')).toBe(15); expect(pushStatus.get('numSent')).toBe(15);
})
.then(() => {
// Check that the installations were actually updated. // Check that the installations were actually updated.
const query = new Parse.Query('_Installation'); const query = new Parse.Query('_Installation');
return query.find({ useMasterKey: true }); const results = await query.find({ useMasterKey: true });
})
.then(results => {
expect(results.length).toBe(15); expect(results.length).toBe(15);
for (let i = 0; i < 15; i++) { for (let i = 0; i < 15; i++) {
const installation = results[i]; const installation = results[i];
expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 3); expect(installation.get('badge')).toBe(parseInt(installation.get('originalBadge')) + 3);
} }
done();
})
.catch(err => {
jfail(err);
done();
});
}); });
it('properly set badges to 1', done => { it('properly set badges to 1', async () => {
const pushAdapter = { const pushAdapter = {
send: function (body, installations) { send: function (body, installations) {
const badge = body.data.badge; const badge = body.data.badge;
@@ -371,55 +328,26 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
await reconfigureServer({
const pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(() => {
return pushController.sendPush(payload, {}, config, auth);
})
.then(() => {
// Wait so the push is completed.
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await Parse.Object.saveAll(installations);
.then(() => { const pushStatusId = await sendPush(payload, {}, config, auth);
// Check we actually sent the pushes. await pushCompleted(pushStatusId);
const query = new Parse.Query('_PushStatus'); const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
return query.find({ useMasterKey: true });
})
.then(results => {
expect(results.length).toBe(1);
const pushStatus = results[0];
expect(pushStatus.get('numSent')).toBe(10); expect(pushStatus.get('numSent')).toBe(10);
})
.then(() => {
// Check that the installations were actually updated. // Check that the installations were actually updated.
const query = new Parse.Query('_Installation'); const query = new Parse.Query('_Installation');
return query.find({ useMasterKey: true }); const results = await query.find({ useMasterKey: true });
})
.then(results => {
expect(results.length).toBe(10); expect(results.length).toBe(10);
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
const installation = results[i]; const installation = results[i];
expect(installation.get('badge')).toBe(1); expect(installation.get('badge')).toBe(1);
} }
done();
})
.catch(err => {
jfail(err);
done();
});
}); });
it('properly set badges to 1 with complex query #2903 #3022', done => { it('properly set badges to 1 with complex query #2903 #3022', async () => {
const payload = { const payload = {
data: { data: {
alert: 'Hello World!', alert: 'Hello World!',
@@ -456,46 +384,26 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
const pushController = new PushController(); await reconfigureServer({
reconfigureServer({ push: { adapter: pushAdapter },
push: { });
adapter: pushAdapter, await Parse.Object.saveAll(installations);
},
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(installations => {
const objectIds = installations.map(installation => { const objectIds = installations.map(installation => {
return installation.id; return installation.id;
}); });
const where = { const where = {
objectId: { $in: objectIds.slice(0, 5) }, objectId: { $in: objectIds.slice(0, 5) },
}; };
return pushController.sendPush(payload, where, config, auth); const pushStatusId = await sendPush(payload, where, config, auth);
}) await pushCompleted(pushStatusId);
.then(() => {
return new Promise(res => {
setTimeout(res, 300);
});
})
.then(() => {
expect(matchedInstallationsCount).toBe(5); expect(matchedInstallationsCount).toBe(5);
const query = new Parse.Query(Parse.Installation); const query = new Parse.Query(Parse.Installation);
query.equalTo('badge', 1); query.equalTo('badge', 1);
return query.find({ useMasterKey: true }); const results = await query.find({ useMasterKey: true });
}) expect(results.length).toBe(5);
.then(installations => {
expect(installations.length).toBe(5);
done();
})
.catch(() => {
fail('should not fail');
done();
});
}); });
it('properly creates _PushStatus', done => { it('properly creates _PushStatus', async () => {
const pushStatusAfterSave = { const pushStatusAfterSave = {
handler: function () {}, handler: function () {},
}; };
@@ -539,31 +447,13 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
const pushController = new PushController(); await reconfigureServer({
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
})
.then(() => {
return Parse.Object.saveAll(installations);
})
.then(() => {
return pushController.sendPush(payload, {}, config, auth);
})
.then(() => {
// it is enqueued so it can take time
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await Parse.Object.saveAll(installations);
.then(() => { const pushStatusId = await sendPush(payload, {}, config, auth);
const query = new Parse.Query('_PushStatus'); await pushCompleted(pushStatusId);
return query.find({ useMasterKey: true }); const result = await Parse.Push.getPushStatus(pushStatusId);
})
.then(results => {
expect(results.length).toBe(1);
const result = results[0];
expect(result.createdAt instanceof Date).toBe(true); expect(result.createdAt instanceof Date).toBe(true);
expect(result.updatedAt instanceof Date).toBe(true); expect(result.updatedAt instanceof Date).toBe(true);
expect(result.id.length).toBe(10); expect(result.id.length).toBe(10);
@@ -580,46 +470,55 @@ describe('PushController', () => {
expect(result.get('failedPerType')).toEqual({ expect(result.get('failedPerType')).toEqual({
android: 5, // android android: 5, // android
}); });
try {
// Try to get it without masterKey // Try to get it without masterKey
const query = new Parse.Query('_PushStatus'); const query = new Parse.Query('_PushStatus');
return query.find(); await query.find();
}) fail();
.catch(error => { } catch (error) {
expect(error.code).toBe(119); expect(error.code).toBe(119);
}) }
.then(() => {
function getPushStatus(callIndex) { function getPushStatus(callIndex) {
return spy.calls.all()[callIndex].args[0].object; return spy.calls.all()[callIndex].args[0].object;
} }
expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalled();
expect(spy.calls.count()).toBe(4); expect(spy.calls.count()).toBe(4);
const allCalls = spy.calls.all(); const allCalls = spy.calls.all();
allCalls.forEach(call => { let pendingCount = 0;
let runningCount = 0;
let succeedCount = 0;
allCalls.forEach((call, index) => {
expect(call.args.length).toBe(1); expect(call.args.length).toBe(1);
const object = call.args[0].object; const object = call.args[0].object;
expect(object instanceof Parse.Object).toBe(true); expect(object instanceof Parse.Object).toBe(true);
}); const pushStatus = getPushStatus(index);
expect(getPushStatus(0).get('status')).toBe('pending'); if (pushStatus.get('status') === 'pending') {
expect(getPushStatus(1).get('status')).toBe('running'); pendingCount += 1;
expect(getPushStatus(1).get('numSent')).toBe(0); }
expect(getPushStatus(2).get('status')).toBe('running'); if (pushStatus.get('status') === 'running') {
expect(getPushStatus(2).get('numSent')).toBe(10); runningCount += 1;
expect(getPushStatus(2).get('numFailed')).toBe(5); }
// Those are updated from a nested . operation, this would if (pushStatus.get('status') === 'succeeded') {
// not render correctly before succeedCount += 1;
expect(getPushStatus(2).get('failedPerType')).toEqual({ }
if (pushStatus.get('status') === 'running' && pushStatus.get('numSent') > 0) {
expect(pushStatus.get('numSent')).toBe(10);
expect(pushStatus.get('numFailed')).toBe(5);
expect(pushStatus.get('failedPerType')).toEqual({
android: 5, android: 5,
}); });
expect(getPushStatus(2).get('sentPerType')).toEqual({ expect(pushStatus.get('sentPerType')).toEqual({
ios: 10, ios: 10,
}); });
expect(getPushStatus(3).get('status')).toBe('succeeded'); }
}) });
.then(done) expect(pendingCount).toBe(1);
.catch(done.fail); expect(runningCount).toBe(2);
expect(succeedCount).toBe(1);
}); });
it('properly creates _PushStatus without serverURL', done => { it('properly creates _PushStatus without serverURL', async () => {
const pushStatusAfterSave = { const pushStatusAfterSave = {
handler: function () {}, handler: function () {},
}; };
@@ -651,36 +550,22 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
const pushController = new PushController(); await installation.save();
return installation await reconfigureServer({
.save()
.then(() => {
return reconfigureServer({
serverURL: 'http://localhost:8378/', // server with borked URL serverURL: 'http://localhost:8378/', // server with borked URL
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
}); });
}) const pushStatusId = await sendPush(payload, {}, config, auth);
.then(() => {
return pushController.sendPush(payload, {}, config, auth);
})
.then(() => {
// it is enqueued so it can take time // it is enqueued so it can take time
return new Promise(resolve => { await new Promise(resolve => {
setTimeout(() => { setTimeout(() => {
resolve(); resolve();
}, 1000); }, 1000);
}); });
})
.then(() => {
Parse.serverURL = 'http://localhost:8378/1'; // GOOD url Parse.serverURL = 'http://localhost:8378/1'; // GOOD url
const query = new Parse.Query('_PushStatus'); const result = await Parse.Push.getPushStatus(pushStatusId);
return query.find({ useMasterKey: true }); expect(result).toBeDefined();
}) await pushCompleted(pushStatusId);
.then(results => {
expect(results.length).toBe(1);
})
.then(done)
.catch(done.fail);
}); });
it('should properly report failures in _PushStatus', done => { it('should properly report failures in _PushStatus', done => {
@@ -696,6 +581,7 @@ describe('PushController', () => {
return ['ios']; return ['ios'];
}, },
}; };
// $ins is invalid query
const where = { const where = {
channels: { channels: {
$ins: ['Giants', 'Mets'], $ins: ['Giants', 'Mets'],
@@ -733,7 +619,7 @@ describe('PushController', () => {
}); });
}); });
it('should support full RESTQuery for increment', done => { it('should support full RESTQuery for increment', async () => {
const payload = { const payload = {
data: { data: {
alert: 'Hello World!', alert: 'Hello World!',
@@ -759,12 +645,9 @@ describe('PushController', () => {
$in: ['device_token_0', 'device_token_1', 'device_token_2'], $in: ['device_token_0', 'device_token_1', 'device_token_2'],
}, },
}; };
await reconfigureServer({
const pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
}) });
.then(() => {
const installations = []; const installations = [];
while (installations.length != 5) { while (installations.length != 5) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
@@ -775,36 +658,14 @@ describe('PushController', () => {
installation.set('deviceType', 'ios'); installation.set('deviceType', 'ios');
installations.push(installation); installations.push(installation);
} }
return Parse.Object.saveAll(installations); await Parse.Object.saveAll(installations);
}) const pushStatusId = await sendPush(payload, where, config, auth);
.then(() => { await pushCompleted(pushStatusId);
return pushController.sendPush(payload, where, config, auth); const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
})
.then(() => {
// Wait so the push is completed.
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.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('numSent')).toBe(3); expect(pushStatus.get('numSent')).toBe(3);
done();
})
.catch(err => {
jfail(err);
done();
});
}); });
it('should support object type for alert', done => { it('should support object type for alert', async () => {
const payload = { const payload = {
data: { data: {
alert: { alert: {
@@ -826,16 +687,12 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
const where = { const where = {
deviceType: 'ios', deviceType: 'ios',
}; };
await reconfigureServer({
const pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
}) });
.then(() => {
const installations = []; const installations = [];
while (installations.length != 5) { while (installations.length != 5) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
@@ -846,33 +703,11 @@ describe('PushController', () => {
installation.set('deviceType', 'ios'); installation.set('deviceType', 'ios');
installations.push(installation); installations.push(installation);
} }
return Parse.Object.saveAll(installations); await Parse.Object.saveAll(installations);
}) const pushStatusId = await sendPush(payload, where, config, auth);
.then(() => { await pushCompleted(pushStatusId);
return pushController.sendPush(payload, where, config, auth); const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
})
.then(() => {
// Wait so the push is completed.
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.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('numSent')).toBe(5); expect(pushStatus.get('numSent')).toBe(5);
done();
})
.catch(() => {
fail('should not fail');
done();
});
}); });
it('should flatten', () => { it('should flatten', () => {
@@ -1012,7 +847,6 @@ describe('PushController', () => {
return ['ios']; return ['ios'];
}, },
}; };
const pushController = new PushController(); const pushController = new PushController();
const payload = { const payload = {
data: { data: {
@@ -1020,7 +854,6 @@ describe('PushController', () => {
}, },
push_time: new Date().getTime() / 1000, push_time: new Date().getTime() / 1000,
}; };
const installations = []; const installations = [];
while (installations.length != 10) { while (installations.length != 10) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
@@ -1031,7 +864,6 @@ describe('PushController', () => {
installation.set('deviceType', 'ios'); installation.set('deviceType', 'ios');
installations.push(installation); installations.push(installation);
} }
reconfigureServer({ reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
scheduledPush: true, scheduledPush: true,
@@ -1056,7 +888,7 @@ describe('PushController', () => {
.catch(done.err); .catch(done.err);
}); });
it('should not enqueue push when device token is not set', done => { it('should not enqueue push when device token is not set', async () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
@@ -1079,15 +911,12 @@ describe('PushController', () => {
return ['ios']; return ['ios'];
}, },
}; };
const pushController = new PushController();
const payload = { const payload = {
data: { data: {
alert: 'hello', alert: 'hello',
}, },
push_time: new Date().getTime() / 1000, push_time: new Date().getTime() / 1000,
}; };
const installations = []; const installations = [];
while (installations.length != 5) { while (installations.length != 5) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
@@ -1098,7 +927,6 @@ describe('PushController', () => {
installation.set('deviceType', 'ios'); installation.set('deviceType', 'ios');
installations.push(installation); installations.push(installation);
} }
while (installations.length != 15) { while (installations.length != 15) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
installation.set('installationId', 'installation_' + installations.length); installation.set('installationId', 'installation_' + installations.length);
@@ -1107,36 +935,19 @@ describe('PushController', () => {
installation.set('deviceType', 'ios'); installation.set('deviceType', 'ios');
installations.push(installation); installations.push(installation);
} }
await reconfigureServer({
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
}) });
.then(() => {
const config = Config.get(Parse.applicationId); const config = Config.get(Parse.applicationId);
return Parse.Object.saveAll(installations) await Parse.Object.saveAll(installations);
.then(() => { const pushStatusId = await sendPush(payload, {}, config, auth);
return pushController.sendPush(payload, {}, config, auth); await pushCompleted(pushStatusId);
}) const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
.then(() => new Promise(resolve => setTimeout(resolve, 100)));
})
.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('numSent')).toBe(5); expect(pushStatus.get('numSent')).toBe(5);
expect(pushStatus.get('status')).toBe('succeeded'); expect(pushStatus.get('status')).toBe('succeeded');
done();
});
})
.catch(err => {
console.error(err);
fail('should not fail');
done();
});
}); });
it('should not mark the _PushStatus as failed when audience has no deviceToken', done => { it('should not mark the _PushStatus as failed when audience has no deviceToken', async () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
@@ -1159,15 +970,12 @@ describe('PushController', () => {
return ['ios']; return ['ios'];
}, },
}; };
const pushController = new PushController();
const payload = { const payload = {
data: { data: {
alert: 'hello', alert: 'hello',
}, },
push_time: new Date().getTime() / 1000, push_time: new Date().getTime() / 1000,
}; };
const installations = []; const installations = [];
while (installations.length != 5) { while (installations.length != 5) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
@@ -1177,36 +985,18 @@ describe('PushController', () => {
installation.set('deviceType', 'ios'); installation.set('deviceType', 'ios');
installations.push(installation); installations.push(installation);
} }
await reconfigureServer({
reconfigureServer({
push: { adapter: pushAdapter }, push: { adapter: pushAdapter },
}) });
.then(() => {
const config = Config.get(Parse.applicationId); const config = Config.get(Parse.applicationId);
return Parse.Object.saveAll(installations) await Parse.Object.saveAll(installations);
.then(() => { const pushStatusId = await sendPush(payload, {}, config, auth);
return pushController.sendPush(payload, {}, config, auth); await pushCompleted(pushStatusId);
}) const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
.then(() => new Promise(resolve => setTimeout(resolve, 100)));
})
.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('numSent')).toBe(0);
expect(pushStatus.get('status')).toBe('succeeded'); expect(pushStatus.get('status')).toBe('succeeded');
done();
});
})
.catch(err => {
console.error(err);
fail('should not fail');
done();
});
}); });
it('should support localized payload data', done => { it('should support localized payload data', async () => {
const payload = { const payload = {
data: { data: {
alert: 'Hello!', alert: 'Hello!',
@@ -1214,7 +1004,6 @@ describe('PushController', () => {
'alert-es': 'Ola', 'alert-es': 'Ola',
}, },
}; };
const pushAdapter = { const pushAdapter = {
send: function (body, installations) { send: function (body, installations) {
return successfulTransmissions(body, installations); return successfulTransmissions(body, installations);
@@ -1223,21 +1012,13 @@ describe('PushController', () => {
return ['ios']; return ['ios'];
}, },
}; };
const config = Config.get(Parse.applicationId); const config = Config.get(Parse.applicationId);
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
const where = { const where = {
deviceType: 'ios', deviceType: 'ios',
}; };
spyOn(pushAdapter, 'send').and.callThrough();
const pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter },
})
.then(() => {
const installations = []; const installations = [];
while (installations.length != 5) { while (installations.length != 5) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
@@ -1251,20 +1032,15 @@ describe('PushController', () => {
installations[0].set('localeIdentifier', 'fr-CA'); installations[0].set('localeIdentifier', 'fr-CA');
installations[1].set('localeIdentifier', 'fr-FR'); installations[1].set('localeIdentifier', 'fr-FR');
installations[2].set('localeIdentifier', 'en-US'); installations[2].set('localeIdentifier', 'en-US');
return Parse.Object.saveAll(installations);
}) spyOn(pushAdapter, 'send').and.callThrough();
.then(() => { await reconfigureServer({
return pushController.sendPush(payload, where, config, auth); push: { adapter: pushAdapter },
})
.then(() => {
// Wait so the push is completed.
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
}); });
}) await Parse.Object.saveAll(installations);
.then(() => { const pushStatusId = await sendPush(payload, where, config, auth);
await pushCompleted(pushStatusId);
expect(pushAdapter.send.calls.count()).toBe(2); expect(pushAdapter.send.calls.count()).toBe(2);
const firstCall = pushAdapter.send.calls.first(); const firstCall = pushAdapter.send.calls.first();
expect(firstCall.args[0].data).toEqual({ expect(firstCall.args[0].data).toEqual({
@@ -1278,12 +1054,9 @@ describe('PushController', () => {
}); });
expect(lastCall.args[1].length).toBe(2); // 2 installations expect(lastCall.args[1].length).toBe(2); // 2 installations
// No installation is in es so only 1 call for fr, and another for default // No installation is in es so only 1 call for fr, and another for default
done();
})
.catch(done.fail);
}); });
it('should update audiences', done => { it('should update audiences', async () => {
const pushAdapter = { const pushAdapter = {
send: function (body, installations) { send: function (body, installations) {
return successfulTransmissions(body, installations); return successfulTransmissions(body, installations);
@@ -1297,20 +1070,12 @@ describe('PushController', () => {
const auth = { const auth = {
isMaster: true, isMaster: true,
}; };
let audienceId = null; let audienceId = null;
const now = new Date(); const now = new Date();
let timesUsed = 0; let timesUsed = 0;
const where = { const where = {
deviceType: 'ios', deviceType: 'ios',
}; };
spyOn(pushAdapter, 'send').and.callThrough();
const pushController = new PushController();
reconfigureServer({
push: { adapter: pushAdapter },
})
.then(() => {
const installations = []; const installations = [];
while (installations.length != 5) { while (installations.length != 5) {
const installation = new Parse.Object('_Installation'); const installation = new Parse.Object('_Installation');
@@ -1321,9 +1086,12 @@ describe('PushController', () => {
installation.set('deviceType', 'ios'); installation.set('deviceType', 'ios');
installations.push(installation); installations.push(installation);
} }
return Parse.Object.saveAll(installations); spyOn(pushAdapter, 'send').and.callThrough();
}) await reconfigureServer({
.then(() => { push: { adapter: pushAdapter },
});
await Parse.Object.saveAll(installations);
// Create an audience // Create an audience
const query = new Parse.Query('_Audience'); const query = new Parse.Query('_Audience');
query.descending('createdAt'); query.descending('createdAt');
@@ -1340,49 +1108,30 @@ describe('PushController', () => {
const audience = new Parse.Object('_Audience'); const audience = new Parse.Object('_Audience');
audience.set('name', 'testAudience'); audience.set('name', 'testAudience');
audience.set('query', JSON.stringify(where)); audience.set('query', JSON.stringify(where));
return Parse.Object.saveAll(audience).then(() => { await Parse.Object.saveAll(audience);
return query.find({ useMasterKey: true }).then(parseResults); await query.find({ useMasterKey: true }).then(parseResults);
});
})
.then(() => {
const body = { const body = {
data: { alert: 'hello' }, data: { alert: 'hello' },
audience_id: audienceId, audience_id: audienceId,
}; };
return pushController.sendPush(body, where, config, auth); const pushStatusId = await sendPush(body, where, config, auth);
}) await pushCompleted(pushStatusId);
.then(() => {
// Wait so the push is completed.
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, 1000);
});
})
.then(() => {
expect(pushAdapter.send.calls.count()).toBe(1); expect(pushAdapter.send.calls.count()).toBe(1);
const firstCall = pushAdapter.send.calls.first(); const firstCall = pushAdapter.send.calls.first();
expect(firstCall.args[0].data).toEqual({ expect(firstCall.args[0].data).toEqual({
alert: 'hello', alert: 'hello',
}); });
expect(firstCall.args[1].length).toBe(5); expect(firstCall.args[1].length).toBe(5);
})
.then(() => {
// Get the audience we used above. // Get the audience we used above.
const query = new Parse.Query('_Audience'); const audienceQuery = new Parse.Query('_Audience');
query.equalTo('objectId', audienceId); audienceQuery.equalTo('objectId', audienceId);
return query.find({ useMasterKey: true }); const results = await audienceQuery.find({ useMasterKey: true });
})
.then(results => { expect(results[0].get('query')).toBe(JSON.stringify(where));
const audience = results[0]; expect(results[0].get('timesUsed')).toBe(timesUsed + 1);
expect(audience.get('query')).toBe(JSON.stringify(where)); expect(results[0].get('lastUsed')).not.toBeLessThan(now);
expect(audience.get('timesUsed')).toBe(timesUsed + 1);
expect(audience.get('lastUsed')).not.toBeLessThan(now);
})
.then(() => {
done();
})
.catch(done.fail);
}); });
describe('pushTimeHasTimezoneComponent', () => { describe('pushTimeHasTimezoneComponent', () => {
@@ -1446,7 +1195,7 @@ describe('PushController', () => {
}); });
describe('Scheduling pushes in local time', () => { describe('Scheduling pushes in local time', () => {
it('should preserve the push time', done => { it('should preserve the push time', async () => {
const auth = { isMaster: true }; const auth = { isMaster: true };
const pushAdapter = { const pushAdapter = {
send(body, installations) { send(body, installations) {
@@ -1456,7 +1205,6 @@ describe('PushController', () => {
return ['ios']; return ['ios'];
}, },
}; };
const pushTime = '2017-09-06T17:14:01.048'; const pushTime = '2017-09-06T17:14:01.048';
let expectedHour = 17 + new Date(pushTime).getTimezoneOffset() / 60; let expectedHour = 17 + new Date(pushTime).getTimezoneOffset() / 60;
let day = '06'; let day = '06';
@@ -1464,43 +1212,24 @@ describe('PushController', () => {
expectedHour = expectedHour - 24; expectedHour = expectedHour - 24;
day = '07'; day = '07';
} }
const payload = {
reconfigureServer({
push: { adapter: pushAdapter },
scheduledPush: true,
})
.then(() => {
const config = Config.get(Parse.applicationId);
return new Promise((resolve, reject) => {
const pushController = new PushController();
pushController
.sendPush(
{
data: { data: {
alert: 'Hello World!', alert: 'Hello World!',
badge: 'Increment', badge: 'Increment',
}, },
push_time: pushTime, push_time: pushTime,
}, };
{}, await reconfigureServer({
config, push: { adapter: pushAdapter },
auth, scheduledPush: true,
resolve
)
.catch(reject);
}); });
}) const config = Config.get(Parse.applicationId);
.then(pushStatusId => { const pushStatusId = await sendPush(payload, {}, config, auth);
const q = new Parse.Query('_PushStatus'); const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
return q.get(pushStatusId, { useMasterKey: true });
})
.then(pushStatus => {
expect(pushStatus.get('status')).toBe('scheduled'); expect(pushStatus.get('status')).toBe('scheduled');
expect(pushStatus.get('pushTime')).toBe( expect(pushStatus.get('pushTime')).toBe(
`2017-09-${day}T${expectedHour.toString().padStart(2, '0')}:14:01.048` `2017-09-${day}T${expectedHour.toString().padStart(2, '0')}:14:01.048`
); );
})
.then(done, done.fail);
}); });
}); });
@@ -1579,47 +1308,32 @@ describe('PushController', () => {
}); });
describe('For immediate pushes', () => { describe('For immediate pushes', () => {
it('should transform the expiration_interval into an absolute time', done => { it('should transform the expiration_interval into an absolute time', async () => {
const now = new Date('2017-09-25T13:30:10.452Z'); const now = new Date('2017-09-25T13:30:10.452Z');
const payload = {
reconfigureServer({
push: { adapter: pushAdapter },
})
.then(
() =>
new Promise(resolve => {
pushController.sendPush(
{
data: { data: {
alert: 'immediate push', alert: 'immediate push',
}, },
expiration_interval: 20 * 60, // twenty minutes expiration_interval: 20 * 60, // twenty minutes
}, };
await reconfigureServer({
push: { adapter: pushAdapter },
});
const pushStatusId = await sendPush(
payload,
{}, {},
Config.get(Parse.applicationId), Config.get(Parse.applicationId),
auth, auth,
resolve,
now now
); );
}) const pushStatus = await Parse.Push.getPushStatus(pushStatusId);
)
.then(pushStatusId => {
const p = new Parse.Object('_PushStatus');
p.id = pushStatusId;
return p.fetch({ useMasterKey: true });
})
.then(pushStatus => {
expect(pushStatus.get('expiry')).toBeDefined('expiry must be set'); expect(pushStatus.get('expiry')).toBeDefined('expiry must be set');
expect(pushStatus.get('expiry')).toEqual( expect(pushStatus.get('expiry')).toEqual(new Date('2017-09-25T13:50:10.452Z').valueOf());
new Date('2017-09-25T13:50:10.452Z').valueOf()
);
expect(pushStatus.get('expiration_interval')).toBeDefined( expect(pushStatus.get('expiration_interval')).toBeDefined(
'expiration_interval must be defined' 'expiration_interval must be defined'
); );
expect(pushStatus.get('expiration_interval')).toBe(20 * 60); expect(pushStatus.get('expiration_interval')).toBe(20 * 60);
})
.then(done, done.fail);
}); });
}); });
}); });