Changeset 269871 in webkit


Ignore:
Timestamp:
Nov 16, 2020 12:32:08 PM (3 years ago)
Author:
Dewei Zhu
Message:

Performance dashboard should avoid building same configuration under one analysis task.
https://bugs.webkit.org/show_bug.cgi?id=218413

Reviewed by Ryosuke Niwa.

Add logic in syncing script to reuse already built roots from same build request under current analysis task.
If there is another same build request scheduled/running, will defer scheduling current build request.

  • public/admin/platforms.php: Fixed newer version of PHP warns on accessing invalid key in an array.
  • public/admin/tests.php: Added a null check against $selected_parent.
  • public/api/build-requests.php: Extended this API to allow reusing roots from existing build request.
  • public/v3/models/build-request.js:

(BuildRequest.prototype.async findBuildRequestWithSameRoots): Find build type build request with same commit set
which can/will be reused under current analysis task.

  • public/v3/models/commit-set.js:

(CommitSet.prototype.equalsIgnoringRoot): Added a helper function which checks commit set equality ignoring the root.
(CommitSet.prototype.equals): Use '_equalsOptionallyIgnoringRoot' as underlying implementation.
(CommitSet.prototype._equalsOptionallyIgnoringRoot): Implementation for both equals and equalsIngnoringRoot.

  • server-tests/api-build-requests-tests.js: Added unit tests.
  • server-tests/resources/mock-data.js: Added new mock data for new unit tests.

(MockData.addMockConfiguration):
(MockData.addMockData):
(MockData.set addMockBuildRequestsWithRoots):
(MockData.set addTwoMockTestGroupWithOwnedCommits):
(MockData.mockTestSyncConfigWithPatchAcceptingBuilder):

  • server-tests/tools-buildbot-triggerable-tests.js: Added unit tests.
  • tools/js/buildbot-triggerable.js:

(BuildbotTriggerable.prototype.async syncOnce):
(BuildbotTriggerable.prototype.async _scheduleRequest): A helper function to reuse the roots if there are built
roots available for same build type build request. If there is another build scheduled for same build request,
will defer scheduling the build request.

  • unit-tests/build-request-tests.js: Add unit tests.
