feat(aio): verify uploaded builds based on JWT from Travis
This commit is contained in:
parent
028b274750
commit
2796790c7d
|
@ -13,6 +13,8 @@ EXPOSE 80 443
|
|||
|
||||
ENV AIO_BUILDS_DIR=/var/www/aio-builds TEST_AIO_BUILDS_DIR=/tmp/aio-builds \
|
||||
AIO_DOMAIN_NAME=ngbuilds.io TEST_AIO_DOMAIN_NAME=test-ngbuilds.io \
|
||||
AIO_GITHUB_ORGANIZATION=angular TEST_AIO_GITHUB_ORGANIZATION=angular \
|
||||
AIO_GITHUB_TEAM_SLUGS=angular-core TEST_AIO_GITHUB_TEAM_SLUGS=angular-core \
|
||||
AIO_NGINX_HOSTNAME=nginx.localhost TEST_AIO_NGINX_HOSTNAME=nginx.localhost \
|
||||
AIO_NGINX_PORT_HTTP=80 TEST_AIO_NGINX_PORT_HTTP=8080 \
|
||||
AIO_NGINX_PORT_HTTPS=443 TEST_AIO_NGINX_PORT_HTTPS=4433 \
|
||||
|
|
|
@ -3,8 +3,9 @@ import {assertNotMissingOrEmpty} from '../common/utils';
|
|||
import {GithubApi} from './github-api';
|
||||
|
||||
// Interfaces - Types
|
||||
interface PullRequest {
|
||||
export interface PullRequest {
|
||||
number: number;
|
||||
user: {login: string};
|
||||
}
|
||||
|
||||
export type PullRequestState = 'all' | 'closed' | 'open';
|
||||
|
@ -28,6 +29,10 @@ export class GithubPullRequests extends GithubApi {
|
|||
return this.post<void>(`/repos/${this.repoSlug}/issues/${pr}/comments`, null, {body});
|
||||
}
|
||||
|
||||
public fetch(pr: number): Promise<PullRequest> {
|
||||
return this.get<PullRequest>(`/repos/${this.repoSlug}/pulls/${pr}`);
|
||||
}
|
||||
|
||||
public fetchAll(state: PullRequestState = 'all'): Promise<PullRequest[]> {
|
||||
console.log(`Fetching ${state} pull requests...`);
|
||||
|
||||
|
|
|
@ -2,15 +2,16 @@
|
|||
process.setuid('www-data');
|
||||
|
||||
// Imports
|
||||
import {GithubPullRequests} from '../common/github-pull-requests';
|
||||
import {getEnvVar} from '../common/utils';
|
||||
import {CreatedBuildEvent} from './build-events';
|
||||
import {uploadServerFactory} from './upload-server-factory';
|
||||
|
||||
// Constants
|
||||
const AIO_BUILDS_DIR = getEnvVar('AIO_BUILDS_DIR');
|
||||
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN', true);
|
||||
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG', true);
|
||||
const AIO_GITHUB_ORGANIZATION = getEnvVar('AIO_GITHUB_ORGANIZATION');
|
||||
const AIO_GITHUB_TEAM_SLUGS = getEnvVar('AIO_GITHUB_TEAM_SLUGS');
|
||||
const AIO_GITHUB_TOKEN = getEnvVar('AIO_GITHUB_TOKEN');
|
||||
const AIO_PREVIEW_DEPLOYMENT_TOKEN = getEnvVar('AIO_PREVIEW_DEPLOYMENT_TOKEN');
|
||||
const AIO_REPO_SLUG = getEnvVar('AIO_REPO_SLUG');
|
||||
const AIO_UPLOAD_HOSTNAME = getEnvVar('AIO_UPLOAD_HOSTNAME');
|
||||
const AIO_UPLOAD_PORT = +getEnvVar('AIO_UPLOAD_PORT');
|
||||
|
||||
|
@ -20,23 +21,13 @@ _main();
|
|||
// Functions
|
||||
function _main() {
|
||||
uploadServerFactory.
|
||||
create(AIO_BUILDS_DIR).
|
||||
on(CreatedBuildEvent.type, createOnBuildCreatedHanlder()).
|
||||
create({
|
||||
buildsDir: AIO_BUILDS_DIR,
|
||||
githubOrganization: AIO_GITHUB_ORGANIZATION,
|
||||
githubTeamSlugs: AIO_GITHUB_TEAM_SLUGS.split(','),
|
||||
githubToken: AIO_GITHUB_TOKEN,
|
||||
repoSlug: AIO_REPO_SLUG,
|
||||
secret: AIO_PREVIEW_DEPLOYMENT_TOKEN,
|
||||
}).
|
||||
listen(AIO_UPLOAD_PORT, AIO_UPLOAD_HOSTNAME);
|
||||
}
|
||||
|
||||
function createOnBuildCreatedHanlder() {
|
||||
if (!AIO_REPO_SLUG) {
|
||||
console.warn('No repo specified. Preview links will not be posted on PRs.');
|
||||
return () => null;
|
||||
}
|
||||
|
||||
const githubPullRequests = new GithubPullRequests(AIO_REPO_SLUG, AIO_GITHUB_TOKEN);
|
||||
|
||||
return ({pr, sha}: CreatedBuildEvent) => {
|
||||
const body = `The angular.io preview for ${sha.slice(0, 7)} is available [here][1].\n\n` +
|
||||
`[1]: https://pr${pr}-${sha}.ngbuilds.io/`;
|
||||
|
||||
githubPullRequests.addComment(pr, body);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,25 +1,43 @@
|
|||
// Imports
|
||||
import * as express from 'express';
|
||||
import * as http from 'http';
|
||||
import {assertNotMissingOrEmpty} from '../common/utils';
|
||||
import {GithubPullRequests} from '../common/github-pull-requests';
|
||||
import {BuildCreator} from './build-creator';
|
||||
import {CreatedBuildEvent} from './build-events';
|
||||
import {BuildVerifier} from './build-verifier';
|
||||
import {UploadError} from './upload-error';
|
||||
|
||||
// Constants
|
||||
const AUTHORIZATION_HEADER = 'AUTHORIZATION';
|
||||
const X_FILE_HEADER = 'X-FILE';
|
||||
|
||||
// Interfaces - Types
|
||||
interface UploadServerConfig {
|
||||
buildsDir: string;
|
||||
githubOrganization: string;
|
||||
githubTeamSlugs: string[];
|
||||
githubToken: string;
|
||||
repoSlug: string;
|
||||
secret: string;
|
||||
}
|
||||
|
||||
// Classes
|
||||
class UploadServerFactory {
|
||||
// Methods - Public
|
||||
public create(buildsDir: string): http.Server {
|
||||
assertNotMissingOrEmpty('buildsDir', buildsDir);
|
||||
public create({
|
||||
buildsDir,
|
||||
githubOrganization,
|
||||
githubTeamSlugs,
|
||||
githubToken,
|
||||
repoSlug,
|
||||
secret,
|
||||
}: UploadServerConfig): http.Server {
|
||||
const buildVerifier = new BuildVerifier(secret, githubToken, repoSlug, githubOrganization, githubTeamSlugs);
|
||||
const buildCreator = this.createBuildCreator(buildsDir, githubToken, repoSlug);
|
||||
|
||||
const buildCreator = new BuildCreator(buildsDir);
|
||||
const middleware = this.createMiddleware(buildCreator);
|
||||
const middleware = this.createMiddleware(buildVerifier, buildCreator);
|
||||
const httpServer = http.createServer(middleware);
|
||||
|
||||
buildCreator.on(CreatedBuildEvent.type, (data: CreatedBuildEvent) => httpServer.emit(CreatedBuildEvent.type, data));
|
||||
httpServer.on('listening', () => {
|
||||
const info = httpServer.address();
|
||||
console.info(`Up and running (and listening on ${info.address}:${info.port})...`);
|
||||
|
@ -29,20 +47,38 @@ class UploadServerFactory {
|
|||
}
|
||||
|
||||
// Methods - Protected
|
||||
protected createMiddleware(buildCreator: BuildCreator): express.Express {
|
||||
protected createBuildCreator(buildsDir: string, githubToken: string, repoSlug: string): BuildCreator {
|
||||
const buildCreator = new BuildCreator(buildsDir);
|
||||
const githubPullRequests = new GithubPullRequests(githubToken, repoSlug);
|
||||
|
||||
buildCreator.on(CreatedBuildEvent.type, ({pr, sha}: CreatedBuildEvent) => {
|
||||
const body = `The angular.io preview for ${sha.slice(0, 7)} is available [here][1].\n\n` +
|
||||
`[1]: https://pr${pr}-${sha}.ngbuilds.io/`;
|
||||
|
||||
githubPullRequests.addComment(pr, body);
|
||||
});
|
||||
|
||||
return buildCreator;
|
||||
}
|
||||
|
||||
protected createMiddleware(buildVerifier: BuildVerifier, buildCreator: BuildCreator): express.Express {
|
||||
const middleware = express();
|
||||
|
||||
middleware.get(/^\/create-build\/([1-9][0-9]*)\/([0-9a-f]{40})\/?$/, (req, res) => {
|
||||
const pr = req.params[0];
|
||||
const sha = req.params[1];
|
||||
const archive = req.header(X_FILE_HEADER);
|
||||
const authHeader = req.header(AUTHORIZATION_HEADER);
|
||||
|
||||
if (!archive) {
|
||||
if (!authHeader) {
|
||||
this.throwRequestError(401, `Missing or empty '${AUTHORIZATION_HEADER}' header`, req);
|
||||
} else if (!archive) {
|
||||
this.throwRequestError(400, `Missing or empty '${X_FILE_HEADER}' header`, req);
|
||||
}
|
||||
|
||||
buildCreator.
|
||||
create(pr, sha, archive).
|
||||
buildVerifier.
|
||||
verify(+pr, authHeader).
|
||||
then(() => buildCreator.create(pr, sha, archive)).
|
||||
then(() => res.sendStatus(201)).
|
||||
catch(err => this.respondWithError(res, err));
|
||||
});
|
||||
|
|
|
@ -2,12 +2,27 @@
|
|||
import * as express from 'express';
|
||||
import * as http from 'http';
|
||||
import * as supertest from 'supertest';
|
||||
import {GithubPullRequests} from '../../lib/common/github-pull-requests';
|
||||
import {BuildCreator} from '../../lib/upload-server/build-creator';
|
||||
import {CreatedBuildEvent} from '../../lib/upload-server/build-events';
|
||||
import {BuildVerifier} from '../../lib/upload-server/build-verifier';
|
||||
import {uploadServerFactory as usf} from '../../lib/upload-server/upload-server-factory';
|
||||
|
||||
// Tests
|
||||
describe('uploadServerFactory', () => {
|
||||
const defaultConfig = {
|
||||
buildsDir: 'builds/dir',
|
||||
githubOrganization: 'organization',
|
||||
githubTeamSlugs: ['team1', 'team2'],
|
||||
githubToken: '12345',
|
||||
repoSlug: 'repo/slug',
|
||||
secret: 'secret',
|
||||
};
|
||||
|
||||
// Helpers
|
||||
const createUploadServer = (partialConfig: Partial<typeof defaultConfig> = {}) =>
|
||||
usf.create({...defaultConfig, ...partialConfig});
|
||||
|
||||
|
||||
describe('create()', () => {
|
||||
let usfCreateMiddlewareSpy: jasmine.Spy;
|
||||
|
@ -17,55 +32,77 @@ describe('uploadServerFactory', () => {
|
|||
});
|
||||
|
||||
|
||||
it('should throw if \'buildsDir\' is empty', () => {
|
||||
expect(() => usf.create('')).toThrowError('Missing or empty required parameter \'buildsDir\'!');
|
||||
it('should throw if \'secret\' is missing or empty', () => {
|
||||
expect(() => createUploadServer({secret: ''})).
|
||||
toThrowError('Missing or empty required parameter \'secret\'!');
|
||||
});
|
||||
|
||||
|
||||
it('should throw if \'githubToken\' is missing or empty', () => {
|
||||
expect(() => createUploadServer({githubToken: ''})).
|
||||
toThrowError('Missing or empty required parameter \'githubToken\'!');
|
||||
});
|
||||
|
||||
|
||||
it('should throw if \'githubOrganization\' is missing or empty', () => {
|
||||
expect(() => createUploadServer({githubOrganization: ''})).
|
||||
toThrowError('Missing or empty required parameter \'organization\'!');
|
||||
});
|
||||
|
||||
|
||||
it('should throw if \'githubTeamSlugs\' is missing or empty', () => {
|
||||
expect(() => createUploadServer({githubTeamSlugs: []})).
|
||||
toThrowError('Missing or empty required parameter \'allowedTeamSlugs\'!');
|
||||
});
|
||||
|
||||
|
||||
it('should throw if \'repoSlug\' is missing or empty', () => {
|
||||
expect(() => createUploadServer({repoSlug: ''})).
|
||||
toThrowError('Missing or empty required parameter \'repoSlug\'!');
|
||||
});
|
||||
|
||||
|
||||
it('should throw if \'secret\' is missing or empty', () => {
|
||||
expect(() => createUploadServer({secret: ''})).
|
||||
toThrowError('Missing or empty required parameter \'secret\'!');
|
||||
});
|
||||
|
||||
|
||||
it('should return an http.Server', () => {
|
||||
const httpCreateServerSpy = spyOn(http, 'createServer').and.callThrough();
|
||||
const server = usf.create('builds/dir');
|
||||
const server = createUploadServer();
|
||||
|
||||
expect(server).toBe(httpCreateServerSpy.calls.mostRecent().returnValue);
|
||||
});
|
||||
|
||||
|
||||
it('should create and use an appropriate BuildCreator', () => {
|
||||
const usfCreateBuildCreatorSpy = spyOn(usf as any, 'createBuildCreator').and.callThrough();
|
||||
|
||||
createUploadServer();
|
||||
const buildCreator: BuildCreator = usfCreateBuildCreatorSpy.calls.mostRecent().returnValue;
|
||||
|
||||
expect(usfCreateMiddlewareSpy).toHaveBeenCalledWith(jasmine.any(BuildVerifier), buildCreator);
|
||||
expect(usfCreateBuildCreatorSpy).toHaveBeenCalledWith('builds/dir', '12345', 'repo/slug');
|
||||
});
|
||||
|
||||
|
||||
it('should create and use an appropriate middleware', () => {
|
||||
const httpCreateServerSpy = spyOn(http, 'createServer').and.callThrough();
|
||||
|
||||
usf.create('builds/dir');
|
||||
createUploadServer();
|
||||
const middleware: express.Express = usfCreateMiddlewareSpy.calls.mostRecent().returnValue;
|
||||
const buildVerifier = jasmine.any(BuildVerifier);
|
||||
const buildCreator = jasmine.any(BuildCreator);
|
||||
|
||||
expect(usfCreateMiddlewareSpy).toHaveBeenCalledWith(jasmine.any(BuildCreator));
|
||||
expect(httpCreateServerSpy).toHaveBeenCalledWith(middleware);
|
||||
});
|
||||
|
||||
|
||||
it('should pass \'buildsDir\' to the created BuildCreator', () => {
|
||||
usf.create('builds/dir');
|
||||
const buildCreator: BuildCreator = usfCreateMiddlewareSpy.calls.argsFor(0)[0];
|
||||
|
||||
expect((buildCreator as any).buildsDir).toBe('builds/dir');
|
||||
});
|
||||
|
||||
|
||||
it('should pass CreatedBuildEvents emitted on BuildCreator through to the server', done => {
|
||||
const server = usf.create('builds/dir');
|
||||
const buildCreator: BuildCreator = usfCreateMiddlewareSpy.calls.argsFor(0)[0];
|
||||
const evt = new CreatedBuildEvent(42, 'foo');
|
||||
|
||||
server.on(CreatedBuildEvent.type, (data: CreatedBuildEvent) => {
|
||||
expect(data).toBe(evt);
|
||||
done();
|
||||
});
|
||||
|
||||
buildCreator.emit(CreatedBuildEvent.type, evt);
|
||||
expect(usfCreateMiddlewareSpy).toHaveBeenCalledWith(buildVerifier, buildCreator);
|
||||
});
|
||||
|
||||
|
||||
it('should log the server address info on \'listening\'', () => {
|
||||
const consoleInfoSpy = spyOn(console, 'info');
|
||||
const server = usf.create('builds/dir');
|
||||
const server = createUploadServer('builds/dir');
|
||||
server.address = () => ({address: 'foo', family: '', port: 1337});
|
||||
|
||||
expect(consoleInfoSpy).not.toHaveBeenCalled();
|
||||
|
@ -79,7 +116,50 @@ describe('uploadServerFactory', () => {
|
|||
|
||||
// Protected methods
|
||||
|
||||
describe('createBuildCreator()', () => {
|
||||
let buildCreator: BuildCreator;
|
||||
|
||||
beforeEach(() => {
|
||||
buildCreator = (usf as any).createBuildCreator(
|
||||
defaultConfig.buildsDir,
|
||||
defaultConfig.githubToken,
|
||||
defaultConfig.repoSlug,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it('should pass the \'buildsDir\' to the BuildCreator', () => {
|
||||
expect((buildCreator as any).buildsDir).toBe('builds/dir');
|
||||
});
|
||||
|
||||
|
||||
it('should post a comment on GitHub on \'build.created\'', () => {
|
||||
const prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment');
|
||||
const commentBody = 'The angular.io preview for 1234567 is available [here][1].\n\n' +
|
||||
'[1]: https://pr42-1234567890.ngbuilds.io/';
|
||||
|
||||
buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890'});
|
||||
|
||||
expect(prsAddCommentSpy).toHaveBeenCalledWith(42, commentBody);
|
||||
});
|
||||
|
||||
|
||||
it('should pass the correct \'githubToken\' and \'repoSlug\' to GithubPullRequests', () => {
|
||||
const prsAddCommentSpy = spyOn(GithubPullRequests.prototype, 'addComment');
|
||||
|
||||
buildCreator.emit(CreatedBuildEvent.type, {pr: 42, sha: '1234567890'});
|
||||
const prs = prsAddCommentSpy.calls.mostRecent().object;
|
||||
|
||||
expect(prs).toEqual(jasmine.any(GithubPullRequests));
|
||||
expect((prs as any).repoSlug).toBe('repo/slug');
|
||||
expect((prs as any).requestHeaders.Authorization).toContain('12345');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('createMiddleware()', () => {
|
||||
let buildVerifier: BuildVerifier;
|
||||
let buildCreator: BuildCreator;
|
||||
let agent: supertest.SuperTest<supertest.Test>;
|
||||
|
||||
|
@ -90,8 +170,15 @@ describe('uploadServerFactory', () => {
|
|||
Promise.all(reqs.map(promisifyRequest)).then(done, done.fail);
|
||||
|
||||
beforeEach(() => {
|
||||
buildCreator = new BuildCreator('builds/dir');
|
||||
agent = supertest.agent((usf as any).createMiddleware(buildCreator));
|
||||
buildVerifier = new BuildVerifier(
|
||||
defaultConfig.secret,
|
||||
defaultConfig.githubToken,
|
||||
defaultConfig.repoSlug,
|
||||
defaultConfig.githubOrganization,
|
||||
defaultConfig.githubTeamSlugs,
|
||||
);
|
||||
buildCreator = new BuildCreator(defaultConfig.buildsDir);
|
||||
agent = supertest.agent((usf as any).createMiddleware(buildVerifier, buildCreator));
|
||||
|
||||
spyOn(console, 'error');
|
||||
});
|
||||
|
@ -100,14 +187,12 @@ describe('uploadServerFactory', () => {
|
|||
describe('GET /create-build/<pr>/<sha>', () => {
|
||||
const pr = '9';
|
||||
const sha = '9'.repeat(40);
|
||||
let buildVerifierVerifySpy: jasmine.Spy;
|
||||
let buildCreatorCreateSpy: jasmine.Spy;
|
||||
let deferred: {resolve: Function, reject: Function};
|
||||
|
||||
beforeEach(() => {
|
||||
const promise = new Promise((resolve, reject) => deferred = {resolve, reject});
|
||||
promise.catch(() => null); // Avoid "unhandled rejection" warnings.
|
||||
|
||||
buildCreatorCreateSpy = spyOn(buildCreator, 'create').and.returnValue(promise);
|
||||
buildVerifierVerifySpy = spyOn(buildVerifier, 'verify').and.returnValue(Promise.resolve());
|
||||
buildCreatorCreateSpy = spyOn(buildCreator, 'create').and.returnValue(Promise.resolve());
|
||||
});
|
||||
|
||||
|
||||
|
@ -121,13 +206,27 @@ describe('uploadServerFactory', () => {
|
|||
});
|
||||
|
||||
|
||||
it('should respond with 401 for requests without an \'AUTHORIZATION\' header', done => {
|
||||
const url = `/create-build/${pr}/${sha}`;
|
||||
const responseBody = `Missing or empty 'AUTHORIZATION' header in request: GET ${url}`;
|
||||
|
||||
verifyRequests([
|
||||
agent.get(url).expect(401, responseBody),
|
||||
agent.get(url).set('AUTHORIZATION', '').expect(401, responseBody),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
||||
it('should respond with 400 for requests without an \'X-FILE\' header', done => {
|
||||
const url = `/create-build/${pr}/${sha}`;
|
||||
const responseBody = `Missing or empty 'X-FILE' header in request: GET ${url}`;
|
||||
|
||||
const request1 = agent.get(url).set('AUTHORIZATION', 'foo');
|
||||
const request2 = agent.get(url).set('AUTHORIZATION', 'foo').set('X-FILE', '');
|
||||
|
||||
verifyRequests([
|
||||
agent.get(url).expect(400, responseBody),
|
||||
agent.get(url).field('X-FILE', '').expect(400, responseBody),
|
||||
request1.expect(400, responseBody),
|
||||
request2.expect(400, responseBody),
|
||||
], done);
|
||||
});
|
||||
|
||||
|
@ -146,34 +245,68 @@ describe('uploadServerFactory', () => {
|
|||
});
|
||||
|
||||
|
||||
it('should propagate errors from BuildCreator', done => {
|
||||
it('should call \'BuildVerifier#verify()\' with the correct arguments', done => {
|
||||
const req = agent.
|
||||
get(`/create-build/${pr}/${sha}`).
|
||||
set('X-FILE', 'foo').
|
||||
set('AUTHORIZATION', 'foo').
|
||||
set('X-FILE', 'bar');
|
||||
|
||||
promisifyRequest(req).
|
||||
then(() => expect(buildVerifierVerifySpy).toHaveBeenCalledWith(9, 'foo')).
|
||||
then(done, done.fail);
|
||||
});
|
||||
|
||||
|
||||
it('should propagate errors from BuildVerifier', done => {
|
||||
buildVerifierVerifySpy.and.callFake(() => Promise.reject('Test'));
|
||||
|
||||
const req = agent.
|
||||
get(`/create-build/${pr}/${sha}`).
|
||||
set('AUTHORIZATION', 'foo').
|
||||
set('X-FILE', 'bar').
|
||||
expect(500, 'Test');
|
||||
|
||||
promisifyRequest(req).
|
||||
then(() => {
|
||||
expect(buildVerifierVerifySpy).toHaveBeenCalledWith(9, 'foo');
|
||||
expect(buildCreatorCreateSpy).not.toHaveBeenCalled();
|
||||
}).
|
||||
then(done, done.fail);
|
||||
});
|
||||
|
||||
|
||||
it('should call \'BuildCreator#create()\' with the correct arguments', done => {
|
||||
const req = agent.
|
||||
get(`/create-build/${pr}/${sha}`).
|
||||
set('AUTHORIZATION', 'foo').
|
||||
set('X-FILE', 'bar');
|
||||
|
||||
promisifyRequest(req).
|
||||
then(() => expect(buildCreatorCreateSpy).toHaveBeenCalledWith(pr, sha, 'bar')).
|
||||
then(done, done.fail);
|
||||
});
|
||||
|
||||
|
||||
it('should propagate errors from BuildCreator', done => {
|
||||
buildCreatorCreateSpy.and.callFake(() => Promise.reject('Test'));
|
||||
const req = agent.
|
||||
get(`/create-build/${pr}/${sha}`).
|
||||
set('AUTHORIZATION', 'foo').
|
||||
set('X-FILE', 'bar').
|
||||
expect(500, 'Test');
|
||||
|
||||
verifyRequests([req], done);
|
||||
deferred.reject('Test');
|
||||
});
|
||||
|
||||
|
||||
it('should respond with 201 on successful upload', done => {
|
||||
const req = agent.
|
||||
get(`/create-build/${pr}/${sha}`).
|
||||
set('X-FILE', 'foo').
|
||||
set('AUTHORIZATION', 'foo').
|
||||
set('X-FILE', 'bar').
|
||||
expect(201, http.STATUS_CODES[201]);
|
||||
|
||||
verifyRequests([req], done);
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
|
||||
it('should call \'BuildCreator#create()\' with appropriate arguments', done => {
|
||||
promisifyRequest(agent.get(`/create-build/${pr}/${sha}`).set('X-FILE', 'foo').expect(201)).
|
||||
then(() => expect(buildCreatorCreateSpy).toHaveBeenCalledWith(pr, sha, 'foo')).
|
||||
then(done, done.fail);
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
|
||||
|
@ -183,16 +316,18 @@ describe('uploadServerFactory', () => {
|
|||
|
||||
|
||||
it('should accept SHAs with leading zeros (but not ignore them)', done => {
|
||||
const sha41 = '0'.repeat(41);
|
||||
const sha40 = '0'.repeat(40);
|
||||
const sha41 = `0${sha40}`;
|
||||
|
||||
const request41 = agent.get(`/create-build/${pr}/${sha41}`);
|
||||
const request40 = agent.get(`/create-build/${pr}/${sha40}`).
|
||||
set('AUTHORIZATION', 'foo').
|
||||
set('X-FILE', 'bar');
|
||||
|
||||
Promise.all([
|
||||
promisifyRequest(agent.get(`/create-build/${pr}/${sha41}`).expect(404)),
|
||||
promisifyRequest(agent.get(`/create-build/${pr}/${sha40}`).set('X-FILE', 'foo')).
|
||||
then(() => expect(buildCreatorCreateSpy).toHaveBeenCalledWith(pr, sha40, 'foo')),
|
||||
promisifyRequest(request41.expect(404)),
|
||||
promisifyRequest(request40.expect(201)),
|
||||
]).then(done, done.fail);
|
||||
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -3,6 +3,9 @@ set -e -o pipefail
|
|||
|
||||
# Set up env variables for testing
|
||||
export AIO_BUILDS_DIR=$TEST_AIO_BUILDS_DIR
|
||||
export AIO_GITHUB_ORGANIZATION=$TEST_AIO_GITHUB_ORGANIZATION
|
||||
export AIO_GITHUB_TEAM_SLUGS=$TEST_AIO_GITHUB_TEAM_SLUGS
|
||||
export AIO_PREVIEW_DEPLOYMENT_TOKEN=$TEST_AIO_PREVIEW_DEPLOYMENT_TOKEN
|
||||
export AIO_REPO_SLUG=$TEST_AIO_REPO_SLUG
|
||||
export AIO_UPLOAD_HOSTNAME=$TEST_AIO_UPLOAD_HOSTNAME
|
||||
export AIO_UPLOAD_PORT=$TEST_AIO_UPLOAD_PORT
|
||||
|
|
Loading…
Reference in New Issue