'use strict'; const assert = require('assert'); require('../tools/js/v3-models.js'); const BrowserPrivilegedAPI = require('../public/v3/privileged-api.js').PrivilegedAPI; const NodePrivilegedAPI = require('../tools/js/privileged-api.js').PrivilegedAPI; const MockModels = require('./resources/mock-v3-models.js').MockModels; const MockRemoteAPI = require('./resources/mock-remote-api.js').MockRemoteAPI; function sampleTestGroup(needsNotification = true, initialRepetitionCount = 2, mayNeedMoreRequests = true) { return { "testGroups": [{ "id": "2128", "task": "1376", "platform": "31", "name": "Confirm", "author": "rniwa", "createdAt": 1458688514000, "hidden": false, "needsNotification": needsNotification, "buildRequests": ["16985", "16986", "16987", "16988", "16989", "16990", "16991", "16992"], "commitSets": ["4255", "4256"], "notificationSentAt": null, initialRepetitionCount, mayNeedMoreRequests }], "buildRequests": [{ "id": "16985", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "0", "commitSet": "4255", "status": "pending", "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16986", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "1", "commitSet": "4256", "status": "pending", "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16987", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "2", "commitSet": "4255", "status": "pending", "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16988", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "3", "commitSet": "4256", "status": "pending", "url": null, "build": null, "createdAt": 1458688514000 }], "commitSets": [{ "id": "4255", "revisionItems": [{"commit": "87832"}, {"commit": "93116"}], "customRoots": [], }, { "id": "4256", "revisionItems": [{"commit": "87832"}, {"commit": "96336"}], "customRoots": [], }], "commits": [{ "id": "87832", "repository": "9", "revision": "10.11 15A284", "time": 0 }, { "id": "93116", "repository": "11", "revision": "191622", "time": 1445945816878 }, { "id": "87832", "repository": "9", "revision": "10.11 15A284", "time": 0 }, { "id": "96336", "repository": "11", "revision": "192736", "time": 1448225325650 }], "uploadedFiles": [], "status": "OK" }; } function sampleTestGroupForRetry(config) { const needsNotification = config.needsNotification; const initialRepetitionCount = config.initialRepetitionCount; const mayNeedMoreRequests = config.mayNeedMoreRequests; const hidden = config.hidden; const statusList = config.statusList; const commitSetList = config.commitSetList || ['4255', '4256', '4255', '4256', '4255', '4256']; const repetitionType = config.repetitionType || 'alternating'; return { "testGroups": [{ "id": "2128", "task": "1376", "platform": "31", "name": "Confirm", "author": "rniwa", "createdAt": 1458688514000, hidden, needsNotification, "buildRequests": ["16985", "16986", "16987", "16988", "16989", "16990"], "commitSets": ["4255", "4256"], "notificationSentAt": null, initialRepetitionCount, mayNeedMoreRequests, repetitionType }], "buildRequests": [{ "id": "16985", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "0", "commitSet": commitSetList[0], "status": statusList[0], "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16986", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "1", "commitSet": commitSetList[1], "status": statusList[1], "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16987", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "2", "commitSet": commitSetList[2], "status": statusList[2], "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16988", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "3", "commitSet": commitSetList[3], "status": statusList[3], "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16989", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "4", "commitSet": commitSetList[4], "status": statusList[4], "url": null, "build": null, "createdAt": 1458688514000 }, { "id": "16990", "triggerable": "3", "test": "844", "platform": "31", "testGroup": "2128", "order": "5", "commitSet": commitSetList[5], "status": statusList[5], "url": null, "build": null, "createdAt": 1458688514000 }], "commitSets": [{ "id": "4255", "revisionItems": [{"commit": "87832"}, {"commit": "93116"}], "customRoots": [], }, { "id": "4256", "revisionItems": [{"commit": "87832"}, {"commit": "96336"}], "customRoots": [], }], "commits": [{ "id": "87832", "repository": "9", "revision": "10.11 15A284", "time": 0 }, { "id": "93116", "repository": "11", "revision": "191622", "time": 1445945816878 }, { "id": "87832", "repository": "9", "revision": "10.11 15A284", "time": 0 }, { "id": "96336", "repository": "11", "revision": "192736", "time": 1448225325650 }], "uploadedFiles": [], "status": "OK" }; } describe('TestGroup', function () { MockModels.inject(); const requests = MockRemoteAPI.inject('https://perf.webkit.org', BrowserPrivilegedAPI); describe('fetchForTask', () => { it('should be able to fetch the list of test groups for the same task twice using cache', () => { const fetchPromise = TestGroup.fetchForTask(1376); assert.equal(requests.length, 1); assert.equal(requests[0].method, 'GET'); assert.equal(requests[0].url, '/api/test-groups?task=1376'); requests[0].resolve(sampleTestGroup()); let assertTestGroups = (testGroups) => { assert.equal(testGroups.length, 1); assert.equal(testGroups[0].platform(), MockModels.elCapitan); const buildRequests = testGroups[0].buildRequests(); assert.equal(buildRequests.length, 4); for (let request of buildRequests) { assert.equal(buildRequests[0].triggerable(), MockModels.triggerable); assert.equal(buildRequests[0].test(), MockModels.plt); assert.equal(buildRequests[0].platform(), MockModels.elCapitan); } } return fetchPromise.then((testGroups) => { assertTestGroups(testGroups); return TestGroup.fetchForTask(1376); }).then((testGroups) => { assertTestGroups(testGroups); }); }); }); describe('needsNotification', () => { const requests = MockRemoteAPI.inject('https://perf.webkit.org', NodePrivilegedAPI); beforeEach(() => { PrivilegedAPI.configure('test', 'password'); }); it('should update notified author flag', async () => { const fetchPromise = TestGroup.fetchForTask(1376); requests[0].resolve(sampleTestGroup()); let testGroups = await fetchPromise; assert(testGroups.length, 1); let testGroup = testGroups[0]; assert.equal(testGroup.needsNotification(), true); const updatePromise = testGroup.didSendNotification(); assert.equal(requests.length, 2); assert.equal(requests[1].method, 'POST'); assert.equal(requests[1].url, '/privileged-api/update-test-group'); delete requests[1].data.notificationSentAt; assert.deepEqual(requests[1].data, {group: '2128', needsNotification: false, workerName: 'test', workerPassword: 'password'}); requests[1].resolve(); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 3); assert.equal(requests[2].method, 'GET'); assert.equal(requests[2].url, '/api/test-groups/2128'); const updatedTestGroup = sampleTestGroup(false); requests[2].resolve(updatedTestGroup); testGroups = await updatePromise; testGroup = testGroups[0]; assert.equal(testGroup.needsNotification(), false); }); }); describe('initialRepetitionCount', () => { const requests = MockRemoteAPI.inject('https://perf.webkit.org', NodePrivilegedAPI); beforeEach(() => { PrivilegedAPI.configure('test', 'password'); }); it('should construct initialRepetitionCount from data', async () => { const fetchPromise = TestGroup.fetchForTask(1376); requests[0].resolve(sampleTestGroup()); let testGroups = await fetchPromise; assert(testGroups.length, 1); let testGroup = testGroups[0]; assert.equal(testGroup.initialRepetitionCount(), 2); }); }); describe('mayNeedMoreRequests', () => { const requests = MockRemoteAPI.inject('https://perf.webkit.org', NodePrivilegedAPI); beforeEach(() => { PrivilegedAPI.configure('test', 'password'); }); it('should construct mayNeedMoreRequests from data', async () => { const fetchPromise = TestGroup.fetchForTask(1376); requests[0].resolve(sampleTestGroup()); let testGroups = await fetchPromise; assert(testGroups.length, 1); let testGroup = testGroups[0]; assert.ok(testGroup.mayNeedMoreRequests()); }); it('should be able to clear mayNeedMoreRequests flag', async () => { const fetchPromise = TestGroup.fetchForTask(1376); requests[0].resolve(sampleTestGroup()); let testGroups = await fetchPromise; assert(testGroups.length, 1); let testGroup = testGroups[0]; assert.ok(testGroup.mayNeedMoreRequests()); const updatePromise = testGroup.clearMayNeedMoreBuildRequests(); assert.equal(requests.length, 2); assert.equal(requests.length, 2); assert.equal(requests[1].method, 'POST'); assert.equal(requests[1].url, '/privileged-api/update-test-group'); assert.deepEqual(requests[1].data, {group: '2128', mayNeedMoreRequests: false, workerName: 'test', workerPassword: 'password'}); requests[1].resolve(); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 3); assert.equal(requests[2].method, 'GET'); assert.equal(requests[2].url, '/api/test-groups/2128'); const updatedTestGroup = sampleTestGroup(true, 4, false); requests[2].resolve(updatedTestGroup); testGroups = await updatePromise; testGroup = testGroups[0]; assert.equal(testGroup.mayNeedMoreRequests(), false); }); }); describe('_createModelsFromFetchedTestGroups', function () { it('should create test groups', function () { var groups = TestGroup._createModelsFromFetchedTestGroups(sampleTestGroup()); assert.equal(groups.length, 1); var group = groups[0]; assert.ok(group instanceof TestGroup); assert.equal(group.id(), 2128); assert.ok(group.createdAt() instanceof Date); assert.equal(group.isHidden(), false); assert.equal(group.needsNotification(), true); assert.equal(+group.createdAt(), 1458688514000); assert.equal(group.initialRepetitionCount(), sampleTestGroup()['buildRequests'].length / 2); assert.ok(group.hasPending()); assert.ok(!group.hasFinished()); assert.ok(!group.hasStarted()); }); it('should not create a new instance of TestGroup object if there is a matching entry', function () { var firstObject = TestGroup._createModelsFromFetchedTestGroups(sampleTestGroup())[0]; assert.ok(firstObject instanceof TestGroup); assert.equal(TestGroup._createModelsFromFetchedTestGroups(sampleTestGroup())[0], firstObject); }); it('should create build requests for each group', function () { var groups = TestGroup._createModelsFromFetchedTestGroups(sampleTestGroup()); assert.equal(groups.length, 1); assert.equal(groups[0].buildRequests().length, sampleTestGroup()['buildRequests'].length); var buildRequests = groups[0].buildRequests(); assert.equal(buildRequests[0].id(), 16985); assert.equal(buildRequests[0].order(), 0); assert.ok(!buildRequests[0].hasFinished()); assert.ok(!buildRequests[0].hasStarted()); assert.ok(buildRequests[0].isPending()); assert.equal(buildRequests[0].statusLabel(), 'Waiting'); assert.equal(buildRequests[0].buildId(), null); assert.equal(buildRequests[1].id(), 16986); assert.equal(buildRequests[1].order(), 1); assert.ok(!buildRequests[1].hasFinished()); assert.ok(!buildRequests[1].hasStarted()); assert.ok(buildRequests[1].isPending()); assert.equal(buildRequests[1].statusLabel(), 'Waiting'); assert.equal(buildRequests[1].buildId(), null); }); it('should create root sets for each group', function () { var buildRequests = TestGroup._createModelsFromFetchedTestGroups(sampleTestGroup())[0].buildRequests(); var firstSet = buildRequests[0].commitSet(); assert.ok(firstSet instanceof CommitSet); assert.equal(firstSet, buildRequests[2].commitSet()); var secondSet = buildRequests[1].commitSet(); assert.ok(secondSet instanceof CommitSet); assert.equal(secondSet, buildRequests[3].commitSet()); assert.equal(firstSet.revisionForRepository(MockModels.webkit), '191622'); var firstWebKitCommit = firstSet.commitForRepository(MockModels.webkit); assert.ok(firstWebKitCommit instanceof CommitLog); assert.ok(firstWebKitCommit, buildRequests[2].commitSet().commitForRepository(MockModels.webkit)); assert.ok(firstWebKitCommit.repository(), MockModels.webkit); assert.ok(firstWebKitCommit.revision(), '191622'); assert.ok(firstWebKitCommit.time() instanceof Date); assert.ok(+firstWebKitCommit.time(), 1445945816878); assert.equal(secondSet.revisionForRepository(MockModels.webkit), '192736'); var secondWebKitCommit = secondSet.commitForRepository(MockModels.webkit); assert.ok(secondWebKitCommit instanceof CommitLog); assert.ok(secondWebKitCommit, buildRequests[3].commitSet().commitForRepository(MockModels.webkit)); assert.ok(secondWebKitCommit.repository(), MockModels.webkit); assert.ok(secondWebKitCommit.revision(), '192736'); assert.ok(secondWebKitCommit.time() instanceof Date); assert.ok(+secondWebKitCommit.time(), 1445945816878); assert.equal(firstSet.revisionForRepository(MockModels.osx), '10.11 15A284'); var osxCommit = firstSet.commitForRepository(MockModels.osx); assert.ok(osxCommit instanceof CommitLog); assert.equal(osxCommit, buildRequests[1].commitSet().commitForRepository(MockModels.osx)); assert.equal(osxCommit, buildRequests[2].commitSet().commitForRepository(MockModels.osx)); assert.equal(osxCommit, buildRequests[3].commitSet().commitForRepository(MockModels.osx)); assert.ok(osxCommit.repository(), MockModels.osx); assert.ok(osxCommit.revision(), '10.11 15A284'); }); }); function testGroupWithStatusList(list) { var data = sampleTestGroup(); data.buildRequests[0].status = list[0]; data.buildRequests[1].status = list[1]; data.buildRequests[2].status = list[2]; data.buildRequests[3].status = list[3]; return TestGroup._createModelsFromFetchedTestGroups(data)[0]; } describe('hasFinished', function () { it('should return true if all build requests have completed', function () { assert.ok(testGroupWithStatusList(['completed', 'completed', 'completed', 'completed']).hasFinished()); }); it('should return true if all build requests have failed', function () { assert.ok(testGroupWithStatusList(['failed', 'failed', 'failed', 'failed']).hasFinished()); }); it('should return true if all build requests have been canceled', function () { assert.ok(testGroupWithStatusList(['canceled', 'canceled', 'canceled', 'canceled']).hasFinished()); }); it('should return true if all build requests have completed or failed', function () { assert.ok(testGroupWithStatusList(['failed', 'completed', 'failed', 'failed']).hasFinished()); }); it('should return true if all build requests have completed, failed, or canceled', function () { assert.ok(testGroupWithStatusList(['failed', 'completed', 'canceled', 'canceled']).hasFinished()); }); it('should return false if all build requests are pending', function () { assert.ok(!testGroupWithStatusList(['pending', 'pending', 'pending', 'pending']).hasFinished()); }); it('should return false if some build requests are pending', function () { assert.ok(!testGroupWithStatusList(['completed', 'completed', 'completed', 'pending']).hasFinished()); }); it('should return false if some build requests are scheduled', function () { assert.ok(!testGroupWithStatusList(['completed', 'completed', 'completed', 'scheduled']).hasFinished()); }); it('should return false if some build requests are running', function () { assert.ok(!testGroupWithStatusList(['completed', 'canceled', 'completed', 'running']).hasFinished()); }); }); describe('hasStarted', function () { it('should return true if all build requests have completed', function () { assert.ok(testGroupWithStatusList(['completed', 'completed', 'completed', 'completed']).hasStarted()); }); it('should return true if all build requests have failed', function () { assert.ok(testGroupWithStatusList(['failed', 'failed', 'failed', 'failed']).hasStarted()); }); it('should return true if all build requests have been canceled', function () { assert.ok(testGroupWithStatusList(['canceled', 'canceled', 'canceled', 'canceled']).hasStarted()); }); it('should return true if all build requests have completed or failed', function () { assert.ok(testGroupWithStatusList(['failed', 'completed', 'failed', 'failed']).hasStarted()); }); it('should return true if all build requests have completed, failed, or cancled', function () { assert.ok(testGroupWithStatusList(['failed', 'completed', 'canceled', 'canceled']).hasStarted()); }); it('should return false if all build requests are pending', function () { assert.ok(!testGroupWithStatusList(['pending', 'pending', 'pending', 'pending']).hasStarted()); }); it('should return true if some build requests have completed', function () { assert.ok(testGroupWithStatusList(['completed', 'pending', 'pending', 'pending']).hasStarted()); }); it('should return true if some build requests are scheduled', function () { assert.ok(testGroupWithStatusList(['scheduled', 'pending', 'pending', 'pending']).hasStarted()); }); it('should return true if some build requests are running', function () { assert.ok(testGroupWithStatusList(['running', 'pending', 'pending', 'pending']).hasStarted()); }); }); describe('hasPending', function () { it('should return false if all build requests have completed', function () { assert.ok(!testGroupWithStatusList(['completed', 'completed', 'completed', 'completed']).hasPending()); }); it('should return false if all build requests have failed', function () { assert.ok(!testGroupWithStatusList(['failed', 'failed', 'failed', 'failed']).hasPending()); }); it('should return false if all build requests have been canceled', function () { assert.ok(!testGroupWithStatusList(['canceled', 'canceled', 'canceled', 'canceled']).hasPending()); }); it('should return false if all build requests have completed or failed', function () { assert.ok(!testGroupWithStatusList(['failed', 'completed', 'failed', 'failed']).hasPending()); }); it('should return false if all build requests have completed, failed, or cancled', function () { assert.ok(!testGroupWithStatusList(['failed', 'completed', 'canceled', 'canceled']).hasPending()); }); it('should return true if all build requests are pending', function () { assert.ok(testGroupWithStatusList(['pending', 'pending', 'pending', 'pending']).hasPending()); }); it('should return true if some build requests are pending', function () { assert.ok(testGroupWithStatusList(['completed', 'failed', 'canceled', 'pending']).hasPending()); }); it('should return false if some build requests are scheduled and others have completed', function () { assert.ok(!testGroupWithStatusList(['completed', 'completed', 'completed', 'scheduled']).hasPending()); }); }); describe('createWithTask', () => { it('should fetch the newly created analysis task even when all analysis tasks had previously been fetched', async () => { const allAnalysisTasks = AnalysisTask.fetchAll(); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/api/analysis-tasks'); requests[0].resolve({ 'analysisTasks': [], 'bugs': [], 'commits': [], 'status': 'OK' }); const set1 = new CustomCommitSet; set1.setRevisionForRepository(MockModels.webkit, '191622'); set1.setRevisionForRepository(MockModels.sharedRepository, '80229'); const set2 = new CustomCommitSet; set2.setRevisionForRepository(MockModels.webkit, '191623'); set2.setRevisionForRepository(MockModels.sharedRepository, '80229'); const promise = TestGroup.createWithTask('some-task', MockModels.somePlatform, MockModels.someTest, 'some-group', 4, 'alternating', [set1, set2], true, 'alternating'); assert.equal(requests.length, 2); assert.equal(requests[1].url, '/privileged-api/generate-csrf-token'); requests[1].resolve({ token: 'abc', expiration: Date.now() + 100 * 1000, }); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 3); assert.equal(requests[2].method, 'POST'); assert.deepEqual(requests[2].data, {taskName: 'some-task', name: 'some-group', platform: 65, test: 1, repetitionCount: 4, revisionSets: [{'11': {ownerRevision: null, patch: null, revision: "191622"}, '16': {ownerRevision: null, patch: null, revision: "80229"}}, {'11': {ownerRevision: null, patch: null, revision: "191623"}, '16': {ownerRevision: null, patch: null, revision: "80229"}}], needsNotification: true, repetitionType: 'alternating', token: 'abc'}); assert.equal(requests[2].url, '/privileged-api/create-test-group'); requests[2].resolve({ taskId: 123, testGroupId: 456, }); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 4); assert.equal(requests[3].method, 'GET'); assert.equal(requests[3].url, '/api/analysis-tasks?id=123'); }); }); describe('scheduleMoreRequestsOrClearFlag', () => { const requests = MockRemoteAPI.inject(null, NodePrivilegedAPI); MockModels.inject(); beforeEach(() => { PrivilegedAPI.configure('worker_name', 'password'); }); it('should add one more build request when one of the existing requests failed', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: false, statusList: ["completed", "completed", "completed", "completed", "completed", "failed"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/add-build-requests'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', addCount: 1, commitSet: null}); requests[0].resolve(); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 2); assert.equal(requests[1].url, '/api/test-groups/2128'); }); it('should add two more build requests when two failed build request found for a commit set', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: false, statusList: ["completed", "failed", "completed", "completed", "completed", "failed"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/add-build-requests'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', addCount: 2, commitSet: null}); requests[0].resolve(); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 2); assert.equal(requests[1].url, '/api/test-groups/2128'); }); it('should not schedule more build requests when "may_need_more_requests" is not set', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: false, hidden: false, statusList: ["completed", "failed", "completed", "completed", "completed", "failed"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); assert.equal(requests.length, 0); }); it('should not schedule more build requests when a test group is hidden', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: true, statusList: ["completed", "failed", "completed", "completed", "completed", "failed"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/update-test-group'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', mayNeedMoreRequests: false}); requests[0].resolve(); }); it('should not schedule more build requests when all requests for a commit set had failed', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: false, statusList: ["completed", "failed", "completed", "failed", "completed", "failed"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/update-test-group'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', mayNeedMoreRequests: false}); requests[0].resolve(); }); it('should schedule more build requests to reach the retry limit even though completed iterations will not meet expectation', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: false, statusList: ["completed", "completed", "failed", "completed", "failed", "failed"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(1.5); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/add-build-requests'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', addCount: 1, commitSet: null}); requests[0].resolve(); }); it('should not schedule more build requests when additional build requests are still pending', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 2, mayNeedMoreRequests: true, hidden: false, statusList: ["completed", "completed", "failed", "failed", "pending", "pending"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/update-test-group'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', mayNeedMoreRequests: false}); requests[0].resolve(); }); it('should not clear "may need more requests" flag when one commit set has not got a successful run but have pending builds', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: false, statusList: ["completed", "failed", "completed", "failed", "pending", "pending"]}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); assert.equal(requests.length, 0); }); it('should schedule retry build requests and keep "may need more requests" flag when not all requests for a configuration had failed for a sequential test group', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: false, repetitionType: 'sequential', statusList: ["completed", "failed", "failed", "pending", "pending", "pending"], commitSetList: ['4255', '4255', '4255', '4256', '4256', '4256']}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/add-build-requests'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', addCount: 2, commitSet: '4255'}); requests[0].resolve(); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 2); assert.equal(requests[1].url, '/api/test-groups/2128'); requests[1].resolve(sampleTestGroupForRetry(testGroupConfig)); }); it('should retry the second configuration (B) if the first configuration (A) reached the retry limit but had at least one successful iteration for a sequential test group', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 2, mayNeedMoreRequests: true, hidden: false, repetitionType: 'sequential', statusList: ["completed", "failed", "failed", "failed", "completed", "failed"], commitSetList: ['4255', '4255', '4255', '4255', '4256', '4256']}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(2); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/add-build-requests'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', addCount: 1, commitSet: '4256'}); requests[0].resolve(); }); it('should clear test group "may need more requests" flag in sequential mode if all initially scheduled A repetitions failed', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 3, mayNeedMoreRequests: true, hidden: false, repetitionType: 'sequential', statusList: ["failed", "failed", "failed", "pending", "pending", "pending"], commitSetList: ['4255', '4255', '4255', '4256', '4256', '4256']}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(2); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/update-test-group'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', mayNeedMoreRequests: false}); requests[0].resolve(); }); it('should clear a sequential test group "may need more requests" flag when initial requested repetition is satisfied', async () => { const testGroupConfig = {needsNotification: false, initialRepetitionCount: 2, mayNeedMoreRequests: true, hidden: false, repetitionType: 'sequential', statusList: ["completed", "completed", "completed", "failed", "failed", "completed"], commitSetList: ['4255', '4255', '4256', '4256', '4256', '4256']}; const data = sampleTestGroupForRetry(testGroupConfig); const testGroups = TestGroup._createModelsFromFetchedTestGroups(data); testGroups[0].scheduleMoreRequestsOrClearFlag(3); await MockRemoteAPI.waitForRequest(); assert.equal(requests.length, 1); assert.equal(requests[0].url, '/privileged-api/update-test-group'); assert.deepEqual(requests[0].data, {workerName: 'worker_name', workerPassword: 'password', group: '2128', mayNeedMoreRequests: false}); requests[0].resolve(); }); }); });