3 class TestGroup extends LabeledObject {
5 constructor(id, object)
8 this._taskId = object.task;
9 this._authorName = object.author;
10 this._createdAt = new Date(object.createdAt);
11 this._isHidden = object.hidden;
12 this._buildRequests = [];
13 this._requestsAreInOrder = false;
14 this._repositories = null;
15 this._requestedRootSets = null;
16 this._rootSetToLabel = new Map;
17 this._allRootSets = null;
18 console.assert(!object.platform || object.platform instanceof Platform);
19 this._platform = object.platform;
22 updateSingleton(object)
24 super.updateSingleton(object);
26 console.assert(this._taskId == object.task);
27 console.assert(+this._createdAt == +object.createdAt);
28 console.assert(this._platform == object.platform);
30 this._isHidden = object.hidden;
33 createdAt() { return this._createdAt; }
34 isHidden() { return this._isHidden; }
35 buildRequests() { return this._buildRequests; }
36 addBuildRequest(request)
38 this._buildRequests.push(request);
39 this._requestsAreInOrder = false;
40 this._requestedRootSets = null;
41 this._rootSetToLabel.clear();
46 if (!this._buildRequests.length)
48 var rootSet = this._buildRequests[0].rootSet();
50 for (var request of this._buildRequests) {
51 if (request.rootSet() == rootSet)
59 if (!this._requestedRootSets) {
60 this._orderBuildRequests();
61 this._requestedRootSets = [];
62 for (var request of this._buildRequests) {
63 var set = request.rootSet();
64 if (!this._requestedRootSets.includes(set))
65 this._requestedRootSets.push(set);
67 this._requestedRootSets.sort(function (a, b) { return a.latestCommitTime() - b.latestCommitTime(); });
69 for (var set of this._requestedRootSets) {
70 this._rootSetToLabel.set(set, String.fromCharCode('A'.charCodeAt(0) + setIndex));
75 return this._requestedRootSets;
78 requestsForRootSet(rootSet)
80 this._orderBuildRequests();
81 return this._buildRequests.filter(function (request) { return request.rootSet() == rootSet; });
84 labelForRootSet(rootSet)
86 console.assert(this._requestedRootSets);
87 return this._rootSetToLabel.get(rootSet);
92 if (this._requestsAreInOrder)
94 this._buildRequests = this._buildRequests.sort(function (a, b) { return a.order() - b.order(); });
95 this._requestsAreInOrder = true;
100 this._allRootSets = null;
105 return this._buildRequests.every(function (request) { return request.hasFinished(); });
110 return this._buildRequests.some(function (request) { return request.hasStarted(); });
115 return this._buildRequests.some(function (request) { return request.isPending(); });
118 compareTestResults(rootSetA, rootSetB)
120 var beforeValues = this._valuesForRootSet(rootSetA);
121 var afterValues = this._valuesForRootSet(rootSetB);
122 var beforeMean = Statistics.sum(beforeValues) / beforeValues.length;
123 var afterMean = Statistics.sum(afterValues) / afterValues.length;
125 var metric = AnalysisTask.findById(this._taskId).metric();
126 console.assert(metric);
128 var result = {changeType: null, status: 'failed', label: 'Failed', fullLabel: 'Failed', isStatisticallySignificant: false};
130 var hasCompleted = this.hasFinished();
132 if (this.hasStarted()) {
133 result.status = 'running';
134 result.label = 'Running';
135 result.fullLabel = 'Running';
137 console.assert(result.changeType === null);
138 result.status = 'pending';
139 result.label = 'Pending';
140 result.fullLabel = 'Pending';
144 if (beforeValues.length && afterValues.length) {
145 var diff = afterMean - beforeMean;
146 var smallerIsBetter = metric.isSmallerBetter();
147 var changeType = diff < 0 == smallerIsBetter ? 'better' : 'worse';
148 var changeLabel = Math.abs(diff / beforeMean * 100).toFixed(2) + '% ' + changeType;
149 var isSignificant = Statistics.testWelchsT(beforeValues, afterValues);
150 var significanceLabel = isSignificant ? 'significant' : 'insignificant';
152 result.changeType = changeType;
153 result.label = changeLabel;
155 result.status = isSignificant ? result.changeType : 'unchanged';
156 result.fullLabel = `${result.label} (statistically ${significanceLabel})`;
157 result.isStatisticallySignificant = isSignificant;
163 _valuesForRootSet(rootSet)
165 var requests = this.requestsForRootSet(rootSet);
167 for (var request of requests) {
168 if (request.result())
169 values.push(request.result().value);
178 return PrivilegedAPI.sendRequest('update-test-group', {
181 }).then(function (data) {
182 return TestGroup.cachedFetch(`../api/test-groups/${id}`, {}, true)
183 .then(TestGroup._createModelsFromFetchedTestGroups.bind(TestGroup));
187 updateHiddenFlag(hidden)
191 return PrivilegedAPI.sendRequest('update-test-group', {
194 }).then(function (data) {
195 return TestGroup.cachedFetch(`../api/test-groups/${id}`, {}, true)
196 .then(TestGroup._createModelsFromFetchedTestGroups.bind(TestGroup));
200 static createAndRefetchTestGroups(task, name, repetitionCount, rootSets)
203 return PrivilegedAPI.sendRequest('create-test-group', {
206 repetitionCount: repetitionCount,
208 }).then(function (data) {
209 return self.cachedFetch('../api/test-groups', {task: task.id()}, true).then(self._createModelsFromFetchedTestGroups.bind(self));
213 static fetchByTask(taskId)
215 return this.cachedFetch('../api/test-groups', {task: taskId}).then(this._createModelsFromFetchedTestGroups.bind(this));
218 static _createModelsFromFetchedTestGroups(data)
220 var testGroups = data['testGroups'].map(function (row) {
221 row.platform = Platform.findById(row.platform);
222 return TestGroup.ensureSingleton(row.id, row);
225 BuildRequest.constructBuildRequestsFromData(data);
231 if (typeof module != 'undefined')
232 module.exports.TestGroup = TestGroup;