Changeset 215203 in webkit
- Timestamp:
- Apr 10, 2017 2:43:11 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 1 deleted
- 36 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/ChangeLog
r215202 r215203 1 2017-04-10 Ryosuke Niwa <rniwa@webkit.org>2 3 Add the UI for scheduling a A/B testing with a custom root4 https://bugs.webkit.org/show_bug.cgi?id=1706225 6 Reviewed by Anders Carlsson.7 8 This patch adds the support for creating a new analysis task with a custom darwinup roots. A follow up patch9 would update the syncing script to schedule such an A/B testing job to a buildbot instance.10 11 12 * ReadMe.md: Updated instructions for backing up and restoring the database so that it's easier to replace13 the file path for the backup.14 15 * init-database.sql: Make task_platform and task_metric optional in each analysis task. Also added a column16 to store the root file in commit_set_relationships.17 18 * public/api/build-requests.php:19 (main): Include the uploaded files.20 21 * public/api/commits.php:22 (main): Added the support for querying the latest commits for a given platform. This is used in a new page23 to create a custom analysis task to autofill the latest revisions for a given platform.24 25 * public/api/test-groups.php:26 (main): Include the uploaded files.27 28 * public/include/build-requests-fetcher.php:29 (BuildRequestsFetcher::__construct): Added a list of uploaded_files and a map from its id.30 (BuildRequestsFetcher::uploaded_files): Added.31 (BuildRequestsFetcher::fetch_commits_for_set_if_needed): Added the support for including custom roots' id in32 each commit set, and inserting its meta data in the list of uplaoded files.33 34 * public/include/commit-log-fetcher.php:35 (CommitLogFetcher::fetch_latest_for_platform): Added. Finds the latest commit for a given platform. Ideally,36 we should be finding the latest commit for a given platform, but this is very slow so instead find the commit37 of the latest build for a given platform.38 39 * public/privileged-api/create-test-group.php:40 (main): Added the support for creating an analysis task along with a group.41 (commit_sets_from_revision_sets): Added the support for custom roots. Verify the specified uploaded file exists42 and include it in commit_set_relationships. Because commits and upload files are stored in a different column43 in commit_set_relationships, this function now stores the information for each row of commit_set_relationships44 except the commit set ID, which is unknown until the set is created, instead of a commit ID.45 (ensure_commit_sets): Made the each entry in a commit set a row instead of a commit ID as done. As this format46 is only by v2 UI and detect-changes.js, we don't add the support for specifying custom roots here.47 48 * public/privileged-api/upload-file.php:49 (main): Fixed a typo. Also added one more error check.50 51 * public/v3/components/custom-analysis-task-configurator.js: Added. The UI for selecting a test, a platform,52 and a set of revisions, as well as custom roots for a custom A/B testing job. The first set of revision with53 custom roots is referred as "baseline", and the second configuration is referred as "comparison" in this class.54 (CustomAnalysisTaskConfigurator):55 (CustomAnalysisTaskConfigurator.prototype.tests): Added.56 (CustomAnalysisTaskConfigurator.prototype.platform): Added.57 (CustomAnalysisTaskConfigurator.prototype.commitSets): Added. Returns a pair of baseline and comparsion if both58 have been configured by the user.59 (CustomAnalysisTaskConfigurator.prototype.didConstructShadowTree): Added.60 (CustomAnalysisTaskConfigurator.prototype._configureComparison): Added. Called when the user is to configu the61 "comparison" configuration.62 (CustomAnalysisTaskConfigurator.prototype.render): Added.63 (CustomAnalysisTaskConfigurator.prototype._renderTriggerableTests): Added. Renders the list of top-level tests64 that can be scheduled by a triggerable.65 (CustomAnalysisTaskConfigurator.prototype._renderTriggerablePlatforms): Added. Renders the list of platforms66 that can be schedule with the currently selected list of tests by a triggerable. Note that the current UI only67 lets the user select a single test but the intent is to allow multiple tests to be selected in the near future.68 (CustomAnalysisTaskConfigurator.prototype._buildCheckboxList): Added. Creates a list of radio boxes to select69 an item with a callback for each. It automatically sets "selected" class on the selected item. It's used to70 render both the list of tests and platforms.71 (CustomAnalysisTaskConfigurator.prototype._updateTriggerable): Added. Finds the triggerable for a given list of72 tests and platforms. Returns an error when some tests belong to another triggearalbe.73 (CustomAnalysisTaskConfigurator.prototype._updateRepositoryGroups): Added. Finds a repository group to use when74 the current triggerable has changed. We try to use the repository group of the same name if there is any, and75 defaults to the first repository group if there is none. This allows the set of repositories to be specified to76 more or less persist across different triggerables. For example, if iOS platforms and Mac platforms use two77 distinct triggerables , and both triggerables have two repository groups: one that only specify the OS and the78 other that specifies both teh OS and WebKit revision, then this code allows the choice the user had made to79 specify either just the OS or the OS and WebKit will be preserved when the user switches from an iOS platform80 to a Mac platform.81 (CustomAnalysisTaskConfigurator.prototype._updateCommitSetMap): Added. Create a commit set map, the format that82 TestGroup.createWithTask accepts given "baseline" and "comparison" commit sets. Pretend "comparison" is not set83 if two sets are identical since it makes no sense to schedule an A/B testing job when A and B are identical.84 (CustomAnalysisTaskConfigurator.prototype._computeCommitSet): Added. Creates a commit set using the revisions85 and the csutom roots the user had specified.86 (CustomAnalysisTaskConfigurator.prototype._renderRepositoryPanes): Added. Renders the pane to specify revisions87 and custom roots for "baseline" and "comparison".88 (CustomAnalysisTaskConfigurator.prototype._renderBaselineRevisionTable): Added.89 (CustomAnalysisTaskConfigurator.prototype._renderComparisonRevisionTable): Added.90 (CustomAnalysisTaskConfigurator.prototype._optionalRepositoryList): Added.91 (CustomAnalysisTaskConfigurator.prototype._buildRevisionTable): Added. Creates a table for specifying revisions92 and custom roots along with a list of repository groups to pick. The set of repositories and custom roots are93 shown at the all if all repository groups require them. Otherwise, they are grouped at the bottom as optional.94 (CustomAnalysisTaskConfigurator.prototype._buildRepositoryGroupList): Added.95 (CustomAnalysisTaskConfigurator.prototype._selectRepositoryGroup): Added.96 (CustomAnalysisTaskConfigurator.prototype._buildRevisionInput): Added. Creates an input element to specify97 a revision for a given repository. Autofills it with the latest commit for the currently selected platform if98 the user had not modified the field by the time the revisions are fetched.99 (CustomAnalysisTaskConfigurator.htmlTemplate): Added.100 (CustomAnalysisTaskConfigurator.cssTemplate): Added.101 102 * public/v3/components/instant-file-uploader.js: Added. A form to upload a custom darwinup root in "baseline"103 or "comparison" configurations of CustomAnalysisTaskConfigurator. It's "instant" because it auto-detects when a104 file to be uploaded had already been uploaded elsewhere by checking its SHA-256 hash.105 (InstantFileUploader):106 (InstantFileUploader.prototype.hasFileToUpload): Added.107 (InstantFileUploader.prototype.uploadedFiles): Added.108 (InstantFileUploader.prototype.addUploadedFile): Added. It's called on the uploader for "comparison"109 configuration when the uploader for "baseline" configuration dipsatches "uploadedFile" action to automatically110 mirror the newly uploaded custom root to "comparision" configuration.111 (InstantFileUploader.prototype.didConstructShadowTree): Added.112 (InstantFileUploader.prototype.render): Added.113 (InstantFileUploader.prototype._renderUploadedFiles): Added. Renders the list of the uploaded files.114 (InstantFileUploader.prototype._renderPreuploadFiles): Added. Renders the list of the files to be uploaded with115 a progress bar.116 (InstantFileUploader.prototype._updateUploadStatus): Added. Updates the progress bar for uploading the file.117 (InstantFileUploader.prototype._formatUploadError): Added.118 (InstantFileUploader.prototype._didFileInputChange): Added. Called when the user picks a file to uploaded on119 the input element. Fetch the meta data for the uploaded file with the same SHA-256 hash if there is any, and120 start uploading the file if there isn't one.121 (InstantFileUploader.prototype._removeUploadedFile): Added.122 (InstantFileUploader.prototype._didUploadFile): Added. Move a file from the list of files to be uploaded to123 the list of uploaded files.124 (InstantFileUploader.htmlTemplate): Added.125 (InstantFileUploader.cssTemplate): Added.126 127 * public/v3/index.html:128 129 * public/v3/models/analysis-task.js:130 (AnalysisTask): Made platform and metric optional as it is now.131 (AnalysisTask.findByPlatformAndMetric): Skip analysis tasks without a platform or a metric.132 (AnalysisTask.prototype.isCustom): Added. Returns true for a custom analysis task.133 (AnalysisTask.fetchRelatedTasks): Skip custom analysis tasks.134 (AnalysisTask._constructAnalysisTasksFromRawData): Construct analysis tasks even if they were missing a metric135 or a platform instead of silently skipping them.136 137 * public/v3/models/build-request.js:138 (BuildRequest.constructBuildRequestsFromData): Construct uploaded file objects returned by /api/build-requests.139 140 * public/v3/models/commit-log.js:141 (CommitLog.fetchLatestCommitForPlatform): Added.142 143 * public/v3/models/commit-set.js:144 (CommitSet): Added this._customRoots.145 (CommitSet.prototype.customRoots): Returns this._customRoots.146 (CommitSet.prototype.equals): Returns false when the set of custom roots are not equal.147 (CommitSet.areCustomRootsEqual): Added.148 (CustomCommitSet):149 (CustomCommitSet.prototype.equals): Added.150 (CustomCommitSet.prototype.customRoots): Added.151 (CustomCommitSet.prototype.addCustomRoot): Added.152 153 * public/v3/models/manifest.js:154 (Manifest._didFetchManifest): Store fileUploadSizeLimit in the manifest as UploadedFile.fileUploadSizeLimit.155 This allows a file size check in the client size instead of uploading it to the server and receiving an error.156 157 * public/v3/models/metric.js:158 (Metric.formatTime): Moved from ChartPaneStatusView to be also used by InstantFileUploader._renderUploadedFiles.159 160 * public/v3/models/test-group.js:161 (TestGroup.prototype.createWithTask): Added.162 (TestGroup.prototype.createAndRefetchTestGroups):163 (TestGroup.prototype._revisionSetsFromCommitSets): Added. Extracted from createAndRefetchTestGroups.164 (TestGroup.prototype._fetchTestGroupsForTask): Added. Extracted from createAndRefetchTestGroups.165 166 * public/v3/models/triggerable.js:167 (Triggerable.triggerablePlatformsForTests): Added.168 (Triggerable.sortByNamePreferringSmallerRepositories): Added.169 170 * public/v3/models/uploaded-file.js:171 (UploadedFile.prototype.createdAt): Added.172 (UploadedFile.prototype.filename): Added.173 (UploadedFile.prototype.author): Added.174 (UploadedFile.prototype.size): Added.175 (UploadedFile.uploadFile): Added a client-side check for the file size using UploadedFile.fileUploadSizeLimit.176 (UploadedFile.fetchUnloadedFileWithIdenticalHash): Ditto. Also fixed a bug that 404 was resulting in a rejected177 promise instead of a resolved promise with null.178 179 * public/v3/pages/analysis-category-page.js:180 (AnalysisCategoryPage.prototype._reconstructTaskList): Modernized the code. Added the support for platform and181 metric being null for some analysis tasks.182 183 * public/v3/pages/analysis-task-page.js:184 (AnalysisTaskPage.prototype._didFetchTask): Don't fetch the measurement set or create a chart for custom tasks.185 (AnalysisTaskPage.prototype.render): Don't display the charts or the stacking table for custom tasks.186 (AnalysisTaskPage.prototype._renderTaskNameAndStatus): Don't try to show the full test name for custom tasks187 since it's not associated with exactly one pair.188 189 * public/v3/pages/chart-pane-status-view.js:190 (ChartPaneStatusView.prototype._renderBuildRevisionTable):191 (ChartPaneStatusView.prototype._formatTime): Moved to Metric.formatTime.192 193 * public/v3/pages/chart-pane.js:194 (ChartPane.prototype._analyzeRange): Set inProgress to true to hide CustomAnalysisTaskConfigurator in195 CreateAnalysisTaskPage when creating a non-custom analysis task for a specific range.196 197 * public/v3/pages/create-analysis-task-page.js:198 (CreateAnalysisTaskPage): This page now shows CustomAnalysisTaskConfigurator by default, and lets a user create199 a custom analysis task by picking a test, a platform, and a set of revisions and custom darwinup roots.200 (CreateAnalysisTaskPage.prototype.updateFromSerializedState): Show a message when inProgress is set. This is201 the old behavior of this page.202 (CreateAnalysisTaskPage.prototype.didConstructShadowTree): Added.203 (CreateAnalysisTaskPage.prototype._createAnalysisTaskWithGroup): Added.204 (CreateAnalysisTaskPage.prototype.render):205 (CreateAnalysisTaskPage.prototype._renderMessage): Added. Hides CustomAnalysisTaskConfigurator and the select206 element to specify the numebr of iterations when a message is set.207 (CreateAnalysisTaskPage.htmlTemplate):208 (CreateAnalysisTaskPage.cssTemplate):209 210 * public/v3/pages/page-router.js:211 (PageRouter.prototype.route): Always enqueue the page to re-render when the route has changed.212 213 * server-tests/api-build-requests-tests.js: Updated test cases now that the response contains a list of214 uploaded files associated with build requests.215 *server-tests/api-commits-tests.js: Added a test case for /api/commits/<repository-name>/latest?platform=X.216 * server-tests/privileged-api-create-test-group-tests.js: Added test cases for creating a custom analysis task217 and a test group with custom roots.218 * server-tests/resources/mock-data.js:219 (MockData.addMockData): Updated the mock data to satisfy new constraint on analysis-tasks table. Also inserted220 more commits, builds, and build_commits rows for testing /api/commits/<repository-name>/latest?platform=X.221 222 * tools/js/remote.js: Include global.FormData from form-data.js.223 224 * unit-tests/analysis-task-tests.js: Added a test for calling findByPlatformAndMetric when there is a custom225 analysis task.226 (sampleAnalysisTask): Removed the category since /api/analysis-tasks/ no longer generate this property.227 (sampleCustomAnalysisTask): Added.228 * unit-tests/build-request-tests.js:229 (sampleBuildRequestData): Updated the mock response. Added a test case for fetcing custom roots.230 * unit-tests/buildbot-syncer-tests.js:231 (createSampleBuildRequest): Ditto.232 * unit-tests/test-groups-tests.js:233 (sampleTestGroup): Ditto.234 235 1 2017-04-08 Ting-Wei Lan <lantw44@gmail.com> 236 2 -
trunk/Websites/perf.webkit.org/ChangeLog
r215202 r215203 1 2017-04-10 Commit Queue <commit-queue@webkit.org> 2 3 Unreviewed, rolling out r215202. 4 https://bugs.webkit.org/show_bug.cgi?id=170694 5 6 Committed incorrectly (Requested by rniwa on #webkit). 7 8 Reverted changeset: 9 10 "Add the UI for scheduling a A/B testing with a custom root" 11 https://bugs.webkit.org/show_bug.cgi?id=170622 12 http://trac.webkit.org/changeset/215202 13 1 14 2017-04-10 Ryosuke Niwa <rniwa@webkit.org> 2 15 -
trunk/Websites/perf.webkit.org/ReadMe.md
r215202 r215203 72 72 Use `pg_dump` and `pg_restore` to backup and restore the database. If you're replicating the production database for development purposes, you may consider excluding `run_iterations` table, which takes up 2/3 of the storage space, to reduce the size of the database for your local copy. Adjust the number of concurrent processes to use by `--jobs` and adjust the compression level by `--compress` (0 is no compression, 9 is most compressed). 73 73 74 - Making the fullbackup of the database: `/Applications/Server.app/Contents/ServerRoot/usr/bin/pg_dump -h localhost webkit-perf-db --format=directory -- jobs=4 --no-owner --compress=7 --file=<path to backup directory>`75 76 - Making an abridged backup without `run_iterations` table: `/Applications/Server.app/Contents/ServerRoot/usr/bin/pg_dump -h localhost webkit-perf-db --format=directory -- jobs=4 --no-owner --compress=7 --exclude-table=run_iterations --file=<path to backup directory>`77 78 - Restoring the database: `/Applications/Server.app/Contents/ServerRoot/usr/bin/pg_restore --format=directory --jobs=4 --no-owner --host localhost --username=webkit-perf-db-user --dbname=webkit-perf-db <path to backup directory>`74 - Making the fullbackup of the database: `/Applications/Server.app/Contents/ServerRoot/usr/bin/pg_dump -h localhost webkit-perf-db --format=directory --file=<path to backup directory> --jobs=4 --no-owner --compress=7` 75 76 - Making an abridged backup without `run_iterations` table: `/Applications/Server.app/Contents/ServerRoot/usr/bin/pg_dump -h localhost webkit-perf-db --format=directory --file=<path to backup directory> --jobs=4 --no-owner --compress=7 --exclude-table=run_iterations` 77 78 - Restoring the database: `/Applications/Server.app/Contents/ServerRoot/usr/bin/pg_restore --format=directory --jobs=4 --no-owner --host localhost --username=webkit-perf-db-user <path to backup directory> --dbname=webkit-perf-db` 79 79 80 80 ## Configuring Apache … … 89 89 ### Instructions if you're not using Server.app 90 90 91 - Edit `/private/etc/apache2/httpd.conf`91 - Edit /private/etc/apache2/httpd.conf 92 92 93 93 1. Change DocumentRoot to `/Volumes/Data/perf.webkit.org/public/` -
trunk/Websites/perf.webkit.org/init-database.sql
r215202 r215203 205 205 task_test_range integer REFERENCES analysis_strategies, 206 206 task_created_at timestamp NOT NULL DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC'), 207 task_platform integer REFERENCES platforms ,208 task_metric integer REFERENCES test_metrics ,207 task_platform integer REFERENCES platforms NOT NULL, 208 task_metric integer REFERENCES test_metrics NOT NULL, 209 209 task_start_run integer REFERENCES test_runs, 210 210 task_start_run_time timestamp, … … 214 214 task_needed boolean, 215 215 CONSTRAINT analysis_task_should_be_unique_for_range UNIQUE(task_start_run, task_end_run), 216 CONSTRAINT analysis_task_must_be_associated_with_run_or_be_custom 217 CHECK ((task_start_run IS NULL AND task_start_run_time IS NULL 218 AND task_end_run IS NULL AND task_end_run_time IS NULL 219 AND task_platform IS NULL AND task_metric IS NULL) 220 OR (task_start_run IS NOT NULL AND task_start_run_time IS NOT NULL 221 AND task_end_run IS NOT NULL AND task_end_run_time IS NOT NULL 222 AND task_platform IS NOT NULL AND task_metric IS NOT NULL))); 216 CONSTRAINT analysis_task_should_not_be_associated_with_single_run 217 CHECK ((task_start_run IS NULL AND task_end_run IS NULL) OR (task_start_run IS NOT NULL AND task_end_run IS NOT NULL))); 223 218 224 219 CREATE TABLE task_commits ( … … 286 281 CREATE TABLE commit_set_relationships ( 287 282 commitset_set integer REFERENCES commit_sets NOT NULL, 288 commitset_commit integer REFERENCES commits, 289 commitset_root_file integer REFERENCES uploaded_files, 290 CONSTRAINT commitset_must_have_commit_or_root CHECK (commitset_commit IS NOT NULL OR commitset_root_file IS NOT NULL)); 283 commitset_commit integer REFERENCES commits NOT NULL); 291 284 292 285 CREATE TYPE build_request_status_type as ENUM ('pending', 'scheduled', 'running', 'failed', 'completed', 'canceled'); -
trunk/Websites/perf.webkit.org/public/api/build-requests.php
r215202 r215203 36 36 'commitSets' => $requests_fetcher->commit_sets(), 37 37 'commits' => $requests_fetcher->commits(), 38 'uploadedFiles' => $requests_fetcher->uploaded_files(),39 38 )); 40 39 } -
trunk/Websites/perf.webkit.org/public/api/commits.php
r215202 r215203 31 31 $commits = $fetcher->fetch_oldest($repository_id); 32 32 } else if ($filter == 'latest') { 33 $platform_id = array_get($_GET, 'platform'); 34 if ($platform_id) { 35 if (!is_numeric($platform_id)) 36 exit_with_error('InvalidPlatform', array('platform' => $platform_id)); 37 $platform_id = intval($platform_id); 38 $commits = $fetcher->fetch_latest_for_platform($repository_id, $platform_id); 39 } else 40 $commits = $fetcher->fetch_latest($repository_id); 33 $commits = $fetcher->fetch_latest($repository_id); 41 34 } else if ($filter == 'last-reported') { 42 35 $from = array_get($_GET, 'from'); -
trunk/Websites/perf.webkit.org/public/api/test-groups.php
r215202 r215203 56 56 'buildRequests' => $build_requests, 57 57 'commitSets' => $build_requests_fetcher->commit_sets(), 58 'commits' => $build_requests_fetcher->commits(), 59 'uploadedFiles' => $build_requests_fetcher->uploaded_files())); 58 'commits' => $build_requests_fetcher->commits())); 60 59 } 61 60 -
trunk/Websites/perf.webkit.org/public/include/build-requests-fetcher.php
r215202 r215203 2 2 3 3 require_once('test-path-resolver.php'); 4 require_once('uploaded-file-helpers.php');5 4 6 5 class BuildRequestsFetcher { … … 12 11 $this->commits = array(); 13 12 $this->commit_sets_by_id = array(); 14 $this->uploaded_files = array();15 $this->uploaded_files_by_id = array();16 13 } 17 14 … … 87 84 } 88 85 89 function commit_sets() { return $this->commit_sets; } 90 function commits() { return $this->commits; } 91 function uploaded_files() { return $this->uploaded_files; } 86 function commit_sets() { 87 return $this->commit_sets; 88 } 89 90 function commits() { 91 return $this->commits; 92 } 92 93 93 94 private function fetch_commits_for_set_if_needed($commit_set_id, $resolve_ids) { … … 96 97 97 98 $commit_rows = $this->db->query_and_fetch_all('SELECT * 98 FROM commit_set_relationships LEFT OUTER JOIN commits ON commitset_commit = commit_id 99 LEFT OUTER JOIN repositories ON repository_id = commit_repository 100 WHERE commitset_set = $1', array($commit_set_id)); 99 FROM commit_set_relationships, commits LEFT OUTER JOIN repositories ON commit_repository = repository_id 100 WHERE commitset_commit = commit_id AND commitset_set = $1', array($commit_set_id)); 101 101 102 102 $commit_ids = array(); 103 $custom_roots = array();104 105 103 foreach ($commit_rows as $row) { 106 104 $repository_id = $resolve_ids ? $row['repository_name'] : $row['repository_id']; 107 105 $revision = $row['commit_revision']; 108 106 $commit_time = $row['commit_time']; 109 110 $root_file_id = $row['commitset_root_file'];111 if ($root_file_id) {112 if (!array_key_exists($root_file_id, $this->uploaded_files_by_id)) {113 $uploaded_file_row = $this->db->select_first_row('uploaded_files', 'file', array('id' => $root_file_id));114 array_push($this->uploaded_files, format_uploaded_file($uploaded_file_row));115 }116 array_push($custom_roots, $root_file_id);117 continue;118 }119 120 107 array_push($commit_ids, $row['commit_id']); 121 108 … … 135 122 $this->commit_sets_by_id[$commit_set_id] = TRUE; 136 123 137 array_push($this->commit_sets, array('id' => $commit_set_id, 'commits' => $commit_ids , 'customRoots' => $custom_roots));124 array_push($this->commit_sets, array('id' => $commit_set_id, 'commits' => $commit_ids)); 138 125 } 139 126 } -
trunk/Websites/perf.webkit.org/public/include/commit-log-fetcher.php
r215202 r215203 119 119 } 120 120 121 function fetch_latest_for_platform($repository_id, $platform_id)122 {123 $query_result = $this->db->query_and_fetch_all("SELECT commits.* FROM test_runs, builds, build_commits, commits124 WHERE run_build = build_id AND NOT EXISTS (SELECT * FROM build_requests WHERE request_build = build_id)125 AND run_config IN (SELECT config_id FROM test_configurations126 WHERE config_type = 'current' AND config_platform = $2 AND config_metric127 IN (SELECT metric_id FROM test_metrics, tests WHERE metric_test = test_id and test_parent IS NULL))128 AND run_build = build_id AND commit_build = build_id AND build_commit = commit_id AND commit_repository = $1129 ORDER BY build_time DESC LIMIT 1;", array($repository_id, $platform_id));130 /* This query is approximation. It finds the commit of the last build instead of the last commit.131 We would ideally run the following query but it's much slower ~70s compared to 300ms.132 SELECT commits.*, commit_build, run_id133 FROM commits, build_commits, test_runs134 WHERE commit_repository = 9 AND commit_id = build_commit AND commit_build = run_build135 AND run_config IN (SELECT config_id FROM test_configurations WHERE config_platform = 38 AND config_type = 'current')136 AND NOT EXISTS (SELECT * FROM build_requests WHERE request_build = commit_build)137 ORDER BY commit_time DESC, commit_order DESC LIMIT 1; */138 if (!$query_result)139 return array();140 return $this->format_single_commit($query_result[0]);141 }142 143 121 function fetch_last_reported($repository_id) { 144 122 return $this->format_single_commit($this->db->select_last_row('commits', 'commit', array('repository' => $repository_id, 'reported' => true), array('time', 'order'))); -
trunk/Websites/perf.webkit.org/public/privileged-api/create-test-group.php
r215202 r215203 12 12 $arguments = validate_arguments($data, array( 13 13 'name' => '/.+/', 14 'task' => 'int ?',14 'task' => 'int', 15 15 'repetitionCount' => 'int?', 16 16 )); 17 17 $name = $arguments['name']; 18 $task_id = array_get($arguments, 'task'); 19 $task_name = array_get($data, 'taskName'); 18 $task_id = $arguments['task']; 20 19 $repetition_count = $arguments['repetitionCount']; 21 $platform_id = array_get($data, 'platform');22 $test_id = array_get($data, 'test');23 20 $revision_set_list = array_get($data, 'revisionSets'); 24 21 $commit_sets_info = array_get($data, 'commitSets'); 25 22 26 if (!$task_id == !$task_name) 27 exit_with_error('InvalidTask'); 28 29 if ($task_id) 30 require_format('Task', $task_id, '/^\d+$/'); 31 if ($task_name || $platform_id || $test_id) { 32 require_format('Platform', $platform_id, '/^\d+$/'); 33 require_format('Test', $test_id, '/^\d+$/'); 34 } 35 23 require_format('Task', $task_id, '/^\d+$/'); 36 24 if (!$revision_set_list && !$commit_sets_info) 37 25 exit_with_error('InvalidCommitSets'); … … 42 30 exit_with_error('InvalidRepetitionCount', array('repetitionCount' => $repetition_count)); 43 31 44 $triggerable_id = NULL; 45 if ($task_id) { 46 $task = $db->select_first_row('analysis_tasks', 'task', array('id' => $task_id)); 47 if (!$task) 48 exit_with_error('InvalidTask', array('task' => $task_id)); 49 $triggerable = find_triggerable_for_task($db, $task_id); 50 if ($triggerable) { 51 $triggerable_id = $triggerable['id']; 52 if (!$platform_id && !$test_id) { 53 $platform_id = $triggerable['platform']; 54 $test_id = $triggerable['test']; 55 } else { 56 if ($triggerable['platform'] && $platform_id != $triggerable['platform']) 57 exit_with_error('InconsistentPlatform', array('groupPlatform' => $platform_id, 'taskPlatform' => $triggerable['platform'])); 58 if ($triggerable['test'] && $test_id != $triggerable['test']) 59 exit_with_error('InconsistentTest', array('groupTest' => $test_id, 'taskTest' => $triggerable['test'])); 60 } 61 } 62 } else if ($platform_id && $test_id) { 63 $triggerable_configuration = $db->select_first_row('triggerable_configurations', 'trigconfig', 64 array('test' => $test_id, 'platform' => $platform_id)); 65 if ($triggerable_configuration) 66 $triggerable_id = $triggerable_configuration['trigconfig_triggerable']; 67 } 68 69 if (!$triggerable_id) 70 exit_with_error('TriggerableNotFoundForTask', array('task' => $task_id, 'platform' => $platform_id, 'test' => $test_id)); 32 $task = $db->select_first_row('analysis_tasks', 'task', array('id' => $task_id)); 33 if (!$task) 34 exit_with_error('InvalidTask', array('task' => $task_id)); 35 $triggerable = find_triggerable_for_task($db, $task_id); 36 if (!$triggerable) 37 exit_with_error('TriggerableNotFoundForTask', array('task' => $task_id)); 71 38 72 39 if ($revision_set_list) 73 $commit_sets = commit_sets_from_revision_sets($db, $triggerable _id, $revision_set_list);40 $commit_sets = commit_sets_from_revision_sets($db, $triggerable['id'], $revision_set_list); 74 41 else // V2 UI compatibility 75 $commit_sets = ensure_commit_sets($db, $triggerable _id, $commit_sets_info);42 $commit_sets = ensure_commit_sets($db, $triggerable['id'], $commit_sets_info); 76 43 77 44 $db->begin_transaction(); 78 79 if ($task_name)80 $task_id = $db->insert_row('analysis_tasks', 'task', array('name' => $task_name, 'author' => $author));81 45 82 46 $configuration_list = array(); 83 47 foreach ($commit_sets as $commit_list) { 84 48 $commit_set_id = $db->insert_row('commit_sets', 'commitset', array()); 85 foreach ($commit_list['set'] as $commit_row) { 86 $commit_row['set'] = $commit_set_id; 87 $db->insert_row('commit_set_relationships', 'commitset', $commit_row, 'commit'); 88 } 49 foreach ($commit_list['set'] as $commit) 50 $db->insert_row('commit_set_relationships', 'commitset', array('set' => $commit_set_id, 'commit' => $commit), 'commit'); 89 51 array_push($configuration_list, array('commit_set' => $commit_set_id, 'repository_group' => $commit_list['repository_group'])); 90 52 } 91 53 92 54 $group_id = $db->insert_row('analysis_test_groups', 'testgroup', 93 array('task' => $task _id, 'name' => $name, 'author' => $author));55 array('task' => $task['task_id'], 'name' => $name, 'author' => $author)); 94 56 95 57 $order = 0; … … 97 59 foreach ($configuration_list as $config) { 98 60 $db->insert_row('build_requests', 'request', array( 99 'triggerable' => $triggerable _id,61 'triggerable' => $triggerable['id'], 100 62 'repository_group' => $config['repository_group'], 101 'platform' => $ platform_id,102 'test' => $t est_id,63 'platform' => $triggerable['platform'], 64 'test' => $triggerable['test'], 103 65 'group' => $group_id, 104 66 'order' => $order, … … 110 72 $db->commit_transaction(); 111 73 112 exit_with_success(array('t askId' => $task_id, 'testGroupId' => $group_id));74 exit_with_success(array('testGroupId' => $group_id)); 113 75 } 114 76 … … 126 88 $commit_set = array(); 127 89 $repository_list = array(); 90 128 91 foreach ($revision_set as $repository_id => $revision) { 129 if ($repository_id == 'customRoots') {130 $file_id_list = $revision;131 foreach ($file_id_list as $file_id) {132 if (!$db->select_first_row('uploaded_files', 'file', array('id' => $file_id)))133 exit_with_error('InvalidUploadedFile', array('file' => $file_id));134 array_push($commit_set, array('root_file' => $file_id));135 }136 continue;137 }138 92 if (!is_numeric($repository_id)) 139 93 exit_with_error('InvalidRepository', array('repository' => $repository_id)); … … 142 96 if (!$commit) 143 97 exit_with_error('RevisionNotFound', array('repository' => $repository_id, 'revision' => $revision)); 144 array_push($commit_set, array('commit' => $commit['commit_id']));98 array_push($commit_set, $commit['commit_id']); 145 99 array_push($repository_list, $repository_id); 146 100 } … … 174 128 exit_with_error('RevisionNotFound', array('repository' => $repository_name, 'revision' => $revision)); 175 129 array_set_default($commit_sets, $i, array('set' => array())); 176 array_push($commit_sets[$i]['set'], array('commit' => $commit['commit_id']));130 array_push($commit_sets[$i]['set'], $commit['commit_id']); 177 131 } 178 132 } -
trunk/Websites/perf.webkit.org/public/privileged-api/upload-file.php
r215202 r215203 11 11 { 12 12 if (array_get($_SERVER, 'CONTENT_LENGTH') && empty($_POST) && empty($_FILES)) 13 exit_with_error('FileSizeLimitExceeded ');13 exit_with_error('FileSizeLimitExceeded2'); 14 14 15 15 if (!verify_token(array_get($_POST, 'token'))) … … 22 22 if (!$input_file) 23 23 exit_with_error('NoFileSpecified'); 24 25 if ($input_file['error'] == UPLOAD_ERR_INI_SIZE || $input_file['error'] == UPLOAD_ERR_FORM_SIZE)26 exit_with_error('FileSizeLimitExceeded');27 24 28 25 if ($input_file['error'] != UPLOAD_ERR_OK) -
trunk/Websites/perf.webkit.org/public/v3/index.html
r215202 r215203 66 66 <script src="models/commit-set.js"></script> 67 67 <script src="models/triggerable.js"></script> 68 <script src="models/uploaded-file.js"></script>69 68 <script src="models/manifest.js"></script> 70 69 … … 93 92 <script src="components/analysis-task-bug-list.js"></script> 94 93 <script src="components/ratio-bar-graph.js"></script> 95 <script src="components/custom-analysis-task-configurator.js"></script>96 <script src="components/instant-file-uploader.js"></script>97 94 98 95 <script src="pages/page.js"></script> -
trunk/Websites/perf.webkit.org/public/v3/models/analysis-task.js
r215202 r215203 8 8 this._createdAt = object.createdAt; 9 9 10 console.assert( !object.platform ||object.platform instanceof Platform);10 console.assert(object.platform instanceof Platform); 11 11 this._platform = object.platform; 12 12 13 console.assert( !object.metric ||object.metric instanceof Metric);13 console.assert(object.metric instanceof Metric); 14 14 this._metric = object.metric; 15 15 … … 30 30 static findByPlatformAndMetric(platformId, metricId) 31 31 { 32 return this.all().filter((task) => { 33 const platform = task._platform; 34 const metric = task._metric; 35 return platform && metric && platform.id() == platformId && metric.id() == metricId; 36 }); 32 return this.all().filter(function (task) { return task._platform.id() == platformId && task._metric.id() == metricId; }); 37 33 } 38 34 … … 60 56 } 61 57 62 isCustom() { return !this._platform; } 63 hasResults() { return !!this._finishedBuildRequestCount; } 58 hasResults() { return this._finishedBuildRequestCount; } 64 59 hasPendingRequests() { return this._finishedBuildRequestCount < this._buildRequestCount; } 65 60 requestLabel() { return `${this._finishedBuildRequestCount} of ${this._buildRequestCount}`; } … … 207 202 } 208 203 for (var otherTask of AnalysisTask.all()) { 209 if (task.isCustom())210 continue;211 204 if (task.endTime() < otherTask.startTime() 212 205 || otherTask.endTime() < task.startTime() … … 265 258 rawData.platform = Platform.findById(rawData.platform); 266 259 rawData.metric = Metric.findById(rawData.metric); 260 if (!rawData.platform || !rawData.metric) 261 continue; 262 267 263 rawData.bugs = taskToBug[rawData.id]; 268 264 rawData.causes = resolveCommits(rawData.causes); -
trunk/Websites/perf.webkit.org/public/v3/models/build-request.js
r215202 r215203 128 128 } 129 129 130 for (let uploadedFile of data['uploadedFiles'])131 UploadedFile.ensureSingleton(uploadedFile.id, uploadedFile);132 133 130 const commitSets = data['commitSets'].map((row) => { 134 131 row.commits = row.commits.map((commitId) => commitIdMap[commitId]); -
trunk/Websites/perf.webkit.org/public/v3/models/commit-log.js
r215202 r215203 69 69 } 70 70 71 static fetchLatestCommitForPlatform(repository, platform)72 {73 console.assert(repository instanceof Repository);74 console.assert(platform instanceof Platform);75 return this.cachedFetch(`/api/commits/${repository.id()}/latest`, {platform: platform.id()}).then((data) => {76 const commits = data['commits'];77 if (!commits || !commits.length)78 return null;79 const rawData = commits[0];80 rawData.repository = repository;81 return CommitLog.ensureSingleton(rawData.id, rawData);82 });83 }84 85 71 static fetchBetweenRevisions(repository, precedingRevision, lastRevision) 86 72 { -
trunk/Websites/perf.webkit.org/public/v3/models/commit-set.js
r215202 r215203 9 9 this._repositoryToCommitMap = {}; 10 10 this._latestCommitTime = null; 11 this._customRoots = [];12 11 13 12 if (!object) … … 20 19 this._repositories.push(row.repository); 21 20 } 22 for (let fileId of object.customRoots) {23 const uploadedFile = UploadedFile.findById(fileId);24 this._customRoots.push(uploadedFile);25 }26 21 } 27 22 28 23 repositories() { return this._repositories; } 29 customRoots() { return this._customRoots; }30 24 commitForRepository(repository) { return this._repositoryToCommitMap[repository.id()]; } 31 25 … … 54 48 for (var repositoryId in this._repositoryToCommitMap) { 55 49 if (this._repositoryToCommitMap[repositoryId] != other._repositoryToCommitMap[repositoryId]) 56 return false;57 }58 return CommitSet.areCustomRootsEqual(this._customRoots, other._customRoots);59 }60 61 static areCustomRootsEqual(customRoots1, customRoots2)62 {63 if (customRoots1.length != customRoots2.length)64 return false;65 const set2 = new Set(customRoots2);66 for (let file of customRoots1) {67 if (!set2.has(file))68 50 return false; 69 51 } … … 125 107 { 126 108 this._revisionListByRepository = new Map; 127 this._customRoots = [];128 109 } 129 110 … … 134 115 } 135 116 136 equals(other)137 {138 console.assert(other instanceof CustomCommitSet);139 if (this._revisionListByRepository.size != other._revisionListByRepository.size)140 return false;141 for (let repository of this._revisionListByRepository.keys()) {142 const thisRevision = this._revisionListByRepository.get(repository);143 const otherRevision = other._revisionListByRepository.get(repository);144 if (thisRevision != otherRevision)145 return false;146 }147 return CommitSet.areCustomRootsEqual(this._customRoots, other._customRoots);148 }149 150 117 repositories() { return Array.from(this._revisionListByRepository.keys()); } 151 118 revisionForRepository(repository) { return this._revisionListByRepository.get(repository); } 152 customRoots() { return this._customRoots; }153 119 154 addCustomRoot(uploadedFile)155 {156 console.assert(uploadedFile instanceof UploadedFile);157 this._customRoots.push(uploadedFile);158 }159 120 } 160 121 -
trunk/Websites/perf.webkit.org/public/v3/models/manifest.js
r215202 r215203 58 58 }); 59 59 60 if (typeof(UploadedFile) != 'undefined')61 UploadedFile.fileUploadSizeLimit = rawResponse.fileUploadSizeLimit || 0;62 63 60 Instrumentation.endMeasuringTime('Manifest', '_didFetchManifest'); 64 61 -
trunk/Websites/perf.webkit.org/public/v3/models/metric.js
r215202 r215203 120 120 return formatter; 121 121 }; 122 123 static formatTime(utcTime)124 {125 // FIXME: This is incorrect when the offset cross day-life-saving change. It's good enough for now.126 const offsetInMinutes = (new Date(utcTime)).getTimezoneOffset();127 const timeInLocalTimeZone = new Date(utcTime - offsetInMinutes * 60 * 1000);128 return timeInLocalTimeZone.toISOString().replace('T', ' ').replace(/\.\d+Z$/, '');129 }130 122 } 131 123 -
trunk/Websites/perf.webkit.org/public/v3/models/test-group.js
r215202 r215203 179 179 } 180 180 181 static create WithTask(taskName, platform, test, groupName, repetitionCount, commitSets)181 static createAndRefetchTestGroups(task, name, repetitionCount, commitSets) 182 182 { 183 183 console.assert(commitSets.length == 2); 184 const revisionSets = this._revisionSetsFromCommitSets(commitSets); 185 const params = {taskName, name: groupName, platform: platform.id(), test: test.id(), repetitionCount, revisionSets}; 186 return PrivilegedAPI.sendRequest('create-test-group', params).then((data) => { 187 return AnalysisTask.fetchById(data['taskId']); 188 }).then((task) => { 189 return this._fetchTestGroupsForTask(task.id()).then(() => task); 190 }); 191 } 192 193 static createAndRefetchTestGroups(task, name, repetitionCount, commitSets) 194 { 195 console.assert(commitSets.length == 2); 196 const revisionSets = this._revisionSetsFromCommitSets(commitSets); 184 185 const revisionSets = commitSets.map((commitSet) => { 186 console.assert(commitSet instanceof CustomCommitSet || commitSet instanceof CommitSet); 187 const revisionSet = {}; 188 for (let repository of commitSet.repositories()) 189 revisionSet[repository.id()] = commitSet.revisionForRepository(repository); 190 return revisionSet; 191 }); 192 197 193 return PrivilegedAPI.sendRequest('create-test-group', { 198 194 task: task.id(), … … 200 196 repetitionCount: repetitionCount, 201 197 revisionSets: revisionSets, 202 }).then((data) => this._fetchTestGroupsForTask(task.id())); 203 } 204 205 static _revisionSetsFromCommitSets(commitSets) 206 { 207 return commitSets.map((commitSet) => { 208 console.assert(commitSet instanceof CustomCommitSet || commitSet instanceof CommitSet); 209 const revisionSet = {}; 210 for (let repository of commitSet.repositories()) 211 revisionSet[repository.id()] = commitSet.revisionForRepository(repository); 212 const customRoots = commitSet.customRoots(); 213 if (customRoots && customRoots.length) 214 revisionSet['customRoots'] = customRoots.map((uploadedFile) => uploadedFile.id()); 215 return revisionSet; 216 }); 217 } 218 219 static _fetchTestGroupsForTask(taskId) 220 { 221 return this.cachedFetch('/api/test-groups', {task: taskId}, true).then((data) => this._createModelsFromFetchedTestGroups(data)); 198 }).then((data) => { 199 return this.cachedFetch('/api/test-groups', {task: task.id()}, true).then((data) => this._createModelsFromFetchedTestGroups(data)); 200 }); 222 201 } 223 202 -
trunk/Websites/perf.webkit.org/public/v3/models/triggerable.js
r215202 r215203 38 38 return null; 39 39 } 40 41 static triggerablePlatformsForTests(tests)42 {43 console.assert(tests instanceof Array);44 if (!tests.length)45 return [];46 return this.sortByName(Platform.all().filter((platform) => {47 return tests.every((test) => {48 const triggerable = Triggerable.findByTestConfiguration(test, platform);49 return triggerable && !triggerable.isDisabled();50 });51 }));52 }53 40 } 54 41 … … 78 65 acceptsCustomRoots() { return this._acceptsCustomRoots; } 79 66 repositories() { return this._repositories; } 80 81 static sortByNamePreferringSmallerRepositories(groupList)82 {83 return groupList.sort((a, b) => {84 if (a.repositories().length < b.repositories().length)85 return -1;86 else if (a.repositories().length > b.repositories().length)87 return 1;88 if (a.name() < b.name())89 return -1;90 else if (a.name() > b.name())91 return 1;92 return 0;93 });94 }95 67 } 96 68 -
trunk/Websites/perf.webkit.org/public/v3/models/uploaded-file.js
r215202 r215203 13 13 } 14 14 15 createdAt() { return this._createdAt; }16 filename() { return this._filename; }17 author() { return this._author; }18 size() { return this._size; }19 20 15 static uploadFile(file, uploadProgressCallback = null) 21 16 { 22 if (file.size > UploadedFile.fileUploadSizeLimit)23 return Promise.reject('FileSizeLimitExceeded');24 17 return PrivilegedAPI.sendRequest('upload-file', {'newFile': file}, {useFormData: true, uploadProgressCallback}).then((rawData) => { 25 18 return UploadedFile.ensureSingleton(rawData['uploadedFile'].id, rawData['uploadedFile']); … … 29 22 static fetchUnloadedFileWithIdenticalHash(file) 30 23 { 31 if (file.size > UploadedFile.fileUploadSizeLimit)32 return Promise.reject('FileSizeLimitExceeded');33 24 return new Promise((resolve, reject) => { 34 25 const reader = new FileReader(); … … 42 33 if (map && sha256 in map) 43 34 return map[sha256]; 44 return RemoteAPI.getJSON (`../api/uploaded-file?sha256=${sha256}`).then((rawData) => {45 if ( rawData['status'] == 'NotFound' ||!rawData['uploadedFile'])35 return RemoteAPI.getJSONWithStatus(`../api/uploaded-file?sha256=${sha256}`).then((rawData) => { 36 if (!rawData['uploadedFile']) 46 37 return null; 47 if (rawData['status'] != 'OK')48 return Promise.reject(rawData['status']);49 38 return UploadedFile.ensureSingleton(rawData['uploadedFile'].id, rawData['uploadedFile']); 50 39 }); … … 64 53 65 54 } 66 67 UploadedFile.fileUploadSizeLimit = 0;68 69 if (typeof module != 'undefined')70 module.exports.UploadedFile = UploadedFile; -
trunk/Websites/perf.webkit.org/public/v3/pages/analysis-category-page.js
r215202 r215203 124 124 125 125 console.assert(this.router()); 126 const currentCategory = this._categoryToolbar.currentCategory(); 127 128 const tasks = AnalysisTask.all().filter((task) => task.category() == currentCategory).sort((a, b) => { 126 var currentCategory = this._categoryToolbar.currentCategory(); 127 128 var tasks = AnalysisTask.all().filter(function (task) { 129 return task.category() == currentCategory; 130 }).sort(function (a, b) { 129 131 if (a.hasPendingRequests() == b.hasPendingRequests()) 130 132 return b.createdAt() - a.createdAt(); … … 136 138 }); 137 139 138 constelement = ComponentBase.createElement;139 constlink = ComponentBase.createLink;140 constrouter = this.router();140 var element = ComponentBase.createElement; 141 var link = ComponentBase.createLink; 142 var router = this.router(); 141 143 this.renderReplace(this.content().querySelector('tbody.analysis-tasks'), 142 tasks.map( (task) =>{143 conststatus = AnalysisCategoryPage._computeStatus(task);144 tasks.map(function (task) { 145 var status = AnalysisCategoryPage._computeStatus(task); 144 146 return element('tr', [ 145 147 element('td', {class: 'status'}, … … 147 149 element('td', link(task.label(), router.url(`analysis/task/${task.id()}`))), 148 150 element('td', {class: 'bugs'}, 149 element('ul', task.bugs().map( (bug) =>{150 consturl = bug.url();151 consttitle = bug.title();151 element('ul', task.bugs().map(function (bug) { 152 var url = bug.url(); 153 var title = bug.title(); 152 154 return element('li', url ? link(bug.label(), title, url, true) : title); 153 155 }))), 154 156 element('td', {class: 'author'}, task.author()), 155 element('td', {class: 'platform'}, task.platform() ? task.platform().label() : null),156 element('td', task.metric() ? task.metric().fullName() : null),157 element('td', {class: 'platform'}, task.platform().label()), 158 element('td', task.metric().fullName()), 157 159 ]); 158 160 })); -
trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js
r215202 r215203 410 410 411 411 this._task = task; 412 const bugList = this.part('bug-list');413 this.part('bug-list').setTask(this._task);414 this.enqueueToRender();415 416 if (task.isCustom())417 return task;418 412 419 413 const platform = task.platform(); … … 433 427 chart.setMainDomain(domain[0], domain[1]); 434 428 429 const bugList = this.part('bug-list'); 430 this.part('bug-list').setTask(this._task); 431 432 this.enqueueToRender(); 433 435 434 return task; 436 435 } … … 509 508 this._renderRelatedTasksLazily.evaluate(this._task, this._relatedTasks); 510 509 511 this.content('chart-pane').style.display = this._task && !this._task.isCustom()? null : 'none';510 this.content('chart-pane').style.display = this._task ? null : 'none'; 512 511 this.part('chart-pane').setShowForm(!!this._triggerable); 513 512 514 this.content('results-pane').style.display = this._task && !this._task.isCustom()? null : 'none';513 this.content('results-pane').style.display = this._task ? null : 'none'; 515 514 this.part('results-pane').setShowForm(!!this._triggerable); 516 515 … … 521 520 { 522 521 this.part('analysis-task-name').setText(taskName); 523 if (task && !task.isCustom()) {522 if (task) { 524 523 const link = ComponentBase.createLink; 525 524 const platform = task.platform(); -
trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane-status-view.js
r215202 r215203 50 50 element('td', {colspan: 2}, [ 51 51 url ? link(buildNumber, build.label(), url, true) : buildNumber, 52 ` (${ Metric.formatTime(build.buildTime())})`52 ` (${this._formatTime(build.buildTime())})` 53 53 ]), 54 54 ])); … … 71 71 72 72 this.renderReplace(this.content('build-revision'), tableContent); 73 } 74 75 _formatTime(date) 76 { 77 console.assert(date instanceof Date); 78 return date.toISOString().replace('T', ' ').replace(/\.\d+Z$/, ''); 73 79 } 74 80 -
trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane.js
r215202 r215203 20 20 } 21 21 22 constChartTrendLineTypes = [22 var ChartTrendLineTypes = [ 23 23 { 24 24 id: 0, … … 197 197 _analyzeRange(startPoint, endPoint) 198 198 { 199 constrouter = this._chartsPage.router();200 const newWindow = window.open(router.url('analysis/task/create', {inProgress: true}), '_blank');201 202 constanalyzePopover = this.content().querySelector('.chart-pane-analyze-popover');203 constname = analyzePopover.querySelector('input').value;199 var router = this._chartsPage.router(); 200 var newWindow = window.open(router.url('analysis/task/create'), '_blank'); 201 202 var analyzePopover = this.content().querySelector('.chart-pane-analyze-popover'); 203 var name = analyzePopover.querySelector('input').value; 204 204 AnalysisTask.create(name, startPoint.id, endPoint.id).then((data) => { 205 205 newWindow.location.href = router.url('analysis/task/' + data['taskId']); 206 206 this.fetchAnalysisTasks(true); 207 }, (error) =>{207 }, function (error) { 208 208 newWindow.location.href = router.url('analysis/task/create', {error: error}); 209 209 }); … … 273 273 actions.push(this._makePopoverActionItem(analyzePopover, 'Analyze', false)); 274 274 analyzePopover.onsubmit = this.createEventHandler(() => { 275 console.log(selectedPoints.length()); 275 276 this._analyzeRange(selectedPoints.firstPoint(), selectedPoints.lastPoint()); 276 277 }); -
trunk/Websites/perf.webkit.org/public/v3/pages/create-analysis-task-page.js
r215202 r215203 4 4 { 5 5 super('Create Analysis Task'); 6 this._message = null; 7 this._renderMessageLazily = new LazilyEvaluatedFunction(this._renderMessage.bind(this)); 6 this._errorMessage = null; 8 7 } 9 8 … … 15 14 if (state.error instanceof Set) 16 15 state.error = Array.from(state.error.values())[0]; 17 this._message = state.error || (state.inProgress ? 'Creating the analysis task page...' : '');18 }19 16 20 didConstructShadowTree() 21 { 22 this.part('configurator').listenToAction('commitSetChange', () => this.enqueueToRender()); 23 this.content('start-button').onclick = this.createEventHandler(() => this._createAnalysisTaskWithGroup()); 24 } 25 26 _createAnalysisTaskWithGroup() 27 { 28 const taskNameInput = this.content('task-name'); 29 if (!taskNameInput.reportValidity()) 30 return; 31 32 const testGroupInput = this.content('test-group-name'); 33 if (!testGroupInput.reportValidity()) 34 return; 35 36 const configurator = this.part('configurator'); 37 const tests = configurator.tests(); 38 if (tests.length != 1) 39 return alert('Exactly one test must be selected'); 40 41 const taskName = taskNameInput.value; 42 const testGroupName = testGroupInput.value; 43 const iterationCount = this.content('iteration-count').value; 44 const platform = configurator.platform(); 45 const commitSets = configurator.commitSets(); 46 47 TestGroup.createWithTask(taskName, platform, tests[0], testGroupName, iterationCount, commitSets).then((task) => { 48 console.log('yay?', task); 49 const url = this.router().url(`analysis/task/${task.id()}`); 50 console.log('moving to ' + url); 51 location.href = this.router().url(`analysis/task/${task.id()}`); 52 }, (error) => { 53 alert('Failed to create a new test group: ' + error); 54 }); 17 this._errorMessage = state.error; 18 if (!isOpen) 19 this.enqueueToRender(); 55 20 } 56 21 … … 58 23 { 59 24 super.render(); 60 const configurator = this.part('configurator');61 this._renderMessageLazily.evaluate(this._message, !!configurator.commitSets(), configurator.tests(), configurator.platform());25 if (this._errorMessage) 26 this.content().querySelector('.message').textContent = this._errorMessage; 62 27 } 63 64 _renderMessage(message, hasValidCommitSets, tests, platform)65 {66 const messageContainer = this.content('message');67 messageContainer.textContent = this._message;68 messageContainer.style.display = this._message ? null : 'none';69 this.content('new-task').style.display = this._message ? 'none' : null;70 if (platform)71 this.content('test-group-name').value = `${tests.map((test) => test.name()).join(', ')} on ${platform.name()}`;72 this.content('iteration-start-pane').style.display = !this._message && hasValidCommitSets ? null : 'none';73 }74 28 75 29 static htmlTemplate() 76 30 { 77 31 return ` 78 <p id="message"></p> 79 <div id="new-task"> 80 <input id="task-name" type="text" placeholder="Name this task" required> 81 <custom-analysis-task-configurator id="configurator"></custom-analysis-task-configurator> 82 <div id="iteration-start-pane"> 83 <input id="test-group-name" placeholder="Name this test group" required> 84 <label><select id="iteration-count"> 85 <option>1</option> 86 <option>2</option> 87 <option>3</option> 88 <option selected>4</option> 89 <option>5</option> 90 <option>6</option> 91 </select> iterations per configuration</label> 92 <button id="start-button">Start</button> 93 </div> 94 </div>`; 32 <div class="create-analysis-task-container"> 33 <p class="message">Creating the analysis task page...</p> 34 </div> 35 `; 95 36 } 96 37 … … 98 39 { 99 40 return ` 100 #message{101 text-align: center;41 .create-analysis-task-container { 42 display: flex; 102 43 } 103 44 104 #new-task> * {105 display: block;106 margin: 1rem;45 .create-analysis-task-container > * { 46 margin: 1rem auto; 47 display: inline-block; 107 48 } 108 49 109 #new-task input { 110 width: 30%; 111 min-width: 10rem; 112 font-size: 1rem; 113 font-weight: inherit; 114 } 115 116 #start-button { 117 display: block; 118 margin-top: 0.5rem; 119 font-size: 1.2rem; 120 font-weight: inherit; 50 .create-analysis-task input { 51 font-size: inherit; 121 52 } 122 53 `; -
trunk/Websites/perf.webkit.org/public/v3/pages/page-router.js
r215202 r215203 53 53 } else 54 54 destinationPage.updateFromSerializedState(parsed.state, false); 55 destinationPage.enqueueToRender();56 55 57 56 return true; -
trunk/Websites/perf.webkit.org/server-tests/api-build-requests-tests.js
r215202 r215203 24 24 assert.deepEqual(content['commitSets'], []); 25 25 assert.deepEqual(content['commits'], []); 26 assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status' , 'uploadedFiles']);26 assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status']); 27 27 }); 28 28 }); … … 32 32 return TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit'); 33 33 }).then((content) => { 34 assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status' , 'uploadedFiles']);34 assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status']); 35 35 36 36 assert.equal(content['commitSets'].length, 2); … … 86 86 return TestServer.remoteAPI().getJSONWithStatus('/api/build-requests/build-webkit?useLegacyIdResolution=true'); 87 87 }).then((content) => { 88 assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status' , 'uploadedFiles']);88 assert.deepEqual(Object.keys(content).sort(), ['buildRequests', 'commitSets', 'commits', 'status']); 89 89 90 90 assert.equal(content['commitSets'].length, 2); … … 218 218 let firstWebKitCommit = firstCommitSet.commitForRepository(webkit); 219 219 assert.equal(firstWebKitCommit.revision(), '191622'); 220 assert.equal(+firstWebKitCommit.time(), +new Date('2015-10-27T11:36:56.88Z'));220 assert.equal(+firstWebKitCommit.time(), 1445945816878); 221 221 222 222 let secondWebKitCommit = secondCommitSet.commitForRepository(webkit); 223 223 assert.equal(secondWebKitCommit.revision(), '192736'); 224 assert.equal(+secondWebKitCommit.time(), +new Date('2015-11-22T20:48:45.65Z'));224 assert.equal(+secondWebKitCommit.time(), 1448225325650); 225 225 }); 226 226 }); … … 397 397 }); 398 398 }); 399 400 it('should place build requests created by user before automatically created ones', () => {401 const db = TestServer.database();402 const someSize = 24 * 1024; // hashlib.sha256('1' * 24 * 1024).hexdigest()403 const someHash = '3ffaa9e09f49d4d212582c092af2c1dcb2c9b52c8ca49c72ff99dcc5dc503a2b';404 const otherSize = 42; // hashlib.sha256('2' * 42).hexdigest()405 const otherHash = '66e378b3fb356925154435803c01afd10daebbf4a2edb583b34034aaca775a26';406 return MockData.addMockData(db).then(() => Manifest.fetch()).then(() => {407 return BuildRequest.fetchForTriggerable('build-webkit');408 }).then((buildRequests) => {409 assert.deepEqual(UploadedFile.all(), []);410 assert.equal(buildRequests.length, 4);411 const set0 = buildRequests[0].commitSet();412 const set1 = buildRequests[1].commitSet();413 assert.equal(buildRequests[2].commitSet(), set0);414 assert.equal(buildRequests[3].commitSet(), set1);415 assert.deepEqual(set0.customRoots(), []);416 assert.deepEqual(set1.customRoots(), []);417 return Promise.all([418 db.insert('uploaded_files', {id: 1, filename: 'some-file.tar.gz', extension: '.tar.gz', size: someSize, sha256: someHash}),419 db.insert('uploaded_files', {id: 2, filename: 'other-file.zip', extension: '.zip', size: otherSize, sha256: otherHash}),420 ]).then(() => {421 return db.insert('commit_set_relationships', {set: set0.id(), root_file: 1});422 });423 }).then(() => {424 CommitSet.clearStaticMap();425 BuildRequest.clearStaticMap();426 return BuildRequest.fetchForTriggerable('build-webkit');427 }).then((buildRequests) => {428 const uploadedFiles = UploadedFile.all();429 assert.equal(uploadedFiles.length, 1);430 431 const someFile = UploadedFile.findById(1);432 assert.equal(someFile.filename(), 'some-file.tar.gz');433 assert.equal(someFile.size(), someSize);434 435 assert.equal(buildRequests.length, 4);436 const set0 = buildRequests[0].commitSet();437 const set1 = buildRequests[1].commitSet();438 assert.equal(buildRequests[2].commitSet(), set0);439 assert.equal(buildRequests[3].commitSet(), set1);440 assert.deepEqual(set0.customRoots(), [someFile]);441 assert.deepEqual(set1.customRoots(), []);442 });443 });444 445 399 }); -
trunk/Websites/perf.webkit.org/server-tests/api-commits-tests.js
r215202 r215203 3 3 const assert = require('assert'); 4 4 5 const MockData = require('./resources/mock-data.js');6 5 const TestServer = require('./resources/test-server.js'); 7 6 const addSlaveForReport = require('./resources/common-operations.js').addSlaveForReport; … … 215 214 }); 216 215 217 it("should return the latest commit", () => {216 it("should return the oldest commit", () => { 218 217 const remote = TestServer.remoteAPI(); 219 218 return addSlaveForReport(subversionCommits).then(() => { … … 238 237 assert.equal(result['commits'].length, 1); 239 238 assert.equal(result['commits'][0]['revision'], systemVersionCommits['commits'][0]['revision']); 240 });241 });242 243 it("should return the latest commit for a given platform", () => {244 const mockDataCommitReports = {245 "slaveName": "someSlave",246 "slavePassword": "somePassword",247 "commits": [248 {249 "repository": "WebKit",250 "revision": "191622",251 "time": "2015-10-27T11:36:56.88Z",252 "author": {"account": "calvaris@igalia.com"},253 "message": "a message",254 },255 {256 "repository": "WebKit",257 "revision": "192736",258 "time": "2015-11-22T20:48:45.65Z",259 "author": {"account": "aestes@apple.com"},260 "message": "some message",261 },262 {263 "repository": "WebKit",264 "revision": "192903",265 "time": "2015-12-01T21:14:46.99Z",266 "author": {"account": "darin@apple.com"},267 "message": "another message",268 }269 ]270 }271 const remote = TestServer.remoteAPI();272 return MockData.addMockData(TestServer.database()).then(() => {273 return addSlaveForReport(mockDataCommitReports);274 }).then(() => {275 return remote.postJSONWithStatus('/api/report-commits/', mockDataCommitReports);276 }).then(() => {277 return remote.getJSON('/api/commits/WebKit/latest?platform=' + MockData.somePlatformId());278 }).then((result) => {279 assert.equal(result['status'], 'OK');280 assert.equal(result['commits'].length, 1);281 const commit = result['commits'][0];282 assert.equal(commit['revision'], '192736');283 assert.equal(commit['time'], +new Date('2015-11-22T20:48:45.65Z'));284 239 }); 285 240 }); -
trunk/Websites/perf.webkit.org/server-tests/privileged-api-create-test-group-tests.js
r215202 r215203 1 1 'use strict'; 2 2 3 const assert = require('assert'); 4 5 const MockData = require('./resources/mock-data.js'); 6 const TestServer = require('./resources/test-server.js'); 7 const TemporaryFile = require('./resources/temporary-file.js').TemporaryFile; 3 let assert = require('assert'); 4 5 let MockData = require('./resources/mock-data.js'); 6 let TestServer = require('./resources/test-server.js'); 8 7 const addSlaveForReport = require('./resources/common-operations.js').addSlaveForReport; 9 8 const prepareServerTest = require('./resources/common-operations.js').prepareServerTest; … … 118 117 describe('/privileged-api/create-test-group', function () { 119 118 prepareServerTest(this); 120 TemporaryFile.inject();121 119 122 120 it('should return "InvalidName" on an empty request', () => { … … 261 259 }, (error) => { 262 260 assert.equal(error, 'RevisionNotFound'); 263 });264 });265 });266 267 it('should return "InvalidUploadedFile" when revision sets contains an invalid file ID', () => {268 return addTriggerableAndCreateTask('some task').then((taskId) => {269 const webkit = Repository.all().find((repository) => repository.name() == 'WebKit');270 const revisionSets = [{[webkit.id()]: '191622', 'customRoots': ['1']}, {[webkit.id()]: '1'}];271 return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, revisionSets}).then((content) => {272 assert(false, 'should never be reached');273 }, (error) => {274 assert.equal(error, 'InvalidUploadedFile');275 261 }); 276 262 }); … … 448 434 }); 449 435 450 it('should create a test group with a custom root', () => {451 return addTriggerableAndCreateTask('some task').then((taskId) => {452 let insertedGroupId;453 const webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];454 const macos = Repository.all().filter((repository) => repository.name() == 'macOS')[0];455 let uploadedFile;456 return TemporaryFile.makeTemporaryFile('some.dat', 'some content').then((stream) => {457 return PrivilegedAPI.sendRequest('upload-file', {newFile: stream}, {useFormData: true});458 }).then((response) => {459 uploadedFile = response['uploadedFile'];460 const revisionSets = [{[webkit.id()]: '191622', [macos.id()]: '15A284'},461 {[webkit.id()]: '191622', [macos.id()]: '15A284', 'customRoots': [uploadedFile['id']]}];462 return PrivilegedAPI.sendRequest('create-test-group', {name: 'test', task: taskId, repetitionCount: 2, revisionSets}).then((content) => {463 insertedGroupId = content['testGroupId'];464 return TestGroup.fetchByTask(taskId);465 });466 }).then((testGroups) => {467 assert.equal(testGroups.length, 1);468 const group = testGroups[0];469 assert.equal(group.id(), insertedGroupId);470 assert.equal(group.repetitionCount(), 2);471 const requests = group.buildRequests();472 assert.equal(requests.length, 4);473 474 const set0 = requests[0].commitSet();475 const set1 = requests[1].commitSet();476 assert.equal(requests[2].commitSet(), set0);477 assert.equal(requests[3].commitSet(), set1);478 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set0.repositories()), [webkit, macos]);479 assert.deepEqual(set0.customRoots(), []);480 assert.deepEqual(Repository.sortByNamePreferringOnesWithURL(set1.repositories()), [webkit, macos]);481 assert.deepEqual(set1.customRoots(), [UploadedFile.ensureSingleton(uploadedFile['id'], uploadedFile)]);482 assert.equal(set0.revisionForRepository(webkit), '191622');483 assert.equal(set0.revisionForRepository(webkit), set1.revisionForRepository(webkit));484 assert.equal(set0.commitForRepository(webkit), set1.commitForRepository(webkit));485 assert.equal(set0.revisionForRepository(macos), '15A284');486 assert.equal(set0.commitForRepository(macos), set1.commitForRepository(macos));487 assert.equal(set0.revisionForRepository(macos), set1.revisionForRepository(macos));488 assert(!set0.equals(set1));489 });490 });491 });492 493 it('should create a test group with an analysis task', () => {494 let insertedGroupId;495 let webkit;496 return addTriggerableAndCreateTask('some task').then(() => {497 webkit = Repository.all().filter((repository) => repository.name() == 'WebKit')[0];498 const revisionSets = [{[webkit.id()]: '191622'}, {[webkit.id()]: '191623'}];499 return PrivilegedAPI.sendRequest('create-test-group',500 {name: 'test', taskName: 'other task', platform: MockData.somePlatformId(), test: MockData.someTestId(), revisionSets});501 }).then((result) => {502 insertedGroupId = result['testGroupId'];503 return Promise.all([AnalysisTask.fetchById(result['taskId']), TestGroup.fetchByTask(result['taskId'])]);504 }).then((result) => {505 const [analysisTask, testGroups] = result;506 507 assert.equal(analysisTask.name(), 'other task');508 509 assert.equal(testGroups.length, 1);510 const group = testGroups[0];511 assert.equal(group.id(), insertedGroupId);512 assert.equal(group.repetitionCount(), 1);513 const requests = group.buildRequests();514 assert.equal(requests.length, 2);515 516 const set0 = requests[0].commitSet();517 const set1 = requests[1].commitSet();518 assert.deepEqual(set0.repositories(), [webkit]);519 assert.deepEqual(set0.customRoots(), []);520 assert.deepEqual(set1.repositories(), [webkit]);521 assert.deepEqual(set1.customRoots(), []);522 assert.equal(set0.revisionForRepository(webkit), '191622');523 assert.equal(set1.revisionForRepository(webkit), '191623');524 });525 });526 527 436 }); -
trunk/Websites/perf.webkit.org/server-tests/resources/mock-data.js
r215202 r215203 38 38 db.insert('triggerable_repositories', {repository: this.webkitRepositoryId(), group: 2001}), 39 39 db.insert('commits', {id: 87832, repository: this.macosRepositoryId(), revision: '10.11 15A284'}), 40 db.insert('commits', {id: 93116, repository: this.webkitRepositoryId(), revision: '191622', time: '2015-10-27T11:36:56.88Z'}), 41 db.insert('commits', {id: 96336, repository: this.webkitRepositoryId(), revision: '192736', time: '2015-11-22T20:48:45.65Z'}), 42 db.insert('commits', {id: 96629, repository: this.webkitRepositoryId(), revision: '192903', time: '2015-12-01T21:14:46.99Z'}), 43 db.insert('builds', {id: 901, number: '901', time: '2015-10-27T12:05:27.1Z'}), 44 db.insert('builds', {id: 902, number: '902', time: '2015-10-27T12:06:54.2Z'}), 45 db.insert('build_commits', {commit_build: 901, build_commit: 93116}), 46 db.insert('build_commits', {commit_build: 902, build_commit: 96336}), 40 db.insert('commits', {id: 93116, repository: this.webkitRepositoryId(), revision: '191622', time: (new Date(1445945816878)).toISOString()}), 41 db.insert('commits', {id: 96336, repository: this.webkitRepositoryId(), revision: '192736', time: (new Date(1448225325650)).toISOString()}), 47 42 db.insert('platforms', {id: MockData.somePlatformId(), name: 'some platform'}), 48 43 db.insert('tests', {id: MockData.someTestId(), name: 'some test'}), 49 db.insert('test_metrics', {id: 300, test: MockData.someTestId(), name: 'some metric'}), 50 db.insert('test_configurations', {id: 301, metric: 300, platform: MockData.somePlatformId(), type: 'current'}), 51 db.insert('test_runs', {id: 801, config: 301, build: 901, mean_cache: 101}), 52 db.insert('test_runs', {id: 802, config: 301, build: 902, mean_cache: 92}), 44 db.insert('test_metrics', {id: 300, test: 200, name: 'some metric'}), 45 db.insert('test_configurations', {id: 301, metric: 300, platform: 65, type: 'current'}), 53 46 db.insert('commit_sets', {id: 401}), 54 47 db.insert('commit_set_relationships', {set: 401, commit: 87832}), … … 57 50 db.insert('commit_set_relationships', {set: 402, commit: 87832}), 58 51 db.insert('commit_set_relationships', {set: 402, commit: 96336}), 59 db.insert('analysis_tasks', {id: 500, platform: 65, metric: 300, name: 'some task', 60 start_run: 801, start_run_time: '2015-10-27T12:05:27.1Z', 61 end_run: 801, end_run_time: '2015-10-27T12:05:27.1Z'}), 52 db.insert('analysis_tasks', {id: 500, platform: 65, metric: 300, name: 'some task'}), 62 53 db.insert('analysis_test_groups', {id: 600, task: 500, name: 'some test group'}), 63 54 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}), -
trunk/Websites/perf.webkit.org/tools/js/remote.js
r215202 r215203 1 1 'use strict'; 2 2 3 const assert = require('assert'); 4 const http = require('http'); 5 const https = require('https'); 6 const querystring = require('querystring'); 7 const CommonRemoteAPI = require('../../public/shared/common-remote.js').CommonRemoteAPI; 8 9 global.FormData = require('form-data'); 3 let assert = require('assert'); 4 let http = require('http'); 5 let https = require('https'); 6 let querystring = require('querystring'); 7 let CommonRemoteAPI = require('../../public/shared/common-remote.js').CommonRemoteAPI; 10 8 11 9 class NodeRemoteAPI extends CommonRemoteAPI { -
trunk/Websites/perf.webkit.org/unit-tests/analysis-task-tests.js
r215202 r215203 16 16 'buildRequestCount': '14', 17 17 'finishedBuildRequestCount': '6', 18 'category': 'identified', 18 19 'causes': [ 19 20 '105975' … … 24 25 'fixes': [], 25 26 'id': '1082', 26 'metric': MockModels.someMetric.id(),27 'metric': '2884', 27 28 'name': 'Potential 1.2% regression between 2016-02-02 20:20 and 02-03 15:57', 28 29 'needed': null, 29 'platform': MockModels.somePlatform.id(),30 'platform': '65', 30 31 'result': 'regression', 31 32 'segmentationStrategy': '1', … … 49 50 } 50 51 ], 51 'status': 'OK'52 };53 }54 55 function sampleCustomAnalysisTask()56 {57 return {58 'analysisTasks': [59 {60 'id': '1000',61 'createdAt': 1454594330000,62 'author': null,63 'buildRequestCount': '0',64 'finishedBuildRequestCount': '0',65 'bugs': [],66 'causes': [ ],67 'fixes': [],68 'startRun': null,69 'startRunTime': null,70 'endRun': null,71 'endRunTime': null,72 'metric': null,73 'name': 'Potential 1.2% regression between 2016-02-02 20:20 and 02-03 15:57',74 'needed': null,75 'platform': null,76 'result': null,77 'segmentationStrategy': null,78 'testRangeStragegy': null,79 }80 ],81 'commits': [],82 'bugs': [],83 52 'status': 'OK' 84 53 }; … … 152 121 let requests = MockRemoteAPI.inject(); 153 122 154 function loadAnalysisTasks(rawData)155 {156 AnalysisTask._constructAnalysisTasksFromRawData(rawData);157 return Promise.resolve();158 }159 160 describe('findByPlatformAndMetric', () => {161 it('should return an empty array when there are no analysis tasks', () => {162 assert.deepEqual(AnalysisTask.findByPlatformAndMetric(MockModels.somePlatform, MockModels.someMetric), []);163 });164 165 it('should return an array containing the matching non-custom analysis tasks', () => {166 return loadAnalysisTasks(sampleAnalysisTask()).then(() => {167 return loadAnalysisTasks(sampleCustomAnalysisTask());168 }).then(() => {169 const tasks = AnalysisTask.findByPlatformAndMetric(MockModels.somePlatform.id(), MockModels.someMetric.id());170 assert.equal(tasks.length, 1);171 const task = tasks[0];172 assert.equal(task.id(), 1082);173 assert.equal(task.isCustom(), false);174 assert.equal(task.hasResults(), true);175 assert.equal(task.hasPendingRequests(), true);176 assert.equal(task.requestLabel(), '6 of 14');177 assert.equal(task.startMeasurementId(), 37117949);178 assert.equal(task.endMeasurementId(), 37253448);179 assert.equal(task.author(), '');180 assert.deepEqual(task.bugs(), []);181 assert.deepEqual(task.causes(), [CommitLog.findById(105975)]);182 assert.deepEqual(task.fixes(), []);183 assert.deepEqual(task.platform(), MockModels.somePlatform);184 assert.deepEqual(task.metric(), MockModels.someMetric);185 assert.deepEqual(task.changeType(), 'regression');186 assert.deepEqual(task.category(), 'investigated');187 });188 });189 });190 191 123 describe('fetchAll', () => { 192 124 it('should request all analysis tasks', () => { -
trunk/Websites/perf.webkit.org/unit-tests/build-request-tests.js
r215202 r215203 24 24 "commitSets": [{ 25 25 "id": "4255", 26 "commits": ["87832", "93116"], 27 "customRoots": [], 26 "commits": ["87832", "93116"] 28 27 }, { 29 28 "id": "4256", 30 "commits": ["87832", "96336"], 31 "customRoots": [], 29 "commits": ["87832", "96336"] 32 30 }], 33 31 "commits": [{ … … 52 50 "time": 1448225325650 53 51 }], 54 "uploadedFiles": [],55 52 "status": "OK" 56 53 }; -
trunk/Websites/perf.webkit.org/unit-tests/buildbot-syncer-tests.js
r215202 r215203 193 193 assert(test instanceof Test); 194 194 195 let commitSet = CommitSet.ensureSingleton('4197', {c ustomRoots: [], commits: [195 let commitSet = CommitSet.ensureSingleton('4197', {commits: [ 196 196 {'id': '111127', 'time': 1456955807334, 'repository': MockModels.webkit, 'revision': '197463'}, 197 197 {'id': '111237', 'time': 1456931874000, 'repository': MockModels.sharedRepository, 'revision': '80229'}, -
trunk/Websites/perf.webkit.org/unit-tests/test-groups-tests.js
r215202 r215203 16 16 "hidden": false, 17 17 "buildRequests": ["16985", "16986", "16987", "16988", "16989", "16990", "16991", "16992"], 18 "commitSets": ["4255", "4256"], 19 }], 18 "commitSets": ["4255", "4256", "4255", "4256", "4255", "4256", "4255", "4256"] 19 } 20 ], 20 21 "buildRequests": [{ 21 22 "id": "16985", … … 67 68 "build": null, 68 69 "createdAt": 1458688514000 69 }], 70 } 71 ], 70 72 "commitSets": [{ 71 73 "id": "4255", 72 "commits": ["87832", "93116"], 73 "customRoots": [], 74 "commits": ["87832", "93116"] 74 75 }, { 75 76 "id": "4256", 76 "commits": ["87832", "96336"] ,77 "customRoots": [],78 }],77 "commits": ["87832", "96336"] 78 } 79 ], 79 80 "commits": [{ 80 81 "id": "87832", … … 97 98 "revision": "192736", 98 99 "time": 1448225325650 99 } ],100 "uploadedFiles": [],100 } 101 ], 101 102 "status": "OK" 102 103 };
Note: See TracChangeset
for help on using the changeset viewer.