@@ -17,15 +17,8 @@ import sinon from 'sinon';
1717import nock from 'nock' ;
1818
1919import { Webhooks } from '@octokit/webhooks' ;
20- import * as express from 'express' ;
21- import fs from 'fs' ;
2220import { Bootstrapper , HandlerFunction } from '../src/bootstrapper' ;
2321import { NoopTaskEnqueuer } from '../src/background/task-enqueuer' ;
24- import {
25- InstallationHandler ,
26- AppInstallation ,
27- InstalledRepository ,
28- } from '../src/installations' ;
2922import { GCFLogger } from '../src' ;
3023// eslint-disable-next-line node/no-extraneous-import
3124import { RequestError } from '@octokit/request-error' ;
@@ -34,89 +27,92 @@ import {GraphqlResponseError} from '@octokit/graphql';
3427import * as errorLoggingModule from '../src/logging/error-logging' ;
3528import AggregateError from 'aggregate-error' ;
3629import { ServiceUnavailable } from '../src/errors' ;
30+ import {
31+ mockRequest ,
32+ mockResponse ,
33+ mockRequestFromFixture ,
34+ MockInstallationHandler ,
35+ MockSecretLoader ,
36+ } from './helpers' ;
37+ import { RestoreFn } from 'mocked-env' ;
38+ import mockedEnv from 'mocked-env' ;
39+ import assert from 'assert' ;
40+ import { GoogleSecretLoader } from '../src/secrets/google-secret-loader' ;
3741
3842nock . disableNetConnect ( ) ;
39-
4043const sandbox = sinon . createSandbox ( ) ;
4144
42- function mockRequest ( body : object , headers : Record < string , any > ) {
43- const request = Object . create (
44- Object . getPrototypeOf ( express . request ) ,
45- Object . getOwnPropertyDescriptors ( express . request )
46- ) ;
47- request . rawBody = Buffer . from ( JSON . stringify ( body ) ) ;
48- request . body = body ;
49- request . headers = headers ;
50- return request ;
51- }
52- function mockRequestFromFixture ( fixture : string , headers : Record < string , any > ) {
53- const request = Object . create (
54- Object . getPrototypeOf ( express . request ) ,
55- Object . getOwnPropertyDescriptors ( express . request )
56- ) ;
57- const rawBody = fs . readFileSync ( fixture ) ;
58- request . rawBody = rawBody ;
59- request . body = JSON . parse ( rawBody . toString ( 'utf-8' ) ) ;
60- request . headers = headers ;
61- return request ;
62- }
63-
64- function mockResponse ( ) {
65- const response = { } as any ;
66- response . status = sandbox . stub ( ) . returns ( response ) ;
67- response . json = sandbox . stub ( ) . returns ( response ) ;
68- response . send = sandbox . stub ( ) . returns ( response ) ;
69- return response ;
70- }
71-
72- class MockInstallationHandler implements InstallationHandler {
73- private installations : AppInstallation [ ] = [ ] ;
74- private installedRepositoriesByInstallation : Map <
75- number ,
76- InstalledRepository [ ]
77- > = new Map ( ) ;
78-
79- reset ( ) {
80- this . installations = [ ] ;
81- this . installedRepositoriesByInstallation = new Map ( ) ;
82- }
83-
84- setInstallations ( installations : AppInstallation [ ] ) {
85- this . installations = installations ;
86- }
87-
88- setInstalledRepositories (
89- installationId : number ,
90- InstalledRepositories : InstalledRepository [ ]
91- ) {
92- this . installedRepositoriesByInstallation . set (
93- installationId ,
94- InstalledRepositories
95- ) ;
96- }
97-
98- async * eachInstallation ( ) : AsyncGenerator < AppInstallation , void , void > {
99- for ( const installation of this . installations ) {
100- yield installation ;
101- }
102- }
103- async * eachInstalledRepository (
104- installationId : number
105- ) : AsyncGenerator < InstalledRepository , void , void > {
106- const installedRepositories =
107- this . installedRepositoriesByInstallation . get ( installationId ) || [ ] ;
108- for ( const repo of installedRepositories ) {
109- yield repo ;
110- }
111- }
112- }
113-
11445describe ( 'Bootstrapper' , ( ) => {
46+ let restoreEnv : RestoreFn | null ;
11547 afterEach ( ( ) => {
11648 sandbox . restore ( ) ;
49+ if ( restoreEnv ) {
50+ restoreEnv ( ) ;
51+ restoreEnv = null ;
52+ }
11753 } ) ;
11854
119- describe ( 'load' , ( ) => { } ) ;
55+ describe ( 'load' , ( ) => {
56+ it ( 'requires a project id' , async ( ) => {
57+ await assert . rejects (
58+ async ( ) => {
59+ await Bootstrapper . load ( { } ) ;
60+ } ,
61+ e => {
62+ return ( e as Error ) . message . includes ( 'PROJECT_ID' ) ;
63+ }
64+ ) ;
65+ } ) ;
66+ it ( 'requires a bot name' , async ( ) => {
67+ await assert . rejects (
68+ async ( ) => {
69+ await Bootstrapper . load ( {
70+ projectId : 'my-project' ,
71+ } ) ;
72+ } ,
73+ e => {
74+ return ( e as Error ) . message . includes ( 'GCF_SHORT_FUNCTION_NAME' ) ;
75+ }
76+ ) ;
77+ } ) ;
78+ it ( 'requires a location' , async ( ) => {
79+ await assert . rejects (
80+ async ( ) => {
81+ await Bootstrapper . load ( {
82+ projectId : 'my-project' ,
83+ botName : 'my-bot-name' ,
84+ } ) ;
85+ } ,
86+ e => {
87+ return ( e as Error ) . message . includes ( 'GCF_LOCATION' ) ;
88+ }
89+ ) ;
90+ } ) ;
91+ it ( 'detects from env var' , async ( ) => {
92+ restoreEnv = mockedEnv ( {
93+ GCF_SHORT_FUNCTION_NAME : 'my-bot-name' ,
94+ GCF_LOCATION : 'my-location' ,
95+ PROJECT_ID : 'my-project' ,
96+ } ) ;
97+ const bootstrapper = await Bootstrapper . load ( {
98+ secretLoader : new MockSecretLoader ( ) ,
99+ } ) ;
100+ assert . ok ( bootstrapper ) ;
101+ } ) ;
102+ it ( 'loads secrets from Secret Manager' , async ( ) => {
103+ sandbox . stub ( GoogleSecretLoader . prototype , 'load' ) . resolves ( {
104+ privateKey : 'my-private-key' ,
105+ webhookSecret : 'my-webhook-secret' ,
106+ appId : '123456' ,
107+ } ) ;
108+ const bootstrapper = await Bootstrapper . load ( {
109+ projectId : 'my-project' ,
110+ botName : 'my-bot-name' ,
111+ location : 'my-location' ,
112+ } ) ;
113+ assert . ok ( bootstrapper ) ;
114+ } ) ;
115+ } ) ;
120116
121117 describe ( 'handler' , ( ) => {
122118 describe ( 'webhooks' , async ( ) => {
0 commit comments