blob: 1bab008c36a90d5b7b4cfdd83620e714415dd8f4 [file] [log] [blame]
import {assertRejects} from './test-util';
import {BuildbucketV2Client} from '../buildbucket-client';
import {CrTryjobPicker} from '../cr-tryjob-picker';
suite('cr-tryjob-picker basic tests', () => {
let sandbox: sinon.SinonSandbox;
let element: CrTryjobPicker;
let closeFired = false;
setup(() => {
element = document.createElement('cr-tryjob-picker') as CrTryjobPicker;
Object.assign(element, {
buildbucketHost: 'foo.bar',
change: {
owner: {email: 'jane@example.com'},
_number: 1,
},
revision: {_number: 1},
pluginConfig: {
gitHost: 'example.googlesource.com',
},
});
closeFired = false;
element.addEventListener('close', _ => {
closeFired = true;
});
document.body.appendChild(element);
sandbox = sandbox = sinon.createSandbox();
sandbox.stub(window, 'alert');
sandbox
.stub(BuildbucketV2Client.prototype, 'listBuilders')
.callsFake(({project, bucket, pageToken}) => {
assert.equal(bucket, 'try');
const response: any = {};
if (project == 'internal' && !pageToken) {
return Promise.reject('404');
} else if (project === 'v8' && !pageToken) {
response.builders = [{id: {project, bucket, builder: 'linux'}}];
} else if (project === 'chromium' && !pageToken) {
response.builders = [{id: {project, bucket, builder: 'linux'}}];
response.nextPageToken = 'next';
} else if (project === 'chromium' && pageToken === 'next') {
response.builders = [{id: {project, bucket, builder: 'windows'}}];
} else {
assert.fail(`Unexpected request: ${{project, bucket, pageToken}}`);
}
return Promise.resolve(response);
});
});
teardown(() => {
document.body.removeChild(element);
sandbox.restore();
});
test('bucket filter function filters builders', () => {
let fn = element.computeBucketFilterFn(_ => true);
assert.isTrue(
fn({
builders: ['blerp', 'GERP'],
project: '',
bucket: '',
})
);
fn = element.computeBucketFilterFn(s => /gerp/.test(s));
assert.isTrue(
fn({
builders: ['blerp', 'gerp'],
project: '',
bucket: '',
})
);
assert.isTrue(
fn({
builders: ['gerp'],
project: '',
bucket: '',
})
);
assert.isFalse(
fn({
builders: ['blerp'],
project: '',
bucket: '',
})
);
});
test('filter compilation with literal string', () => {
element.filter = 'abc';
assert.isTrue(element.matchesFilter('abc'));
assert.isFalse(element.matchesFilter('a'));
assert.equal(element.filterClass, '');
});
test('filter compilation with wildcard dot', () => {
element.filter = 'a.c';
assert.isTrue(element.matchesFilter('abc'));
assert.isTrue(element.matchesFilter('adc'));
assert.isFalse(element.matchesFilter('a'));
assert.equal(element.filterClass, '');
});
test('filter compilation with optional part, parens', () => {
element.filter = 'a(b)c';
assert.isTrue(element.matchesFilter('abc'));
assert.isFalse(element.matchesFilter('adc'));
assert.isFalse(element.matchesFilter('a'));
assert.equal(element.filterClass, '');
});
test('filter compilation with an invalid expression', () => {
element.filter = 'abc)';
assert.isFalse(element.matchesFilter('abc'));
assert.isFalse(element.matchesFilter('a'));
assert.equal(element.filterClass, 'error');
});
test('selectedBuilders updated on checkbox change', async () => {
await element.bucketsUpdating;
const addButton = element.shadowRoot?.querySelector('gr-button[primary]');
const el = document.createElement('input');
el.type = 'checkbox';
el.setAttribute('data-project', 'proj.foo');
el.setAttribute('data-bucket', 'bucket.bar');
el.value = 'builder.baz';
el.checked = true;
assert.equal(Object.keys(element.selectedBuilders).length, 0);
element.handleCheckboxChange({target: el} as unknown as Event);
assert.deepEqual(element.selectedBuilders, {
'proj##foo/bucket##bar/builder##baz': {
project: 'proj.foo',
bucket: 'bucket.bar',
builder: 'builder.baz',
},
});
assert.equal(Object.keys(element.selectedBuilders).length, 1);
assert.isTrue(
element.computeChecked('proj.foo', 'bucket.bar', 'builder.baz')
);
assert.equal(addButton?.getAttribute('disabled'), '');
});
test('computeBuckets merges builders', async () => {
// The two groups of builders that are merged are from the
// config (passed to computeBuckets) and from getBuilders.
// In this test, the return value of getBuilders is set in
// the setup method above.
const buckets = await element.computeBuckets([
{
name: 'luci.chromium.try',
builders: ['extra'],
},
]);
assert.deepEqual(buckets, [
{
project: 'chromium',
bucket: 'try',
builders: ['extra', 'linux', 'windows'],
},
]);
});
test('computeBuckets ignores errors when listing builders', async () => {
sandbox.stub(window.console, 'error');
await element.bucketsUpdating;
element.pluginConfigChanged({
buckets: [{name: 'luci.v8.try'}, {name: 'luci.internal.try'}],
});
await element.bucketsUpdating;
assert.deepEqual(element.buckets, [
{project: 'v8', bucket: 'try', builders: ['linux']},
{project: 'internal', bucket: 'try', builders: []},
]);
});
test('pluginConfigChanged called twice, second config wins', async () => {
await element.bucketsUpdating;
element.pluginConfigChanged({
buckets: [
{
name: 'luci.chromium.try',
},
],
});
element.pluginConfigChanged({
buckets: [
{
name: 'luci.v8.try',
},
],
});
await element.bucketsUpdating;
assert.deepEqual(element.buckets, [
{project: 'v8', bucket: 'try', builders: ['linux']},
]);
});
test('add button is disabled when no builds are selected', async () => {
element.pluginConfig = {
buckets: [
{
name: 'luci.chromium.try',
builders: ['builder'],
},
],
};
await element.bucketsUpdating;
const addButton = element.shadowRoot?.querySelector('gr-button[primary]');
assert.isTrue(addButton?.hasAttribute('disabled'));
const checkbox = element.shadowRoot?.querySelector(
'input[type="checkbox"]'
);
assert.ok(checkbox);
const changePromise = new Promise(resolve => {
element.addEventListener('change', resolve);
});
(checkbox as any).checked = true;
checkbox?.dispatchEvent(
new CustomEvent('change', {bubbles: true, composed: true})
);
await changePromise;
assert.isFalse(addButton?.hasAttribute('disabled'));
});
test('includeTrybots updated when bots selected', async () => {
const fn = (
project: string,
bucket: string,
builder: string,
isChecked: boolean
) => {
const el = document.createElement('input');
el.type = 'checkbox';
el.setAttribute('data-project', project);
el.setAttribute('data-bucket', bucket);
el.value = builder;
el.checked = isChecked;
return el;
};
// Check one builder.
const el1 = fn('proj.foo', 'bucket.bar', 'builder.baz', true);
assert.equal(element.includeTrybots, '');
element.handleCheckboxChange({target: el1} as unknown as Event);
assert.equal(
element.includeTrybots,
'luci.proj.foo.bucket.bar:builder.baz'
);
// Uncheck the builder.
el1.checked = false;
element.handleCheckboxChange({target: el1} as unknown as Event);
assert.equal(element.includeTrybots, '');
// Check two builders.
el1.checked = true;
const el2 = fn('proj.foo2', 'bucket.bar2', 'builder.baz2', true);
element.handleCheckboxChange({target: el1} as unknown as Event);
element.handleCheckboxChange({target: el2} as unknown as Event);
assert.equal(
element.includeTrybots,
'luci.proj.foo.bucket.bar:builder.baz;' +
'luci.proj.foo2.bucket.bar2:builder.baz2'
);
// Uncheck one builder.
el1.checked = false;
element.handleCheckboxChange({target: el1} as unknown as Event);
assert.equal(
element.includeTrybots,
'luci.proj.foo2.bucket.bar2:builder.baz2'
);
// Uncheck the second builder.
el2.checked = false;
element.handleCheckboxChange({target: el2} as unknown as Event);
assert.equal(element.includeTrybots, '');
});
test('on successful scheduling', async () => {
element.clientOperationId = 'opid';
element.selectedBuilders = {
'chromium/try/linux-rel': {
project: 'chromium',
bucket: 'try',
builder: 'linux-rel',
},
};
sandbox
.stub(BuildbucketV2Client.prototype, 'batch')
.returns(Promise.resolve({}));
await element.onAddTap();
assert.isTrue(closeFired);
assert.isFalse(element.disabled);
assert.deepEqual(element.selectedBuilders, {});
assert.isUndefined(element.clientOperationId);
});
test('on HTTP request error', async () => {
sandbox
.stub(BuildbucketV2Client.prototype, 'batch')
.returns(Promise.reject(new Error('no')));
const selectedBuilders = {
'chromium/try/linux-rel': {
project: 'chromium',
bucket: 'try',
builder: 'linux-rel',
},
};
element.selectedBuilders = {...selectedBuilders};
element.clientOperationId = 'opid';
await assertRejects(element.onAddTap(), 'no');
assert.isFalse(closeFired);
assert.isFalse(element.disabled);
assert.deepEqual(element.selectedBuilders, selectedBuilders);
assert.equal(element.clientOperationId, 'opid');
});
test('_onAddTap rejects on build request error', async () => {
const result = {responses: [{error: {message: 'no'}}]};
sandbox
.stub(BuildbucketV2Client.prototype, 'batch')
.returns(Promise.resolve(result));
const selectedBuilders = {
'chromium/try/linux-rel': {
project: 'chromium',
bucket: 'try',
builder: 'linux-rel',
},
};
element.selectedBuilders = {...selectedBuilders};
element.clientOperationId = 'opid';
// _onTapAdd rejects, which is handled by the caller.
// The picker remains open, and the client operation ID is unchanged
// in case the caller wants to try again.
await assertRejects(element.onAddTap(), 'no');
assert.isFalse(closeFired);
assert.isFalse(element.disabled);
assert.deepEqual(element.selectedBuilders, selectedBuilders);
assert.equal(element.clientOperationId, 'opid');
});
});