| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | // Imports
 | 
					
						
							|  |  |  | import * as http from 'http'; | 
					
						
							|  |  |  | import * as supertest from 'supertest'; | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  | import {CircleCiApi} from '../../lib/common/circle-ci-api'; | 
					
						
							|  |  |  | import {GithubApi} from '../../lib/common/github-api'; | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | import {GithubPullRequests} from '../../lib/common/github-pull-requests'; | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  | import {GithubTeams} from '../../lib/common/github-teams'; | 
					
						
							| 
									
										
										
										
											2018-08-27 18:07:25 +03:00
										 |  |  | import {Logger} from '../../lib/common/utils'; | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  | import {BuildCreator} from '../../lib/preview-server/build-creator'; | 
					
						
							|  |  |  | import {ChangedPrVisibilityEvent, CreatedBuildEvent} from '../../lib/preview-server/build-events'; | 
					
						
							|  |  |  | import {BuildRetriever, GithubInfo} from '../../lib/preview-server/build-retriever'; | 
					
						
							|  |  |  | import {BuildVerifier} from '../../lib/preview-server/build-verifier'; | 
					
						
							|  |  |  | import {PreviewServerConfig, PreviewServerFactory} from '../../lib/preview-server/preview-server-factory'; | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | interface CircleCiWebHookPayload { | 
					
						
							|  |  |  |   payload: { | 
					
						
							|  |  |  |     build_num: number; | 
					
						
							|  |  |  |     build_parameters: { | 
					
						
							|  |  |  |       CIRCLE_JOB: string; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Tests
 | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  | describe('PreviewServerFactory', () => { | 
					
						
							|  |  |  |   const defaultConfig: PreviewServerConfig = { | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     buildArtifactPath: 'artifact/path.zip', | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     buildsDir: 'builds/dir', | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     circleCiToken: 'CIRCLE_CI_TOKEN', | 
					
						
							| 
									
										
										
										
											2017-03-02 00:04:03 +02:00
										 |  |  |     domainName: 'domain.name', | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     downloadSizeLimit: 999, | 
					
						
							|  |  |  |     downloadsDir: '/tmp/aio-create-builds', | 
					
						
							|  |  |  |     githubOrg: 'organisation', | 
					
						
							|  |  |  |     githubRepo: 'repo', | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     githubTeamSlugs: ['team1', 'team2'], | 
					
						
							|  |  |  |     githubToken: '12345', | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     significantFilesPattern: '^(?:aio|packages)\\/(?!.*[._]spec\\.[jt]s$)', | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |     trustedPrLabel: 'trusted: pr-label', | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  |   let loggerErrorSpy: jasmine.Spy; | 
					
						
							| 
									
										
										
										
											2018-08-27 18:07:25 +03:00
										 |  |  |   let loggerInfoSpy: jasmine.Spy; | 
					
						
							|  |  |  |   let loggerLogSpy: jasmine.Spy; | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Helpers
 | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |   const createPreviewServer = (partialConfig: Partial<PreviewServerConfig> = {}) => | 
					
						
							|  |  |  |     PreviewServerFactory.create({...defaultConfig, ...partialConfig}); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-12 15:39:16 +01:00
										 |  |  |   beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  |     loggerErrorSpy = spyOn(Logger.prototype, 'error'); | 
					
						
							| 
									
										
										
										
											2018-08-27 18:07:25 +03:00
										 |  |  |     loggerInfoSpy = spyOn(Logger.prototype, 'info'); | 
					
						
							|  |  |  |     loggerLogSpy = spyOn(Logger.prototype, 'log'); | 
					
						
							| 
									
										
										
										
											2018-05-12 15:39:16 +01:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   describe('create()', () => { | 
					
						
							|  |  |  |     let usfCreateMiddlewareSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       usfCreateMiddlewareSpy = spyOn(PreviewServerFactory, 'createMiddleware').and.callThrough(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-02 00:04:03 +02:00
										 |  |  |     it('should throw if \'buildsDir\' is missing or empty', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       expect(() => createPreviewServer({buildsDir: ''})). | 
					
						
							| 
									
										
										
										
											2017-03-02 00:04:03 +02:00
										 |  |  |         toThrowError('Missing or empty required parameter \'buildsDir\'!'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should throw if \'domainName\' is missing or empty', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       expect(() => createPreviewServer({domainName: ''})). | 
					
						
							| 
									
										
										
										
											2017-03-02 00:04:03 +02:00
										 |  |  |         toThrowError('Missing or empty required parameter \'domainName\'!'); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     it('should throw if \'githubToken\' is missing or empty', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       expect(() => createPreviewServer({githubToken: ''})). | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |         toThrowError('Missing or empty required parameter \'githubToken\'!'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     it('should throw if \'githubOrg\' is missing or empty', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       expect(() => createPreviewServer({githubOrg: ''})). | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         toThrowError('Missing or empty required parameter \'githubOrg\'!'); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     it('should throw if \'githubTeamSlugs\' is missing or empty', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       expect(() => createPreviewServer({githubTeamSlugs: []})). | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |         toThrowError('Missing or empty required parameter \'allowedTeamSlugs\'!'); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     it('should throw if \'githubRepo\' is missing or empty', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       expect(() => createPreviewServer({githubRepo: ''})). | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         toThrowError('Missing or empty required parameter \'githubRepo\'!'); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |     it('should throw if \'trustedPrLabel\' is missing or empty', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       expect(() => createPreviewServer({trustedPrLabel: ''})). | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |         toThrowError('Missing or empty required parameter \'trustedPrLabel\'!'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     it('should return an http.Server', () => { | 
					
						
							|  |  |  |       const httpCreateServerSpy = spyOn(http, 'createServer').and.callThrough(); | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       const server = createPreviewServer(); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       expect(server).toBe(httpCreateServerSpy.calls.mostRecent().returnValue); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     it('should create and use an appropriate BuildCreator', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       const usfCreateBuildCreatorSpy = spyOn(PreviewServerFactory, 'createBuildCreator').and.callThrough(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       createPreviewServer(); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       const buildRetriever = jasmine.any(BuildRetriever); | 
					
						
							|  |  |  |       const buildVerifier = jasmine.any(BuildVerifier); | 
					
						
							|  |  |  |       const prs = jasmine.any(GithubPullRequests); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       const buildCreator: BuildCreator = usfCreateBuildCreatorSpy.calls.mostRecent().returnValue; | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       expect(usfCreateMiddlewareSpy).toHaveBeenCalledWith(buildRetriever, buildVerifier, buildCreator, defaultConfig); | 
					
						
							|  |  |  |       expect(usfCreateBuildCreatorSpy).toHaveBeenCalledWith(prs, 'builds/dir', 'domain.name'); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should create and use an appropriate middleware', () => { | 
					
						
							|  |  |  |       const httpCreateServerSpy = spyOn(http, 'createServer').and.callThrough(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       createPreviewServer(); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       const buildRetriever = jasmine.any(BuildRetriever); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       const buildVerifier = jasmine.any(BuildVerifier); | 
					
						
							|  |  |  |       const buildCreator = jasmine.any(BuildCreator); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       expect(usfCreateMiddlewareSpy).toHaveBeenCalledWith(buildRetriever, buildVerifier, buildCreator, defaultConfig); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:05 +03:00
										 |  |  |       const middleware = usfCreateMiddlewareSpy.calls.mostRecent().returnValue; | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       expect(httpCreateServerSpy).toHaveBeenCalledWith(middleware); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should log the server address info on \'listening\'', () => { | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       const server = createPreviewServer(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       server.address = () => ({address: 'foo', family: '', port: 1337}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-27 18:07:25 +03:00
										 |  |  |       expect(loggerInfoSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       server.emit('listening'); | 
					
						
							| 
									
										
										
										
											2018-08-27 18:07:25 +03:00
										 |  |  |       expect(loggerInfoSpy).toHaveBeenCalledWith('Up and running (and listening on foo:1337)...'); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Protected methods
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |   describe('createBuildCreator()', () => { | 
					
						
							|  |  |  |     let buildCreator: BuildCreator; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       const api = new GithubApi(defaultConfig.githubToken); | 
					
						
							|  |  |  |       const prs = new GithubPullRequests(api, defaultConfig.githubOrg, defaultConfig.githubRepo); | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       buildCreator = PreviewServerFactory.createBuildCreator(prs, defaultConfig.buildsDir, defaultConfig.domainName); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     it('should pass the \'buildsDir\' to the BuildCreator', () => { | 
					
						
							|  |  |  |       expect((buildCreator as any).buildsDir).toBe('builds/dir'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |     describe('on \'build.created\'', () => { | 
					
						
							|  |  |  |       let prsAddCommentSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment')); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |       it('should post a comment on GitHub for public previews', () => { | 
					
						
							|  |  |  |         const commentBody = 'You can preview 1234567890 at https://pr42-1234567890.domain.name/.'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890', isPublic: true}); | 
					
						
							|  |  |  |         expect(prsAddCommentSpy).toHaveBeenCalledWith(42, commentBody); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not post a comment on GitHub for non-public previews', () => { | 
					
						
							|  |  |  |         buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890', isPublic: false}); | 
					
						
							|  |  |  |         expect(prsAddCommentSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     describe('on \'pr.changedVisibility\'', () => { | 
					
						
							|  |  |  |       let prsAddCommentSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should post a comment on GitHub (for all SHAs) for PRs made public', () => { | 
					
						
							|  |  |  |         const commentBody = 'You can preview 12345 at https://pr42-12345.domain.name/.\n' + | 
					
						
							|  |  |  |                             'You can preview 67890 at https://pr42-67890.domain.name/.'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: ['12345', '67890'], isPublic: true}); | 
					
						
							|  |  |  |         expect(prsAddCommentSpy).toHaveBeenCalledWith(42, commentBody); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not post a comment on GitHub if no SHAs were affected', () => { | 
					
						
							|  |  |  |         buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: [], isPublic: true}); | 
					
						
							|  |  |  |         expect(prsAddCommentSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should not post a comment on GitHub for PRs made non-public', () => { | 
					
						
							|  |  |  |         buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: ['12345', '67890'], isPublic: false}); | 
					
						
							|  |  |  |         expect(prsAddCommentSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     it('should pass the correct parameters to GithubPullRequests', () => { | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       const prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |       buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890', isPublic: true}); | 
					
						
							|  |  |  |       buildCreator.emit(ChangedPrVisibilityEvent.type, {pr: 42, shas: ['12345', '67890'], isPublic: true}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const allCalls = prsAddCommentSpy.calls.all(); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       const prs: GithubPullRequests = allCalls[0].object; | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |       expect(prsAddCommentSpy).toHaveBeenCalledTimes(2); | 
					
						
							|  |  |  |       expect(prs).toBe(allCalls[1].object); | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |       expect(prs).toBeInstanceOf(GithubPullRequests); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       expect(prs.repoSlug).toBe('organisation/repo'); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |   describe('createMiddleware()', () => { | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     let buildRetriever: BuildRetriever; | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |     let buildVerifier: BuildVerifier; | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     let buildCreator: BuildCreator; | 
					
						
							|  |  |  |     let agent: supertest.SuperTest<supertest.Test>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       const circleCiApi = new CircleCiApi(defaultConfig.githubOrg, defaultConfig.githubRepo, | 
					
						
							|  |  |  |                                           defaultConfig.circleCiToken); | 
					
						
							|  |  |  |       const githubApi = new GithubApi(defaultConfig.githubToken); | 
					
						
							|  |  |  |       const prs = new GithubPullRequests(githubApi, defaultConfig.githubOrg, defaultConfig.githubRepo); | 
					
						
							|  |  |  |       const teams = new GithubTeams(githubApi, defaultConfig.githubOrg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       buildRetriever = new BuildRetriever(circleCiApi, defaultConfig.downloadSizeLimit, defaultConfig.downloadsDir); | 
					
						
							|  |  |  |       buildVerifier = new BuildVerifier(prs, teams, defaultConfig.githubTeamSlugs, defaultConfig.trustedPrLabel); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       buildCreator = new BuildCreator(defaultConfig.buildsDir); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-15 13:47:45 +01:00
										 |  |  |       const middleware = PreviewServerFactory.createMiddleware(buildRetriever, buildVerifier, buildCreator, | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |                                                                defaultConfig); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       agent = supertest.agent(middleware); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     describe('GET /health-check', () => { | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 200', async () => { | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await Promise.all([ | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |           agent.get('/health-check').expect(200), | 
					
						
							|  |  |  |           agent.get('/health-check/').expect(200), | 
					
						
							|  |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 404 for non-GET requests', async () => { | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await Promise.all([ | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |           agent.put('/health-check').expect(404), | 
					
						
							|  |  |  |           agent.post('/health-check').expect(404), | 
					
						
							|  |  |  |           agent.patch('/health-check').expect(404), | 
					
						
							|  |  |  |           agent.delete('/health-check').expect(404), | 
					
						
							|  |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 404 if the path does not match exactly', async () => { | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await Promise.all([ | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |           agent.get('/health-check/foo').expect(404), | 
					
						
							|  |  |  |           agent.get('/health-check-foo').expect(404), | 
					
						
							|  |  |  |           agent.get('/health-checknfoo').expect(404), | 
					
						
							|  |  |  |           agent.get('/foo/health-check').expect(404), | 
					
						
							|  |  |  |           agent.get('/foo-health-check').expect(404), | 
					
						
							|  |  |  |           agent.get('/foonhealth-check').expect(404), | 
					
						
							|  |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     describe('GET /can-have-public-preview/<pr>', () => { | 
					
						
							|  |  |  |       const baseUrl = '/can-have-public-preview'; | 
					
						
							|  |  |  |       const pr = 777; | 
					
						
							|  |  |  |       const url = `${baseUrl}/${pr}`; | 
					
						
							|  |  |  |       let bvGetPrIsTrustedSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let bvGetSignificantFilesChangedSpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bvGetPrIsTrustedSpy = spyOn(buildVerifier, 'getPrIsTrusted').and.resolveTo(true); | 
					
						
							|  |  |  |         bvGetSignificantFilesChangedSpy = spyOn(buildVerifier, 'getSignificantFilesChanged').and.resolveTo(true); | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should respond with 404 for non-GET requests', async () => { | 
					
						
							|  |  |  |         await Promise.all([ | 
					
						
							|  |  |  |           agent.put(url).expect(404), | 
					
						
							|  |  |  |           agent.post(url).expect(404), | 
					
						
							|  |  |  |           agent.patch(url).expect(404), | 
					
						
							|  |  |  |           agent.delete(url).expect(404), | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should respond with 404 if the path does not match exactly', async () => { | 
					
						
							|  |  |  |         await Promise.all([ | 
					
						
							|  |  |  |           agent.get('/can-have-public-preview/42/foo').expect(404), | 
					
						
							|  |  |  |           agent.get('/can-have-public-preview-foo/42').expect(404), | 
					
						
							|  |  |  |           agent.get('/can-have-public-previewnfoo/42').expect(404), | 
					
						
							|  |  |  |           agent.get('/foo/can-have-public-preview/42').expect(404), | 
					
						
							|  |  |  |           agent.get('/foo-can-have-public-preview/42').expect(404), | 
					
						
							|  |  |  |           agent.get('/fooncan-have-public-preview/42').expect(404), | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should respond appropriately if the PR did not touch any significant files', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bvGetSignificantFilesChangedSpy.and.resolveTo(false); | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const expectedResponse = {canHavePublicPreview: false, reason: 'No significant files touched.'}; | 
					
						
							|  |  |  |         const expectedLog = `PR:${pr} - Cannot have a public preview, because it did not touch any significant files.`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await agent.get(url).expect(200, expectedResponse); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(bvGetSignificantFilesChangedSpy).toHaveBeenCalledWith(pr, jasmine.any(RegExp)); | 
					
						
							|  |  |  |         expect(bvGetPrIsTrustedSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(loggerLogSpy).toHaveBeenCalledWith(expectedLog); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should respond appropriately if the PR is not automatically verifiable as "trusted"', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bvGetPrIsTrustedSpy.and.resolveTo(false); | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         const expectedResponse = {canHavePublicPreview: false, reason: 'Not automatically verifiable as "trusted".'}; | 
					
						
							|  |  |  |         const expectedLog = | 
					
						
							|  |  |  |           `PR:${pr} - Cannot have a public preview, because not automatically verifiable as "trusted".`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await agent.get(url).expect(200, expectedResponse); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(bvGetSignificantFilesChangedSpy).toHaveBeenCalledWith(pr, jasmine.any(RegExp)); | 
					
						
							|  |  |  |         expect(bvGetPrIsTrustedSpy).toHaveBeenCalledWith(pr); | 
					
						
							|  |  |  |         expect(loggerLogSpy).toHaveBeenCalledWith(expectedLog); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should respond appropriately if the PR can have a preview', async () => { | 
					
						
							|  |  |  |         const expectedResponse = {canHavePublicPreview: true, reason: null}; | 
					
						
							|  |  |  |         const expectedLog = `PR:${pr} - Can have a public preview.`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await agent.get(url).expect(200, expectedResponse); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         expect(bvGetSignificantFilesChangedSpy).toHaveBeenCalledWith(pr, jasmine.any(RegExp)); | 
					
						
							|  |  |  |         expect(bvGetPrIsTrustedSpy).toHaveBeenCalledWith(pr); | 
					
						
							|  |  |  |         expect(loggerLogSpy).toHaveBeenCalledWith(expectedLog); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should respond with error if `getSignificantFilesChanged()` fails', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bvGetSignificantFilesChangedSpy.and.rejectWith('getSignificantFilesChanged error'); | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         await agent.get(url).expect(500, 'getSignificantFilesChanged error'); | 
					
						
							|  |  |  |         expect(loggerErrorSpy).toHaveBeenCalledWith('Previewability check error', 'getSignificantFilesChanged error'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       it('should respond with error if `getPrIsTrusted()` fails', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bvGetPrIsTrustedSpy.and.throwError('getPrIsTrusted error'); | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         await agent.get(url).expect(500, 'getPrIsTrusted error'); | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         expect(loggerErrorSpy).toHaveBeenCalledWith('Previewability check error', new Error('getPrIsTrusted error')); | 
					
						
							| 
									
										
										
										
											2018-08-26 00:29:14 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     describe('POST /circle-build', () => { | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       let getGithubInfoSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let getSignificantFilesChangedSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let downloadBuildArtifactSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let getPrIsTrustedSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let createBuildSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let IS_PUBLIC: boolean; | 
					
						
							|  |  |  |       let BUILD_INFO: GithubInfo; | 
					
						
							|  |  |  |       let AFFECTS_SIGNIFICANT_FILES: boolean; | 
					
						
							|  |  |  |       let BASIC_PAYLOAD: CircleCiWebHookPayload; | 
					
						
							|  |  |  |       const URL = '/circle-build'; | 
					
						
							|  |  |  |       const BUILD_NUM = 12345; | 
					
						
							|  |  |  |       const PR = 777; | 
					
						
							|  |  |  |       const SHA = 'COMMIT'; | 
					
						
							|  |  |  |       const DOWNLOADED_ARTIFACT_PATH = 'downloads/777-COMMIT-build.zip'; | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       beforeEach(() => { | 
					
						
							|  |  |  |         IS_PUBLIC = true; | 
					
						
							|  |  |  |         BUILD_INFO  = { | 
					
						
							|  |  |  |           org: defaultConfig.githubOrg, | 
					
						
							|  |  |  |           pr: PR, | 
					
						
							|  |  |  |           repo: defaultConfig.githubRepo, | 
					
						
							|  |  |  |           sha: SHA, | 
					
						
							|  |  |  |           success: true, | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         BASIC_PAYLOAD = { payload: { build_num: BUILD_NUM, build_parameters: { CIRCLE_JOB: 'aio_preview' } } }; | 
					
						
							|  |  |  |         AFFECTS_SIGNIFICANT_FILES = true; | 
					
						
							|  |  |  |         getGithubInfoSpy = spyOn(buildRetriever, 'getGithubInfo') | 
					
						
							|  |  |  |           .and.callFake(() => Promise.resolve(BUILD_INFO)); | 
					
						
							|  |  |  |         getSignificantFilesChangedSpy = spyOn(buildVerifier, 'getSignificantFilesChanged') | 
					
						
							|  |  |  |           .and.callFake(() => Promise.resolve(AFFECTS_SIGNIFICANT_FILES)); | 
					
						
							|  |  |  |         downloadBuildArtifactSpy = spyOn(buildRetriever, 'downloadBuildArtifact') | 
					
						
							|  |  |  |           .and.callFake(() => Promise.resolve(DOWNLOADED_ARTIFACT_PATH)); | 
					
						
							|  |  |  |         getPrIsTrustedSpy = spyOn(buildVerifier, 'getPrIsTrusted') | 
					
						
							|  |  |  |           .and.callFake(() => Promise.resolve(IS_PUBLIC)); | 
					
						
							|  |  |  |         createBuildSpy = spyOn(buildCreator, 'create'); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 400 if the request body is not in the correct format', async () => { | 
					
						
							|  |  |  |         await Promise.all([ | 
					
						
							|  |  |  |           agent.post(URL).expect(400), | 
					
						
							|  |  |  |           agent.post(URL).send().expect(400), | 
					
						
							|  |  |  |           agent.post(URL).send({}).expect(400), | 
					
						
							|  |  |  |           agent.post(URL).send({ payload: {} }).expect(400), | 
					
						
							|  |  |  |           agent.post(URL).send({ payload: { build_num: -1 } }).expect(400), | 
					
						
							|  |  |  |           agent.post(URL).send({ payload: { build_num: 4000 } }).expect(400), | 
					
						
							|  |  |  |           agent.post(URL).send({ payload: { build_num: 4000, build_parameters: { } } }).expect(400), | 
					
						
							|  |  |  |           agent.post(URL).send({ payload: { build_num: 4000, build_parameters: { CIRCLE_JOB: '' } } }).expect(400), | 
					
						
							|  |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should create a preview if everything is good and the build succeeded', async () => { | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(201); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); | 
					
						
							|  |  |  |         expect(getSignificantFilesChangedSpy).toHaveBeenCalledWith(PR, jasmine.any(RegExp)); | 
					
						
							|  |  |  |         expect(downloadBuildArtifactSpy).toHaveBeenCalledWith(BUILD_NUM, PR, SHA, defaultConfig.buildArtifactPath); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).toHaveBeenCalledWith(PR); | 
					
						
							|  |  |  |         expect(createBuildSpy).toHaveBeenCalledWith(PR, SHA, DOWNLOADED_ARTIFACT_PATH, IS_PUBLIC); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 204 if the reported build is not the "AIO preview" job', async () => { | 
					
						
							|  |  |  |         BASIC_PAYLOAD.payload.build_parameters.CIRCLE_JOB = 'lint'; | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(204); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getSignificantFilesChangedSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2018-08-27 18:07:25 +03:00
										 |  |  |         expect(loggerLogSpy).toHaveBeenCalledWith( | 
					
						
							|  |  |  |           'Build:12345, Job:lint -', 'Skipping preview processing because this is not the "aio_preview" job.'); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         expect(downloadBuildArtifactSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(createBuildSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 204 if the build did not affect any significant files', async () => { | 
					
						
							|  |  |  |         AFFECTS_SIGNIFICANT_FILES = false; | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(204); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); | 
					
						
							|  |  |  |         expect(getSignificantFilesChangedSpy).toHaveBeenCalledWith(PR, jasmine.any(RegExp)); | 
					
						
							| 
									
										
										
										
											2018-08-27 18:07:25 +03:00
										 |  |  |         expect(loggerLogSpy).toHaveBeenCalledWith( | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |           'PR:777, Build:12345 - Skipping preview processing because this PR did not touch any significant files.'); | 
					
						
							|  |  |  |         expect(downloadBuildArtifactSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(createBuildSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-02-28 21:10:46 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 201 if the build is trusted', async () => { | 
					
						
							|  |  |  |         IS_PUBLIC = true; | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(201); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 202 if the build is not trusted', async () => { | 
					
						
							|  |  |  |         IS_PUBLIC = false; | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(202); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should not create a preview if the build was not successful', async () => { | 
					
						
							|  |  |  |         BUILD_INFO.success = false; | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(204); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); | 
					
						
							|  |  |  |         expect(downloadBuildArtifactSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(createBuildSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-06-19 01:15:07 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should fail if the CircleCI request fails', async () => { | 
					
						
							|  |  |  |         // Note it is important to put the `reject` into `and.callFake`;
 | 
					
						
							|  |  |  |         // If you just `and.returnValue` the rejected promise
 | 
					
						
							|  |  |  |         // then you get an "unhandled rejection" message in the console.
 | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         getGithubInfoSpy.and.rejectWith('Test Error'); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); | 
					
						
							|  |  |  |         expect(downloadBuildArtifactSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(createBuildSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should fail if the Github organisation of the build does not match the configured organisation', async () => { | 
					
						
							|  |  |  |         BUILD_INFO.org = 'bad'; | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD) | 
					
						
							|  |  |  |           .expect(500, `Invalid webhook: expected "githubOrg" property to equal "organisation" but got "bad".`); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should fail if the Github repo of the build does not match the configured repo', async () => { | 
					
						
							|  |  |  |         BUILD_INFO.repo = 'bad'; | 
					
						
							|  |  |  |         await agent.post(URL).send(BASIC_PAYLOAD) | 
					
						
							|  |  |  |           .expect(500, `Invalid webhook: expected "githubRepo" property to equal "repo" but got "bad".`); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should fail if the artifact fetch request fails', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         downloadBuildArtifactSpy.and.rejectWith('Test Error'); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); | 
					
						
							|  |  |  |         expect(downloadBuildArtifactSpy).toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(createBuildSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should fail if verifying the PR fails', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         getPrIsTrustedSpy.and.rejectWith('Test Error'); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); | 
					
						
							|  |  |  |         expect(downloadBuildArtifactSpy).toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(createBuildSpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should fail if creating the preview build fails', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         createBuildSpy.and.rejectWith('Test Error'); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         await agent.post(URL).send(BASIC_PAYLOAD).expect(500, 'Test Error'); | 
					
						
							|  |  |  |         expect(getGithubInfoSpy).toHaveBeenCalledWith(BUILD_NUM); | 
					
						
							|  |  |  |         expect(downloadBuildArtifactSpy).toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(getPrIsTrustedSpy).toHaveBeenCalled(); | 
					
						
							|  |  |  |         expect(createBuildSpy).toHaveBeenCalled(); | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |     describe('POST /pr-updated', () => { | 
					
						
							|  |  |  |       const pr = '9'; | 
					
						
							|  |  |  |       const url = '/pr-updated'; | 
					
						
							|  |  |  |       let bvGetPrIsTrustedSpy: jasmine.Spy; | 
					
						
							|  |  |  |       let bcUpdatePrVisibilitySpy: jasmine.Spy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Helpers
 | 
					
						
							|  |  |  |       const createRequest = (num: number, action?: string) => | 
					
						
							|  |  |  |         agent.post(url).send({number: num, action}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       beforeEach(() => { | 
					
						
							|  |  |  |         bvGetPrIsTrustedSpy = spyOn(buildVerifier, 'getPrIsTrusted'); | 
					
						
							|  |  |  |         bcUpdatePrVisibilitySpy = spyOn(buildCreator, 'updatePrVisibility'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 404 for non-POST requests', async () => { | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await Promise.all([ | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |           agent.get(url).expect(404), | 
					
						
							|  |  |  |           agent.put(url).expect(404), | 
					
						
							|  |  |  |           agent.patch(url).expect(404), | 
					
						
							|  |  |  |           agent.delete(url).expect(404), | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 400 for requests without a payload', async () => { | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |         const responseBody = `Missing or empty 'number' field in request: POST ${url} {}`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const request1 = agent.post(url); | 
					
						
							|  |  |  |         const request2 = agent.post(url).send(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await Promise.all([ | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |           request1.expect(400, responseBody), | 
					
						
							|  |  |  |           request2.expect(400, responseBody), | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 400 for requests without a \'number\' field', async () => { | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |         const responseBodyPrefix = `Missing or empty 'number' field in request: POST ${url}`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const request1 = agent.post(url).send({}); | 
					
						
							|  |  |  |         const request2 = agent.post(url).send({number: null}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await Promise.all([ | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |           request1.expect(400, `${responseBodyPrefix} {}`), | 
					
						
							|  |  |  |           request2.expect(400, `${responseBodyPrefix} {"number":null}`), | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should call \'BuildVerifier#gtPrIsTrusted()\' with the correct arguments', async () => { | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await createRequest(+pr); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         expect(bvGetPrIsTrustedSpy).toHaveBeenCalledWith(9); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should propagate errors from BuildVerifier', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bvGetPrIsTrustedSpy.and.rejectWith('Test'); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await createRequest(+pr).expect(500, 'Test'); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         expect(bvGetPrIsTrustedSpy).toHaveBeenCalledWith(9); | 
					
						
							|  |  |  |         expect(bcUpdatePrVisibilitySpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should call \'BuildCreator#updatePrVisibility()\' with the correct arguments', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bvGetPrIsTrustedSpy. | 
					
						
							|  |  |  |           withArgs(24).and.resolveTo(false). | 
					
						
							|  |  |  |           withArgs(42).and.resolveTo(true); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await createRequest(24); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith(24, false); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await createRequest(42); | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         expect(bcUpdatePrVisibilitySpy).toHaveBeenCalledWith(42, true); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should propagate errors from BuildCreator', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |         bcUpdatePrVisibilitySpy.and.rejectWith('Test'); | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await createRequest(+pr).expect(500, 'Test'); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       describe('on success', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         it('should respond with 200 (action: undefined)', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |           bvGetPrIsTrustedSpy. | 
					
						
							|  |  |  |             withArgs(2).and.resolveTo(false). | 
					
						
							|  |  |  |             withArgs(4).and.resolveTo(true); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |           const reqs = [4, 2].map(num => createRequest(num).expect(200, http.STATUS_CODES[200])); | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |           await Promise.all(reqs); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         it('should respond with 200 (action: labeled)', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |           bvGetPrIsTrustedSpy. | 
					
						
							|  |  |  |             withArgs(2).and.resolveTo(false). | 
					
						
							|  |  |  |             withArgs(4).and.resolveTo(true); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |           const reqs = [4, 2].map(num => createRequest(num, 'labeled').expect(200, http.STATUS_CODES[200])); | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |           await Promise.all(reqs); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         it('should respond with 200 (action: unlabeled)', async () => { | 
					
						
							| 
									
										
										
										
											2020-05-02 16:14:14 +03:00
										 |  |  |           bvGetPrIsTrustedSpy. | 
					
						
							|  |  |  |             withArgs(2).and.resolveTo(false). | 
					
						
							|  |  |  |             withArgs(4).and.resolveTo(true); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |           const reqs = [4, 2].map(num => createRequest(num, 'unlabeled').expect(200, http.STATUS_CODES[200])); | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |           await Promise.all(reqs); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         it('should respond with 200 (and do nothing) if \'action\' implies no visibility change', async () => { | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |           const promises = ['foo', 'notlabeled']. | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |             map(action => createRequest(+pr, action).expect(200, http.STATUS_CODES[200])); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |           await Promise.all(promises); | 
					
						
							|  |  |  |           expect(bvGetPrIsTrustedSpy).not.toHaveBeenCalled(); | 
					
						
							|  |  |  |           expect(bcUpdatePrVisibilitySpy).not.toHaveBeenCalled(); | 
					
						
							| 
									
										
										
										
											2017-06-27 19:43:02 +03:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |     describe('ALL *', () => { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |       it('should respond with 404', async () => { | 
					
						
							| 
									
										
										
										
											2017-06-27 20:14:41 +03:00
										 |  |  |         const responseFor = (method: string) => `Unknown resource in request: ${method.toUpperCase()} /some/url`; | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-06 15:48:00 +03:00
										 |  |  |         await Promise.all([ | 
					
						
							| 
									
										
										
										
											2017-06-27 20:14:41 +03:00
										 |  |  |           agent.get('/some/url').expect(404, responseFor('get')), | 
					
						
							|  |  |  |           agent.put('/some/url').expect(404, responseFor('put')), | 
					
						
							|  |  |  |           agent.post('/some/url').expect(404, responseFor('post')), | 
					
						
							|  |  |  |           agent.patch('/some/url').expect(404, responseFor('patch')), | 
					
						
							|  |  |  |           agent.delete('/some/url').expect(404, responseFor('delete')), | 
					
						
							| 
									
										
										
										
											2018-05-10 13:56:07 +01:00
										 |  |  |         ]); | 
					
						
							| 
									
										
										
										
											2017-02-06 20:40:28 +02:00
										 |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }); |