Location:
trunk/Websites/perf.webkit.org
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Websites/perf.webkit.org/ChangeLog

    r269083 r269871  
     12020-10-30  Dewei Zhu  <dewei_zhu@apple.com>
     2
     3        Performance dashboard should avoid building same configuration under one analysis task.
     4        https://bugs.webkit.org/show_bug.cgi?id=218413
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Add logic in syncing script to reuse already built roots from same build request under current analysis task.
     9        If there is another same build request scheduled/running, will defer scheduling current build request.
     10
     11        * public/admin/platforms.php: Fixed newer version of PHP warns on accessing invalid key in an array.
     12        * public/admin/tests.php: Added a null check against $selected_parent.
     13        * public/api/build-requests.php: Extended this API to allow reusing roots from existing build request.
     14        * public/v3/models/build-request.js:
     15        (BuildRequest.prototype.async findBuildRequestWithSameRoots): Find build type build request with same commit set
     16        which can/will be reused under current analysis task.
     17        * public/v3/models/commit-set.js:
     18        (CommitSet.prototype.equalsIgnoringRoot): Added a helper function which checks commit set equality ignoring the root.
     19        (CommitSet.prototype.equals): Use '_equalsOptionallyIgnoringRoot' as underlying implementation.
     20        (CommitSet.prototype._equalsOptionallyIgnoringRoot): Implementation for both equals and equalsIngnoringRoot.
     21        * server-tests/api-build-requests-tests.js: Added unit tests.
     22        * server-tests/resources/mock-data.js: Added new mock data for new unit tests.
     23        (MockData.addMockConfiguration):
     24        (MockData.addMockData):
     25        (MockData.set addMockBuildRequestsWithRoots):
     26        (MockData.set addTwoMockTestGroupWithOwnedCommits):
     27        (MockData.mockTestSyncConfigWithPatchAcceptingBuilder):
     28        * server-tests/tools-buildbot-triggerable-tests.js: Added unit tests.
     29        * tools/js/buildbot-triggerable.js:
     30        (BuildbotTriggerable.prototype.async syncOnce):
     31        (BuildbotTriggerable.prototype.async _scheduleRequest): A helper function to reuse the roots if there are built
     32        roots available for same build type build request. If there is another build scheduled for same build request,
     33        will defer scheduling the build request.
     34        * unit-tests/build-request-tests.js: Add unit tests.
     35
    1362020-10-27  Dewei Zhu  <dewei_zhu@apple.com>
    237
  • trunk/Websites/perf.webkit.org/public/admin/platforms.php

    r269083 r269871  
    103103        global $platform_group_options;
    104104        $id = intval($platform_row['platform_id']);
    105         $platform_group_id = $platform_row['platform_group'];
     105        $platform_group_id = array_get($platform_row, 'platform_group');
    106106        $content = <<< END
    107107<form method="POST"><input type="hidden" name="id" value="$id">
  • trunk/Websites/perf.webkit.org/public/admin/tests.php

    r202000 r269871  
    6565
    6666        foreach ($test_name_resolver->tests() as $test) {
    67             if ($test['test_parent'] != $selected_parent['test_id'])
     67            if ($selected_parent && $test['test_parent'] != $selected_parent['test_id'])
    6868                continue;
    6969
  • trunk/Websites/perf.webkit.org/public/api/build-requests.php

    r250465 r269871  
    4848        $url = array_get($info, 'url');
    4949        $status_description = array_get($info, 'statusDescription');
     50        $build_request_for_root_reuse_id = array_get($info, 'buildRequestForRootReuse');
    5051        $request_row = $db->select_first_row('build_requests', 'request', array('id' => $id));
    5152        if ($status == 'failedIfNotCompleted') {
     
    6970            }
    7071            $db->update_row('build_requests', 'request', array('id' => $id), array('status' => $status, 'url' => $url, 'status_description' => $status_description));
     72            if ($build_request_for_root_reuse_id) {
     73                $build_request_for_root_reuse_id = intval($build_request_for_root_reuse_id);
     74                $build_request_for_root_reuse = $db->select_first_row('build_requests', 'request', array('id' => $build_request_for_root_reuse_id));
     75                if (!$build_request_for_root_reuse) {
     76                    $db->rollback_transaction();
     77                    exit_with_error('FailedToFindbuildRequestForRootReuse', array('buildRequest' => $build_request_for_root_reuse_id));
     78                }
     79                if ($build_request_for_root_reuse['request_status'] != 'completed') {
     80                    $db->rollback_transaction();
     81                    exit_with_error('CanOnlyReuseCompletedBuildRequest', array('buildRequest' => $build_request_for_root_reuse_id, 'status' => $build_request_for_root_reuse['request_status']));
     82                }
     83                $error = reuse_roots_in_commit_set($db, $build_request_for_root_reuse['request_commit_set'], $request_row['request_commit_set']);
     84                if ($error) {
     85                    $db->rollback_transaction();
     86                    exit_with_error($error['status'], $error['details']);
     87                }
     88            }
    7189            if ($status != 'failed')
    7290                continue;
     
    83101}
    84102
     103function reuse_roots_in_commit_set($db, $source_id, $destination_id) {
     104    $commit_set_items_source = $db->query_and_fetch_all('SELECT * FROM commit_set_items WHERE commitset_set = $1 AND commitset_commit IS NOT NULL', array($source_id));
     105    $commit_set_items_destination = $db->query_and_fetch_all('SELECT * FROM commit_set_items WHERE commitset_set = $1 AND commitset_commit IS NOT NULL', array($destination_id));
     106    if (count($commit_set_items_source) != count($commit_set_items_destination)) {
     107        return array('status' => 'CannotReuseRootWithNonMatchingCommitSets', 'details' => array('sourceCommitSet' => $source_id,
     108            'destinationCommitSet' => $destination_id));
     109    }
     110
     111    $root_file_ids = array();
     112    foreach ($commit_set_items_destination as &$destination_item) {
     113        $source_item = NULL;
     114        foreach ($commit_set_items_source as &$item) {
     115            if ($destination_item['commitset_commit'] == $item['commitset_commit']
     116                && $destination_item['commitset_patch_file'] == $item['commitset_patch_file']
     117                && $destination_item['commitset_commit_owner'] == $item['commitset_commit_owner']
     118                && $destination_item['commitset_requires_build'] == $item['commitset_requires_build']) {
     119                $source_item = $item;
     120                break;
     121            }
     122        }
     123        if (!$source_item)
     124            return array('status' => 'NoMatchingCommitSetItem', 'details' => array('commitSet' => $source_id));
     125
     126        $root_file_id = $source_item['commitset_root_file'];
     127        if (!$root_file_id) {
     128            if (!$db->is_true($source_item['commitset_requires_build']))
     129                continue;
     130            return array('status' => 'MissingRootFileFromSourceCommitSet', 'details' => array('commitSet' => $destination_id, 'rootFile' => $root_file_id));
     131        }
     132
     133        $root_file_row = $db->select_first_row('uploaded_files', 'file', array('id' => $root_file_id));
     134        if ($root_file_row['file_deleted_at'])
     135            return array('status' => 'CannotReuseDeletedRoot', 'details' => array('commitSet' => $destination_id, 'rootFile' => $root_file_id));
     136
     137        $db->update_row('commit_set_items', 'commitset', array('set' => $destination_id, 'commit' => $destination_item['commitset_commit']),
     138            array('root_file' => $root_file_id), 'set');
     139
     140        array_push($root_file_ids, $root_file_id);
     141    }
     142
     143    // There could be a race that those root files get purged after updating commit_set_items.
     144    // Add another round of check to ensure they are not deleted by the end of this function to
     145    // mitigate the race condition.
     146    foreach ($root_file_ids as &$root_file_id) {
     147        $root_file_row = $db->select_first_row('uploaded_files', 'file', array('id' => $root_file_id));
     148        if ($root_file_row['file_deleted_at'])
     149            return array('status' => 'CannotReuseDeletedRoot', 'details' => array('commitSet' => $destination_id, 'rootFile' => $root_file_id));
     150    }
     151
     152    return NULL;
     153}
     154
    85155main(array_get($_GET, 'id'),
    86156    array_key_exists('PATH_INFO', $_SERVER) ? explode('/', trim($_SERVER['PATH_INFO'], '/')) : array(),
  • trunk/Websites/perf.webkit.org/public/v3/models/build-request.js

    r250465 r269871  
    8888    buildId() { return this._buildId; }
    8989    createdAt() { return this._createdAt; }
    90 
    91     static formatTimeInterval(intervalInMillionSeconds) {
     90    async findBuildRequestWithSameRoots()
     91    {
     92        if (!this.isBuild())
     93            return null;
     94        let scheduledBuildRequest = null;
     95        let runningBuildRequest = null;
     96        // Set ignoreCache = true as latest status of test groups is expected.
     97        const allTestGroupsInTask = await TestGroup.fetchForTask(this.analysisTaskId(), true);
     98        for (const group of allTestGroupsInTask) {
     99            if (group.id() == this.testGroupId())
     100                continue;
     101            if (group.isHidden())
     102                continue;
     103            for (const buildRequest of group.buildRequests()) {
     104                if (!buildRequest.isBuild())
     105                    continue;
     106                if (!this.platform().isInSameGroupAs(buildRequest.platform()))
     107                    continue;
     108                if (!buildRequest.commitSet().equalsIgnoringRoot(this.commitSet()))
     109                    continue;
     110                if (!buildRequest.commitSet().areAllRootsAvailable())
     111                    continue;
     112                if (buildRequest.hasCompleted())
     113                    return buildRequest;
     114                if (buildRequest.isScheduled()
     115                    && (!scheduledBuildRequest || buildRequest.createdAt() < scheduledBuildRequest.createdAt())) {
     116                    scheduledBuildRequest = buildRequest;
     117                }
     118                if (buildRequest.status() == 'running'
     119                    && (!runningBuildRequest || buildRequest.createdAt() < runningBuildRequest.createdAt())) {
     120                    runningBuildRequest = buildRequest;
     121                }
     122            }
     123        }
     124        return runningBuildRequest || scheduledBuildRequest;
     125    }
     126
     127    static formatTimeInterval(intervalInMillionSeconds)
     128    {
    92129        let intervalInSeconds = intervalInMillionSeconds / 1000;
    93130        const units = [
  • trunk/Websites/perf.webkit.org/public/v3/models/commit-set.js

    r246581 r269871  
    7575    commits() { return  Array.from(this._repositoryToCommitMap.values()); }
    7676
     77    areAllRootsAvailable()
     78    {
     79        return this.allRootFiles().every(rootFile => !rootFile.deletedAt() || this.customRoots().find(rootFile));
     80    }
     81
    7782    revisionForRepository(repository)
    7883    {
     
    103108    }
    104109
     110    equalsIgnoringRoot(other)
     111    {
     112        return this._equalsOptionallyIgnoringRoot(other, true);
     113    }
     114
    105115    equals(other)
     116    {
     117        return this._equalsOptionallyIgnoringRoot(other, false);
     118    }
     119
     120    _equalsOptionallyIgnoringRoot(other, ignoringRoot)
    106121    {
    107122        if (this._repositories.length != other._repositories.length)
     
    112127            if (this.patchForRepository(repository) != other.patchForRepository(repository))
    113128                return false;
    114             if (this.rootForRepository(repository) != other.rootForRepository(repository))
     129            if (this.rootForRepository(repository) != other.rootForRepository(repository) && !ignoringRoot)
    115130                return false;
    116131            if (this.ownerCommitForRepository(repository) != other.ownerCommitForRepository(repository))
  • trunk/Websites/perf.webkit.org/public/v3/models/platform.js

    r269083 r269871  
    2323        var map = this.namedStaticMap('name');
    2424        return map ? map[name] : null;
     25    }
     26
     27    isInSameGroupAs(other)
     28    {
     29        if (!this.group() && !other.group())
     30            return this == other;
     31        return this.group() == other.group();
    2532    }
    2633
  • trunk/Websites/perf.webkit.org/server-tests/api-build-requests-tests.js

    r250465 r269871  
    66let TestServer = require('./resources/test-server.js');
    77const prepareServerTest = require('./resources/common-operations.js').prepareServerTest;
     8const assertThrows = require('../server-tests/resources/common-operations').assertThrows;
     9const crypto = require('crypto');
    810
    911describe('/api/build-requests', function () {
     
    6365            assert.deepEqual(content['buildRequests'][3], {id: '707', task: '1080', triggerable: '1000', repositoryGroup: '2001', test: '200', platform: '65', testGroup: '900', order: '3', commitSet: '404', status: 'pending', statusDescription: null, url: null, build: null, createdAt: 0});
    6466       });
     67    });
     68
     69    it('reuse roots from existing build requests if the commits sets are equal except the existence of roots', async () => {
     70        await MockData.addMockBuildRequestsWithRoots(TestServer.database());
     71        let content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     72
     73        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     74        assert.equal(content['commitSets'].length, 4);
     75        assert.equal(content['commitSets'][0].id, 500);
     76        assert.equal(content['commitSets'][2].id, 600);
     77
     78        assert.deepEqual(content['commitSets'][0].revisionItems, [
     79            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     80            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     81        assert.deepEqual(content['commitSets'][2].revisionItems, [
     82            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     83            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     84
     85        assert.equal(content['buildRequests'].length, 8);
     86        assert.equal(content['buildRequests'][0].id, 800);
     87        assert.equal(content['buildRequests'][0].commitSet, 500);
     88        assert.equal(content['buildRequests'][0].status, 'completed');
     89        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     90        assert.equal(content['buildRequests'][4].id, 900);
     91        assert.equal(content['buildRequests'][4].commitSet, 600);
     92        assert.equal(content['buildRequests'][4].status, 'pending');
     93        assert.equal(content['buildRequests'][4].url, null);
     94
     95        const updates = {900: {
     96            status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: content['buildRequests'][0].id}};
     97        const response = await TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     98            'slaveName': 'sync-slave',
     99            'slavePassword': 'password',
     100            'buildRequestUpdates': updates
     101        });
     102
     103        content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     104        assert.equal(content['commitSets'].length, 4);
     105        assert.equal(content['commitSets'][0].id, 500);
     106        assert.equal(content['commitSets'][2].id, 600);
     107        assert.deepEqual(content['commitSets'][0].revisionItems, [
     108            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     109            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     110        assert.deepEqual(content['commitSets'][2].revisionItems, [
     111            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     112            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     113
     114        assert.equal(content['buildRequests'].length, 8);
     115        assert.equal(content['buildRequests'][0].id, 800);
     116        assert.equal(content['buildRequests'][0].commitSet, 500);
     117        assert.equal(content['buildRequests'][0].status, 'completed');
     118        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     119        assert.equal(content['buildRequests'][4].id, 900);
     120        assert.equal(content['buildRequests'][4].commitSet, 600);
     121        assert.equal(content['buildRequests'][4].status, 'completed');
     122        assert.equal(content['buildRequests'][4].url, 'http://build.webkit.org/buids/1');
     123    });
     124
     125    it('should reuse root built for owned commit if same completed build request exists', async () => {
     126        await MockData.addTwoMockTestGroupWithOwnedCommits(TestServer.database());
     127        let content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     128        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     129        assert.equal(content['commitSets'].length, 4);
     130        assert.equal(content['commitSets'][0].id, 403);
     131        assert.equal(content['commitSets'][2].id, 405);
     132
     133        assert.deepEqual(content['commitSets'][0].revisionItems, [
     134            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     135            {commit: '93116', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     136            {commit: '1797', commitOwner: '93116', patch: null, requiresBuild: true, rootFile: 101}]);
     137        assert.deepEqual(content['commitSets'][2].revisionItems, [
     138            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     139            {commit: '93116', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     140            {commit: '1797', commitOwner: '93116', patch: null, requiresBuild: true, rootFile: null}]);
     141
     142        assert.equal(content['buildRequests'].length, 8);
     143        assert.equal(content['buildRequests'][0].id, 704);
     144        assert.equal(content['buildRequests'][0].commitSet, 403);
     145        assert.equal(content['buildRequests'][0].status, 'completed');
     146        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     147        assert.equal(content['buildRequests'][4].id, 708);
     148        assert.equal(content['buildRequests'][4].commitSet, 405);
     149        assert.equal(content['buildRequests'][4].status, 'pending');
     150        assert.equal(content['buildRequests'][4].url, null);
     151
     152        const updates = {708: {
     153            status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: 704}};
     154
     155        const response = await TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     156            'slaveName': 'sync-slave',
     157            'slavePassword': 'password',
     158            'buildRequestUpdates': updates
     159        });
     160
     161        content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     162        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     163        assert.equal(content['commitSets'].length, 4);
     164        assert.equal(content['commitSets'][0].id, 403);
     165        assert.equal(content['commitSets'][2].id, 405);
     166
     167        assert.deepEqual(content['commitSets'][0].revisionItems, [
     168            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     169            {commit: '93116', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     170            {commit: '1797', commitOwner: '93116', patch: null, requiresBuild: true, rootFile: 101}]);
     171        assert.deepEqual(content['commitSets'][2].revisionItems, [
     172            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     173            {commit: '93116', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     174            {commit: '1797', commitOwner: '93116', patch: null, requiresBuild: true, rootFile: 101}]);
     175
     176        assert.equal(content['buildRequests'].length, 8);
     177        assert.equal(content['buildRequests'][0].id, 704);
     178        assert.equal(content['buildRequests'][0].commitSet, 403);
     179        assert.equal(content['buildRequests'][0].status, 'completed');
     180        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     181        assert.equal(content['buildRequests'][4].id, 708);
     182        assert.equal(content['buildRequests'][4].commitSet, 405);
     183        assert.equal(content['buildRequests'][4].status, 'completed');
     184        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     185    });
     186
     187    it('reuse roots from existing build requests if the commits sets are equal except the existence of custom roots', async () => {
     188        const db = TestServer.database();
     189        await MockData.addMockBuildRequestsWithRoots(db);
     190        await Promise.all([
     191            db.insert('uploaded_files', {id: 103, filename: 'custom-root-103', extension: '.tgz', size: 1, sha256: crypto.createHash('sha256').update('custom-root-103').digest('hex')}),
     192            db.insert('commit_set_items', {set: 500, commit: null, patch_file: null, requires_build: false, root_file: 103}),
     193            db.insert('uploaded_files', {id: 104, filename: 'custom-root-104', extension: '.tgz', size: 1, sha256: crypto.createHash('sha256').update('custom-root-104').digest('hex')}),
     194            db.insert('commit_set_items', {set: 600, commit: null, patch_file: null, requires_build: false, root_file: 104}),
     195        ]);
     196        let content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     197
     198        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     199        assert.equal(content['commitSets'].length, 4);
     200        assert.equal(content['commitSets'][0].id, 500);
     201        assert.equal(content['commitSets'][2].id, 600);
     202
     203        assert.deepEqual(content['commitSets'][0].revisionItems, [
     204            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     205            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     206        assert.deepEqual(content['commitSets'][2].revisionItems, [
     207            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     208            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     209        assert.deepEqual(content['commitSets'][0].customRoots, [103]);
     210        assert.deepEqual(content['commitSets'][2].customRoots, [104]);
     211
     212        assert.equal(content['buildRequests'].length, 8);
     213        assert.equal(content['buildRequests'][0].id, 800);
     214        assert.equal(content['buildRequests'][0].commitSet, 500);
     215        assert.equal(content['buildRequests'][0].status, 'completed');
     216        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     217        assert.equal(content['buildRequests'][4].id, 900);
     218        assert.equal(content['buildRequests'][4].commitSet, 600);
     219        assert.equal(content['buildRequests'][4].status, 'pending');
     220        assert.equal(content['buildRequests'][4].url, null);
     221
     222        const updates = {900: {
     223                status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: content['buildRequests'][0].id}};
     224        const response = await TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     225            'slaveName': 'sync-slave',
     226            'slavePassword': 'password',
     227            'buildRequestUpdates': updates
     228        });
     229
     230        content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     231        assert.equal(content['commitSets'].length, 4);
     232        assert.equal(content['commitSets'][0].id, 500);
     233        assert.equal(content['commitSets'][2].id, 600);
     234        assert.deepEqual(content['commitSets'][0].revisionItems, [
     235            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     236            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     237        assert.deepEqual(content['commitSets'][2].revisionItems, [
     238            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     239            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     240        assert.deepEqual(content['commitSets'][0].customRoots, [103]);
     241        assert.deepEqual(content['commitSets'][2].customRoots, [104]);
     242
     243        assert.equal(content['buildRequests'].length, 8);
     244        assert.equal(content['buildRequests'][0].id, 800);
     245        assert.equal(content['buildRequests'][0].commitSet, 500);
     246        assert.equal(content['buildRequests'][0].status, 'completed');
     247        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     248        assert.equal(content['buildRequests'][4].id, 900);
     249        assert.equal(content['buildRequests'][4].commitSet, 600);
     250        assert.equal(content['buildRequests'][4].status, 'completed');
     251        assert.equal(content['buildRequests'][4].url, 'http://build.webkit.org/buids/1');
     252    });
     253
     254    it('should fail request with "CannotReuseDeletedRoot" if any root to reuse is deleted', async () => {
     255        await MockData.addMockBuildRequestsWithRoots(TestServer.database());
     256        await TestServer.database().query("UPDATE uploaded_files SET file_deleted_at = now() at time zone 'utc' WHERE file_id=101");
     257        const content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     258
     259        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     260        assert.equal(content['commitSets'].length, 4);
     261        assert.equal(content['commitSets'][0].id, 500);
     262        assert.equal(content['commitSets'][2].id, 600);
     263
     264        assert.deepEqual(content['commitSets'][0].revisionItems, [
     265            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     266            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     267        assert.deepEqual(content['commitSets'][2].revisionItems, [
     268            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     269            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     270
     271        assert.equal(content['buildRequests'].length, 8);
     272        assert.equal(content['buildRequests'][0].id, 800);
     273        assert.equal(content['buildRequests'][0].commitSet, 500);
     274        assert.equal(content['buildRequests'][0].status, 'completed');
     275        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     276        assert.equal(content['buildRequests'][4].id, 900);
     277        assert.equal(content['buildRequests'][4].commitSet, 600);
     278        assert.equal(content['buildRequests'][4].status, 'pending');
     279        assert.equal(content['buildRequests'][4].url, null);
     280
     281        const updates = {900: {
     282            status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: content['buildRequests'][0].id}};
     283        await assertThrows('CannotReuseDeletedRoot', () => TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     284            'slaveName': 'sync-slave',
     285            'slavePassword': 'password',
     286            'buildRequestUpdates': updates
     287        }));
     288    });
     289
     290    it('should fail request with "CannotReuseDeletedRoot" if any root to reuse is deleted while updating commit set items ', async () => {
     291        await MockData.addMockBuildRequestsWithRoots(TestServer.database());
     292        await TestServer.database().query(`CREATE OR REPLACE FUNCTION emunlate_file_purge() RETURNS TRIGGER AS $emunlate_file_purge$
     293            BEGIN
     294                UPDATE uploaded_files SET file_deleted_at = (CURRENT_TIMESTAMP AT TIME ZONE 'UTC') WHERE file_id = NEW.commitset_root_file;
     295                RETURN NULL;
     296            END;
     297            $emunlate_file_purge$ LANGUAGE plpgsql;`);
     298        await TestServer.database().query(`CREATE TRIGGER emunlate_file_purge AFTER UPDATE OF commitset_root_file ON commit_set_items
     299            FOR EACH ROW EXECUTE PROCEDURE emunlate_file_purge();`);
     300        const content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     301
     302        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     303        assert.equal(content['commitSets'].length, 4);
     304        assert.equal(content['commitSets'][0].id, 500);
     305        assert.equal(content['commitSets'][2].id, 600);
     306
     307        assert.deepEqual(content['commitSets'][0].revisionItems, [
     308            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     309            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     310        assert.deepEqual(content['commitSets'][2].revisionItems, [
     311            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     312            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     313
     314        assert.equal(content['buildRequests'].length, 8);
     315        assert.equal(content['buildRequests'][0].id, 800);
     316        assert.equal(content['buildRequests'][0].commitSet, 500);
     317        assert.equal(content['buildRequests'][0].status, 'completed');
     318        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     319        assert.equal(content['buildRequests'][4].id, 900);
     320        assert.equal(content['buildRequests'][4].commitSet, 600);
     321        assert.equal(content['buildRequests'][4].status, 'pending');
     322        assert.equal(content['buildRequests'][4].url, null);
     323
     324        const updates = {900: {
     325            status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: content['buildRequests'][0].id}};
     326
     327        await assertThrows('CannotReuseDeletedRoot', () => TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     328            'slaveName': 'sync-slave',
     329            'slavePassword': 'password',
     330            'buildRequestUpdates': updates
     331        }));
     332    });
     333
     334    it('should fail request with "NoMatchingCommitSetItem" if build request to reuse does not have patch', async () => {
     335        await MockData.addMockData(TestServer.database(), ['completed', 'pending', 'pending', 'pending'], true, ['http://build.webkit.org/buids/2', null, null, null]);
     336        await MockData.addMockBuildRequestsWithRoots(TestServer.database(), ['running', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending'], true, false);
     337        const content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     338
     339        assert.equal(content['commitSets'].length, 6);
     340        assert.equal(content['commitSets'][0].id, 401);
     341        assert.equal(content['commitSets'][4].id, 600);
     342
     343        assert.deepEqual(content['commitSets'][0].revisionItems, [
     344            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     345            {commit: '93116', commitOwner: null, patch: null, requiresBuild: false, rootFile: null}]);
     346        assert.deepEqual(content['commitSets'][4].revisionItems, [
     347            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     348            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     349
     350        assert.equal(content['buildRequests'].length, 12);
     351        assert.equal(content['buildRequests'][0].id, 700);
     352        assert.equal(content['buildRequests'][0].commitSet, 401);
     353        assert.equal(content['buildRequests'][0].status, 'completed');
     354        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/2');
     355        assert.equal(content['buildRequests'][8].id, 900);
     356        assert.equal(content['buildRequests'][8].commitSet, 600);
     357        assert.equal(content['buildRequests'][8].status, 'pending');
     358        assert.equal(content['buildRequests'][8].url, null);
     359
     360        const updates = {900: {
     361                status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: content['buildRequests'][0].id}};
     362
     363        await assertThrows('NoMatchingCommitSetItem', () => TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     364            'slaveName': 'sync-slave',
     365            'slavePassword': 'password',
     366            'buildRequestUpdates': updates
     367        }));
     368    });
     369
     370    it('should fail request with "CannotReuseRootWithNonMatchingCommitSets" if commit sets have different number of entries', async () => {
     371        await MockData.addMockData(TestServer.database(), ['completed', 'pending', 'pending', 'pending'], true, ['http://build.webkit.org/buids/2', null, null, null]);
     372        await MockData.addMockBuildRequestsWithRoots(TestServer.database(), ['running', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending'], true, false);
     373        await TestServer.database().insert('commit_set_items', {set: 401, commit: 111168})
     374        const content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     375
     376        assert.equal(content['commitSets'].length, 6);
     377        assert.equal(content['commitSets'][0].id, 401);
     378        assert.equal(content['commitSets'][4].id, 600);
     379
     380        assert.deepEqual(content['commitSets'][0].revisionItems, [
     381            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     382            {commit: '93116', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     383            {commit: '111168', commitOwner: null, patch: null, requiresBuild: false, rootFile: null}]);
     384        assert.deepEqual(content['commitSets'][4].revisionItems, [
     385            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     386            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     387
     388        assert.equal(content['buildRequests'].length, 12);
     389        assert.equal(content['buildRequests'][0].id, 700);
     390        assert.equal(content['buildRequests'][0].commitSet, 401);
     391        assert.equal(content['buildRequests'][0].status, 'completed');
     392        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/2');
     393        assert.equal(content['buildRequests'][8].id, 900);
     394        assert.equal(content['buildRequests'][8].commitSet, 600);
     395        assert.equal(content['buildRequests'][8].status, 'pending');
     396        assert.equal(content['buildRequests'][8].url, null);
     397
     398        const updates = {900: {
     399                status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: content['buildRequests'][0].id}};
     400
     401        await assertThrows('CannotReuseRootWithNonMatchingCommitSets', () => TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     402            'slaveName': 'sync-slave',
     403            'slavePassword': 'password',
     404            'buildRequestUpdates': updates
     405        }));
     406    });
     407
     408    it('should fail request with "CanOnlyReuseCompletedBuildRequest" if build request to reuse is not completed', async () => {
     409        await MockData.addMockBuildRequestsWithRoots(TestServer.database(), ['running', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending']);
     410        const content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     411
     412        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     413        assert.equal(content['commitSets'].length, 4);
     414        assert.equal(content['commitSets'][0].id, 500);
     415        assert.equal(content['commitSets'][2].id, 600);
     416
     417        assert.deepEqual(content['commitSets'][0].revisionItems, [
     418            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     419            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     420        assert.deepEqual(content['commitSets'][2].revisionItems, [
     421            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     422            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     423
     424        assert.equal(content['buildRequests'].length, 8);
     425        assert.equal(content['buildRequests'][0].id, 800);
     426        assert.equal(content['buildRequests'][0].commitSet, 500);
     427        assert.equal(content['buildRequests'][0].status, 'running');
     428        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     429        assert.equal(content['buildRequests'][4].id, 900);
     430        assert.equal(content['buildRequests'][4].commitSet, 600);
     431        assert.equal(content['buildRequests'][4].status, 'pending');
     432        assert.equal(content['buildRequests'][4].url, null);
     433
     434        const updates = {900: {
     435            status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: content['buildRequests'][0].id}};
     436        await assertThrows('CanOnlyReuseCompletedBuildRequest', () => TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     437            'slaveName': 'sync-slave',
     438            'slavePassword': 'password',
     439            'buildRequestUpdates': updates
     440        }));
     441    });
     442
     443    it('should fail request with "FailedToFindReuseBuildRequest" if the build request to reuse does not exist', async () => {
     444        await MockData.addMockBuildRequestsWithRoots(TestServer.database());
     445        const content = await TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit');
     446
     447        assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status', 'uploadedFiles']);
     448        assert.equal(content['commitSets'].length, 4);
     449        assert.equal(content['commitSets'][0].id, 500);
     450        assert.equal(content['commitSets'][2].id, 600);
     451
     452        assert.deepEqual(content['commitSets'][0].revisionItems, [
     453            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     454            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: 101}]);
     455        assert.deepEqual(content['commitSets'][2].revisionItems, [
     456            {commit: '87832', commitOwner: null, patch: null, requiresBuild: false, rootFile: null},
     457            {commit: '93116', commitOwner: null, patch: 100, requiresBuild: true, rootFile: null}]);
     458
     459        assert.equal(content['buildRequests'].length, 8);
     460        assert.equal(content['buildRequests'][0].id, 800);
     461        assert.equal(content['buildRequests'][0].commitSet, 500);
     462        assert.equal(content['buildRequests'][0].status, 'completed');
     463        assert.equal(content['buildRequests'][0].url, 'http://build.webkit.org/buids/1');
     464        assert.equal(content['buildRequests'][4].id, 900);
     465        assert.equal(content['buildRequests'][4].commitSet, 600);
     466        assert.equal(content['buildRequests'][4].status, 'pending');
     467        assert.equal(content['buildRequests'][4].url, null);
     468
     469        const updates = {900: {
     470            status: content['buildRequests'][0].status, url: content['buildRequests'][0].url, buildRequestForRootReuse: 999}};
     471
     472        await assertThrows('FailedToFindbuildRequestForRootReuse', () => TestServer.remoteAPI().postJSONWithStatus('/api/build-requests/build-webkit', {
     473            'slaveName': 'sync-slave',
     474            'slavePassword': 'password',
     475            'buildRequestUpdates': updates
     476        }));
    65477    });
    66478
  • trunk/Websites/perf.webkit.org/server-tests/resources/mock-data.js

    r251564 r269871  
    4141            db.insert('repositories', {id: this.ownedJSCRepositoryId(), owner: this.webkitRepositoryId(), name: 'JavaScriptCore'}),
    4242            db.insert('repositories', {id: this.jscRepositoryId(), name: 'JavaScriptCore'}),
    43             db.insert('triggerable_repository_groups', {id: 2001, name: 'webkit-svn', triggerable: 1000}),
     43            db.insert('triggerable_repository_groups', {id: 2001, name: 'webkit-svn', triggerable: 1000, accepts_roots: true}),
    4444            db.insert('triggerable_repositories', {repository: this.macosRepositoryId(), group: 2001}),
    45             db.insert('triggerable_repositories', {repository: this.webkitRepositoryId(), group: 2001}),
     45            db.insert('triggerable_repositories', {repository: this.webkitRepositoryId(), group: 2001, accepts_patch: true}),
    4646            db.insert('commits', {id: 87832, repository: this.macosRepositoryId(), revision: '10.11 15A284'}),
    4747            db.insert('commits', {id: 93116, repository: this.webkitRepositoryId(), revision: '191622', time: (new Date(1445945816878)).toISOString()}),
     
    6565        ]);
    6666    },
    67     addMockData: function (db, statusList, needsNotification=true)
     67    addMockData: function (db, statusList, needsNotification=true, urlList=[])
    6868    {
    6969        if (!statusList)
    7070            statusList = ['pending', 'pending', 'pending', 'pending'];
     71        if (!urlList)
     72            urlList = [null, null, null, null];
    7173        return Promise.all([
    7274            this.addMockConfiguration(db),
     
    8183                end_run: 801, end_run_time: '2015-10-27T12:05:27.1Z'}),
    8284            db.insert('analysis_test_groups', {id: 600, task: 500, name: 'some test group', initial_repetition_count: 4, needs_notification: needsNotification}),
    83             db.insert('build_requests', {id: 700, status: statusList[0], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 0, commit_set: 401}),
    84             db.insert('build_requests', {id: 701, status: statusList[1], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 1, commit_set: 402}),
    85             db.insert('build_requests', {id: 702, status: statusList[2], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 2, commit_set: 401}),
    86             db.insert('build_requests', {id: 703, status: statusList[3], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 3, commit_set: 402}),
     85            db.insert('build_requests', {id: 700, status: statusList[0], url: urlList[0], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 0, commit_set: 401}),
     86            db.insert('build_requests', {id: 701, status: statusList[1], url: urlList[1], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 1, commit_set: 402}),
     87            db.insert('build_requests', {id: 702, status: statusList[2], url: urlList[2], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 2, commit_set: 401}),
     88            db.insert('build_requests', {id: 703, status: statusList[3], url: urlList[3], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 600, order: 3, commit_set: 402}),
     89        ]);
     90    },
     91    addMockBuildRequestsWithRoots(db, statusList, needsNotification=true, addMockConfiguration=true)
     92    {
     93        const setupSteps = addMockConfiguration ? [this.addMockConfiguration(db)] : [];
     94        if (!statusList)
     95            statusList = ['completed', 'running', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending'];
     96        return Promise.all([
     97            ...setupSteps,
     98            db.insert('uploaded_files', {id: 100, filename: 'patch-100', extension: '.txt', size: 1, sha256: crypto.createHash('sha256').update('patch-100').digest('hex')}),
     99            db.insert('uploaded_files', {id: 101, filename: 'root-101', extension: '.tgz', size: 1, sha256: crypto.createHash('sha256').update('root-101').digest('hex')}),
     100            db.insert('uploaded_files', {id: 102, filename: 'patch-102', extension: '.txt', size: 1, sha256: crypto.createHash('sha256').update('patch-102').digest('hex')}),
     101
     102            db.insert('commit_sets', {id: 500}),
     103            db.insert('commit_set_items', {set: 500, commit: 87832}),
     104            db.insert('commit_set_items', {set: 500, commit: 93116, patch_file: 100, requires_build: true, root_file: 101}),
     105            db.insert('commit_sets', {id: 501}),
     106            db.insert('commit_set_items', {set: 501, commit: 87832}),
     107            db.insert('commit_set_items', {set: 501, commit: 96336, patch_file: 102, requires_build: true}),
     108
     109            db.insert('commit_sets', {id: 600}),
     110            db.insert('commit_set_items', {set: 600, commit: 87832}),
     111            db.insert('commit_set_items', {set: 600, commit: 93116, patch_file: 100, requires_build: true}),
     112            db.insert('commit_sets', {id: 601}),
     113            db.insert('commit_set_items', {set: 601, commit: 87832}),
     114            db.insert('commit_set_items', {set: 601, commit: 96336, patch_file: 102, requires_build: true}),
     115
     116            db.insert('analysis_tasks', {id: 600, name: 'another task'}),
     117
     118            db.insert('analysis_test_groups', {id: 700, task: 600, name: 'test with root built', initial_repetition_count: 1, needs_notification: needsNotification}),
     119            db.insert('build_requests', {id: 800, status: statusList[0], triggerable: 1000, repository_group: 2001, platform: 65, group: 700, order: -2, commit_set: 500, url: 'http://build.webkit.org/buids/1'}),
     120            db.insert('build_requests', {id: 801, status: statusList[1], triggerable: 1000, repository_group: 2001, platform: 65, group: 700, order: -1, commit_set: 501}),
     121            db.insert('build_requests', {id: 802, status: statusList[2], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 700, order: 0, commit_set: 500}),
     122            db.insert('build_requests', {id: 803, status: statusList[3], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 700, order: 1, commit_set: 501}),
     123
     124            db.insert('analysis_test_groups', {id: 701, task: 600, name: 'test will reuse root', initial_repetition_count: 1, needs_notification: needsNotification}),
     125            db.insert('build_requests', {id: 900, status: statusList[4], triggerable: 1000, repository_group: 2001, platform: 65, group: 701, order: -2, commit_set: 600}),
     126            db.insert('build_requests', {id: 901, status: statusList[5], triggerable: 1000, repository_group: 2001, platform: 65, group: 701, order: -1, commit_set: 601}),
     127            db.insert('build_requests', {id: 902, status: statusList[6], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 701, order: 0, commit_set: 600}),
     128            db.insert('build_requests', {id: 903, status: statusList[7], triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 701, order: 1, commit_set: 601}),
    87129        ]);
    88130    },
     
    173215        ]);
    174216    },
     217    addTwoMockTestGroupWithOwnedCommits(db)
     218    {
     219        return Promise.all([
     220            this.addMockConfiguration(db),
     221            this.addAnotherTriggerable(db),
     222            db.insert('analysis_tasks', {id: 1080, platform: 65, metric: 300, name: 'some task with component test',
     223                start_run: 801, start_run_time: '2015-10-27T12:05:27.1Z',
     224                end_run: 801, end_run_time: '2015-10-27T12:05:27.1Z'}),
     225
     226            db.insert('uploaded_files', {id: 101, filename: 'root-101', size: 1, sha256: crypto.createHash('sha256').update('root-101').digest('hex'), }),
     227            db.insert('analysis_test_groups', {id: 900, task: 1080, name: 'some test group with component test(root built)', initial_repetition_count: 1}),
     228            db.insert('commit_sets', {id: 403}),
     229            db.insert('commit_set_items', {set: 403, commit: 87832}),
     230            db.insert('commit_set_items', {set: 403, commit: 93116}),
     231            db.insert('commit_set_items', {set: 403, commit: 1797, commit_owner: 93116, requires_build: true, root_file: 101}),
     232            db.insert('commit_sets', {id: 404}),
     233            db.insert('commit_set_items', {set: 404, commit: 87832}),
     234            db.insert('commit_set_items', {set: 404, commit: 96336}),
     235            db.insert('commit_set_items', {set: 404, commit: 2017, commit_owner: 96336, requires_build: true}),
     236            db.insert('build_requests', {id: 704, status: 'completed', triggerable: 1000, repository_group: 2001, platform: 65, group: 900, order: -2, commit_set: 403, url: 'http://build.webkit.org/buids/1'}),
     237            db.insert('build_requests', {id: 705, status: 'pending', triggerable: 1000, repository_group: 2001, platform: 65, group: 900, order: -1, commit_set: 404}),
     238            db.insert('build_requests', {id: 706, status: 'pending', triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 900, order: 0, commit_set: 403}),
     239            db.insert('build_requests', {id: 707, status: 'pending', triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 900, order: 1, commit_set: 404}),
     240
     241            db.insert('analysis_test_groups', {id: 901, task: 1080, name: 'some test group with component test', initial_repetition_count: 1}),
     242            db.insert('commit_sets', {id: 405}),
     243            db.insert('commit_set_items', {set: 405, commit: 87832}),
     244            db.insert('commit_set_items', {set: 405, commit: 93116}),
     245            db.insert('commit_set_items', {set: 405, commit: 1797, commit_owner: 93116, requires_build: true}),
     246            db.insert('commit_sets', {id: 406}),
     247            db.insert('commit_set_items', {set: 406, commit: 87832}),
     248            db.insert('commit_set_items', {set: 406, commit: 96336}),
     249            db.insert('commit_set_items', {set: 406, commit: 2017, commit_owner: 96336, requires_build: true}),
     250            db.insert('build_requests', {id: 708, status: 'pending', triggerable: 1000, repository_group: 2001, platform: 65, group: 901, order: -2, commit_set: 405}),
     251            db.insert('build_requests', {id: 709, status: 'pending', triggerable: 1000, repository_group: 2001, platform: 65, group: 901, order: -1, commit_set: 406}),
     252            db.insert('build_requests', {id: 710, status: 'pending', triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 901, order: 0, commit_set: 405}),
     253            db.insert('build_requests', {id: 711, status: 'pending', triggerable: 1000, repository_group: 2001, platform: 65, test: 200, group: 901, order: 1, commit_set: 406}),
     254        ]);
     255    },
    175256    addTestGroupWithOwnerCommitNotInCommitSet(db)
    176257    {
     
    216297                    'types': ['some-test'],
    217298                    'builders': ['builder-1'],
     299                }
     300            ]
     301        }
     302    },
     303    mockTestSyncConfigWithPatchAcceptingBuilder: function ()
     304    {
     305        return {
     306            'triggerableName': 'build-webkit',
     307            'lookbackCount': 2,
     308            'buildRequestArgument': 'build-request-id',
     309            'repositoryGroups': {
     310                'webkit-svn': {
     311                    'repositories': {'WebKit': {'acceptsPatch': true}, 'macOS': {}},
     312                    'acceptsRoots': true,
     313                    'testProperties': {
     314                        'os': {'revision': 'macOS'},
     315                        'wk': {'revision': 'WebKit'},
     316                        'roots': {"roots": {}},
     317                    },
     318                    'buildProperties': {
     319                        'os': {'revision': 'macOS'},
     320                        'wk': {'revision': 'WebKit'},
     321                        'wk-patch': {'patch': 'WebKit'},
     322                    }
     323                }
     324            },
     325            'types': {
     326                'some-test': {'test': ['some test']}
     327            },
     328            'builders': {
     329                'tester': {'builder': 'some tester', properties: {forcescheduler: 'force-some-tester'}},
     330                'builder-1': {'builder': 'some-builder-1', properties: {forcescheduler: 'force-some-builder-1'}},
     331                'builder-2': {'builder': 'some builder 2', properties: {forcescheduler: 'force-some-builder-2'}},
     332            },
     333            'testConfigurations': [
     334                {
     335                    'platforms': ['some platform'],
     336                    'types': ['some-test'],
     337                    'builders': ['tester'],
     338                }
     339            ],
     340            'buildConfigurations': [
     341                {
     342                    'platforms': ['some platform'],
     343                    'builders': ['builder-1', 'builder-2'],
    218344                }
    219345            ]
  • trunk/Websites/perf.webkit.org/server-tests/tools-buildbot-triggerable-tests.js

    r230960 r269871  
    946946                MockRemoteAPI.requests[2].resolve('OK');
    947947            });
     948        });
     949
     950        it('should reuse the roots from a completed build request with the same commit set', async () => {
     951            await MockData.addMockBuildRequestsWithRoots(TestServer.database());
     952            await Manifest.fetch();
     953            const config = MockData.mockTestSyncConfigWithPatchAcceptingBuilder();
     954            const logger = new MockLogger;
     955            const slaveInfo = {name: 'sync-slave', password: 'password'};
     956            const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
     957            const syncPromise = triggerable.initSyncers().then(() => triggerable.syncOnce());
     958            assertRequestAndResolve(MockRemoteAPI.requests[0], 'GET', MockData.buildbotBuildersURL(), MockData.mockBuildbotBuilders());
     959            MockRemoteAPI.reset();
     960            await MockRemoteAPI.waitForRequest();
     961
     962            assert.equal(BuildRequest.all().length, 8);
     963            let buildRequest = BuildRequest.findById(800);
     964            let anotherBuildRequest = BuildRequest.findById(900);
     965            assert.equal(buildRequest.status(), 'completed');
     966            assert.equal(anotherBuildRequest.status(), 'pending');
     967            assert.equal(buildRequest.statusUrl(), 'http://build.webkit.org/buids/1');
     968            assert.equal(anotherBuildRequest.statusUrl(), null);
     969            let commitSet = buildRequest.commitSet();
     970            let anotherCommitSet = anotherBuildRequest.commitSet();
     971            assert.ok(commitSet.equalsIgnoringRoot(anotherCommitSet));
     972            assert.ok(!commitSet.equals(anotherCommitSet));
     973
     974            assert.equal(MockRemoteAPI.requests.length, 3);
     975            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     976            assert.equal(MockRemoteAPI.requests[0].url, MockData.pendingBuildsUrl('some tester'));
     977            MockRemoteAPI.requests[0].resolve({});
     978            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     979            assert.equal(MockRemoteAPI.requests[1].url, MockData.pendingBuildsUrl('some-builder-1'));
     980            MockRemoteAPI.requests[1].resolve({});
     981            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     982            assert.equal(MockRemoteAPI.requests[2].url, MockData.pendingBuildsUrl('some builder 2'));
     983            MockRemoteAPI.requests[2].resolve({});
     984            MockRemoteAPI.reset();
     985            await MockRemoteAPI.waitForRequest();
     986
     987            assert.equal(MockRemoteAPI.requests.length, 3);
     988            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     989            assert.equal(MockRemoteAPI.requests[0].url, MockData.recentBuildsUrl('some tester', 2));
     990            MockRemoteAPI.requests[0].resolve({});
     991            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     992            assert.equal(MockRemoteAPI.requests[1].url, MockData.recentBuildsUrl('some-builder-1', 2));
     993            MockRemoteAPI.requests[1].resolve({'builds': [MockData.runningBuildData({buildRequestId: 801}), MockData.finishedBuildData({buildRequestId: 800})]});
     994            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     995            assert.equal(MockRemoteAPI.requests[2].url, MockData.recentBuildsUrl('some builder 2', 2));
     996            MockRemoteAPI.requests[2].resolve({});
     997            MockRemoteAPI.reset();
     998            await MockRemoteAPI.waitForRequest();
     999
     1000            assert.equal(MockRemoteAPI.requests.length, 3);
     1001            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1002            assert.equal(MockRemoteAPI.requests[0].url, MockData.pendingBuildsUrl('some tester'));
     1003            MockRemoteAPI.requests[0].resolve({});
     1004            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1005            assert.equal(MockRemoteAPI.requests[1].url, MockData.pendingBuildsUrl('some-builder-1'));
     1006            MockRemoteAPI.requests[1].resolve({});
     1007            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1008            assert.equal(MockRemoteAPI.requests[2].url, MockData.pendingBuildsUrl('some builder 2'));
     1009            MockRemoteAPI.requests[2].resolve({});
     1010            MockRemoteAPI.reset();
     1011            await MockRemoteAPI.waitForRequest();
     1012
     1013            assert.equal(MockRemoteAPI.requests.length, 3);
     1014            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1015            assert.equal(MockRemoteAPI.requests[0].url, MockData.recentBuildsUrl('some tester', 2));
     1016            MockRemoteAPI.requests[0].resolve({});
     1017            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1018            assert.equal(MockRemoteAPI.requests[1].url, MockData.recentBuildsUrl('some-builder-1', 2));
     1019            MockRemoteAPI.requests[1].resolve({'builds': [MockData.runningBuildData({buildRequestId: 801}), MockData.finishedBuildData({buildRequestId: 800})]});
     1020            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1021            assert.equal(MockRemoteAPI.requests[2].url, MockData.recentBuildsUrl('some builder 2', 2));
     1022            MockRemoteAPI.requests[2].resolve({});
     1023            MockRemoteAPI.reset();
     1024
     1025            await syncPromise;
     1026            await BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithPatchAcceptingBuilder().triggerableName);
     1027            assert.equal(BuildRequest.all().length, 8);
     1028            buildRequest = BuildRequest.findById(800);
     1029            anotherBuildRequest = BuildRequest.findById(900);
     1030            assert.equal(buildRequest.status(), 'completed');
     1031            assert.equal(anotherBuildRequest.status(), 'completed');
     1032            assert.equal(buildRequest.statusUrl(), 'http://build.webkit.org/buids/1');
     1033            assert.equal(anotherBuildRequest.statusUrl(), 'http://build.webkit.org/buids/1');
     1034        });
     1035
     1036        it('should defer scheduling a build request if there is a "running" build request with same commit set, but should schedule the build request if "running" build request with same commit set fails later on', async () => {
     1037            await MockData.addMockBuildRequestsWithRoots(TestServer.database(),  ['running', 'scheduled', 'pending', 'pending', 'pending', 'pending', 'pending', 'pending']);
     1038            await Manifest.fetch();
     1039            const config = MockData.mockTestSyncConfigWithPatchAcceptingBuilder();
     1040            const logger = new MockLogger;
     1041            const slaveInfo = {name: 'sync-slave', password: 'password'};
     1042            const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
     1043            const syncPromise = triggerable.initSyncers().then(() => triggerable.syncOnce());
     1044            assertRequestAndResolve(MockRemoteAPI.requests[0], 'GET', MockData.buildbotBuildersURL(), MockData.mockBuildbotBuilders());
     1045            MockRemoteAPI.reset();
     1046            await MockRemoteAPI.waitForRequest();
     1047
     1048            assert.equal(BuildRequest.all().length, 8);
     1049            let buildRequest = BuildRequest.findById(800);
     1050            let anotherBuildRequest = BuildRequest.findById(900);
     1051            assert.equal(buildRequest.status(), 'running');
     1052            assert.equal(anotherBuildRequest.status(), 'pending');
     1053            assert.equal(buildRequest.statusUrl(), 'http://build.webkit.org/buids/1');
     1054            assert.equal(anotherBuildRequest.statusUrl(), null);
     1055            let commitSet = buildRequest.commitSet();
     1056            let anotherCommitSet = anotherBuildRequest.commitSet();
     1057            assert.ok(commitSet.equalsIgnoringRoot(anotherCommitSet));
     1058            assert.ok(!commitSet.equals(anotherCommitSet));
     1059
     1060            assert.equal(MockRemoteAPI.requests.length, 3);
     1061            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1062            assert.equal(MockRemoteAPI.requests[0].url, MockData.pendingBuildsUrl('some tester'));
     1063            MockRemoteAPI.requests[0].resolve({});
     1064            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1065            assert.equal(MockRemoteAPI.requests[1].url, MockData.pendingBuildsUrl('some-builder-1'));
     1066            MockRemoteAPI.requests[1].resolve({'builds': [MockData.pendingBuild({buildRequestId: 801})]});
     1067            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1068            assert.equal(MockRemoteAPI.requests[2].url, MockData.pendingBuildsUrl('some builder 2'));
     1069            MockRemoteAPI.requests[2].resolve({});
     1070            MockRemoteAPI.reset();
     1071            await MockRemoteAPI.waitForRequest();
     1072
     1073            assert.equal(MockRemoteAPI.requests.length, 3);
     1074            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1075            assert.equal(MockRemoteAPI.requests[0].url, MockData.recentBuildsUrl('some tester', 2));
     1076            MockRemoteAPI.requests[0].resolve({});
     1077            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1078            assert.equal(MockRemoteAPI.requests[1].url, MockData.recentBuildsUrl('some-builder-1', 2));
     1079            MockRemoteAPI.requests[1].resolve({'builds': [MockData.runningBuildData({buildRequestId: 800})]});
     1080            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1081            assert.equal(MockRemoteAPI.requests[2].url, MockData.recentBuildsUrl('some builder 2', 2));
     1082            MockRemoteAPI.requests[2].resolve({});
     1083            MockRemoteAPI.reset();
     1084            await MockRemoteAPI.waitForRequest();
     1085
     1086            assert.equal(MockRemoteAPI.requests.length, 3);
     1087            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1088            assert.equal(MockRemoteAPI.requests[0].url, MockData.pendingBuildsUrl('some tester'));
     1089            MockRemoteAPI.requests[0].resolve({});
     1090            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1091            assert.equal(MockRemoteAPI.requests[1].url, MockData.pendingBuildsUrl('some-builder-1'));
     1092            MockRemoteAPI.requests[1].resolve({});
     1093            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1094            assert.equal(MockRemoteAPI.requests[2].url, MockData.pendingBuildsUrl('some builder 2'));
     1095            MockRemoteAPI.requests[2].resolve({});
     1096            MockRemoteAPI.reset();
     1097            await MockRemoteAPI.waitForRequest();
     1098
     1099            assert.equal(MockRemoteAPI.requests.length, 3);
     1100            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1101            assert.equal(MockRemoteAPI.requests[0].url, MockData.recentBuildsUrl('some tester', 2));
     1102            MockRemoteAPI.requests[0].resolve({});
     1103            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1104            assert.equal(MockRemoteAPI.requests[1].url, MockData.recentBuildsUrl('some-builder-1', 2));
     1105            MockRemoteAPI.requests[1].resolve({'builds': [MockData.runningBuildData({buildRequestId: 801}), MockData.finishedBuildData({buildRequestId: 800})]});
     1106            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1107            assert.equal(MockRemoteAPI.requests[2].url, MockData.recentBuildsUrl('some builder 2', 2));
     1108            MockRemoteAPI.requests[2].resolve({});
     1109            MockRemoteAPI.reset();
     1110
     1111            await syncPromise;
     1112            await BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithPatchAcceptingBuilder().triggerableName);
     1113            assert.equal(BuildRequest.all().length, 8);
     1114            buildRequest = BuildRequest.findById(800);
     1115            anotherBuildRequest = BuildRequest.findById(900);
     1116            assert.equal(buildRequest.status(), 'failed');
     1117            assert.equal(anotherBuildRequest.status(), 'pending');
     1118            assert.equal(buildRequest.statusUrl(), MockData.statusUrl('some-builder-1', 123));
     1119            assert.equal(anotherBuildRequest.statusUrl(), null);
     1120
     1121            const secondSyncPromise = triggerable.initSyncers().then(() => triggerable.syncOnce());
     1122            assertRequestAndResolve(MockRemoteAPI.requests[0], 'GET', MockData.buildbotBuildersURL(), MockData.mockBuildbotBuilders());
     1123            MockRemoteAPI.reset();
     1124            await MockRemoteAPI.waitForRequest();
     1125
     1126            assert.equal(MockRemoteAPI.requests.length, 3);
     1127            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1128            assert.equal(MockRemoteAPI.requests[0].url, MockData.pendingBuildsUrl('some tester'));
     1129            MockRemoteAPI.requests[0].resolve({});
     1130            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1131            assert.equal(MockRemoteAPI.requests[1].url, MockData.pendingBuildsUrl('some-builder-1'));
     1132            MockRemoteAPI.requests[1].resolve({});
     1133            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1134            assert.equal(MockRemoteAPI.requests[2].url, MockData.pendingBuildsUrl('some builder 2'));
     1135            MockRemoteAPI.requests[2].resolve({});
     1136            MockRemoteAPI.reset();
     1137            await MockRemoteAPI.waitForRequest();
     1138
     1139            assert.equal(MockRemoteAPI.requests.length, 3);
     1140            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1141            assert.equal(MockRemoteAPI.requests[0].url, MockData.recentBuildsUrl('some tester', 2));
     1142            MockRemoteAPI.requests[0].resolve({});
     1143            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1144            assert.equal(MockRemoteAPI.requests[1].url, MockData.recentBuildsUrl('some-builder-1', 2));
     1145            MockRemoteAPI.requests[1].resolve({'builds': [MockData.runningBuildData({buildRequestId: 801})]});
     1146            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1147            assert.equal(MockRemoteAPI.requests[2].url, MockData.recentBuildsUrl('some builder 2', 2));
     1148            MockRemoteAPI.requests[2].resolve({});
     1149            MockRemoteAPI.reset();
     1150            await MockRemoteAPI.waitForRequest();
     1151
     1152            assert.equal(MockRemoteAPI.requests.length, 1);
     1153            assert.equal(MockRemoteAPI.requests[0].method, 'POST');
     1154            assert.equal(MockRemoteAPI.requests[0].url, '/api/v2/forceschedulers/force-some-builder-2');
     1155            assert.deepEqual(MockRemoteAPI.requests[0].data, {'id': 900, 'jsonrpc': '2.0', 'method': 'force', 'params':
     1156                {'wk': '191622', 'os': '10.11 15A284', 'wk-patch': 'http://localhost:8180/api/uploaded-file/100.txt',
     1157                'build-request-id': '900', 'forcescheduler': 'force-some-builder-2'}});
     1158        });
     1159
     1160        it('should not reuse the root when a build request with same commit set is avaialble but the build request has been scheduled', async () => {
     1161            await MockData.addMockBuildRequestsWithRoots(TestServer.database());
     1162            await Manifest.fetch();
     1163            const config = MockData.mockTestSyncConfigWithPatchAcceptingBuilder();
     1164            const logger = new MockLogger;
     1165            const slaveInfo = {name: 'sync-slave', password: 'password'};
     1166            const triggerable = new BuildbotTriggerable(config, TestServer.remoteAPI(), MockRemoteAPI, slaveInfo, logger);
     1167            const syncPromise = triggerable.initSyncers().then(() => triggerable.syncOnce());
     1168            assertRequestAndResolve(MockRemoteAPI.requests[0], 'GET', MockData.buildbotBuildersURL(), MockData.mockBuildbotBuilders());
     1169            MockRemoteAPI.reset();
     1170            await MockRemoteAPI.waitForRequest();
     1171
     1172            assert.equal(BuildRequest.all().length, 8);
     1173            let buildRequest = BuildRequest.findById(800);
     1174            let anotherBuildRequest = BuildRequest.findById(900);
     1175            assert.equal(buildRequest.status(), 'completed');
     1176            assert.equal(anotherBuildRequest.status(), 'pending');
     1177            assert.equal(buildRequest.statusUrl(), 'http://build.webkit.org/buids/1');
     1178            assert.equal(anotherBuildRequest.statusUrl(), null);
     1179            let commitSet = buildRequest.commitSet();
     1180            let anotherCommitSet = anotherBuildRequest.commitSet();
     1181            assert.ok(commitSet.equalsIgnoringRoot(anotherCommitSet));
     1182            assert.ok(!commitSet.equals(anotherCommitSet));
     1183
     1184            assert.equal(MockRemoteAPI.requests.length, 3);
     1185            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1186            assert.equal(MockRemoteAPI.requests[0].url, MockData.pendingBuildsUrl('some tester'));
     1187            MockRemoteAPI.requests[0].resolve({});
     1188            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1189            assert.equal(MockRemoteAPI.requests[1].url, MockData.pendingBuildsUrl('some-builder-1'));
     1190            MockRemoteAPI.requests[1].resolve({});
     1191            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1192            assert.equal(MockRemoteAPI.requests[2].url, MockData.pendingBuildsUrl('some builder 2'));
     1193            MockRemoteAPI.requests[2].resolve({});
     1194            MockRemoteAPI.reset();
     1195            await MockRemoteAPI.waitForRequest();
     1196
     1197            assert.equal(MockRemoteAPI.requests.length, 3);
     1198            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1199            assert.equal(MockRemoteAPI.requests[0].url, MockData.recentBuildsUrl('some tester', 2));
     1200            MockRemoteAPI.requests[0].resolve({});
     1201            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1202            assert.equal(MockRemoteAPI.requests[1].url, MockData.recentBuildsUrl('some-builder-1', 2));
     1203            MockRemoteAPI.requests[1].resolve({'builds': [MockData.runningBuildData({buildRequestId: 801}), MockData.finishedBuildData({buildRequestId: 800})]});
     1204            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1205            assert.equal(MockRemoteAPI.requests[2].url, MockData.recentBuildsUrl('some builder 2', 2));
     1206            MockRemoteAPI.requests[2].resolve({});
     1207            MockRemoteAPI.reset();
     1208            await MockRemoteAPI.waitForRequest();
     1209
     1210            assert.equal(MockRemoteAPI.requests.length, 3);
     1211            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1212            assert.equal(MockRemoteAPI.requests[0].url, MockData.pendingBuildsUrl('some tester'));
     1213            MockRemoteAPI.requests[0].resolve({});
     1214            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1215            assert.equal(MockRemoteAPI.requests[1].url, MockData.pendingBuildsUrl('some-builder-1'));
     1216            MockRemoteAPI.requests[1].resolve({});
     1217            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1218            assert.equal(MockRemoteAPI.requests[2].url, MockData.pendingBuildsUrl('some builder 2'));
     1219            MockRemoteAPI.requests[2].resolve({});
     1220            MockRemoteAPI.reset();
     1221            await MockRemoteAPI.waitForRequest();
     1222
     1223            assert.equal(MockRemoteAPI.requests.length, 3);
     1224            assert.equal(MockRemoteAPI.requests[0].method, 'GET');
     1225            assert.equal(MockRemoteAPI.requests[0].url, MockData.recentBuildsUrl('some tester', 2));
     1226            MockRemoteAPI.requests[0].resolve({});
     1227            assert.equal(MockRemoteAPI.requests[1].method, 'GET');
     1228            assert.equal(MockRemoteAPI.requests[1].url, MockData.recentBuildsUrl('some-builder-1', 2));
     1229            MockRemoteAPI.requests[1].resolve({'builds': [MockData.runningBuildData({buildRequestId: 801}), MockData.finishedBuildData({buildRequestId: 800})]});
     1230            assert.equal(MockRemoteAPI.requests[2].method, 'GET');
     1231            assert.equal(MockRemoteAPI.requests[2].url, MockData.recentBuildsUrl('some builder 2', 2));
     1232            MockRemoteAPI.requests[2].resolve({'builds': [MockData.runningBuildData({buildRequestId: 900, builderId: 3})]});
     1233            MockRemoteAPI.reset();
     1234
     1235            await syncPromise;
     1236            await BuildRequest.fetchForTriggerable(MockData.mockTestSyncConfigWithPatchAcceptingBuilder().triggerableName);
     1237            assert.equal(BuildRequest.all().length, 8);
     1238            buildRequest = BuildRequest.findById(800);
     1239            anotherBuildRequest = BuildRequest.findById(900);
     1240            assert.equal(buildRequest.status(), 'completed');
     1241            assert.equal(anotherBuildRequest.status(), 'running');
     1242            assert.equal(buildRequest.statusUrl(), 'http://build.webkit.org/buids/1');
     1243            assert.equal(anotherBuildRequest.statusUrl(), 'http://build.webkit.org/#/builders/3/builds/124');
    9481244        });
    9491245    });
  • trunk/Websites/perf.webkit.org/tools/js/buildbot-triggerable.js

    r250465 r269871  
    7878    }
    7979
    80     syncOnce()
    81     {
    82         let syncerList = this._syncers;
    83         let buildReqeustsByGroup = new Map;
    84 
     80    async syncOnce()
     81    {
    8582        this._logger.log(`Fetching build requests for ${this._name}...`);
    86         let validRequests;
    87         return BuildRequest.fetchForTriggerable(this._name).then((buildRequests) => {
    88             validRequests = this._validateRequests(buildRequests);
    89             buildReqeustsByGroup = BuildbotTriggerable._testGroupMapForBuildRequests(buildRequests);
    90             return this._pullBuildbotOnAllSyncers(buildReqeustsByGroup);
    91         }).then((updates) => {
    92             this._logger.log('Scheduling builds');
    93             const promistList = [];
    94             const testGroupList = Array.from(buildReqeustsByGroup.values()).sort(function (a, b) { return a.groupOrder - b.groupOrder; });
    95             for (const group of testGroupList) {
    96                 const nextRequest = this._nextRequestInGroup(group, updates);
    97                 if (!validRequests.has(nextRequest))
    98                     continue;
    99                 const promise = this._scheduleRequestIfSlaveIsAvailable(nextRequest, group.requests,
    100                     nextRequest.isBuild() ? group.buildSyncer : group.testSyncer,
    101                     nextRequest.isBuild() ? group.buildSlaveName : group.testSlaveName);
    102                 if (promise)
    103                     promistList.push(promise);
    104             }
    105             return Promise.all(promistList);
    106         }).then(() => {
    107             // Pull all buildbots for the second time since the previous step may have scheduled more builds.
    108             return this._pullBuildbotOnAllSyncers(buildReqeustsByGroup);
    109         }).then((updates) => {
    110             // FIXME: Add a new API that just updates the requests.
    111             return this._remote.postJSONWithStatus(`/api/build-requests/${this._name}`, {
    112                 'slaveName': this._slaveInfo.name,
    113                 'slavePassword': this._slaveInfo.password,
    114                 'buildRequestUpdates': updates});
    115         });
     83
     84        const buildRequests = await BuildRequest.fetchForTriggerable(this._name);
     85        const validRequests = this._validateRequests(buildRequests);
     86        const buildReqeustsByGroup = BuildbotTriggerable._testGroupMapForBuildRequests(buildRequests);
     87        let updates = await this._pullBuildbotOnAllSyncers(buildReqeustsByGroup);
     88        let rootReuseUpdates = {}
     89        this._logger.log('Scheduling builds');
     90        const promiseList = [];
     91        const testGroupList = Array.from(buildReqeustsByGroup.values()).sort(function (a, b) { return a.groupOrder - b.groupOrder; });
     92
     93        await Promise.all(testGroupList.map((group) => [group, this._nextRequestInGroup(group, updates)])
     94            .filter(([group, request]) => validRequests.has(request))
     95            .map(([group, request]) => this._scheduleRequest(group, request, rootReuseUpdates)));
     96
     97        // Pull all buildbots for the second time since the previous step may have scheduled more builds
     98        updates = await this._pullBuildbotOnAllSyncers(buildReqeustsByGroup);
     99
     100        // rootReuseUpdates will be overridden by status fetched from buildbot.
     101        updates = {
     102            ...rootReuseUpdates,
     103            ...updates
     104        };
     105        return await this._remote.postJSONWithStatus(`/api/build-requests/${this._name}`, {
     106            'slaveName': this._slaveInfo.name,
     107            'slavePassword': this._slaveInfo.password,
     108            'buildRequestUpdates': updates});
     109    }
     110
     111    async _scheduleRequest(testGroup, buildRequest, updates)
     112    {
     113        const buildRequestForRootReuse = await buildRequest.findBuildRequestWithSameRoots();
     114        if (buildRequestForRootReuse) {
     115            if (!buildRequestForRootReuse.hasCompleted()) {
     116                this._logger.log(`Found build request ${buildRequestForRootReuse.id()} is building the same root, will wait until it finishes.`);
     117                return;
     118            }
     119
     120            this._logger.log(`Will reuse existing root built from ${buildRequestForRootReuse.id()} for ${buildRequest.id()}`);
     121            updates[buildRequest.id()] = {status: 'completed', url: buildRequestForRootReuse.statusUrl(),
     122                statusDescription: buildRequestForRootReuse.statusDescription(),
     123                buildRequestForRootReuse: buildRequestForRootReuse.id()};
     124            return;
     125        }
     126
     127        return await this._scheduleRequestIfSlaveIsAvailable(buildRequest, testGroup.requests,
     128            buildRequest.isBuild() ? testGroup.buildSyncer : testGroup.testSyncer,
     129            buildRequest.isBuild() ? testGroup.buildSlaveName : testGroup.testSlaveName);
    116130    }
    117131
  • trunk/Websites/perf.webkit.org/unit-tests/build-request-tests.js

    r225898 r269871  
    44
    55require('../tools/js/v3-models.js');
    6 let MockModels = require('./resources/mock-v3-models.js').MockModels;
     6const MockModels = require('./resources/mock-v3-models.js').MockModels;
     7const NodePrivilegedAPI = require('../tools/js/privileged-api.js').PrivilegedAPI;
     8const MockRemoteAPI = require('./resources/mock-remote-api.js').MockRemoteAPI;
    79
    810function sampleBuildRequestData()
     
    5759}
    5860
     61function oneTestGroup()
     62{
     63    return {
     64        "testGroups": [{
     65            "id": "2128",
     66            "task": "1376",
     67            "platform": "31",
     68            "name": "Confirm",
     69            "author": "rniwa",
     70            "createdAt": 1458688514000,
     71            "hidden": false,
     72            "needsNotification": true,
     73            "buildRequests": ["16985", "16986", "16987", "16988"],
     74            "commitSets": ["4255", "4256"],
     75            "notificationSentAt": null,
     76            'initialRepetitionCount': 1
     77        }],
     78        "buildRequests": [{
     79            "id": "16985",
     80            "triggerable": "3",
     81            "task": "1376",
     82            "test": "844",
     83            "platform": "31",
     84            "testGroup": "2128",
     85            "order": "-2",
     86            "commitSet": "4255",
     87            "status": "pending",
     88            "url": null,
     89            "build": null,
     90            "createdAt": 1458688514000
     91        }, {
     92            "id": "16986",
     93            "triggerable": "3",
     94            "task": "1376",
     95            "test": "844",
     96            "platform": "31",
     97            "testGroup": "2128",
     98            "order": "-1",
     99            "commitSet": "4256",
     100            "status": "pending",
     101            "url": null,
     102            "build": null,
     103            "createdAt": 1458688514000
     104        }, {
     105            "id": "16987",
     106            "triggerable": "3",
     107            "task": "1376",
     108            "test": "844",
     109            "platform": "31",
     110            "testGroup": "2128",
     111            "order": "0",
     112            "commitSet": "4255",
     113            "status": "pending",
     114            "url": null,
     115            "build": null,
     116            "createdAt": 1458688514000
     117        }, {
     118            "id": "16988",
     119            "triggerable": "3",
     120            "task": "1376",
     121            "test": "844",
     122            "platform": "31",
     123            "testGroup": "2128",
     124            "order": "3",
     125            "commitSet": "4256",
     126            "status": "pending",
     127            "url": null,
     128            "build": null,
     129            "createdAt": 1458688514000
     130        }],
     131        "commitSets": [{
     132            "id": "4255",
     133            "revisionItems": [{"commit": "87832"}, {"commit": "93116"}],
     134            "customRoots": [],
     135        }, {
     136            "id": "4256",
     137            "revisionItems": [{"commit": "87832"}, {"commit": "96336"}],
     138            "customRoots": [],
     139        }],
     140        "commits": [{
     141            "id": "87832",
     142            "repository": "9",
     143            "revision": "10.11 15A284",
     144            "time": 0
     145        }, {
     146            "id": "93116",
     147            "repository": "11",
     148            "revision": "191622",
     149            "time": 1445945816878
     150        }, {
     151            "id": "87832",
     152            "repository": "9",
     153            "revision": "10.11 15A284",
     154            "time": 0
     155        }, {
     156            "id": "96336",
     157            "repository": "11",
     158            "revision": "192736",
     159            "time": 1448225325650
     160        }],
     161        "uploadedFiles": [],
     162        "status": "OK"
     163    };
     164}
     165
     166function threeTestGroups(secondTestGroupOverrides, thirdTestGroupOverrides)
     167{
     168    if (!secondTestGroupOverrides)
     169        secondTestGroupOverrides = {};
     170    if (!thirdTestGroupOverrides)
     171        thirdTestGroupOverrides = {};
     172    return {
     173        "testGroups": [{
     174            "id": "2128",
     175            "task": "1376",
     176            "platform": "32",
     177            "name": "Confirm",
     178            "author": "rniwa",
     179            "createdAt": 1458688514000,
     180            "hidden": false,
     181            "needsNotification": true,
     182            "buildRequests": ["16985", "16986", "16987", "16988"],
     183            "commitSets": ["4255", "4256"],
     184            "notificationSentAt": null,
     185            'initialRepetitionCount': 1
     186        }, {
     187            "id": "2129",
     188            "task": secondTestGroupOverrides.task || '1376',
     189            "platform": secondTestGroupOverrides.platform || '32',
     190            "name": "Confirm",
     191            "author": "rniwa",
     192            "createdAt": 1458688514000,
     193            "hidden": false,
     194            "needsNotification": true,
     195            "buildRequests": ["16989", "16990", "16991", "16992"],
     196            "commitSets": ["4255", "4256"],
     197            "notificationSentAt": null,
     198            'initialRepetitionCount': 1
     199        }, {
     200            "id": "2130",
     201            "task": thirdTestGroupOverrides.task || '1376',
     202            "platform": thirdTestGroupOverrides.platform || '32',
     203            "name": "Confirm",
     204            "author": "rniwa",
     205            "createdAt": 1458688514000,
     206            "hidden": false,
     207            "needsNotification": true,
     208            "buildRequests": ["16993", "16994", "16995", "16996"],
     209            "commitSets": ["4255", "4256"],
     210            "notificationSentAt": null,
     211            'initialRepetitionCount': 1
     212        }],
     213        "buildRequests": [{
     214            "id": "16985",
     215            "triggerable": "3",
     216            "task": "1376",
     217            "test": "844",
     218            "platform": "32",
     219            "testGroup": "2128",
     220            "order": "-2",
     221            "commitSet": "4255",
     222            "status": "pending",
     223            "url": null,
     224            "build": null,
     225            "createdAt": 1458688514000
     226        }, {
     227            "id": "16986",
     228            "triggerable": "3",
     229            "task": "1376",
     230            "test": "844",
     231            "platform": "32",
     232            "testGroup": "2128",
     233            "order": "-1",
     234            "commitSet": "4256",
     235            "status": "pending",
     236            "url": null,
     237            "build": null,
     238            "createdAt": 1458688514000
     239        }, {
     240            "id": "16987",
     241            "triggerable": "3",
     242            "task": "1376",
     243            "test": "844",
     244            "platform": "32",
     245            "testGroup": "2128",
     246            "order": "0",
     247            "commitSet": "4255",
     248            "status": "pending",
     249            "url": null,
     250            "build": null,
     251            "createdAt": 1458688514000
     252        }, {
     253            "id": "16988",
     254            "triggerable": "3",
     255            "task": "1376",
     256            "test": "844",
     257            "platform": "32",
     258            "testGroup": "2128",
     259            "order": "1",
     260            "commitSet": "4256",
     261            "status": "pending",
     262            "url": null,
     263            "build": null,
     264            "createdAt": 1458688514000
     265        }, {
     266            "id": "16989",
     267            "triggerable": "3",
     268            "task": secondTestGroupOverrides.task || '1376',
     269            "test": "844",
     270            "platform": secondTestGroupOverrides.platform || '32',
     271            "testGroup": "2129",
     272            "order": "-2",
     273            "commitSet": "4255",
     274            "status": secondTestGroupOverrides.status && secondTestGroupOverrides.status[0] || 'pending',
     275            "url": null,
     276            "build": null,
     277            "createdAt": 1458688514000
     278        }, {
     279            "id": "16990",
     280            "triggerable": "3",
     281            "task": secondTestGroupOverrides.task || '1376',
     282            "test": "844",
     283            "platform": secondTestGroupOverrides.platform || '32',
     284            "testGroup": "2129",
     285            "order": "-1",
     286            "commitSet": "4256",
     287            "status": secondTestGroupOverrides.status && secondTestGroupOverrides.status[1] || 'pending',
     288            "url": null,
     289            "build": null,
     290            "createdAt": 1458688514000
     291        }, {
     292            "id": "16991",
     293            "triggerable": "3",
     294            "task": secondTestGroupOverrides.task || '1376',
     295            "test": "844",
     296            "platform": secondTestGroupOverrides.platform || '32',
     297            "testGroup": "2129",
     298            "order": "0",
     299            "commitSet": "4255",
     300            "status": secondTestGroupOverrides.status && secondTestGroupOverrides.status[2] || 'pending',
     301            "url": null,
     302            "build": null,
     303            "createdAt": 1458688514000
     304        }, {
     305            "id": "16992",
     306            "triggerable": "3",
     307            "task": secondTestGroupOverrides.task || '1376',
     308            "test": "844",
     309            "platform": secondTestGroupOverrides.platform || '32',
     310            "testGroup": "2129",
     311            "order": "3",
     312            "commitSet": "4256",
     313            "status": secondTestGroupOverrides.status && secondTestGroupOverrides.status[3] || 'pending',
     314            "url": null,
     315            "build": null,
     316            "createdAt": 1458688514000
     317        }, {
     318            "id": "16993",
     319            "triggerable": "3",
     320            "task": thirdTestGroupOverrides.task || '1376',
     321            "test": "844",
     322            "platform": thirdTestGroupOverrides.platform || '32',
     323            "testGroup": "2130",
     324            "order": "-2",
     325            "commitSet": "4255",
     326            "status": thirdTestGroupOverrides.status && thirdTestGroupOverrides.status[0] || 'pending',
     327            "url": null,
     328            "build": null,
     329            "createdAt": 1458688513000
     330        }, {
     331            "id": "16994",
     332            "triggerable": "3",
     333            "task": thirdTestGroupOverrides.task || '1376',
     334            "test": "844",
     335            "platform": thirdTestGroupOverrides.platform || '32',
     336            "testGroup": "2130",
     337            "order": "-1",
     338            "commitSet": "4256",
     339            "status": thirdTestGroupOverrides.status && thirdTestGroupOverrides.status[1] || 'pending',
     340            "url": null,
     341            "build": null,
     342            "createdAt": 1458688514000
     343        }, {
     344            "id": "16995",
     345            "triggerable": "3",
     346            "task": thirdTestGroupOverrides.task || '1376',
     347            "test": "844",
     348            "platform": thirdTestGroupOverrides.platform || '32',
     349            "testGroup": "2130",
     350            "order": "0",
     351            "commitSet": "4255",
     352            "status": thirdTestGroupOverrides.status && thirdTestGroupOverrides.status[2] || 'pending',
     353            "url": null,
     354            "build": null,
     355            "createdAt": 1458688514000
     356        }, {
     357            "id": "16996",
     358            "triggerable": "3",
     359            "task": secondTestGroupOverrides.task || '1376',
     360            "test": "844",
     361            "platform": secondTestGroupOverrides.platform || '32',
     362            "testGroup": "2130",
     363            "order": "1",
     364            "commitSet": "4256",
     365            "status": thirdTestGroupOverrides.status && thirdTestGroupOverrides.status[3] || 'pending',
     366            "url": null,
     367            "build": null,
     368            "createdAt": 1458688514000
     369        }],
     370        "commitSets": [{
     371            "id": "4255",
     372            "revisionItems": [{"commit": "87832"}, {"commit": "93116"}],
     373            "customRoots": [],
     374        }, {
     375            "id": "4256",
     376            "revisionItems": [{"commit": "87832"}, {"commit": "96336"}],
     377            "customRoots": [],
     378        }],
     379        "commits": [{
     380            "id": "87832",
     381            "repository": "9",
     382            "revision": "10.11 15A284",
     383            "time": 0
     384        }, {
     385            "id": "93116",
     386            "repository": "11",
     387            "revision": "191622",
     388            "time": 1445945816878
     389        }, {
     390            "id": "87832",
     391            "repository": "9",
     392            "revision": "10.11 15A284",
     393            "time": 0
     394        }, {
     395            "id": "96336",
     396            "repository": "11",
     397            "revision": "192736",
     398            "time": 1448225325650
     399        }],
     400        "uploadedFiles": [],
     401        "status": "OK"
     402    };
     403}
     404
    59405describe('BuildRequest', function () {
    60406    MockModels.inject();
     407
     408    describe('findBuildRequestWithSameRoots', () => {
     409        const requests = MockRemoteAPI.inject('https://perf.webkit.org');
     410
     411        it('should return null when the build request is not build type build request', async () => {
     412            const data = sampleBuildRequestData();
     413            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     414            const result = await request.findBuildRequestWithSameRoots();
     415            assert.equal(result, null);
     416        });
     417
     418        it('should return null if this there is no other test group under current analysis task', async () => {
     419            const data = oneTestGroup();
     420            const platformId = data.buildRequests[0].platform;
     421            Platform.ensureSingleton(platformId, {id: platformId, metrics: [], name: 'some platform'});
     422            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     423            const promise = request.findBuildRequestWithSameRoots();
     424            assert.equal(requests.length, 1);
     425
     426            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     427            assert.equal(requests[0].method, 'GET');
     428            requests[0].resolve(oneTestGroup());
     429
     430            const result = await promise;
     431            assert.equal(result, null);
     432        });
     433
     434        it('should return completed build request if a completed reusable build request found', async () => {
     435            const overrides = {
     436                task: '1376',
     437                platform: '32',
     438                status: ['completed', 'pending', 'pending', 'pending']
     439            }
     440            const data = threeTestGroups(overrides);
     441            const platformId = data.buildRequests[0].platform;
     442            Platform.ensureSingleton(platformId, {id: platformId, metrics: [], name: 'some platform'});
     443            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     444            const promise = request.findBuildRequestWithSameRoots();
     445            assert.equal(requests.length, 1);
     446
     447            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     448            assert.equal(requests[0].method, 'GET');
     449            requests[0].resolve(threeTestGroups(overrides));
     450
     451            const result = await promise;
     452            assert.equal(result, BuildRequest.findById(16989))
     453        });
     454
     455        it('should not use cache while fetching test groups under analysis task', async () => {
     456            const overrides = {
     457                task: '1376',
     458                platform: '32',
     459                status: ['completed', 'pending', 'pending', 'pending']
     460            };
     461            const data = threeTestGroups(overrides);
     462            const platformId = data.buildRequests[0].platform;
     463            Platform.ensureSingleton(platformId, {id: platformId, metrics: [], name: 'some platform'});
     464            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     465            let promise = request.findBuildRequestWithSameRoots();
     466            assert.equal(requests.length, 1);
     467
     468            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     469            assert.equal(requests[0].method, 'GET');
     470            requests[0].resolve(threeTestGroups(overrides));
     471
     472            let result = await promise;
     473            assert.equal(result, BuildRequest.findById(16989))
     474
     475            MockRemoteAPI.reset();
     476            promise = request.findBuildRequestWithSameRoots();
     477            assert.equal(requests.length, 1);
     478
     479            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     480            assert.equal(requests[0].method, 'GET');
     481            requests[0].resolve(threeTestGroups(overrides));
     482
     483            result = await promise;
     484            assert.equal(result, BuildRequest.findById(16989))
     485        });
     486
     487        it('should only allow identical platform if the platform is not under a platform group', async () => {
     488            const overrides = {
     489                task: '1376',
     490                platform: '33',
     491                status: ['completed', 'pending', 'pending', 'pending']
     492            };
     493            const data = threeTestGroups(overrides);
     494            const platformId = data.buildRequests[0].platform;
     495            Platform.ensureSingleton(platformId, {id: platformId, metrics: [], name: 'some platform'});
     496            Platform.ensureSingleton('33', {id: '33', metrics: [], name: 'another platform'});
     497            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     498            const promise = request.findBuildRequestWithSameRoots();
     499            assert.equal(requests.length, 1);
     500
     501            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     502            assert.equal(requests[0].method, 'GET');
     503            requests[0].resolve(threeTestGroups(overrides));
     504
     505            const result = await promise;
     506            assert.equal(result, null);
     507        });
     508
     509        it('should allow different platform if the platforms are under the same platform group', async () => {
     510            const overrides = {
     511                task: '1376',
     512                platform: '33',
     513                status: ['completed', 'pending', 'pending', 'pending']
     514            };
     515            const data = threeTestGroups(overrides);
     516            const platformId = data.buildRequests[0].platform;
     517            const platformGroup = PlatformGroup.ensureSingleton('1', {id: 1, name: 'some platform group'});
     518            Platform.ensureSingleton(platformId, {id: platformId, metrics: [], name: 'some platform', group: platformGroup});
     519            Platform.ensureSingleton('33', {id: '33', metrics: [], name: 'another platform', group: platformGroup});
     520            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     521            const promise = request.findBuildRequestWithSameRoots();
     522            assert.equal(requests.length, 1);
     523
     524            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     525            assert.equal(requests[0].method, 'GET');
     526            requests[0].resolve(threeTestGroups(overrides));
     527
     528            const result = await promise;
     529            assert.equal(result, BuildRequest.findById(16989))
     530        });
     531
     532        it('should in favor of running build request over scheduled build request', async () => {
     533            const secondOverrides = {
     534                task: '1376',
     535                platform: '32',
     536                status: ['scheduled', 'pending', 'pending', 'pending']
     537            };
     538            const thirdOverrides = {
     539                task: '1376',
     540                platform: '32',
     541                status: ['running', 'pending', 'pending', 'pending']
     542            }
     543            const data = threeTestGroups(secondOverrides, thirdOverrides);
     544            const platformId = data.buildRequests[0].platform;
     545            Platform.ensureSingleton(platformId, {id: platformId, metrics: [], name: 'some platform'});
     546            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     547            const promise = request.findBuildRequestWithSameRoots();
     548            assert.equal(requests.length, 1);
     549
     550            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     551            assert.equal(requests[0].method, 'GET');
     552            requests[0].resolve(threeTestGroups(secondOverrides, thirdOverrides));
     553
     554            const result = await promise;
     555            assert.equal(result, BuildRequest.findById(16993))
     556        });
     557
     558        it('should in favor of running build request which has earlier creation time', async () => {
     559            const secondOverrides = {
     560                task: '1376',
     561                platform: '32',
     562                status: ['running', 'pending', 'pending', 'pending']
     563            };
     564            const thirdOverrides = {
     565                task: '1376',
     566                platform: '32',
     567                status: ['running', 'pending', 'pending', 'pending']
     568            }
     569            const data = threeTestGroups(secondOverrides, thirdOverrides);
     570            const platformId = data.buildRequests[0].platform;
     571            Platform.ensureSingleton(platformId, {id: platformId, metrics: [], name: 'some platform'});
     572            const request = BuildRequest.constructBuildRequestsFromData(data)[0];
     573            const promise = request.findBuildRequestWithSameRoots();
     574            assert.equal(requests.length, 1);
     575
     576            assert.equal(requests[0].url, '/api/test-groups?task=1376');
     577            assert.equal(requests[0].method, 'GET');
     578            requests[0].resolve(threeTestGroups(secondOverrides, thirdOverrides));
     579
     580            const result = await promise;
     581            assert.equal(result, BuildRequest.findById(16993));
     582            assert.ok(BuildRequest.findById(16993).createdAt() < BuildRequest.findById(16989).createdAt());
     583        });
     584    });
    61585
    62586    describe('waitingTime', function () {
Note: See TracChangeset for help on using the changeset viewer.