Skip to content

Commit

Permalink
Add region tags + human review (#1499)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ace Nassri authored and fhinkel committed Oct 3, 2019
1 parent 8fe451e commit 43e2d90
Show file tree
Hide file tree
Showing 31 changed files with 2,071 additions and 1,868 deletions.
38 changes: 20 additions & 18 deletions functions/background/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,25 @@ it('should make a promise request', async () => {
assert.ok(response.body.includes(`Example Domain`));
});

it('should return synchronously', () => {
assert.strictEqual(
program.helloSynchronous({
something: true,
}),
'Something is true!'
);
});

it('should throw an error', () => {
assert.throws(
() => {
describe('functions_background_synchronous', () => {
it('should return synchronously', () => {
assert.strictEqual(
program.helloSynchronous({
something: false,
});
},
Error,
'Something was not true!'
);
something: true,
}),
'Something is true!'
);
});

it('should throw an error', () => {
assert.throws(
() => {
program.helloSynchronous({
something: false,
});
},
Error,
'Something was not true!'
);
});
});
135 changes: 72 additions & 63 deletions functions/billing/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,28 @@ describe('functions/billing tests', () => {
await handleLinuxFailures(ffProc);
});

it('should notify Slack when budget is exceeded', async () => {
const jsonData = {costAmount: 500, budgetAmount: 400};
const encodedData = Buffer.from(JSON.stringify(jsonData)).toString(
'base64'
);
const pubsubMessage = {data: encodedData, attributes: {}};

const response = await requestRetry({
url: `${BASE_URL}/notifySlack`,
method: 'POST',
body: {data: pubsubMessage},
retryDelay: 200,
json: true,
describe('functions_billing_slack', () => {
it('should notify Slack when budget is exceeded', async () => {
const jsonData = {costAmount: 500, budgetAmount: 400};
const encodedData = Buffer.from(JSON.stringify(jsonData)).toString(
'base64'
);
const pubsubMessage = {data: encodedData, attributes: {}};

const response = await requestRetry({
url: `${BASE_URL}/notifySlack`,
method: 'POST',
body: {data: pubsubMessage},
retryDelay: 200,
json: true,
});

assert.strictEqual(response.statusCode, 200);
assert.strictEqual(
response.body,
'Slack notification sent successfully'
);
});

assert.strictEqual(response.statusCode, 200);
assert.strictEqual(response.body, 'Slack notification sent successfully');
});
});

Expand All @@ -105,60 +110,64 @@ describe('functions/billing tests', () => {
await handleLinuxFailures(ffProc);
});

it('should disable billing when budget is exceeded', async () => {
// Use functions framework to ensure sample follows GCF specification
// (Invoking it directly works too, but DOES NOT ensure GCF compatibility)
describe('functions_billing_stop', () => {
it('should disable billing when budget is exceeded', async () => {
// Use functions framework to ensure sample follows GCF specification
// (Invoking it directly works too, but DOES NOT ensure GCF compatibility)
const jsonData = {costAmount: 500, budgetAmount: 400};
const encodedData = Buffer.from(JSON.stringify(jsonData)).toString(
'base64'
);
const pubsubMessage = {data: encodedData, attributes: {}};

const response = await requestRetry({
url: `${BASE_URL}/stopBilling`,
method: 'POST',
body: {data: pubsubMessage},
retryDelay: 200,
json: true,
});

assert.strictEqual(response.statusCode, 200);
assert.ok(response.body.includes('Billing disabled'));
});
});
});
});

describe('shuts down GCE instances', () => {
describe('functions_billing_limit', () => {
it('should attempt to shut down GCE instances when budget is exceeded', async () => {
// Mock GCE (because real GCE instances take too long to start/stop)
const listInstancesResponseMock = {
data: {
items: [{name: 'test-instance-1', status: 'RUNNING'}],
},
};

const computeMock = {
instances: {
list: sinon.stub().returns(listInstancesResponseMock),
stop: sinon.stub().resolves({data: {}}),
},
};

const googleapisMock = Object.assign({}, googleapis);
googleapisMock.google.compute = sinon.stub().returns(computeMock);

// Run test
const jsonData = {costAmount: 500, budgetAmount: 400};
const encodedData = Buffer.from(JSON.stringify(jsonData)).toString(
'base64'
);
const pubsubMessage = {data: encodedData, attributes: {}};

const response = await requestRetry({
url: `${BASE_URL}/stopBilling`,
method: 'POST',
body: {data: pubsubMessage},
retryDelay: 200,
json: true,
});
const sample = proxyquire('../', {googleapis: googleapisMock}); // kokoro-allow-mock

assert.strictEqual(response.statusCode, 200);
assert.ok(response.body.includes('Billing disabled'));
});
});
});
await sample.limitUse(pubsubMessage);

describe('shuts down GCE instances', () => {
it('should attempt to shut down GCE instances when budget is exceeded', async () => {
// Mock GCE (because real GCE instances take too long to start/stop)
const listInstancesResponseMock = {
data: {
items: [{name: 'test-instance-1', status: 'RUNNING'}],
},
};

const computeMock = {
instances: {
list: sinon.stub().returns(listInstancesResponseMock),
stop: sinon.stub().resolves({data: {}}),
},
};

const googleapisMock = Object.assign({}, googleapis);
googleapisMock.google.compute = sinon.stub().returns(computeMock);

// Run test
const jsonData = {costAmount: 500, budgetAmount: 400};
const encodedData = Buffer.from(JSON.stringify(jsonData)).toString(
'base64'
);
const pubsubMessage = {data: encodedData, attributes: {}};

const sample = proxyquire('../', {googleapis: googleapisMock}); // kokoro-allow-mock

await sample.limitUse(pubsubMessage);

assert.strictEqual(computeMock.instances.list.calledOnce, true);
assert.ok(computeMock.instances.stop.calledOnce);
assert.strictEqual(computeMock.instances.list.calledOnce, true);
assert.ok(computeMock.instances.stop.calledOnce);
});
});
});
46 changes: 25 additions & 21 deletions functions/billing/test/periodic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,30 +54,34 @@ before(async () => {
}
});

