Skip to content

Commit 4e526ab

Browse files
authored
Refactoring unit tests to reduce dependency on credentials (#431)
* Refactoring unit tests to reduce dependency on credentials * Fixing refresh token test * Adding missing return * Added a helper function for stubbing getToken() * Removed unused imports
1 parent d52d133 commit 4e526ab

14 files changed

+165
-209
lines changed

test/integration/project-management.spec.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17+
import * as _ from 'lodash';
1718
import * as chai from 'chai';
1819
import * as admin from '../../lib/index';
19-
import * as util from '../unit/utils';
2020
import { projectId } from './setup';
2121

2222
const APP_NAMESPACE_PREFIX = 'com.adminsdkintegrationtest.a';
@@ -224,14 +224,14 @@ function deleteAllShaCertificates(androidApp: admin.projectManagement.AndroidApp
224224
* @return {string} Dot-separated string that can be used as a unique package name or bundle ID.
225225
*/
226226
function generateUniqueAppNamespace() {
227-
return APP_NAMESPACE_PREFIX + util.generateRandomString(APP_NAMESPACE_SUFFIX_LENGTH);
227+
return APP_NAMESPACE_PREFIX + generateRandomString(APP_NAMESPACE_SUFFIX_LENGTH);
228228
}
229229

230230
/**
231231
* @return {string} Dot-separated string that can be used as a unique app display name.
232232
*/
233233
function generateUniqueAppDisplayName() {
234-
return APP_DISPLAY_NAME_PREFIX + util.generateRandomString(APP_DISPLAY_NAME_SUFFIX_LENGTH);
234+
return APP_DISPLAY_NAME_PREFIX + generateRandomString(APP_DISPLAY_NAME_SUFFIX_LENGTH);
235235
}
236236

237237
/**
@@ -240,3 +240,10 @@ function generateUniqueAppDisplayName() {
240240
function isIntegrationTestApp(appNamespace: string): boolean {
241241
return (appNamespace.indexOf(APP_NAMESPACE_PREFIX) > -1);
242242
}
243+
244+
/**
245+
* @return {string} A randomly generated alphanumeric string, of the specified length.
246+
*/
247+
function generateRandomString(stringLength: number): string {
248+
return _.times(stringLength, () => _.random(35).toString(36)).join('');
249+
}

test/unit/auth/auth-api-request.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import * as _ from 'lodash';
2020
import * as chai from 'chai';
21-
import * as nock from 'nock';
2221
import * as sinon from 'sinon';
2322
import * as sinonChai from 'sinon-chai';
2423
import * as chaiAsPromised from 'chai-as-promised';
@@ -722,8 +721,8 @@ describe('FIREBASE_AUTH_SIGN_UP_NEW_USER', () => {
722721

723722
describe('FirebaseAuthRequestHandler', () => {
724723
let mockApp: FirebaseApp;
725-
const mockedRequests: nock.Scope[] = [];
726724
let stubs: sinon.SinonStub[] = [];
725+
let getTokenStub: sinon.SinonStub;
727726
const mockAccessToken: string = utils.generateRandomAccessToken();
728727
const expectedHeaders: {[key: string]: string} = {
729728
'X-Client-Version': 'Node/Admin/<XXX_SDK_VERSION_XXX>',
@@ -739,11 +738,13 @@ describe('FirebaseAuthRequestHandler', () => {
739738
};
740739
};
741740

742-
before(() => utils.mockFetchAccessTokenRequests(mockAccessToken));
741+
before(() => {
742+
getTokenStub = utils.stubGetAccessToken(mockAccessToken);
743+
});
743744

744745
after(() => {
745746
stubs = [];
746-
nock.cleanAll();
747+
getTokenStub.restore();
747748
});
748749

749750
beforeEach(() => {
@@ -753,7 +754,6 @@ describe('FirebaseAuthRequestHandler', () => {
753754

754755
afterEach(() => {
755756
_.forEach(stubs, (stub) => stub.restore());
756-
_.forEach(mockedRequests, (mockedRequest) => mockedRequest.done());
757757
return mockApp.delete();
758758
});
759759

test/unit/auth/auth.spec.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import * as _ from 'lodash';
2020
import * as chai from 'chai';
21-
import * as nock from 'nock';
2221
import * as sinon from 'sinon';
2322
import * as sinonChai from 'sinon-chai';
2423
import * as chaiAsPromised from 'chai-as-promised';
@@ -155,17 +154,15 @@ function getDecodedSessionCookie(uid: string, authTime: Date): DecodedIdToken {
155154
describe('Auth', () => {
156155
let auth: Auth;
157156
let mockApp: FirebaseApp;
157+
let getTokenStub: sinon.SinonStub;
158158
let oldProcessEnv: NodeJS.ProcessEnv;
159159
let nullAccessTokenAuth: Auth;
160160
let malformedAccessTokenAuth: Auth;
161161
let rejectedPromiseAccessTokenAuth: Auth;
162162

163-
before(() => utils.mockFetchAccessTokenRequests());
164-
165-
after(() => nock.cleanAll());
166-
167163
beforeEach(() => {
168164
mockApp = mocks.app();
165+
getTokenStub = utils.stubGetAccessToken(undefined, mockApp);
169166
auth = new Auth(mockApp);
170167

171168
nullAccessTokenAuth = new Auth(mocks.appReturningNullAccessToken());
@@ -179,6 +176,7 @@ describe('Auth', () => {
179176
});
180177

181178
afterEach(() => {
179+
getTokenStub.restore();
182180
process.env = oldProcessEnv;
183181
return mockApp.delete();
184182
});

test/unit/auth/credential.spec.ts

Lines changed: 34 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ chai.use(chaiAsPromised);
4343

4444
const expect = chai.expect;
4545

46-
let TEST_GCLOUD_CREDENTIALS: any;
4746
const GCLOUD_CREDENTIAL_SUFFIX = 'gcloud/application_default_credentials.json';
4847
const GCLOUD_CREDENTIAL_PATH = path.resolve(process.env.HOME, '.config', GCLOUD_CREDENTIAL_SUFFIX);
4948
const MOCK_REFRESH_TOKEN_CONFIG = {
@@ -52,38 +51,6 @@ const MOCK_REFRESH_TOKEN_CONFIG = {
5251
type: 'authorized_user',
5352
refresh_token: 'test_token',
5453
};
55-
try {
56-
TEST_GCLOUD_CREDENTIALS = JSON.parse(fs.readFileSync(GCLOUD_CREDENTIAL_PATH).toString());
57-
} catch (error) {
58-
// tslint:disable-next-line:no-console
59-
console.log(
60-
'WARNING: gcloud credentials not found. Run `gcloud beta auth application-default login`. ' +
61-
'Relevant tests will be skipped.',
62-
);
63-
}
64-
65-
/**
66-
* Logs a warning and returns true if no gcloud credentials are found, meaning the test which calls
67-
* this will be skipped.
68-
*
69-
* The only thing that should ever skip these tests is continuous integration. When developing
70-
* locally, these tests should be run.
71-
*
72-
* @return {boolean} Whether or not the caller should skip the current test.
73-
*/
74-
const skipAndLogWarningIfNoGcloud = () => {
75-
if (typeof TEST_GCLOUD_CREDENTIALS === 'undefined') {
76-
// tslint:disable-next-line:no-console
77-
console.log(
78-
'WARNING: Test being skipped because gcloud credentials not found. Run `gcloud beta auth ' +
79-
'application-default login`.',
80-
);
81-
82-
return true;
83-
}
84-
85-
return false;
86-
};
8754

8855
const ONE_HOUR_IN_SECONDS = 60 * 60;
8956
const FIVE_MINUTES_IN_SECONDS = 5 * 60;
@@ -92,17 +59,32 @@ const FIVE_MINUTES_IN_SECONDS = 5 * 60;
9259
describe('Credential', () => {
9360
let mockCertificateObject: any;
9461
let oldProcessEnv: NodeJS.ProcessEnv;
62+
let getTokenScope: nock.Scope;
63+
let mockedRequests: nock.Scope[] = [];
64+
65+
before(() => {
66+
getTokenScope = nock('https://accounts.google.com')
67+
.persist()
68+
.post('/o/oauth2/token')
69+
.reply(200, {
70+
access_token: utils.generateRandomAccessToken(),
71+
token_type: 'Bearer',
72+
expires_in: 3600,
73+
}, {
74+
'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
75+
});
76+
});
9577

96-
before(() => utils.mockFetchAccessTokenRequests());
97-
98-
after(() => nock.cleanAll());
78+
after(() => getTokenScope.done());
9979

10080
beforeEach(() => {
10181
mockCertificateObject = _.clone(mocks.certificateObject);
10282
oldProcessEnv = process.env;
10383
});
10484

10585
afterEach(() => {
86+
_.forEach(mockedRequests, (mockedRequest) => mockedRequest.done());
87+
mockedRequests = [];
10688
process.env = oldProcessEnv;
10789
});
10890

@@ -289,11 +271,18 @@ describe('Credential', () => {
289271
});
290272

291273
it('should create access tokens', () => {
292-
if (skipAndLogWarningIfNoGcloud()) {
293-
return;
294-
}
274+
const scope = nock('https://www.googleapis.com')
275+
.post('/oauth2/v4/token')
276+
.reply(200, {
277+
access_token: 'token',
278+
token_type: 'Bearer',
279+
expires_in: 60 * 60,
280+
}, {
281+
'cache-control': 'no-cache, no-store, max-age=0, must-revalidate',
282+
});
283+
mockedRequests.push(scope);
295284

296-
const c = new RefreshTokenCredential(TEST_GCLOUD_CREDENTIALS);
285+
const c = new RefreshTokenCredential(mocks.refreshToken);
297286
return c.getAccessToken().then((token) => {
298287
expect(token.access_token).to.be.a('string').and.to.not.be.empty;
299288
expect(token.expires_in).to.greaterThan(FIVE_MINUTES_IN_SECONDS);
@@ -328,16 +317,12 @@ describe('Credential', () => {
328317
});
329318

330319
describe('ApplicationDefaultCredential', () => {
331-
let credPath: string;
332320
let fsStub: sinon.SinonStub;
333321

334-
beforeEach(() => credPath = process.env.GOOGLE_APPLICATION_CREDENTIALS);
335-
336322
afterEach(() => {
337323
if (fsStub) {
338324
fsStub.restore();
339325
}
340-
process.env.GOOGLE_APPLICATION_CREDENTIALS = credPath;
341326
});
342327

343328
it('should return a CertCredential with GOOGLE_APPLICATION_CREDENTIALS set', () => {
@@ -370,10 +355,13 @@ describe('Credential', () => {
370355
});
371356

372357
it('should return a RefreshTokenCredential with gcloud login', () => {
373-
if (skipAndLogWarningIfNoGcloud()) {
358+
if (!fs.existsSync(GCLOUD_CREDENTIAL_PATH)) {
359+
// tslint:disable-next-line:no-console
360+
console.log(
361+
'WARNING: Test being skipped because gcloud credentials not found. Run `gcloud beta auth ' +
362+
'application-default login`.');
374363
return;
375364
}
376-
377365
delete process.env.GOOGLE_APPLICATION_CREDENTIALS;
378366
expect((new ApplicationDefaultCredential()).getCredential()).to.be.an.instanceof(RefreshTokenCredential);
379367
});

test/unit/auth/token-generator.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import * as chai from 'chai';
2222
import * as sinon from 'sinon';
2323
import * as sinonChai from 'sinon-chai';
2424
import * as chaiAsPromised from 'chai-as-promised';
25-
import * as nock from 'nock';
2625

2726
import * as mocks from '../../resources/mocks';
2827
import {FirebaseTokenGenerator, ServiceAccountSigner, IAMSigner} from '../../../src/auth/token-generator';
@@ -106,20 +105,17 @@ describe('CryptoSigner', () => {
106105

107106
describe('IAMSigner', () => {
108107
let mockApp: FirebaseApp;
108+
let getTokenStub: sinon.SinonStub;
109109
const mockAccessToken: string = utils.generateRandomAccessToken();
110110

111-
before(() => {
112-
utils.mockFetchAccessTokenRequests(mockAccessToken);
113-
});
114-
115-
after(() => nock.cleanAll());
116-
117111
beforeEach(() => {
118112
mockApp = mocks.app();
113+
getTokenStub = utils.stubGetAccessToken(mockAccessToken, mockApp);
119114
return mockApp.INTERNAL.getToken();
120115
});
121116

122117
afterEach(() => {
118+
getTokenStub.restore();
123119
return mockApp.delete();
124120
});
125121

0 commit comments

Comments
 (0)