Migrate admin-regenerate-manifest.js to mocha.js and test v3 UI code
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Mar 2016 21:55:34 +0000 (21:55 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Mar 2016 21:55:34 +0000 (21:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=155863

Reviewed by Joseph Pecoraro.

Replaced admin-regenerate-manifest.js by a new mocha.js tests using the new server testing capability
added in r198642 and tested v3 UI code (parsing manifest.json and creating models). Also removed
/admin/regenerate-manifest since it has been superseded by /api/manifest.

This patch also extracts manifest.js out of main.js so that it could be used and tested without the
DOM support in node.

* public/admin/regenerate-manifest.php: Deleted.
* public/include/db.php: Fixed a regression from r198642 since CONFIG_DIR now doesn't end with
a trailing backslash.
* public/include/manifest.php:
(ManifestGenerator::bug_trackers): Avoid a warning message when there are no repositories.
* public/v3/index.html:
* public/v3/main.js:
(main):
* public/v3/models/bug-tracker.js:
(BugTracker.prototype.newBugUrl): Added.
(BugTracker.prototype.repositories): Added.
* public/v3/models/manifest.js: Added. Extracted from main.js.
(Manifest.fetch): Moved from main.js' fetchManifest.
(Manifest._didFetchManifest): Moved from main.js' didFetchManifest.
* public/v3/models/platform.js:
(Platform.prototype.hasTest): Fixed the bug that "test" here was shadowing the function parameter of
the same name. This is tested by the newly added test cases.
* server-tests/api-build-requests-tests.js:
* server-tests/api-manifest.js: Added. Migrated test cases from tests/admin-regenerate-manifest.js
with additional assertions for v3 UI model objects.
* server-tests/resources/test-server.js:
(TestServer.prototype.start):
(TestServer.prototype.testConfig): Renamed from _constructTestConfig now that this is a public API.
Also no longer takes dataDirectory as an argument since it's always the same.
(TestServer.prototype._ensureDataDirectory): Fixed a bug that we weren't making public/data.
(TestServer.prototype.cleanDataDirectory): Added. Remove all files inside public/data between tests.
(TestServer.prototype.inject): Added. Calls before, etc... because always calling before had an
unintended side effect of slowing down unit tests even through they don't need Postgres or Apache.
* tests/admin-regenerate-manifest.js: Removed.
* tools/js/database.js:
* tools/js/v3-models.js:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@198691 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Websites/perf.webkit.org/ChangeLog
Websites/perf.webkit.org/public/admin/regenerate-manifest.php [deleted file]
Websites/perf.webkit.org/public/include/db.php
Websites/perf.webkit.org/public/include/manifest.php
Websites/perf.webkit.org/public/v3/index.html
Websites/perf.webkit.org/public/v3/main.js
Websites/perf.webkit.org/public/v3/models/bug-tracker.js
Websites/perf.webkit.org/public/v3/models/manifest.js [new file with mode: 0644]
Websites/perf.webkit.org/public/v3/models/platform.js
Websites/perf.webkit.org/server-tests/api-build-requests-tests.js
Websites/perf.webkit.org/server-tests/api-manifest.js [new file with mode: 0644]
Websites/perf.webkit.org/server-tests/resources/test-server.js
Websites/perf.webkit.org/tests/admin-regenerate-manifest.js [deleted file]
Websites/perf.webkit.org/tools/js/database.js
Websites/perf.webkit.org/tools/js/v3-models.js

index 50740a0..a0c4b25 100644 (file)
@@ -1,3 +1,49 @@
+2016-03-24  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Migrate admin-regenerate-manifest.js to mocha.js and test v3 UI code
+        https://bugs.webkit.org/show_bug.cgi?id=155863
+
+        Reviewed by Joseph Pecoraro.
+
+        Replaced admin-regenerate-manifest.js by a new mocha.js tests using the new server testing capability
+        added in r198642 and tested v3 UI code (parsing manifest.json and creating models). Also removed
+        /admin/regenerate-manifest since it has been superseded by /api/manifest.
+
+        This patch also extracts manifest.js out of main.js so that it could be used and tested without the
+        DOM support in node.
+
+        * public/admin/regenerate-manifest.php: Deleted.
+        * public/include/db.php: Fixed a regression from r198642 since CONFIG_DIR now doesn't end with
+        a trailing backslash.
+        * public/include/manifest.php:
+        (ManifestGenerator::bug_trackers): Avoid a warning message when there are no repositories.
+        * public/v3/index.html:
+        * public/v3/main.js:
+        (main):
+        * public/v3/models/bug-tracker.js:
+        (BugTracker.prototype.newBugUrl): Added.
+        (BugTracker.prototype.repositories): Added.
+        * public/v3/models/manifest.js: Added. Extracted from main.js.
+        (Manifest.fetch): Moved from main.js' fetchManifest.
+        (Manifest._didFetchManifest): Moved from main.js' didFetchManifest.
+        * public/v3/models/platform.js:
+        (Platform.prototype.hasTest): Fixed the bug that "test" here was shadowing the function parameter of
+        the same name. This is tested by the newly added test cases.
+        * server-tests/api-build-requests-tests.js:
+        * server-tests/api-manifest.js: Added. Migrated test cases from tests/admin-regenerate-manifest.js
+        with additional assertions for v3 UI model objects.
+        * server-tests/resources/test-server.js:
+        (TestServer.prototype.start):
+        (TestServer.prototype.testConfig): Renamed from _constructTestConfig now that this is a public API.
+        Also no longer takes dataDirectory as an argument since it's always the same.
+        (TestServer.prototype._ensureDataDirectory): Fixed a bug that we weren't making public/data.
+        (TestServer.prototype.cleanDataDirectory): Added. Remove all files inside public/data between tests.
+        (TestServer.prototype.inject): Added. Calls before, etc... because always calling before had an
+        unintended side effect of slowing down unit tests even through they don't need Postgres or Apache.
+        * tests/admin-regenerate-manifest.js: Removed.
+        * tools/js/database.js:
+        * tools/js/v3-models.js:
+
 2016-03-23  Ryosuke Niwa  <rniwa@webkit.org>
 
         Add mocha server tests for /api/build-requests
diff --git a/Websites/perf.webkit.org/public/admin/regenerate-manifest.php b/Websites/perf.webkit.org/public/admin/regenerate-manifest.php
deleted file mode 100644 (file)
index 956d1ea..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<?php
-
-require_once('../include/admin-header.php');
-require_once('../include/manifest.php');
-
-if ($db) {
-    if (regenerate_manifest())
-        notice("Regenerated the manifest");
-}
-
-require('../include/admin-footer.php');
-
-?>
index 60fc2b0..8749be0 100644 (file)
@@ -34,14 +34,14 @@ function config($key, $default = NULL) {
     if (!$_config) {
         $file_path = getenv('ORG_WEBKIT_PERF_CONFIG_PATH');
         if (!$file_path)
-            $file_path = CONFIG_DIR . 'config.json';
+            $file_path = CONFIG_DIR . '/config.json';
         $_config = json_decode(file_get_contents($file_path), true);
     }
     return array_get($_config, $key, $default);
 }
 
 function config_path($key, $path) {
-    return CONFIG_DIR . config($key) . '/' . $path;
+    return CONFIG_DIR . '/' . config($key) . '/' . $path;
 }
 
 function generate_data_file($filename, $content) {
index 3530610..080f9a6 100644 (file)
@@ -165,7 +165,7 @@ class ManifestGenerator {
                     'name' => $row['tracker_name'],
                     'bugUrl' => $row['tracker_bug_url'],
                     'newBugUrl' => $row['tracker_new_bug_url'],
-                    'repositories' => $tracker_id_to_repositories[$row['tracker_id']]);
+                    'repositories' => array_get($tracker_id_to_repositories, $row['tracker_id']));
             }
         }
 