it('should shut down GCE instances when budget is exceeded', async () => {
const ffProc = execPromise(
`functions-framework --target=limitUse --signature-type=event`,
{timeout: 1000, shell: true, cwd}
);
describe('functions_billing_limit', () => {
it('should shut down GCE instances when budget is exceeded', async () => {
const ffProc = execPromise(
`functions-framework --target=limitUse --signature-type=event`,
{timeout: 1000, shell: true, cwd}
);

const jsonData = {costAmount: 500, budgetAmount: 400};
const encodedData = Buffer.from(JSON.stringify(jsonData)).toString('base64');
const pubsubMessage = {data: encodedData, attributes: {}};
const jsonData = {costAmount: 500, budgetAmount: 400};
const encodedData = Buffer.from(JSON.stringify(jsonData)).toString(
'base64'
);
const pubsubMessage = {data: encodedData, attributes: {}};

const response = await requestRetry({
url: `${BASE_URL}/`,
method: 'POST',
body: {data: pubsubMessage},
retryDelay: 200,
json: true,
});
const response = await requestRetry({
url: `${BASE_URL}/`,
method: 'POST',
body: {data: pubsubMessage},
retryDelay: 200,
json: true,
});

// Wait for the functions framework to stop
// Must be BEFORE assertions, in case they fail
await ffProc;
// Wait for the functions framework to stop
// Must be BEFORE assertions, in case they fail
await ffProc;

console.log(response.body);
console.log(response.body);

assert.strictEqual(response.statusCode, 200);
assert.ok(response.body.includes('instance(s) stopped successfully'));
assert.strictEqual(response.statusCode, 200);
assert.ok(response.body.includes('instance(s) stopped successfully'));
});
});
112 changes: 57 additions & 55 deletions functions/composer-storage-trigger/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,62 +30,64 @@ const getSample = FetchStub => {
};
};

it('Handles error in JSON body', async () => {
const event = {
data: {
file: 'some-file',
},
};
const expectedMsg = 'Something bad happened.';
const bodyJson = {error: expectedMsg};
const body = {
json: sinon.stub().returns(bodyJson),
};
const sample = getSample(sinon.stub().resolves(body));
describe('composer_trigger', () => {
it('Handles error in JSON body', async () => {
const event = {
data: {
file: 'some-file',
},
};
const expectedMsg = 'Something bad happened.';
const bodyJson = {error: expectedMsg};
const body = {
json: sinon.stub().returns(bodyJson),
};
const sample = getSample(sinon.stub().resolves(body));

try {
await sample.program.triggerDag(event);
assert.fail('No error thrown');
} catch (err) {
assert.deepStrictEqual(err, new Error('Something bad happened.'));
}
});
try {
await sample.program.triggerDag(event);
assert.fail('No error thrown');
} catch (err) {
assert.deepStrictEqual(err, new Error('Something bad happened.'));
}
});

it('Handles error in IAP response.', async () => {
const event = {
data: {
file: 'some-file',
},
};
const expectedMsg = 'Default IAP Error Message.';
it('Handles error in IAP response.', async () => {
const event = {
data: {
file: 'some-file',
},
};
const expectedMsg = 'Default IAP Error Message.';

const serviceAccountAccessTokenRes = {
json: sinon.stub().resolves({access_token: 'default-access-token'}),
};
const signJsonClaimRes = {
json: sinon.stub().resolves({signature: 'default-jwt-signature'}),
};
const getTokenRes = {
json: sinon.stub().resolves({id_token: 'default-id-token'}),
};
const makeIapPostRequestRes = {
ok: false,
text: sinon.stub().resolves(expectedMsg),
};
const FetchStub = sinon
.stub()
.onCall(0)
.resolves(serviceAccountAccessTokenRes)
.onCall(1)
.resolves(signJsonClaimRes)
.onCall(2)
.resolves(getTokenRes)
.onCall(3)
.resolves(makeIapPostRequestRes);
const sample = getSample(FetchStub);
try {
await sample.program.triggerDag(event);
} catch (err) {
assert.deepStrictEqual(err, new Error(expectedMsg));
}
const serviceAccountAccessTokenRes = {
json: sinon.stub().resolves({access_token: 'default-access-token'}),
};
const signJsonClaimRes = {
json: sinon.stub().resolves({signature: 'default-jwt-signature'}),
};
const getTokenRes = {
json: sinon.stub().resolves({id_token: 'default-id-token'}),
};
const makeIapPostRequestRes = {
ok: false,
text: sinon.stub().resolves(expectedMsg),
};
const FetchStub = sinon
.stub()
.onCall(0)
.resolves(serviceAccountAccessTokenRes)
.onCall(1)
.resolves(signJsonClaimRes)
.onCall(2)
.resolves(getTokenRes)
.onCall(3)
.resolves(makeIapPostRequestRes);
const sample = getSample(FetchStub);
try {
await sample.program.triggerDag(event);
} catch (err) {
assert.deepStrictEqual(err, new Error(expectedMsg));
}
});
});
14 changes: 8 additions & 6 deletions functions/concepts/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ const sample = require('../');
beforeEach(tools.stubConsole);
afterEach(tools.restoreConsole);

it('should demonstrate error type behavior', () => {
const objError = new Error('Error object!');
describe('functions_concepts_error_object', () => {
it('should demonstrate error type behavior', () => {
const objError = new Error('Error object!');

const req = {body: {throwAsString: true}};
const res = {end: sinon.stub()};
const req = {body: {throwAsString: true}};
const res = {end: sinon.stub()};

sample.errorTypes(req, res);
assert.deepStrictEqual(console.error.getCall(0).args, [objError]);
sample.errorTypes(req, res);
assert.deepStrictEqual(console.error.getCall(0).args, [objError]);
});
});
Loading

0 comments on commit 43e2d90

Please sign in to comment.