Some tests where comparing actual with expected paths, without taking into account that paths will be different on Windows. This commit uses `path.resolve()` to convert expected paths to their OS-specific form. PR Close #25671
		
			
				
	
	
		
			194 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as fs from 'fs';
 | |
| import * as nock from 'nock';
 | |
| import {resolve as resolvePath} from 'path';
 | |
| import {BuildInfo, CircleCiApi} from '../../lib/common/circle-ci-api';
 | |
| import {Logger} from '../../lib/common/utils';
 | |
| import {BuildRetriever} from '../../lib/preview-server/build-retriever';
 | |
| 
 | |
| describe('BuildRetriever', () => {
 | |
|   const MAX_DOWNLOAD_SIZE = 10000;
 | |
|   const DOWNLOAD_DIR = resolvePath('/DOWNLOAD/DIR');
 | |
|   const BASE_URL = 'http://test.com';
 | |
|   const ARTIFACT_PATH = '/some/path/build.zip';
 | |
| 
 | |
|   let api: CircleCiApi;
 | |
|   let BUILD_INFO: BuildInfo;
 | |
|   let WRITEFILE_RESULT: any;
 | |
|   let writeFileSpy: jasmine.Spy;
 | |
|   let EXISTS_RESULT: boolean;
 | |
|   let existsSpy: jasmine.Spy;
 | |
|   let getBuildArtifactUrlSpy: jasmine.Spy;
 | |
| 
 | |
|   beforeEach(() => {
 | |
|     BUILD_INFO = {
 | |
|       branch: 'pull/777',
 | |
|       build_num: 12345,
 | |
|       failed: false,
 | |
|       has_artifacts: true,
 | |
|       outcome: 'success',
 | |
|       reponame: 'REPO',
 | |
|       username: 'ORG',
 | |
|       vcs_revision: 'COMMIT',
 | |
|     };
 | |
| 
 | |
|     api = new CircleCiApi('ORG', 'REPO', 'TOKEN');
 | |
|     spyOn(api, 'getBuildInfo').and.callFake(() => Promise.resolve(BUILD_INFO));
 | |
|     getBuildArtifactUrlSpy = spyOn(api, 'getBuildArtifactUrl')
 | |
|       .and.callFake(() => Promise.resolve(BASE_URL + ARTIFACT_PATH));
 | |
| 
 | |
|     WRITEFILE_RESULT = undefined;
 | |
|     writeFileSpy = spyOn(fs, 'writeFile').and.callFake(
 | |
|       (_path: string, _buffer: Buffer, callback: (err?: any) => {}) => callback(WRITEFILE_RESULT),
 | |
|     );
 | |
| 
 | |
|     EXISTS_RESULT = false;
 | |
|     existsSpy = spyOn(fs, 'exists').and.callFake(
 | |
|       (_path: string, callback: (exists: boolean) => {}) => callback(EXISTS_RESULT),
 | |
|     );
 | |
|   });
 | |
| 
 | |
|   describe('constructor', () => {
 | |
|     it('should fail if the "downloadSizeLimit" is invalid', () => {
 | |
|       expect(() => new BuildRetriever(api, NaN, DOWNLOAD_DIR))
 | |
|         .toThrowError(`Invalid parameter "downloadSizeLimit" should be a number greater than 0.`);
 | |
|       expect(() => new BuildRetriever(api, 0, DOWNLOAD_DIR))
 | |
|         .toThrowError(`Invalid parameter "downloadSizeLimit" should be a number greater than 0.`);
 | |
|       expect(() => new BuildRetriever(api, -1, DOWNLOAD_DIR))
 | |
|         .toThrowError(`Invalid parameter "downloadSizeLimit" should be a number greater than 0.`);
 | |
|     });
 | |
|     it('should fail if the "downloadDir" is missing', () => {
 | |
|       expect(() => new BuildRetriever(api, MAX_DOWNLOAD_SIZE, ''))
 | |
|         .toThrowError(`Missing or empty required parameter 'downloadDir'!`);
 | |
|     });
 | |
|   });
 | |
| 
 | |
| 
 | |
|   describe('getGithubInfo', () => {
 | |
|     it('should request the info from CircleCI', async () => {
 | |
|       const retriever = new BuildRetriever(api, MAX_DOWNLOAD_SIZE, DOWNLOAD_DIR);
 | |
|       const info = await retriever.getGithubInfo(12345);
 | |
|       expect(api.getBuildInfo).toHaveBeenCalledWith(12345);
 | |
|       expect(info).toEqual({org: 'ORG', pr: 777, repo: 'REPO', sha: 'COMMIT', success: true});
 | |
|     });
 | |
| 
 | |
|     it('should error if it is not possible to extract the PR number from the branch', async () => {
 | |
|       const retriever = new BuildRetriever(api, MAX_DOWNLOAD_SIZE, DOWNLOAD_DIR);
 | |
|       try {
 | |
|         BUILD_INFO.branch = 'master';
 | |
|         await retriever.getGithubInfo(12345);
 | |
|         throw new Error('Exception Expected');
 | |
|       } catch (error) {
 | |
|         expect(error.message).toEqual('No PR found in branch field: master');
 | |
|       }
 | |
|     });
 | |
|   });
 | |
| 
 | |
| 
 | |
|   describe('downloadBuildArtifact', () => {
 | |
|     const ARTIFACT_CONTENTS = 'ARTIFACT CONTENTS';
 | |
|     let retriever: BuildRetriever;
 | |
| 
 | |
|     beforeEach(() => {
 | |
|       spyOn(Logger.prototype, 'warn');
 | |
|       retriever = new BuildRetriever(api, MAX_DOWNLOAD_SIZE, DOWNLOAD_DIR);
 | |
|     });
 | |
| 
 | |
|     it('should get the artifact URL from the CircleCI API', async () => {
 | |
|       const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(200, ARTIFACT_CONTENTS);
 | |
|       await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|       expect(api.getBuildArtifactUrl).toHaveBeenCalledWith(12345, ARTIFACT_PATH);
 | |
|       artifactRequest.done();
 | |
|     });
 | |
| 
 | |
|     it('should download the artifact from its URL', async () => {
 | |
|       const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(200, ARTIFACT_CONTENTS);
 | |
|       await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|       // The following line proves that the artifact URL fetch occurred.
 | |
|       artifactRequest.done();
 | |
|     });
 | |
| 
 | |
|     it('should fail if the artifact is too large', async () => {
 | |
|       const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(200, ARTIFACT_CONTENTS);
 | |
|       retriever = new BuildRetriever(api, 10, DOWNLOAD_DIR);
 | |
|       try {
 | |
|         await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|         throw new Error('Exception Expected');
 | |
|       } catch (error) {
 | |
|         expect(error.status).toEqual(413);
 | |
|       }
 | |
|       artifactRequest.done();
 | |
|     });
 | |
| 
 | |
|     it('should not download the artifact if it already exists', async () => {
 | |
|       const artifactRequestInterceptor = nock(BASE_URL).get(ARTIFACT_PATH);
 | |
|       const artifactRequest = artifactRequestInterceptor.reply(200, ARTIFACT_CONTENTS);
 | |
|       EXISTS_RESULT = true;
 | |
|       await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|       expect(existsSpy).toHaveBeenCalled();
 | |
|       expect(getBuildArtifactUrlSpy).not.toHaveBeenCalled();
 | |
|       expect(artifactRequest.isDone()).toEqual(false);
 | |
|       nock.removeInterceptor(artifactRequestInterceptor);
 | |
|     });
 | |
| 
 | |
|     it('should write the artifact file to disk', async () => {
 | |
|       const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(200, ARTIFACT_CONTENTS);
 | |
|       const downloadPath = resolvePath(`${DOWNLOAD_DIR}/777-COMMIT-build.zip`);
 | |
| 
 | |
|       await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|       expect(writeFileSpy).toHaveBeenCalledWith(downloadPath, jasmine.any(Buffer), jasmine.any(Function));
 | |
| 
 | |
|       const buffer: Buffer = writeFileSpy.calls.mostRecent().args[1];
 | |
|       expect(buffer.toString()).toEqual(ARTIFACT_CONTENTS);
 | |
| 
 | |
|       artifactRequest.done();
 | |
|     });
 | |
| 
 | |
|     it('should fail if the CircleCI API fails',  async () => {
 | |
|       try {
 | |
|         getBuildArtifactUrlSpy.and.callFake(() => Promise.reject('getBuildArtifactUrl failed'));
 | |
|         await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|         throw new Error('Exception Expected');
 | |
|       } catch (error) {
 | |
|         expect(error.message).toEqual('CircleCI artifact download failed (getBuildArtifactUrl failed)');
 | |
|       }
 | |
|     });
 | |
| 
 | |
|     it('should fail if the URL fetch errors',  async () => {
 | |
|       // create a new handler that errors
 | |
|       const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).replyWithError('Artifact Request Failed');
 | |
|       try {
 | |
|         await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|         throw new Error('Exception Expected');
 | |
|       } catch (error) {
 | |
|         expect(error.message).toEqual('CircleCI artifact download failed ' +
 | |
|           '(request to http://test.com/some/path/build.zip failed, reason: Artifact Request Failed)');
 | |
|       }
 | |
|       artifactRequest.done();
 | |
|     });
 | |
| 
 | |
|     it('should fail if the URL fetch 404s',  async () => {
 | |
|       // create a new handler that errors
 | |
|       const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(404, 'No such artifact');
 | |
|       try {
 | |
|         await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|         throw new Error('Exception Expected');
 | |
|       } catch (error) {
 | |
|         expect(error.message).toEqual('CircleCI artifact download failed (Error 404 - Not Found)');
 | |
|       }
 | |
|       artifactRequest.done();
 | |
|     });
 | |
| 
 | |
|     it('should fail if file write fails',  async () => {
 | |
|       const artifactRequest = nock(BASE_URL).get(ARTIFACT_PATH).reply(200, ARTIFACT_CONTENTS);
 | |
|       try {
 | |
|         WRITEFILE_RESULT = 'Test Error';
 | |
|         await retriever.downloadBuildArtifact(12345, 777, 'COMMIT', ARTIFACT_PATH);
 | |
|         throw new Error('Exception Expected');
 | |
|       } catch (error) {
 | |
|         expect(error.message).toEqual('CircleCI artifact download failed (Test Error)');
 | |
|       }
 | |
|       artifactRequest.done();
 | |
|     });
 | |
|   });
 | |
| });
 |