index 6753c64..8f80bed 100644 (file)
@@ -61,6 +61,7 @@ Run tools/bundle-v3-scripts to speed up the load time for production.`);
         <script src="models/test-group.js"></script>
         <script src="models/build-request.js"></script>
         <script src="models/root-set.js"></script>
+        <script src="models/manifest.js"></script>
 
         <script src="components/base.js"></script>
         <script src="components/spinner-icon.js"></script>
index bc23f4b..6705625 100644 (file)
@@ -9,7 +9,7 @@ class SpinningPage extends Page {
 function main() {
     (new SpinningPage).open();
 
-    fetchManifest().then(function (manifest) {
+    Manifest.fetch().then(function (manifest) {
         var dashboardToolbar = new DashboardToolbar;
         var dashboardPages = [];
         if (manifest.dashboards) {
@@ -51,66 +51,11 @@ function main() {
 
         heading.setRouter(router);
         router.route();
+    }).catch(function (error) {
+        alert('Failed to load the site manifest: ' + error);
     });
 }
 
-function fetchManifest()
-{
-    return RemoteAPI.getJSON('../data/manifest.json').then(didFetchManifest, function () {
-        return RemoteAPI.getJSON('../api/manifest/').then(didFetchManifest, function (error) {
-            alert('Failed to load the site manifest: ' + error);
-        });
-    });
-}
-
-function didFetchManifest(rawResponse)
-{
-    Instrumentation.startMeasuringTime('Main', 'didFetchManifest');
-
-    var tests = [];
-    var testParentMap = {};
-    for (var testId in rawResponse.tests) {
-        var test = rawResponse.tests[testId];
-        var topLevel = !test.parentId;
-        if (test.parentId)
-            testParentMap[testId] = parseInt(test.parentId);
-        tests.push(new Test(testId, test, topLevel));
-    }
-    for (var testId in testParentMap)
-        Test.findById(testId).setParentTest(Test.findById(testParentMap[testId]));
-
-    function buildObjectsFromIdMap(idMap, constructor, resolver) {
-        for (var id in idMap) {
-            if (resolver)
-                resolver(idMap[id]);
-            new constructor(id, idMap[id]);
-        }
-    }
-    buildObjectsFromIdMap(rawResponse.metrics, Metric, function (raw) {
-        raw.test = Test.findById(raw.test);
-    });
-
-    buildObjectsFromIdMap(rawResponse.all, Platform, function (raw) {
-        raw.lastModifiedByMetric = {};
-        raw.lastModified.forEach(function (lastModified, index) {
-            raw.lastModifiedByMetric[raw.metrics[index]] = lastModified;
-        });
-        raw.metrics = raw.metrics.map(function (id) { return Metric.findById(id); });
-    });
-    buildObjectsFromIdMap(rawResponse.builders, Builder);
-    buildObjectsFromIdMap(rawResponse.repositories, Repository);
-    buildObjectsFromIdMap(rawResponse.bugTrackers, BugTracker, function (raw) {
-        raw.repositories = raw.repositories.map(function (id) { return Repository.findById(id); });
-    });
-
-    Instrumentation.endMeasuringTime('Main', 'didFetchManifest');
-
-    return {
-        siteTitle: rawResponse.siteTitle,
-        dashboards: rawResponse.dashboards, // FIXME: Add an abstraction around dashboards.
-    }
-}
-
 if (document.readyState != 'loading')
     main();
 else
index 5d53210..25bf663 100644 (file)
@@ -1,3 +1,4 @@
+'use strict';
 
 class BugTracker extends LabeledObject {
     constructor(id, object)
@@ -9,4 +10,9 @@ class BugTracker extends LabeledObject {
     }
 
     bugUrl(bugNumber) { return this._bugUrl && bugNumber ? this._bugUrl.replace(/\$number/g, bugNumber) : null; }
+    newBugUrl() { return this._newBugUrl; }
+    repositories() { return this._repositories; }
 }
+
+if (typeof module != 'undefined')
+    module.exports.BugTracker = BugTracker;
diff --git a/Websites/perf.webkit.org/public/v3/models/manifest.js b/Websites/perf.webkit.org/public/v3/models/manifest.js
new file mode 100644 (file)
index 0000000..f429793
--- /dev/null
@@ -0,0 +1,63 @@
+'use strict';
+
+class Manifest {
+
+    static fetch()
+    {
+        return RemoteAPI.getJSON('../data/manifest.json').catch(function () {
+            return RemoteAPI.getJSON('../api/manifest/');
+        }).then(this._didFetchManifest.bind(this));
+    }
+
+    static _didFetchManifest(rawResponse)
+    {
+        Instrumentation.startMeasuringTime('Manifest', '_didFetchManifest');
+
+        var tests = [];
+        var testParentMap = {};
+        for (var testId in rawResponse.tests) {
+            var test = rawResponse.tests[testId];
+            var topLevel = !test.parentId;
+            if (test.parentId)
+                testParentMap[testId] = parseInt(test.parentId);
+            tests.push(new Test(testId, test, topLevel));
+        }
+        for (var testId in testParentMap)
+            Test.findById(testId).setParentTest(Test.findById(testParentMap[testId]));
+
+        function buildObjectsFromIdMap(idMap, constructor, resolver) {
+            for (var id in idMap) {
+                if (resolver)
+                    resolver(idMap[id]);
+                new constructor(id, idMap[id]);
+            }
+        }
+        buildObjectsFromIdMap(rawResponse.metrics, Metric, function (raw) {
+            raw.test = Test.findById(raw.test);
+        });
+
+        buildObjectsFromIdMap(rawResponse.all, Platform, function (raw) {
+            raw.lastModifiedByMetric = {};
+            raw.lastModified.forEach(function (lastModified, index) {
+                raw.lastModifiedByMetric[raw.metrics[index]] = lastModified;
+            });
+            raw.metrics = raw.metrics.map(function (id) { return Metric.findById(id); });
+        });
+        buildObjectsFromIdMap(rawResponse.builders, Builder);
+        buildObjectsFromIdMap(rawResponse.repositories, Repository);
+        buildObjectsFromIdMap(rawResponse.bugTrackers, BugTracker, function (raw) {
+            if (raw.repositories)
+                raw.repositories = raw.repositories.map(function (id) { return Repository.findById(id); });
+        });
+
+        Instrumentation.endMeasuringTime('Manifest', '_didFetchManifest');
+
+        return {
+            siteTitle: rawResponse.siteTitle,
+            dashboards: rawResponse.dashboards, // FIXME: Add an abstraction around dashboards.
+        }
+    }
+}
+
+if (typeof module != 'undefined')
+    module.exports.Manifest = Manifest;
index bcefe49..8d95982 100644 (file)
@@ -17,14 +17,14 @@ class Platform extends LabeledObject {
         if (!this._containingTests) {
             this._containingTests = {};
             for (var metric of this._metrics) {
-                for (var test = metric.test(); test; test = test.parentTest()) {
-                    if (test.id() in this._containingTests)
+                for (var currentTest = metric.test(); currentTest; currentTest = currentTest.parentTest()) {
+                    if (currentTest.id() in this._containingTests)
                         break;
-                    this._containingTests[test.id()] = true;
+                    this._containingTests[currentTest.id()] = true;
                 }
             }
         }
-        return this._containingTests[test.id()];
+        return test.id() in this._containingTests;
     }
 
     hasMetric(metric) { return !!this.lastModified(metric); }
index 9349f27..09965f2 100644 (file)
@@ -5,6 +5,7 @@ let TestServer = require('./resources/test-server.js');
 
 describe('/api/build-requests', function () {
     this.timeout(10000);
+    TestServer.inject();
 
     it('should return "TriggerableNotFound" when the database is empty', function (done) {
         TestServer.remoteAPI().fetchJSON('/api/build-requests/build-webkit').then(function (content) {
diff --git a/Websites/perf.webkit.org/server-tests/api-manifest.js b/Websites/perf.webkit.org/server-tests/api-manifest.js
new file mode 100644 (file)
index 0000000..6bd06d5
--- /dev/null
@@ -0,0 +1,281 @@
+'use strict';
+
+let assert = require('assert');
+
+require('../tools/js/v3-models.js');
+
+let TestServer = require('./resources/test-server.js');
+
+describe('/api/build-requests', function () {
+    this.timeout(10000);
+    TestServer.inject();
+
+    beforeEach(function () {
+        Builder.clearStaticMap();
+        BugTracker.clearStaticMap();
+        Test.clearStaticMap();
+        Metric.clearStaticMap();
+        Platform.clearStaticMap();
+        Repository.clearStaticMap();
+    });
+
+    it("should generate an empty manifest when database is empty", function (done) {
+        TestServer.remoteAPI().fetchJSON('/api/manifest').then(function (manifest) {
+            assert.deepEqual(Object.keys(manifest).sort(), ['all', 'bugTrackers', 'builders', 'dashboard', 'dashboards',
+                'elapsedTime', 'metrics', 'repositories', 'siteTitle', 'status', 'tests']);
+
+            assert.equal(typeof(manifest.elapsedTime), 'number');
+            delete manifest.elapsedTime;
+
+            assert.deepEqual(manifest, {
+                siteTitle: TestServer.testConfig().siteTitle,
+                all: {},
+                bugTrackers: {},
+                builders: {},
+                dashboard: {},
+                dashboards: {},
+                metrics: {},
+                repositories: {},
+                tests: {},
+                status: 'OK'
+            });
+            done();
+        }).catch(done);
+    });
+
+    const bugzillaData = {id: 1, name: 'Bugzilla', bug_url: 'https://webkit.org/b/$number', new_bug_url: 'https://bugs.webkit.org/'};
+    const radarData = {id: 2, name: 'Radar'};
+
+    it("should generate manifest with bug trackers without repositories", function (done) {
+        TestServer.database().connect();
+        TestServer.database().insert('bug_trackers', bugzillaData).then(function () {
+            return TestServer.remoteAPI().fetchJSON('/api/manifest');
+        }).then(function (content) {
+            assert.deepEqual(content.bugTrackers, {1: {name: 'Bugzilla', bugUrl: 'https://webkit.org/b/$number',
+                newBugUrl: 'https://bugs.webkit.org/', repositories: null}});
+
+            let manifest = Manifest._didFetchManifest(content);
+            let tracker = BugTracker.findById(1);
+            assert(tracker);
+            assert.equal(tracker.name(), 'Bugzilla');
+            assert.equal(tracker.bugUrl(123), 'https://webkit.org/b/123');
+            assert.equal(tracker.newBugUrl(), 'https://bugs.webkit.org/');
+
+            done();
+        }).catch(done);
+    });
+
+    it("should generate manifest with bug trackers and repositories", function (done) {
+        let db = TestServer.database();
+        db.connect();
+        Promise.all([
+            db.insert('bug_trackers', bugzillaData),
+            db.insert('bug_trackers', radarData),
+            db.insert('repositories', {id: 11, name: 'WebKit', url: 'https://trac.webkit.org/$1'}),
+            db.insert('repositories', {id: 9, name: 'OS X'}),
+            db.insert('repositories', {id: 22, name: 'iOS'}),
+            db.insert('tracker_repositories', {tracker: bugzillaData.id, repository: 11}),
+            db.insert('tracker_repositories', {tracker: radarData.id, repository: 9}),
+            db.insert('tracker_repositories', {tracker: radarData.id, repository: 22}),
+        ]).then(function () {
+            return TestServer.remoteAPI().fetchJSON('/api/manifest');
+        }).then(function (content) {
+            let manifest = Manifest._didFetchManifest(content);
+
+            let webkit = Repository.findById(11);
+            assert(webkit);
+            assert.equal(webkit.name(), 'WebKit');
+            assert.equal(webkit.urlForRevision(123), 'https://trac.webkit.org/123');
+
+            let osx = Repository.findById(9);
+            assert(osx);
+            assert.equal(osx.name(), 'OS X');
+
+            let ios = Repository.findById(22);
+            assert(ios);
+            assert.equal(ios.name(), 'iOS');
+
+            let tracker = BugTracker.findById(1);
+            assert(tracker);
+            assert.equal(tracker.name(), 'Bugzilla');
+            assert.equal(tracker.bugUrl(123), 'https://webkit.org/b/123');
+            assert.equal(tracker.newBugUrl(), 'https://bugs.webkit.org/');
+            assert.deepEqual(tracker.repositories(), [webkit]);
+
+            tracker = BugTracker.findById(2);
+            assert(tracker);
+            assert.equal(tracker.name(), 'Radar');
+            assert.deepEqual(Repository.sortByName(tracker.repositories()), [osx, ios]);
+
+            done();
+        }).catch(done);
+    });
+
+    it("should generate manifest with builders", function (done) {
+        let db = TestServer.database();
+        db.connect();
+        Promise.all([
+            db.insert('builders', {id: 1, name: 'SomeBuilder', password_hash: 'a',
+                build_url: 'https://build.webkit.org/builders/$builderName/build/$buildNumber'}),
+            db.insert('builders', {id: 2, name: 'SomeOtherBuilder', password_hash: 'b'})
+        ]).then(function () {
+            return TestServer.remoteAPI().fetchJSON('/api/manifest');
+        }).then(function (content) {
+            assert.deepEqual(content.builders, {
+                '1': {name: 'SomeBuilder', buildUrl: 'https://build.webkit.org/builders/$builderName/build/$buildNumber'},
+                '2': {name: 'SomeOtherBuilder', buildUrl: null}
+            });
+
+            let manifest = Manifest._didFetchManifest(content);
+
+            let builder = Builder.findById(1);
+            assert(builder);
+            assert.equal(builder.name(), 'SomeBuilder');
+            assert.equal(builder.urlForBuild(123), 'https://build.webkit.org/builders/SomeBuilder/build/123');
+
+            builder = Builder.findById(2);
+            assert(builder);
+            assert.equal(builder.name(), 'SomeOtherBuilder');
+            assert.equal(builder.urlForBuild(123), null);
+
+            done();
+        }).catch(done);
+    });
+
+    it("should generate manifest with tests, metrics, and platforms", function (done) {
+        let db = TestServer.database();
+        db.connect();
+        Promise.all([
+            db.insert('tests', {id: 1, name: 'SomeTest'}),
+            db.insert('tests', {id: 2, name: 'SomeOtherTest'}),
+            db.insert('tests', {id: 3, name: 'ChildTest', parent: 1}),
+            db.insert('tests', {id: 4, name: 'GrandChild', parent: 3}),
+            db.insert('aggregators', {id: 200, name: 'Total'}),
+            db.insert('test_metrics', {id: 5, test: 1, name: 'Time'}),
+            db.insert('test_metrics', {id: 6, test: 2, name: 'Time', aggregator: 200}),
+            db.insert('test_metrics', {id: 7, test: 2, name: 'Malloc', aggregator: 200}),
+            db.insert('test_metrics', {id: 8, test: 3, name: 'Time'}),
+            db.insert('test_metrics', {id: 9, test: 4, name: 'Time'}),
+            db.insert('platforms', {id: 23, name: 'iOS 9 iPhone 5s'}),
+            db.insert('platforms', {id: 46, name: 'Trunk Mavericks'}),
+            db.insert('test_configurations', {id: 101, metric: 5, platform: 46, type: 'current'}),
+            db.insert('test_configurations', {id: 102, metric: 6, platform: 46, type: 'current'}),
+            db.insert('test_configurations', {id: 103, metric: 7, platform: 46, type: 'current'}),
+            db.insert('test_configurations', {id: 104, metric: 8, platform: 46, type: 'current'}),
+            db.insert('test_configurations', {id: 105, metric: 9, platform: 46, type: 'current'}),
+            db.insert('test_configurations', {id: 106, metric: 5, platform: 23, type: 'current'}),
+            db.insert('test_configurations', {id: 107, metric: 5, platform: 23, type: 'baseline'}),
+        ]).then(function () {
+            return TestServer.remoteAPI().fetchJSON('/api/manifest');
+        }).then(function (content) {
+            assert.deepEqual(content.tests, {
+                "1": {"name": "SomeTest", "parentId": null, "url": null},
+                "2": {"name": "SomeOtherTest", "parentId": null, "url": null},
+                "3": {"name": "ChildTest", "parentId": "1", "url": null},
+                "4": {"name": "GrandChild", "parentId": "3", "url": null},
+            });
+
+            assert.deepEqual(content.metrics, {
+                '5': {name: 'Time', test: '1', aggregator: null},
+                '6': {name: 'Time', test: '2', aggregator: 'Total'},
+                '7': {name: 'Malloc', test: '2', aggregator: 'Total'},
+                '8': {name: 'Time', test: '3', aggregator: null},
+                '9': {name: 'Time', test: '4', aggregator: null},
+            });
+
+            let manifest = Manifest._didFetchManifest(content);
+
+            let someTest = Test.findById(1);
+            let someTestMetric = Metric.findById(5);
+            let someOtherTest = Test.findById(2);
+            let someOtherTestTime = Metric.findById(6);
+            let someOtherTestMalloc = Metric.findById(7);
+            let childTest = Test.findById(3);
+            let childTestMetric = Metric.findById(8);
+            let grandChildTest = Test.findById(4);
+            let ios9iphone5s = Platform.findById(23);
+            let mavericks = Platform.findById(46);
+            assert(someTest);
+            assert(someTestMetric);
+            assert(someOtherTest);
+            assert(someOtherTestTime);
+            assert(someOtherTestMalloc);
+            assert(childTest);
+            assert(childTestMetric);
+            assert(grandChildTest);
+            assert(ios9iphone5s);
+            assert(mavericks);
+
+            assert.equal(mavericks.name(), 'Trunk Mavericks');
+            assert(mavericks.hasTest(someTest));
+            assert(mavericks.hasTest(someOtherTest));
+            assert(mavericks.hasTest(childTest));
+            assert(mavericks.hasTest(grandChildTest));
+            assert(mavericks.hasMetric(someTestMetric));
+            assert(mavericks.hasMetric(someOtherTestTime));
+            assert(mavericks.hasMetric(someOtherTestMalloc));
+            assert(mavericks.hasMetric(childTestMetric));
+
+            assert.equal(ios9iphone5s.name(), 'iOS 9 iPhone 5s');
+            assert(ios9iphone5s.hasTest(someTest));
+            assert(!ios9iphone5s.hasTest(someOtherTest));
+            assert(!ios9iphone5s.hasTest(childTest));
+            assert(!ios9iphone5s.hasTest(grandChildTest));
+            assert(ios9iphone5s.hasMetric(someTestMetric));
+            assert(!ios9iphone5s.hasMetric(someOtherTestTime));
+            assert(!ios9iphone5s.hasMetric(someOtherTestMalloc));
+            assert(!ios9iphone5s.hasMetric(childTestMetric));
+
+            assert.equal(someTest.name(), 'SomeTest');
+            assert.equal(someTest.parentTest(), null);
+            assert.deepEqual(someTest.path(), [someTest]);
+            assert(!someTest.onlyContainsSingleMetric());
+            assert.deepEqual(someTest.childTests(), [childTest]);
+            assert.deepEqual(someTest.metrics(), [someTestMetric]);
+
+            assert.equal(someTestMetric.name(), 'Time');
+            assert.equal(someTestMetric.aggregatorName(), null);
+            assert.equal(someTestMetric.label(), 'Time');
+            assert.deepEqual(someTestMetric.childMetrics(), childTest.metrics());
+            assert.equal(someTestMetric.fullName(), 'SomeTest : Time');
+
+            assert.equal(someOtherTest.name(), 'SomeOtherTest');
+            assert.equal(someOtherTest.parentTest(), null);
+            assert.deepEqual(someOtherTest.path(), [someOtherTest]);
+            assert(!someOtherTest.onlyContainsSingleMetric());
+            assert.deepEqual(someOtherTest.childTests(), []);
+            assert.equal(someOtherTest.metrics().length, 2);
+            assert.equal(someOtherTest.metrics()[0].name(), 'Time');
+            assert.equal(someOtherTest.metrics()[0].aggregatorName(), 'Total');
+            assert.equal(someOtherTest.metrics()[0].label(), 'Time : Total');
+            assert.equal(someOtherTest.metrics()[0].childMetrics().length, 0);
+            assert.equal(someOtherTest.metrics()[0].fullName(), 'SomeOtherTest : Time : Total');
+            assert.equal(someOtherTest.metrics()[1].name(), 'Malloc');
+            assert.equal(someOtherTest.metrics()[1].aggregatorName(), 'Total');
+            assert.equal(someOtherTest.metrics()[1].label(), 'Malloc : Total');
+            assert.equal(someOtherTest.metrics()[1].childMetrics().length, 0);
+            assert.equal(someOtherTest.metrics()[1].fullName(), 'SomeOtherTest : Malloc : Total');
+
+            assert.equal(childTest.name(), 'ChildTest');
+            assert.equal(childTest.parentTest(), someTest);
+            assert.deepEqual(childTest.path(), [someTest, childTest]);
+            assert(!childTest.onlyContainsSingleMetric());
+            assert.deepEqual(childTest.childTests(), [grandChildTest]);
+            assert.equal(childTest.metrics().length, 1);
+            assert.equal(childTest.metrics()[0].label(), 'Time');
+            assert.equal(childTest.metrics()[0].fullName(), 'SomeTest \u220B ChildTest : Time');
+
+            assert.equal(grandChildTest.name(), 'GrandChild');
+            assert.equal(grandChildTest.parentTest(), childTest);
+            assert.deepEqual(grandChildTest.path(), [someTest, childTest, grandChildTest]);
+            assert(grandChildTest.onlyContainsSingleMetric());
+            assert.deepEqual(grandChildTest.childTests(), []);
+            assert.equal(grandChildTest.metrics().length, 1);
+            assert.equal(grandChildTest.metrics()[0].label(), 'Time');
+            assert.equal(grandChildTest.metrics()[0].fullName(), 'SomeTest \u220B ChildTest \u220B GrandChild : Time');
+
+            done();
+        }).catch(done);
+    });
+
+});
index 787cdfd..542cc71 100644 (file)
@@ -30,7 +30,7 @@ let TestServer = (new class TestServer {
 
     start()
     {        
-        let testConfigContent = this._constructTestConfig(this._dataDirectory);
+        let testConfigContent = this.testConfig();
         fs.writeFileSync(this._testConfigPath, JSON.stringify(testConfigContent, null, '    '));
 
         this._ensureTestDatabase();
@@ -61,13 +61,13 @@ let TestServer = (new class TestServer {
         return this._database;
     }
 
-    _constructTestConfig(dataDirectory)
+    testConfig()
     {
         return {
             'siteTitle': 'Test Dashboard',
             'debug': true,
             'jsonCacheMaxAge': 600,
-            'dataDirectory': dataDirectory,
+            'dataDirectory': Config.value('dataDirectory'),
             'database': {
                 'host': Config.value('database.host'),
                 'port': Config.value('database.port'),
@@ -86,17 +86,14 @@ let TestServer = (new class TestServer {
 
     _ensureDataDirectory()
     {
-
         let backupPath = path.resolve(this._dataDirectory, '../original-data');
         if (fs.existsSync(this._dataDirectory)) {
             assert.ok(!fs.existsSync(backupPath), `Both ${this._dataDirectory} and ${backupPath} exist. Cannot make a backup of data`);
-            fs.rename(this._dataDirectory, backupPath);
+            fs.renameSync(this._dataDirectory, backupPath);
             this._backupDataPath = backupPath;
-        } else {
-            if (fs.existsSync(backupPath)) // Assume this is a backup from the last failed run
-                this._backupDataPath = backupPath;
-            fs.mkdirSync(this._dataDirectory, 0o755);
-        }
+        } else if (fs.existsSync(backupPath)) // Assume this is a backup from the last failed run
+            this._backupDataPath = backupPath;
+        fs.mkdirSync(this._dataDirectory, 0o755);
     }
 
     _restoreDataDirectory()
@@ -106,6 +103,13 @@ let TestServer = (new class TestServer {
             fs.rename(this._backupDataPath, this._dataDirectory);
     }
 
+    cleanDataDirectory()
+    {
+        let fileList = fs.readdirSync(this._dataDirectory);
+        for (let filename of fileList)
+            fs.unlinkSync(path.resolve(this._dataDirectory, filename));
+    }
+
     _ensureTestDatabase()
     {
         this._executePgsqlCommand('dropdb');
@@ -206,23 +210,28 @@ let TestServer = (new class TestServer {
         }
         resolve();
     }
-});
 
-
-before(function () {
-    this.timeout(5000);
-    return TestServer.start();
-});
-
-beforeEach(function () {
-    this.timeout(5000);
-    return TestServer.initDatabase();
+    inject()
+    {
+        let self = this;
+        before(function () {
+            this.timeout(5000);
+            return self.start();
+        });
+
+        beforeEach(function () {
+            this.timeout(10000);
+            self.initDatabase();
+            self.cleanDataDirectory();
+        });
+
+        after(function () {
+            this.timeout(5000);
+            return self.stop();
+        });
+    }
 });
 
-after(function () {
-    this.timeout(5000);
-    return TestServer.stop();
-});
 
 if (typeof module != 'undefined')
     module.exports = TestServer;
diff --git a/Websites/perf.webkit.org/tests/admin-regenerate-manifest.js b/Websites/perf.webkit.org/tests/admin-regenerate-manifest.js
deleted file mode 100644 (file)
index a40bad2..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-describe("/admin/regenerate-manifest", function () {
-
-    it("should generate an empty manifest when database is empty", function () {
-        httpGet('/admin/regenerate-manifest', function (response) {
-            assert.equal(response.statusCode, 200);
-            httpGet('/data/manifest', function (response) {
-                assert.equal(response.statusCode, 200);
-                var manifest = JSON.parse(response.responseText);
-                delete manifest.defaultDashboard;
-                delete manifest.dashboards;
-                delete manifest.elapsedTime;
-                delete manifest.siteTitle;
-                assert.deepEqual(manifest, {
-                    all: {},
-                    bugTrackers: {},
-                    builders: {},
-                    dashboard: {},
-                    metrics: {},
-                    repositories: {},
-                    tests: {}});
-                notifyDone();
-            });
-        });
-    });
-
-    it("should generate manifest with bug trackers without repositories", function () {
-        queryAndFetchAll("INSERT INTO bug_trackers (tracker_id, tracker_name, tracker_new_bug_url) VALUES"
-            + " (1, 'Bugzilla', 'bugs.webkit.org')", [], function () {
-            httpGet('/admin/regenerate-manifest', function (response) {
-                assert.equal(response.statusCode, 200);
-                httpGet('/data/manifest', function (response) {
-                    assert.equal(response.statusCode, 200);
-                    var manifest = JSON.parse(response.responseText);
-                    assert.deepEqual(manifest['bugTrackers'],
-                        {1: {name: 'Bugzilla', bugUrl: null, newBugUrl: 'bugs.webkit.org', repositories: null}});
-                    notifyDone();
-                });
-            });
-        });
-    });
-
-    it("should generate manifest with bug trackers and repositories", function () {
-        queryAndFetchAll("INSERT INTO repositories (repository_id, repository_name, repository_url, repository_blame_url) VALUES"
-            + " (1, 'WebKit', 'trac.webkit.org', null), (2, 'Chromium', null, 'SomeBlameURL')", [], function () {
-            queryAndFetchAll("INSERT INTO bug_trackers (tracker_id, tracker_name) VALUES (3, 'Bugzilla'), (4, 'Issue Tracker')", [], function () {
-                queryAndFetchAll("INSERT INTO tracker_repositories (tracrepo_tracker, tracrepo_repository) VALUES (3, 1), (4, 1), (4, 2)", [], function () {
-                    httpGet('/admin/regenerate-manifest', function (response) {
-                        assert.equal(response.statusCode, 200);
-                        httpGet('/data/manifest', function (response) {
-                            assert.equal(response.statusCode, 200);
-                            var manifest = JSON.parse(response.responseText);
-                            assert.deepEqual(manifest['repositories'], {
-                                1: { name: 'WebKit', url: 'trac.webkit.org', blameUrl: null, hasReportedCommits: false },
-                                2: { name: 'Chromium', url: null, blameUrl: 'SomeBlameURL', hasReportedCommits: false }
-                            });
-                            assert.deepEqual(manifest['bugTrackers'][3], {name: 'Bugzilla', bugUrl: null, newBugUrl: null, repositories: ['1']});
-                            assert.deepEqual(manifest['bugTrackers'][4], {name: 'Issue Tracker', bugUrl: null, newBugUrl: null, repositories: ['1', '2']});
-                            notifyDone();
-                        });
-                    });
-                });
-            });
-        });
-    });
-
-    it("should generate manifest with builders", function () {
-        queryAndFetchAll("INSERT INTO builders (builder_id, builder_name, builder_password_hash, builder_build_url) VALUES"
-            + " (1, 'SomeBuilder', 'a', null), (2, 'SomeOtherBuilder', 'b', 'SomeURL')", [], function () {
-            httpGet('/admin/regenerate-manifest', function (response) {
-                assert.equal(response.statusCode, 200);
-                httpGet('/data/manifest', function (response) {
-                    assert.equal(response.statusCode, 200);
-                    var manifest = JSON.parse(response.responseText);
-                    assert.deepEqual(manifest['builders'], {
-                        '1': { name: 'SomeBuilder', buildUrl: null },
-                        '2': { name: 'SomeOtherBuilder', buildUrl: 'SomeURL' }
-                    });
-                    notifyDone();
-                });
-            });
-        });
-    });
-
-    it("should generate manifest with tests", function () {
-        queryAndFetchAll("INSERT INTO tests (test_id, test_name, test_parent) VALUES"
-            + " (1, 'SomeTest', null), (2, 'SomeOtherTest', null),  (3, 'ChildTest', 1)", [], function () {
-            httpGet('/admin/regenerate-manifest', function (response) {
-                assert.equal(response.statusCode, 200);
-                httpGet('/data/manifest', function (response) {
-                    assert.equal(response.statusCode, 200);
-                    var manifest = JSON.parse(response.responseText);
-                    assert.deepEqual(manifest['tests'], {
-                        '1': { name: 'SomeTest', url: null, parentId: null },
-                        '2': { name: 'SomeOtherTest', url: null, parentId: null },
-                        '3': { name: 'ChildTest', url: null, parentId: '1' }
-                    });
-                    notifyDone();
-                });
-            });
-        });
-    });
-
-    it("should generate manifest with metrics", function () {
-        queryAndFetchAll("INSERT INTO tests (test_id, test_name, test_parent) VALUES"
-            + " (1, 'SomeTest', null), (2, 'SomeOtherTest', null),  (3, 'ChildTest', 1)", [], function () {
-            queryAndFetchAll('INSERT INTO aggregators (aggregator_id, aggregator_name, aggregator_definition) values (4, $1, $2)',
-                ['Total', 'values.reduce(function (a, b) { return a + b; })'], function () {
-                queryAndFetchAll("INSERT INTO test_metrics (metric_id, metric_test, metric_name, metric_aggregator) VALUES"
-                    + " (5, 1, 'Time', null), (6, 2, 'Time', 4), (7, 2, 'Malloc', 4)", [], function () {
-                    httpGet('/admin/regenerate-manifest', function (response) {
-                        assert.equal(response.statusCode, 200);
-                        httpGet('/data/manifest', function (response) {
-                            assert.equal(response.statusCode, 200);
-                            var manifest = JSON.parse(response.responseText);
-                            assert.deepEqual(manifest['metrics'], {
-                                '5': { name: 'Time', test: '1', aggregator: null },
-                                '6': { name: 'Time', test: '2', aggregator: 'Total' },
-                                '7': { name: 'Malloc', test: '2', aggregator: 'Total' }
-                            });
-                            notifyDone();
-                        });
-                    });
-                });
-            });
-        });
-    });
-
-    // FIXME: Test the generation of all and dashboard.
-});
index 67b60f9..6fb63ad 100644 (file)
@@ -79,13 +79,18 @@ class Database {
 }
 
 let tableToPrefixMap = {
+    'aggregators': 'aggregator',
     'analysis_tasks': 'task',
     'analysis_test_groups': 'testgroup',
+    'bug_trackers': 'tracker',
     'build_triggerables': 'triggerable',
     'build_requests': 'request',
+    'builders': 'builder',
     'commits': 'commit',
+    'test_configurations': 'config',
     'test_metrics': 'metric',
     'tests': 'test',
+    'tracker_repositories': 'tracrepo',
     'platforms': 'platform',
     'repositories': 'repository',
     'root_sets': 'rootset',
index 4781cc9..a438414 100644 (file)
@@ -10,10 +10,12 @@ importFromV3('models/data-model.js', 'DataModelObject');
 importFromV3('models/data-model.js', 'LabeledObject');
 
 importFromV3('models/analysis-task.js', 'AnalysisTask');
+importFromV3('models/bug-tracker.js', 'BugTracker');
 importFromV3('models/build-request.js', 'BuildRequest');
 importFromV3('models/builder.js', 'Build');
 importFromV3('models/builder.js', 'Builder');
 importFromV3('models/commit-log.js', 'CommitLog');
+importFromV3('models/manifest.js', 'Manifest');
 importFromV3('models/measurement-adaptor.js', 'MeasurementAdaptor');
 importFromV3('models/measurement-cluster.js', 'MeasurementCluster');
 importFromV3('models/measurement-set.js', 'MeasurementSet');