Skip to content

Commit c48e6ad

Browse files
authored
Add integration tests for Project Management service. (#418)
1 parent b232114 commit c48e6ad

File tree

2 files changed

+239
-0
lines changed

2 files changed

+239
-0
lines changed
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/*!
2+
* Copyright 2018 Google Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as chai from 'chai';
18+
import * as admin from '../../lib/index';
19+
import * as util from '../unit/utils';
20+
import { projectId } from './setup';
21+
22+
const APP_NAMESPACE_PREFIX = 'com.adminsdkintegrationtest.a';
23+
const APP_NAMESPACE_SUFFIX_LENGTH = 15;
24+
25+
const APP_DISPLAY_NAME_PREFIX = 'Created By Firebase AdminSDK Nodejs Integration Testing ';
26+
const APP_DISPLAY_NAME_SUFFIX_LENGTH = 15;
27+
28+
const SHA_256_HASH = 'aaaaccccaaaaccccaaaaccccaaaaccccaaaaccccaaaaccccaaaaccccaaaacccc';
29+
30+
const expect = chai.expect;
31+
32+
describe('admin.projectManagement', () => {
33+
34+
let androidApp: admin.projectManagement.AndroidApp;
35+
let iosApp: admin.projectManagement.IosApp;
36+
37+
before(() => {
38+
const androidPromise = ensureAndroidApp()
39+
.then((app) => {
40+
androidApp = app;
41+
return deleteAllShaCertificates(androidApp);
42+
});
43+
const iosPromise = ensureIosApp().then((app) => {
44+
iosApp = app;
45+
});
46+
47+
return Promise.all([androidPromise, iosPromise]);
48+
});
49+
50+
describe('listAndroidApps()', () => {
51+
it('successfully lists Android apps', () => {
52+
return admin.projectManagement().listAndroidApps().then((results) => {
53+
expect(results.length).to.be.at.least(1);
54+
expect(results[0].appId).to.equal(androidApp.appId);
55+
});
56+
});
57+
});
58+
59+
describe('listIosApps()', () => {
60+
it('successfully lists iOS apps', () => {
61+
return admin.projectManagement().listIosApps().then((results) => {
62+
expect(results.length).to.be.at.least(1);
63+
expect(results[0].appId).to.equal(iosApp.appId);
64+
});
65+
});
66+
});
67+
68+
describe('androidApp.getMetadata()', () => {
69+
it('successfully sets Android app\'s display name', () => {
70+
return androidApp.getMetadata().then((appMetadata) => {
71+
expect(appMetadata.displayName).to.include(APP_DISPLAY_NAME_PREFIX);
72+
expect(appMetadata.projectId).to.equal(projectId);
73+
expect(appMetadata.packageName).to.include(APP_NAMESPACE_PREFIX);
74+
});
75+
});
76+
});
77+
78+
describe('iosApp.getMetadata()', () => {
79+
it('successfully sets iOS app\'s display name', () => {
80+
return iosApp.getMetadata().then((appMetadata) => {
81+
expect(appMetadata.displayName).to.include(APP_DISPLAY_NAME_PREFIX);
82+
expect(appMetadata.projectId).to.equal(projectId);
83+
expect(appMetadata.bundleId).to.include(APP_NAMESPACE_PREFIX);
84+
});
85+
});
86+
});
87+
88+
describe('androidApp.setDisplayName()', () => {
89+
it('successfully sets Android app\'s display name', () => {
90+
const newDisplayName = generateUniqueAppDisplayName();
91+
return androidApp.setDisplayName(newDisplayName)
92+
.then(() => androidApp.getMetadata())
93+
.then((appMetadata) => {
94+
expect(appMetadata.displayName).to.equal(newDisplayName);
95+
});
96+
});
97+
});
98+
99+
describe('iosApp.setDisplayName()', () => {
100+
it('successfully sets iOS app\'s display name', () => {
101+
const newDisplayName = generateUniqueAppDisplayName();
102+
return iosApp.setDisplayName(newDisplayName)
103+
.then(() => iosApp.getMetadata())
104+
.then((appMetadata) => {
105+
expect(appMetadata.displayName).to.equal(newDisplayName);
106+
});
107+
});
108+
});
109+
110+
describe('androidApp.{get,add,delete}ShaCertificate()', () => {
111+
it('successfully gets, adds, and deletes SHA certificates', () => {
112+
// Steps:
113+
// 1. Check that this app has no certs.
114+
// 2. Add a cert to this app.
115+
// 3. Check that the cert was added successfully.
116+
// 4. Delete the cert we just created.
117+
// 5. Check that this app has no certs.
118+
return androidApp.getShaCertificates()
119+
.then((certs) => {
120+
expect(certs.length).to.equal(0);
121+
122+
const shaCertificate = admin.projectManagement().shaCertificate(SHA_256_HASH);
123+
return androidApp.addShaCertificate(shaCertificate);
124+
})
125+
.then(() => androidApp.getShaCertificates())
126+
.then((certs) => {
127+
expect(certs.length).to.equal(1);
128+
expect(certs[0].shaHash).to.equal(SHA_256_HASH);
129+
expect(certs[0].certType).to.equal('sha256');
130+
expect(certs[0].resourceName).to.not.be.empty;
131+
132+
return androidApp.deleteShaCertificate(certs[0]);
133+
})
134+
.then(() => androidApp.getShaCertificates())
135+
.then((certs) => {
136+
expect(certs.length).to.equal(0);
137+
});
138+
});
139+
});
140+
141+
describe('androidApp.getConfig()', () => {
142+
it('successfully gets the Android app\'s config', () => {
143+
return androidApp.getConfig().then((config) => {
144+
expect(config).is.not.empty;
145+
expect(config).includes(androidApp.appId);
146+
});
147+
});
148+
});
149+
150+
describe('iosApp.getConfig()', () => {
151+
it('successfully gets the iOS app\'s config', () => {
152+
return iosApp.getConfig().then((config) => {
153+
expect(config).is.not.empty;
154+
expect(config).includes(iosApp.appId);
155+
});
156+
});
157+
});
158+
});
159+
160+
/**
161+
* Ensures that an Android app owned by these integration tests exist. If not one will be created.
162+
*
163+
* @return {Promise<AndroidApp>} Android app owned by these integration tests.
164+
*/
165+
function ensureAndroidApp(): Promise<admin.projectManagement.AndroidApp> {
166+
return admin.projectManagement().listAndroidApps()
167+
.then((apps) => Promise.all(apps.map((app) => app.getMetadata())))
168+
.then((metadatas) => {
169+
const metadataOwnedByTest =
170+
metadatas.find((metadata) => isIntegrationTestApp(metadata.packageName));
171+
if (metadataOwnedByTest) {
172+
return admin.projectManagement().androidApp(metadataOwnedByTest.appId);
173+
}
174+
175+
// If no Android app owned by these integration tests was found, then create one.
176+
return admin.projectManagement()
177+
.createAndroidApp(generateUniqueAppNamespace(), generateUniqueAppDisplayName());
178+
});
179+
}
180+
181+
/**
182+
* Ensures that an iOS app owned by these integration tests exist. If not one will be created.
183+
*
184+
* @return {Promise<IosApp>} iOS app owned by these integration tests.
185+
*/
186+
function ensureIosApp(): Promise<admin.projectManagement.IosApp> {
187+
return admin.projectManagement().listIosApps()
188+
.then((apps) => Promise.all(apps.map((app) => app.getMetadata())))
189+
.then((metadatas) => {
190+
const metadataOwnedByTest =
191+
metadatas.find((metadata) => isIntegrationTestApp(metadata.bundleId));
192+
if (metadataOwnedByTest) {
193+
return admin.projectManagement().iosApp(metadataOwnedByTest.appId);
194+
}
195+
196+
// If no iOS app owned by these integration tests was found, then create one.
197+
return admin.projectManagement()
198+
.createIosApp(generateUniqueAppNamespace(), generateUniqueAppDisplayName());
199+
});
200+
}
201+
202+
/**
203+
* Deletes all SHA certificates from the specified Android app.
204+
*/
205+
function deleteAllShaCertificates(androidApp: admin.projectManagement.AndroidApp): Promise<void> {
206+
return androidApp.getShaCertificates()
207+
.then((shaCertificates: admin.projectManagement.ShaCertificate[]) => {
208+
return Promise.all(shaCertificates.map((cert) => androidApp.deleteShaCertificate(cert)));
209+
})
210+
.then(() => null);
211+
}
212+
213+
/**
214+
* @return {string} Dot-separated string that can be used as a unique package name or bundle ID.
215+
*/
216+
function generateUniqueAppNamespace() {
217+
return APP_NAMESPACE_PREFIX + util.generateRandomString(APP_NAMESPACE_SUFFIX_LENGTH);
218+
}
219+
220+
/**
221+
* @return {string} Dot-separated string that can be used as a unique app display name.
222+
*/
223+
function generateUniqueAppDisplayName() {
224+
return APP_DISPLAY_NAME_PREFIX + util.generateRandomString(APP_DISPLAY_NAME_SUFFIX_LENGTH);
225+
}
226+
227+
/**
228+
* @return {boolean} True if the specified appNamespace belongs to these integration tests.
229+
*/
230+
function isIntegrationTestApp(appNamespace: string): boolean {
231+
return (appNamespace.indexOf(APP_NAMESPACE_PREFIX) > -1);
232+
}

test/unit/utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ export function generateRandomAccessToken(): string {
6868
return 'access_token_' + _.random(999999999);
6969
}
7070

71+
/**
72+
* @return {string} A randomly generated alphanumeric string, of the specified length.
73+
*/
74+
export function generateRandomString(stringLength: number): string {
75+
return _.times(stringLength, () => _.random(35).toString(36)).join('');
76+
}
77+
7178
/**
7279
* Creates a mock HTTP response from the given data and parameters.
7380
*

0 commit comments

Comments
 (0)