WebKit Bugzilla
Attachment 357486 Details for
Bug 191557
: Extend commits table to contain testability warning information.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-191557-20181217154152.patch (text/plain), 76.28 KB, created by
dewei_zhu
on 2018-12-17 15:41:53 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
dewei_zhu
Created:
2018-12-17 15:41:53 PST
Size:
76.28 KB
patch
obsolete
>Subversion Revision: 239135 >diff --git a/Websites/perf.webkit.org/ChangeLog b/Websites/perf.webkit.org/ChangeLog >index d06dc0cadaa935ed13879d5d3ac841a8f7c2a029..b95bc03a462994a85ffd35bffbdb9dd899f73333 100644 >--- a/Websites/perf.webkit.org/ChangeLog >+++ b/Websites/perf.webkit.org/ChangeLog >@@ -1,3 +1,47 @@ >+2018-12-14 Dewei Zhu <dewei_zhu@apple.com> >+ >+ Extend commits table to contain testability warning information. >+ https://bugs.webkit.org/show_bug.cgi?id=191557 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Added the ability to store testability warning message in commits table. >+ Added '/api/update-commits' to support updating an existing commit. >+ Refactored '/api/report-commits' to share code with '/api/update-commits'. >+ Updated os version syncing script to be able to update testability warning information. >+ >+ * init-database.sql: Added 'commit_testability_warning' field to 'commits' table. >+ * public/api/report-commits.php: Refactor to share code with '/api/update-commits'. >+ * public/api/update-commits.php: Added an API to update commit info. >+ * public/include/commit-log-fetcher.php: Expose testability warning information in this API. >+ * public/include/commit-modifier.php: Added 'CommitModifier' to manage commit insert and update. >+ * public/v3/models/commit-log.js: CommitLog object should expose testability warning information. >+ (CommitLog.prototype.updateSingleton): >+ (CommitLog.prototype.testabilityWarning): >+ * public/v3/models/commit-set.js: Added 'commitsWithTestabilityWarnings' and 'commits' to CommitSet and >+ IntermediateCommitSet instances. >+ (CommitSet.prototype.commitsWithTestabilityWarnings): >+ (CommitSet.prototype.commits): >+ (IntermediateCommitSet.prototype.commitsWithTestabilityWarnings): >+ (IntermediateCommitSet.prototype.commits): >+ * server-tests/api-update-commits-tests.js: Added unit tests for '/api/update-commit-testability'. >+ * server-tests/tools-os-build-fetcher-tests.js: Added and updated unit tests. >+ * tools/js/os-build-fetcher.js: Added the ability to update commit testability warnings. >+ (async.fetchReportAndUpdateCommits): >+ (prototype.async.fetchReportAndUpdateBuilds): >+ (prototype.async._fetchAvailableBuilds): >+ (prototype.async._commitsForAvailableBuilds): >+ (prototype._commitsWithinRange): >+ (prototype.async._reportToEndPoint): >+ (fetchAndReportAllInOrder): Deleted. >+ (prototype.fetchAndReportNewBuilds): Deleted. >+ (prototype._fetchAvailableBuilds): Deleted. >+ (prototype._commitsForAvailableBuilds): Deleted. >+ (prototype._submitCommits): Deleted. >+ * tools/sync-os-versions.js: >+ * unit-tests/commit-log-tests.js: Added a unit test for 'testabilityWarning'. >+ * unit-tests/commit-set-tests.js: Added unit tests for 'commitsWithTestabilityWarnings'. >+ > 2018-11-16 Ryosuke Niwa <rniwa@webkit.org> > > Manifest file can contain a test metric which references a non-existent test >diff --git a/Websites/perf.webkit.org/init-database.sql b/Websites/perf.webkit.org/init-database.sql >index 8161efe3e281e34a0dc44edb80cab6c3bbc37ba6..2ee17ad4c92bf52567332c601ff2e2b14dd4f377 100644 >--- a/Websites/perf.webkit.org/init-database.sql >+++ b/Websites/perf.webkit.org/init-database.sql >@@ -101,6 +101,7 @@ CREATE TABLE commits ( > commit_committer integer REFERENCES committers ON DELETE CASCADE, > commit_message text, > commit_reported boolean NOT NULL DEFAULT FALSE, >+ commit_testability_warning varchar(64) DEFAULT NULL, > CONSTRAINT commit_in_repository_must_be_unique UNIQUE(commit_repository, commit_revision)); > CREATE INDEX commit_time_index ON commits(commit_time); > CREATE INDEX commit_order_index ON commits(commit_order); >diff --git a/Websites/perf.webkit.org/public/api/report-commits.php b/Websites/perf.webkit.org/public/api/report-commits.php >index 6c651a98aa4ff77ff290a2823a3afb78bc92145b..884d6aa8185fc178c48eef74ebeba817e703f52f 100644 >--- a/Websites/perf.webkit.org/public/api/report-commits.php >+++ b/Websites/perf.webkit.org/public/api/report-commits.php >@@ -1,6 +1,7 @@ > <?php > > require('../include/json-header.php'); >+require('../include/commit-modifier.php'); > > function main($post_data) > { >@@ -13,92 +14,12 @@ function main($post_data) > verify_slave($db, $report); > > $commits = array_get($report, 'commits', array()); >- >- foreach ($commits as $commit_info) { >- if (!array_key_exists('repository', $commit_info)) >- exit_with_error('MissingRepositoryName', array('commit' => $commit_info)); >- if (!array_key_exists('revision', $commit_info)) >- exit_with_error('MissingRevision', array('commit' => $commit_info)); >- require_format('Revision', $commit_info['revision'], '/^[A-Za-z0-9 \.]+$/'); >- if (array_key_exists('author', $commit_info) && !is_array($commit_info['author'])) >- exit_with_error('InvalidAuthorFormat', array('commit' => $commit_info)); >- } >- >- $db->begin_transaction(); >- foreach ($commits as $commit_info) { >- $repository_id = $db->select_or_insert_row('repositories', 'repository', array('name' => $commit_info['repository'], 'owner' => NULL)); >- if (!$repository_id) { >- $db->rollback_transaction(); >- exit_with_error('FailedToInsertRepository', array('commit' => $commit_info)); >- } >- $owner_commit_id = insert_commit($db, $commit_info, $repository_id, NULL); >- if (!array_key_exists('ownedCommits', $commit_info)) >- continue; >- >- foreach($commit_info['ownedCommits'] as $owned_commit_repository_name => $owned_commit_info) { >- if (array_key_exists('time', $owned_commit_info)) { >- $db->rollback_transaction(); >- exit_with_error('OwnedCommitShouldNotContainTimestamp', array('commit' => $owned_commit_info)); >- } >- $owned_commit_repository_id = $db->select_or_insert_row('repositories', 'repository', array('name' => $owned_commit_repository_name, 'owner' => $repository_id)); >- if (!$owned_commit_repository_id) { >- $db->rollback_transaction(); >- exit_with_error('FailedToInsertRepository', array('commit' => $owned_commit_info)); >- } >- insert_commit($db, $owned_commit_info, $owned_commit_repository_id, $owner_commit_id); >- } >- } >- $db->commit_transaction(); >+ $commit_modifier = new CommitModifier($db); >+ $commit_modifier->update_or_insert_commits($commits); > > exit_with_success(); > } > >-function insert_commit($db, $commit_info, $repository_id, $owner_commit_id) >-{ >- $author = array_get($commit_info, 'author'); >- $committer_id = NULL; >- if ($author) { >- $account = array_get($author, 'account'); >- $committer_query = array('repository' => $repository_id, 'account' => $account); >- $committer_data = $committer_query; >- $name = array_get($author, 'name'); >- if ($name) >- $committer_data['name'] = $name; >- $committer_id = $db->update_or_insert_row('committers', 'committer', $committer_query, $committer_data); >- if (!$committer_id) { >- $db->rollback_transaction(); >- exit_with_error('FailedToInsertCommitter', array('committer' => $committer_data)); >- } >- } >- >- $previous_commit_revision = array_get($commit_info, 'previousCommit'); >- $previous_commit_id = NULL; >- if ($previous_commit_revision) { >- $previous_commit = $db->select_first_row('commits', 'commit', array('repository' => $repository_id, 'revision' => $previous_commit_revision)); >- if (!$previous_commit) { >- $db->rollback_transaction(); >- exit_with_error('FailedToFindPreviousCommit', array('commit' => $commit_info)); >- } >- $previous_commit_id = $previous_commit['commit_id']; >- } >- >- $data = array( >- 'repository' => $repository_id, >- 'revision' => $commit_info['revision'], >- 'previous_commit' => $previous_commit_id, >- 'order' => array_get($commit_info, 'order'), >- 'time' => array_get($commit_info, 'time'), >- 'committer' => $committer_id, >- 'message' => array_get($commit_info, 'message'), >- 'reported' => true, >- ); >- $inserted_commit_id = $db->update_or_insert_row('commits', 'commit', array('repository' => $repository_id, 'revision' => $data['revision']), $data); >- >- if ($owner_commit_id) >- $db->select_or_insert_row('commit_ownerships', 'commit', array('owner' => $owner_commit_id, 'owned' => $inserted_commit_id), NULL, '*'); >- return $inserted_commit_id; >-} >- > main(file_get_contents('php://input')); > > ?> >diff --git a/Websites/perf.webkit.org/public/api/update-commits.php b/Websites/perf.webkit.org/public/api/update-commits.php >new file mode 100644 >index 0000000000000000000000000000000000000000..8c5391e2816811e675569879bdf491e832e88300 >--- /dev/null >+++ b/Websites/perf.webkit.org/public/api/update-commits.php >@@ -0,0 +1,24 @@ >+<?php >+ >+require('../include/json-header.php'); >+require('../include/commit-modifier.php'); >+ >+function main($post_data) >+{ >+ $db = new Database; >+ if (!$db->connect()) >+ exit_with_error('DatabaseConnectionFailure'); >+ >+ $report = json_decode($post_data, true); >+ >+ verify_slave($db, $report); >+ >+ $commits = array_get($report, 'commits', array()); >+ $commit_modifier = new CommitModifier($db); >+ $commit_modifier->update_commits($commits); >+ >+ exit_with_success(); >+} >+ >+main(file_get_contents('php://input')); >+?> >\ No newline at end of file >diff --git a/Websites/perf.webkit.org/public/include/commit-log-fetcher.php b/Websites/perf.webkit.org/public/include/commit-log-fetcher.php >index 9c76263cb6616b595b1dddfb9909472ea1589d08..26476d0d90d1a1840cb310877b7e793e4a004100 100644 >--- a/Websites/perf.webkit.org/public/include/commit-log-fetcher.php >+++ b/Websites/perf.webkit.org/public/include/commit-log-fetcher.php >@@ -62,6 +62,7 @@ class CommitLogFetcher { > commit_repository as "repository", > commit_message as "message", > commit_order as "order", >+ commit_testability_warning as "testabilityWarning", > EXISTS(SELECT * FROM commit_ownerships WHERE commit_owner = commit_id) as "ownsCommits" > FROM commits LEFT OUTER JOIN committers ON commit_committer = committer_id > WHERE commit_repository = $1 AND commit_reported = true'; >@@ -211,6 +212,7 @@ class CommitLogFetcher { > 'authorName' => $committer_row ? $committer_row['committer_name'] : null, > 'authorEmail' => $committer_row ? $committer_row['committer_account'] : null, > 'message' => $commit_row['commit_message'], >+ 'testabilityWarning' => $commit_row['commit_testability_warning'], > 'ownsCommits' => $owns_commits > ); > } >diff --git a/Websites/perf.webkit.org/public/include/commit-modifier.php b/Websites/perf.webkit.org/public/include/commit-modifier.php >new file mode 100644 >index 0000000000000000000000000000000000000000..1c67575e2494eac87e40420af456a25d7a1034b7 >--- /dev/null >+++ b/Websites/perf.webkit.org/public/include/commit-modifier.php >@@ -0,0 +1,253 @@ >+<?php >+ >+class CommitModifier { >+ private $db; >+ private $top_level_repository_id_by_name; >+ private $owned_repository_by_name_and_owner_id; >+ private $commits_by_repository_id; >+ private $authors_by_repository_id; >+ private $commit_identifier_and_update_list; >+ private $commit_data_list; >+ >+ function __construct($db) >+ { >+ $this->db = $db; >+ $this->top_level_repository_id_by_name = array(); >+ $this->owned_repository_by_name_and_owner_id = array(); >+ $this->commits_by_repository_id = array(); >+ $this->authors_by_repository_id = array(); >+ $this->commit_identifier_and_update_list = array(); >+ $this->commit_data_list = array(); >+ } >+ >+ function update_commits($commits) >+ { >+ $this->prepare_commit_update($commits); >+ $this->db->begin_transaction(); >+ >+ foreach ($this->commit_identifier_and_update_list as list($commit_identifier, $commit_update)) { >+ if (array_key_exists('committer', $commit_update)) { >+ $committer_id = $this->resolve_committer_by_repository_id_and_author_account($commit_identifier['repository'], $commit_update['committer']); >+ $commit_update['committer'] = $committer_id; >+ } >+ >+ $updated_commit = $this->db->update_row('commits', 'commit', $commit_identifier, $commit_update); >+ if (!$updated_commit) >+ $this->rollback_with_error('FailedToUpdateCommit', array('commit' => $commit_identifier, 'commitUpdate' => $commit_update)); >+ } >+ >+ $this->db->commit_transaction(); >+ $this->reset(); >+ } >+ >+ private function prepare_commit_update($commits) >+ { >+ $this->validate_commits($commits); >+ >+ foreach ($commits as $commit_info) { >+ $repository_id = $this->find_top_level_repository($commit_info['repository']); >+ $commit_identifier = array('repository' => $repository_id, 'revision' => $commit_info['revision']); >+ $commit_update = array(); >+ >+ if (array_key_exists('time', $commit_info)) >+ $commit_update['time'] = $commit_info['time']; >+ >+ if (array_key_exists('message', $commit_info)) >+ $commit_update['message'] = $commit_info['message']; >+ >+ if (array_key_exists('order', $commit_info)) >+ $commit_update['order'] = $commit_info['order']; >+ >+ if (array_key_exists('testabilityWarning', $commit_info)) >+ $commit_update['testability_warning'] = $commit_info['testabilityWarning']; >+ >+ if (array_key_exists('author', $commit_info)) >+ $commit_update['committer'] = $commit_info['author']; >+ >+ if (array_key_exists('previousCommit', $commit_info)) >+ $commit_update['previous_commit'] = $this->resolve_previous_commit($repository_id, $commit_info['previousCommit'], false); >+ >+ if (array_key_exists('ownedCommits', $commit_info)) >+ exit_with_error('OwnedCommitsUpdateNotSupportedYet', array('commit' => $commit_info)); >+ >+ if (!count($commit_update)) >+ exit_with_error('NothingToUpdate', array('commit' => $commit_info)); >+ >+ array_push($this->commit_identifier_and_update_list, array($commit_identifier, $commit_update)); >+ } >+ } >+ >+ private function validate_commits($commits) >+ { >+ foreach ($commits as $commit_info) { >+ if (!array_key_exists('repository', $commit_info)) >+ exit_with_error('MissingRepositoryName', array('commit' => $commit_info)); >+ if (!array_key_exists('revision', $commit_info)) >+ exit_with_error('MissingRevision', array('commit' => $commit_info)); >+ require_format('Revision', $commit_info['revision'], '/^[A-Za-z0-9 \.]+$/'); >+ if (array_key_exists('author', $commit_info) && !is_array($commit_info['author'])) >+ exit_with_error('InvalidAuthorFormat', array('commit' => $commit_info)); >+ } >+ } >+ >+ private function find_top_level_repository($repository_name) >+ { >+ if (array_key_exists($repository_name, $this->top_level_repository_id_by_name)) >+ return $this->top_level_repository_id_by_name[$repository_name]; >+ >+ $repository = $this->db->select_first_row('repositories', 'repository', array('name' => $repository_name, 'owner' => NULL)); >+ if (!$repository) >+ exit_with_error('InvalidRepository', array('repository' => $repository_name)); >+ $this->top_level_repository_id_by_name[$repository_name] = $repository['repository_id']; >+ return $repository['repository_id']; >+ } >+ >+ private function resolve_previous_commit($repository_id, $revision, $rollback_on_error) >+ { >+ $commit_id_by_revision = &array_ensure_item_has_array($this->commits_by_repository_id, $revision); >+ if (array_key_exists($revision, $commit_id_by_revision)) >+ return $commit_id_by_revision[$revision]; >+ >+ $previous_commit = $this->db->select_first_row('commits', 'commit', array('repository' => $repository_id, 'revision' => $revision)); >+ if (!$previous_commit) { >+ if ($rollback_on_error) >+ $this->rollback_with_error('FailedToFindPreviousCommit', array('revision' => $revision)); >+ exit_with_error('FailedToFindPreviousCommit', array('revision' => $revision)); >+ } >+ >+ $commit_id_by_revision[$revision] = $previous_commit['commit_id']; >+ return $previous_commit['commit_id']; >+ } >+ >+ private function resolve_committer_by_repository_id_and_author_account($repository_id, $author) >+ { >+ $committer_id_by_account = &array_ensure_item_has_array($this->authors_by_repository_id, $repository_id); >+ $account = array_get($author, 'account'); >+ if (array_key_exists($account, $committer_id_by_account)) >+ return $committer_id_by_account[$account]; >+ >+ $committer_data = array('repository' => $repository_id, 'account' => $account); >+ $name = array_get($author, 'name'); >+ if ($name) >+ $committer_data['name'] = $name; >+ $committer_id = $this->db->update_or_insert_row('committers', 'committer', array('repository' => $repository_id, 'account' => $account), $committer_data); >+ >+ if (!$committer_id) >+ $this->rollback_with_error('FailedToInsertCommitter', array('committer' => $committer_data)); >+ $committer_id_by_account[$account] = $committer_id; >+ return $committer_id; >+ } >+ >+ private function rollback_with_error($message, $details) >+ { >+ $this->db->rollback_transaction(); >+ exit_with_error($message, $details); >+ } >+ >+ private function reset() >+ { >+ $this->top_level_repository_id_by_name = array(); >+ $this->owned_repository_by_name_and_owner_id = array(); >+ $this->commits_by_repository_id = array(); >+ $this->authors_by_repository_id = array(); >+ $this->commit_identifier_and_update_list = array(); >+ $this->commit_data_list = array(); >+ } >+ >+ function update_or_insert_commits($commits) >+ { >+ $this->prepare_commit_update_or_insert($commits); >+ >+ $this->db->begin_transaction(); >+ foreach ($this->commit_data_list as list($commit_data, $owned_commit_list)) { >+ list($commit_id, $repository_id) = $this->update_or_insert_commit($commit_data, NULL, NULL); >+ foreach ($owned_commit_list as $owned_commit_data) >+ $this->update_or_insert_commit($owned_commit_data, $commit_id, $repository_id); >+ } >+ $this->db->commit_transaction(); >+ $this->reset(); >+ } >+ >+ private function prepare_commit_update_or_insert($commits) >+ { >+ $this->validate_commits($commits); >+ foreach ($commits as $commit_info) { >+ $commit_data = $this->prepare_single_commit_data($commit_info, false); >+ $owned_commit_list = array(); >+ if (array_key_exists('ownedCommits', $commit_info)) { >+ foreach($commit_info['ownedCommits'] as $owned_commit_repository_name => $owned_commit_info) { >+ $owned_commit_info['repository'] = $owned_commit_repository_name; >+ array_push($owned_commit_list, $this->prepare_single_commit_data($owned_commit_info, true)); >+ } >+ } >+ array_push($this->commit_data_list, array($commit_data, $owned_commit_list)); >+ } >+ } >+ >+ private function prepare_single_commit_data($commit_info, $is_owned_commit) >+ { >+ $commit_data = array( >+ 'repository' => $commit_info['repository'], >+ 'revision' => $commit_info['revision'], >+ 'reported' => true, >+ ); >+ >+ if (array_key_exists('previousCommit', $commit_info)) >+ $commit_data['previous_commit'] = $commit_info['previousCommit']; >+ >+ if (array_key_exists('order', $commit_info)) >+ $commit_data['order'] = $commit_info['order']; >+ >+ if (array_key_exists('time', $commit_info)) { >+ if ($is_owned_commit) >+ exit_with_error('OwnedCommitShouldNotContainTimestamp', array('commit' => $commit_info)); >+ $commit_data['time'] = $commit_info['time']; >+ } >+ >+ if (array_key_exists('author', $commit_info)) >+ $commit_data['committer'] = $commit_info['author']; >+ >+ if (array_key_exists('message', $commit_info)) >+ $commit_data['message'] = $commit_info['message']; >+ >+ return $commit_data; >+ } >+ >+ private function update_or_insert_commit($commit_data, $owner_commit_id, $owner_repository_id) >+ { >+ $repository_id = $this->resolve_repository($commit_data['repository'], $owner_repository_id); >+ $commit_data['repository'] = $repository_id; >+ >+ if (array_key_exists('previous_commit', $commit_data)) >+ $commit_data['previous_commit'] = $this->resolve_previous_commit($repository_id, $commit_data['previous_commit'], true); >+ >+ if (array_key_exists('committer', $commit_data)) >+ $commit_data['committer'] = $this->resolve_committer_by_repository_id_and_author_account($repository_id, $commit_data['committer']); >+ >+ $inserted_commit_id = $this->db->update_or_insert_row('commits', 'commit', array('repository' => $repository_id, 'revision' => $commit_data['revision']), $commit_data); >+ if (!$inserted_commit_id) >+ $this->rollback_with_error('FailedToInsertCommit', array('commit' => $commit_data)); >+ >+ if ($owner_commit_id) >+ $this->db->select_or_insert_row('commit_ownerships', 'commit', array('owner' => $owner_commit_id, 'owned' => $inserted_commit_id), NULL, '*'); >+ >+ return array($inserted_commit_id, $repository_id); >+ } >+ >+ private function resolve_repository($repository_name, $owner_repository_id) >+ { >+ if ($owner_repository_id) >+ $repository_id_by_name = &array_ensure_item_has_array($this->owned_repository_by_name_and_owner_id, $owner_repository_id); >+ else >+ $repository_id_by_name = &$this->top_level_repository_id_by_name; >+ >+ if (array_key_exists($repository_name, $repository_id_by_name)) >+ return $repository_id_by_name[$repository_name]; >+ >+ $repository_id = $this->db->select_or_insert_row('repositories', 'repository', array('name' => $repository_name, 'owner' => $owner_repository_id)); >+ if (!$repository_id) >+ $this->rollback_with_error('FailedToInsertRepository', array('repository' => $repository_name)); >+ $repository_id_by_name[$repository_name] = $repository_id; >+ return $repository_id; >+ } >+} >\ No newline at end of file >diff --git a/Websites/perf.webkit.org/public/v3/models/commit-log.js b/Websites/perf.webkit.org/public/v3/models/commit-log.js >index 130cb90f1498aebe309907f43c5535e4703bec38..2fa2ea0694688b89649fabcdaa20f2ac8d6fc0ca 100644 >--- a/Websites/perf.webkit.org/public/v3/models/commit-log.js >+++ b/Websites/perf.webkit.org/public/v3/models/commit-log.js >@@ -29,11 +29,14 @@ class CommitLog extends DataModelObject { > this._rawData.ownsCommits = rawData.ownsCommits; > if (rawData.order) > this._rawData.order = rawData.order; >+ if (rawData.testabilityWarning) >+ this._rawData.testabilityWarning = rawData.testabilityWarning; > } > > repository() { return this._repository; } > time() { return new Date(this._rawData['time']); } > hasCommitTime() { return this._rawData['time'] > 0 && this._rawData['time'] != null; } >+ testabilityWarning() { return this._rawData['testabilityWarning']; } > author() { return this._rawData['authorName']; } > revision() { return this._rawData['revision']; } > message() { return this._rawData['message']; } >diff --git a/Websites/perf.webkit.org/public/v3/models/commit-set.js b/Websites/perf.webkit.org/public/v3/models/commit-set.js >index 94acc5332898cb4900afe78b7f6cb6979fc33516..45946c887e24f739955a8b52bbe5db7df17a4588 100644 >--- a/Websites/perf.webkit.org/public/v3/models/commit-set.js >+++ b/Websites/perf.webkit.org/public/v3/models/commit-set.js >@@ -71,6 +71,8 @@ class CommitSet extends DataModelObject { > ownerCommitForRepository(repository) { return this._repositoryToCommitOwnerMap.get(repository); } > topLevelRepositories() { return Repository.sortByNamePreferringOnesWithURL(this._repositories.filter((repository) => !this.ownerRevisionForRepository(repository))); } > ownedRepositoriesForOwnerRepository(repository) { return this._ownerRepositoryToOwnedRepositoriesMap.get(repository); } >+ commitsWithTestabilityWarnings() { return this.commits().filter((commit) => !!commit.testabilityWarning()); } >+ commits() { return Array.from(this._repositoryToCommitMap.values()); } > > revisionForRepository(repository) > { >@@ -387,6 +389,9 @@ class IntermediateCommitSet { > return Promise.all(fetchingPromises); > } > >+ commitsWithTestabilityWarnings() { return this.commits().filter((commit) => !!commit.testabilityWarning()); } >+ commits() { return Array.from(this._commitByRepository.values()); } >+ > _fetchCommitLogAndOwnedCommits(repository, revision) > { > return CommitLog.fetchForSingleRevision(repository, revision).then((commits) => { >diff --git a/Websites/perf.webkit.org/server-tests/api-update-commits-tests.js b/Websites/perf.webkit.org/server-tests/api-update-commits-tests.js >new file mode 100644 >index 0000000000000000000000000000000000000000..d141c1e318444ebcd1c3011873f01f5bbdf26531 >--- /dev/null >+++ b/Websites/perf.webkit.org/server-tests/api-update-commits-tests.js >@@ -0,0 +1,163 @@ >+'use strict'; >+ >+const assert = require('assert'); >+ >+const TestServer = require('./resources/test-server.js'); >+const addSlaveForReport = require('./resources/common-operations.js').addSlaveForReport; >+const prepareServerTest = require('./resources/common-operations.js').prepareServerTest; >+const assertThrows = require('./resources/common-operations.js').assertThrows; >+ >+describe("/api/update-commits", function () { >+ prepareServerTest(this); >+ >+ const subversionCommits = { >+ "slaveName": "someSlave", >+ "slavePassword": "somePassword", >+ "commits": [ >+ { >+ "repository": "WebKit", >+ "revision": "210948", >+ "time": "2017-01-20T02:52:34.577Z", >+ "author": {"name": "Zalan Bujtas", "account": "zalan@apple.com"}, >+ "message": "a message", >+ }, >+ { >+ "repository": "WebKit", >+ "revision": "210949", >+ "time": "2017-01-20T03:23:50.645Z", >+ "author": {"name": "Chris Dumez", "account": "cdumez@apple.com"}, >+ "message": "some message", >+ } >+ ] >+ }; >+ >+ const commitsUpdate = { >+ "slaveName": "someSlave", >+ "slavePassword": "somePassword", >+ "commits": [ >+ { >+ "repository": "WebKit", >+ "revision": "210948", >+ "testabilityWarning": "Breaks builds", >+ "message": "another message", >+ "order": 210948, >+ "time": "2017-01-20T03:52:34.577Z", >+ "author": {"name": "Chris Dumez", "account": "cdumez@apple.com"}, >+ }, >+ { >+ "repository": "WebKit", >+ "revision": "210949", >+ "previousCommit": "210948", >+ "testabilityWarning": "Crashes WebKit", >+ "message": "another message", >+ "order": 210949, >+ "time": "2017-01-20T04:23:50.645Z", >+ "author": {"name": "Zalan Bujtas", "account": "zalan@apple.com"}, >+ } >+ ] >+ }; >+ >+ >+ const commitsUpdateWithMissingRevision = { >+ "slaveName": "someSlave", >+ "slavePassword": "somePassword", >+ "commits": [ >+ { >+ "repository": "WebKit", >+ "testabilityWarning": "Breaks builds" >+ } >+ ] >+ }; >+ >+ const commitsUpdateWithMissingRepository = { >+ "slaveName": "someSlave", >+ "slavePassword": "somePassword", >+ "commits": [ >+ { >+ "revision": "210948", >+ "testabilityWarning": "Breaks builds" >+ } >+ ] >+ }; >+ >+ const commitsUpdateWithoutAnyUpdate = { >+ "slaveName": "someSlave", >+ "slavePassword": "somePassword", >+ "commits": [ >+ { >+ "repository": "WebKit", >+ "revision": "210948" >+ } >+ ] >+ }; >+ >+ const commitsUpdateWithOwnedCommitsUpdate = { >+ "slaveName": "someSlave", >+ "slavePassword": "somePassword", >+ "commits": [ >+ { >+ "repository": "WebKit", >+ "revision": "210948", >+ "ownedCommits": [], >+ } >+ ] >+ }; >+ >+ async function setUpTestsWithExpectedStatus(commitsUpdate, expectedStatus) >+ { >+ await addSlaveForReport(subversionCommits); >+ await TestServer.remoteAPI().postJSON('/api/report-commits/', subversionCommits); >+ let result = await TestServer.remoteAPI().getJSON('/api/commits/WebKit/'); >+ assert.equal(result['status'], 'OK'); >+ let commits = result['commits']; >+ assert.equal(commits.length, 2); >+ assert.equal(commits[0].testabilityWarning, null); >+ assert.equal(commits[1].testabilityWarning, null); >+ >+ result = await TestServer.remoteAPI().postJSON('/api/update-commits', commitsUpdate); >+ assert.equal(result['status'], expectedStatus); >+ result = await TestServer.remoteAPI().getJSON('/api/commits/WebKit/'); >+ return result['commits']; >+ } >+ >+ async function testWithExpectedFailure(commitsUpdate, expectedFailureName) >+ { >+ const commits = await setUpTestsWithExpectedStatus(commitsUpdate, expectedFailureName); >+ assert.equal(commits.length, 2); >+ assert.equal(commits[0].testabilityWarning, null); >+ assert.equal(commits[1].testabilityWarning, null); >+ } >+ >+ it('should fail with "MissingRevision" if commit update does not have commit revision specified', async () => { >+ await testWithExpectedFailure(commitsUpdateWithMissingRevision, 'MissingRevision'); >+ }); >+ >+ it('should fail with "MissingRepositoryName" if commit update does not have commit revision specified', async () => { >+ await testWithExpectedFailure(commitsUpdateWithMissingRepository, 'MissingRepositoryName'); >+ }); >+ >+ it('should fail with "NothingToUpdate" if commit update does not have commit revision specified', async () => { >+ await testWithExpectedFailure(commitsUpdateWithoutAnyUpdate, 'NothingToUpdate'); >+ }); >+ >+ it('should fail with "OwnedCommitsUpdateNotSupportedYet" when trying to update owned commits info', async () => { >+ await testWithExpectedFailure(commitsUpdateWithOwnedCommitsUpdate, 'OwnedCommitsUpdateNotSupportedYet'); >+ }); >+ >+ it("should be able to update commits message, time, order, author and previous commit", async () => { >+ const commits = await setUpTestsWithExpectedStatus(commitsUpdate, 'OK'); >+ >+ assert.equal(commits.length, 2); >+ assert.equal(commits[0].testabilityWarning, 'Breaks builds'); >+ assert.equal(commits[1].testabilityWarning, 'Crashes WebKit'); >+ assert.equal(commits[0].message, 'another message'); >+ assert.equal(commits[1].message, 'another message'); >+ assert.equal(commits[0].authorName, 'Chris Dumez'); >+ assert.equal(commits[1].authorName, 'Zalan Bujtas'); >+ assert.equal(commits[0].order, 210948); >+ assert.equal(commits[1].order, 210949); >+ assert.equal(commits[0].time, 1484884354577); >+ assert.equal(commits[1].time, 1484886230645); >+ assert.equal(commits[1].previousCommit, commits[0].id); >+ }); >+}); >\ No newline at end of file >diff --git a/Websites/perf.webkit.org/server-tests/tools-os-build-fetcher-tests.js b/Websites/perf.webkit.org/server-tests/tools-os-build-fetcher-tests.js >index c6f0dc93bbe3286878ca7f90c9c41ceff54ea779..6840a0d7cb7e5c98e02299695ac2950ae60d27e9 100644 >--- a/Websites/perf.webkit.org/server-tests/tools-os-build-fetcher-tests.js >+++ b/Websites/perf.webkit.org/server-tests/tools-os-build-fetcher-tests.js >@@ -134,39 +134,57 @@ describe('OSBuildFetcher', function() { > }); > > describe('OSBuilderFetcher._commitsForAvailableBuilds', () => { >- it('should only return commits whose orders are higher than specified order', () => { >+ it('should compatible with command output only contains lines of revision', async () => { > const logger = new MockLogger; > const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger); > const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >- const fetchCommitsPromise = fetcher._commitsForAvailableBuilds('OSX', ['list', 'build1'], '^\\.*$', 1604000000, 1606000000); >+ const fetchCommitsPromise = fetcher._commitsForAvailableBuilds(['list', 'build1'], '^\\.*$'); > >- return waitForInvocationPromise.then(() => { >- assert.equal(MockSubprocess.invocations.length, 1); >- assert.deepEqual(MockSubprocess.invocations[0].command, ['list', 'build1']); >- MockSubprocess.invocations[0].resolve('16D321\n16E321z\n\n16F321'); >- return fetchCommitsPromise; >- }).then((results) => { >- assert.equal(results.length, 2); >- assert.deepEqual(results[0], {repository: 'OSX', order: 1604032126, revision: '16E321z'}); >- assert.deepEqual(results[1], {repository: 'OSX', order: 1605032100, revision: '16F321'}); >- }); >+ await waitForInvocationPromise; >+ assert.equal(MockSubprocess.invocations.length, 1); >+ assert.deepEqual(MockSubprocess.invocations[0].command, ['list', 'build1']); >+ >+ const expectedResults = {allRevisions: ["16D321", "16E321z", "16F321"], commitsWithTestabilityWarnings: {}}; >+ await MockSubprocess.invocations[0].resolve('16D321\n16E321z\n\n16F321'); >+ const buildInfo = await fetchCommitsPromise; >+ assert.deepEqual(expectedResults, buildInfo); > }); > >- it('should only return commits whose orders are higher than minOrder and lower than the maxOrder', () => { >+ it('should parse the command output as JSON format', async () => { > const logger = new MockLogger; > const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger); > const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >- const fetchCommitsPromise = fetcher._commitsForAvailableBuilds('OSX', ['list', 'build1'], '^\\.*$', 1604000000, 1605000000); >+ const fetchCommitsPromise = fetcher._commitsForAvailableBuilds(['list', 'build1']); > >- return waitForInvocationPromise.then(() => { >- assert.equal(MockSubprocess.invocations.length, 1); >- assert.deepEqual(MockSubprocess.invocations[0].command, ['list', 'build1']); >- MockSubprocess.invocations[0].resolve('16D321\n16E321z\n\n16F321'); >- return fetchCommitsPromise; >- }).then((results) => { >- assert.equal(results.length, 1); >- assert.deepEqual(results[0], {repository: 'OSX', order: 1604032126, revision: '16E321z'}); >- }); >+ await waitForInvocationPromise; >+ assert.equal(MockSubprocess.invocations.length, 1); >+ assert.deepEqual(MockSubprocess.invocations[0].command, ['list', 'build1']); >+ >+ const outputObject = {allRevisions: ["16D321", "16E321z", "16F321"], commitsWithTestabilityWarnings: {"16D321": "Panic"}}; >+ await MockSubprocess.invocations[0].resolve(JSON.stringify(outputObject)); >+ const buildInfo = await fetchCommitsPromise; >+ assert.deepEqual(outputObject, buildInfo); >+ }); >+ }); >+ >+ >+ describe('OSBuilderFetcher._commitsWithinRange', () => { >+ it('should only return commits whose orders are higher than specified order', async () => { >+ const logger = new MockLogger; >+ const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger); >+ const results = fetcher._commitsWithinRange(["16D321", "16E321z", "16F321"], "OSX", 1604000000, 1606000000); >+ assert.equal(results.length, 2); >+ assert.deepEqual(results[0], {repository: 'OSX', order: 1604032126, revision: '16E321z'}); >+ assert.deepEqual(results[1], {repository: 'OSX', order: 1605032100, revision: '16F321'}); >+ >+ }); >+ >+ it('should only return commits whose orders are higher than minOrder and lower than the maxOrder', async () => { >+ const logger = new MockLogger; >+ const fetcher = new OSBuildFetcher({}, null, null, MockSubprocess, logger); >+ const results = fetcher._commitsWithinRange(["16D321", "16E321z", "16F321"], "OSX", 1604000000, 1605000000); >+ assert.equal(results.length, 1); >+ assert.deepEqual(results[0], {repository: 'OSX', order: 1604032126, revision: '16E321z'}); > }); > }); > >@@ -239,9 +257,9 @@ describe('OSBuildFetcher', function() { > }); > }); > }) >- }) >+ }); > >- describe('OSBuildFetcher.fetchAndReportNewBuilds', () => { >+ describe('OSBuildFetcher.fetchReportAndUpdateBuilds', () => { > const invocations = MockSubprocess.invocations; > > beforeEach(function () { >@@ -252,11 +270,12 @@ describe('OSBuildFetcher', function() { > TestServer.database().disconnect(); > }); > >- it('should report all build commits with owned-commits', () => { >+ it('should be backward compatible and report all build commits with owned-commits', () => { > const logger = new MockLogger; > const fetcher = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); > const db = TestServer.database(); >- let fetchAndReportPromise = null; >+ >+ let fetchReportAndUpdateBuildsPromise = null; > let fetchAvailableBuildsPromise = null; > > return addSlaveForReport(emptyReport).then(() => { >@@ -307,10 +326,9 @@ describe('OSBuildFetcher', function() { > assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']); > invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore)); > return fetchAvailableBuildsPromise; >- }).then((results) => { >- assert.equal(results.length, 3); >+ }).then(() => { > MockSubprocess.reset(); >- fetchAndReportPromise = fetcher.fetchAndReportNewBuilds(); >+ fetchReportAndUpdateBuildsPromise = fetcher.fetchReportAndUpdateBuilds(); > return MockSubprocess.waitForInvocation(); > }).then(() => { > assert.equal(invocations.length, 1); >@@ -337,9 +355,141 @@ describe('OSBuildFetcher', function() { > invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore)); > assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']); > >- return fetchAndReportPromise; >+ return fetchReportAndUpdateBuildsPromise; >+ }).then(() => { >+ return Promise.all([ >+ db.selectRows('repositories', {'name': 'WebKit'}), >+ db.selectRows('repositories', {'name': 'JavaScriptCore'}), >+ db.selectRows('commits', {'revision': 'Sierra16D69'}), >+ db.selectRows('commits', {'revision': 'Sierra16E33h'}), >+ db.selectRows('commits', {'revision': 'Sierra16E34'})]); >+ }).then((results) => { >+ const webkitRepository = results[0]; >+ const jscRepository = results[1]; >+ const osxCommit16D69 = results[2]; >+ const osxCommit16E33h = results[3]; >+ const osxCommit16E34 = results[4]; >+ >+ assert.equal(webkitRepository.length, 1); >+ assert.equal(webkitRepository[0]['owner'], 10); >+ assert.equal(jscRepository.length, 1); >+ assert.equal(jscRepository[0]['owner'], 10); >+ >+ assert.equal(osxCommit16D69.length, 1); >+ assert.equal(osxCommit16D69[0]['repository'], 10); >+ assert.equal(osxCommit16D69[0]['order'], 1603006900); >+ >+ assert.equal(osxCommit16E33h.length, 1); >+ assert.equal(osxCommit16E33h[0]['repository'], 10); >+ assert.equal(osxCommit16E33h[0]['order'], 1604003308); >+ >+ assert.equal(osxCommit16E34.length, 1); >+ assert.equal(osxCommit16E34[0]['repository'], 10); >+ assert.equal(osxCommit16E34[0]['order'], 1604003400); >+ >+ return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900'); > }).then((result) => { >- assert.equal(result['status'], 'OK'); >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16D69'); >+ assert.equal(result['commits'][0]['order'], 1603006900); >+ >+ return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900'); >+ }).then((result) => { >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16E34'); >+ assert.equal(result['commits'][0]['order'], 1604003400); >+ }); >+ }); >+ >+ it('should report all build commits with owned-commits', () => { >+ const logger = new MockLogger; >+ const fetcher = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); >+ const db = TestServer.database(); >+ const resultsForSierraD = {allRevisions: ["Sierra16D68", "Sierra16D69"], commitsWithTestabilityWarnings: {}}; >+ const resultsForSierraE = {allRevisions: ["Sierra16E32", "Sierra16E33", "Sierra16E33h", "Sierra16E34"], commitsWithTestabilityWarnings: {}}; >+ >+ let fetchReportAndUpdateBuildsPromise = null; >+ let fetchAvailableBuildsPromise = null; >+ >+ return addSlaveForReport(emptyReport).then(() => { >+ return Promise.all([ >+ db.insert('repositories', {'id': 10, 'name': 'OSX'}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]); >+ }).then(() => { >+ return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900'); >+ }).then((result) => { >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16D68'); >+ assert.equal(result['commits'][0]['order'], 1603006800); >+ return TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900'); >+ }).then((result) => { >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16E33g'); >+ assert.equal(result['commits'][0]['order'], 1604003307); >+ const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >+ fetchAvailableBuildsPromise = fetcher._fetchAvailableBuilds(); >+ return waitForInvocationPromise; >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']); >+ invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']); >+ invocations[0].resolve(JSON.stringify(resultsForSierraE)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']); >+ invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']); >+ invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore)); >+ return fetchAvailableBuildsPromise; >+ }).then(() => { >+ MockSubprocess.reset(); >+ fetchReportAndUpdateBuildsPromise = fetcher.fetchReportAndUpdateBuilds(); >+ return MockSubprocess.waitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']); >+ invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']); >+ invocations[0].resolve(JSON.stringify(resultsForSierraE)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']); >+ invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit)); >+ return MockSubprocess.resetAndWaitForInvocation(); >+ }).then(() => { >+ assert.equal(invocations.length, 1); >+ invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore)); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']); >+ >+ return fetchReportAndUpdateBuildsPromise; >+ }).then(() => { > return Promise.all([ > db.selectRows('repositories', {'name': 'WebKit'}), > db.selectRows('repositories', {'name': 'JavaScriptCore'}), >@@ -384,11 +534,119 @@ describe('OSBuildFetcher', function() { > }); > }); > >+ it('should update testability warning for commits', async () => { >+ const logger = new MockLogger; >+ const fetcher = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); >+ const db = TestServer.database(); >+ const resultsForSierraD = {allRevisions: ["Sierra16D68", "Sierra16D69"], commitsWithTestabilityWarnings: {"Sierra16D68": "Panic", "Sierra16D69": "Spin CPU"}}; >+ const resultsForSierraE = {allRevisions: ["Sierra16E32", "Sierra16E33", "Sierra16E33h", "Sierra16E34"], commitsWithTestabilityWarnings: {"Sierra16E31": "WebKit crashes"}}; >+ >+ await addSlaveForReport(emptyReport); >+ >+ await Promise.all([ >+ db.insert('repositories', {'id': 10, 'name': 'OSX'}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16D67', 'order': 1603006700, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16D68', 'order': 1603006800, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16D69', 'order': 1603006900, 'reported': false}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16E31', 'order': 1604003100, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16E32', 'order': 1604003200, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33', 'order': 1604003300, 'reported': true}), >+ db.insert('commits', {'repository': 10, 'revision': 'Sierra16E33g', 'order': 1604003307, 'reported': true})]); >+ >+ let result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900'); >+ >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16D68'); >+ assert.equal(result['commits'][0]['order'], 1603006800); >+ result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900'); >+ >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16E33g'); >+ assert.equal(result['commits'][0]['order'], 1604003307); >+ >+ const fetchReportAndUpdatePromise = fetcher.fetchReportAndUpdateBuilds(); >+ await MockSubprocess.waitForInvocation(); >+ >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); >+ await MockSubprocess.resetAndWaitForInvocation(); >+ >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16D69']); >+ invocations[0].resolve(JSON.stringify(ownedCommitWithWebKit)); >+ await MockSubprocess.resetAndWaitForInvocation(); >+ >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']); >+ invocations[0].resolve(JSON.stringify(resultsForSierraE)); >+ >+ await MockSubprocess.resetAndWaitForInvocation(); >+ >+ assert.equal(invocations.length, 1); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']); >+ invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKit)); >+ await MockSubprocess.resetAndWaitForInvocation(); >+ assert.equal(invocations.length, 1); >+ invocations[0].resolve(JSON.stringify(anotherownedCommitWithWebKitAndJavaScriptCore)); >+ assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E34']); >+ >+ await fetchReportAndUpdatePromise; >+ >+ const webkitRepository = await db.selectRows('repositories', {'name': 'WebKit'}); >+ const jscRepository = await db.selectRows('repositories', {'name': 'JavaScriptCore'}); >+ const osxCommit16D68 = await db.selectRows('commits', {'revision': 'Sierra16D68'}); >+ const osxCommit16D69 = await db.selectRows('commits', {'revision': 'Sierra16D69'}); >+ const osxCommit16E31 = await db.selectRows('commits', {'revision': 'Sierra16E31'}); >+ const osxCommit16E33h = await db.selectRows('commits', {'revision': 'Sierra16E33h'}); >+ const osxCommit16E34 = await db.selectRows('commits', {'revision': 'Sierra16E34'}); >+ >+ assert.equal(webkitRepository.length, 1); >+ assert.equal(webkitRepository[0]['owner'], 10); >+ assert.equal(jscRepository.length, 1); >+ assert.equal(jscRepository[0]['owner'], 10); >+ >+ assert.equal(osxCommit16D68.length, 1); >+ assert.equal(osxCommit16D68[0]['repository'], 10); >+ assert.equal(osxCommit16D68[0]['order'], 1603006800); >+ assert.equal(osxCommit16D68[0]['testability_warning'], "Panic"); >+ >+ assert.equal(osxCommit16D69.length, 1); >+ assert.equal(osxCommit16D69[0]['repository'], 10); >+ assert.equal(osxCommit16D69[0]['order'], 1603006900); >+ assert.equal(osxCommit16D69[0]['testability_warning'], "Spin CPU"); >+ >+ assert.equal(osxCommit16E31.length, 1); >+ assert.equal(osxCommit16E31[0]['repository'], 10); >+ assert.equal(osxCommit16E31[0]['order'], 1604003100); >+ assert.equal(osxCommit16E31[0]['testability_warning'], "WebKit crashes"); >+ >+ assert.equal(osxCommit16E33h.length, 1); >+ assert.equal(osxCommit16E33h[0]['repository'], 10); >+ assert.equal(osxCommit16E33h[0]['order'], 1604003308); >+ >+ assert.equal(osxCommit16E34.length, 1); >+ assert.equal(osxCommit16E34[0]['repository'], 10); >+ assert.equal(osxCommit16E34[0]['order'], 1604003400); >+ >+ result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1603000000&to=1603099900'); >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16D69'); >+ assert.equal(result['commits'][0]['order'], 1603006900); >+ >+ result = await TestServer.remoteAPI().getJSON('/api/commits/OSX/last-reported?from=1604000000&to=1604099900'); >+ assert.equal(result['commits'].length, 1); >+ assert.equal(result['commits'][0]['revision'], 'Sierra16E34'); >+ assert.equal(result['commits'][0]['order'], 1604003400); >+ }); >+ > it('should report commits without owned-commits if "ownedCommitCommand" is not specified in config', async () => { > > const logger = new MockLogger; > const fetcher = new OSBuildFetcher(configWithoutOwnedCommitCommand, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); > const db = TestServer.database(); >+ const resultsForSierraD = {allRevisions: ["Sierra16D68", "Sierra16D69"], commitsWithTestabilityWarnings: {}}; >+ const resultsForSierraE = {allRevisions: ["Sierra16E32", "Sierra16E33", "Sierra16E33h", "Sierra16E34"], commitsWithTestabilityWarnings: {}}; > > await addSlaveForReport(emptyReport); > await Promise.all([ >@@ -411,19 +669,18 @@ describe('OSBuildFetcher', function() { > assert.equal(result['commits'][0]['order'], 1604003307); > > const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >- const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds(); >+ const fetchReportAndUpdatePromise = fetcher.fetchReportAndUpdateBuilds(); > await waitForInvocationPromise; > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >- invocations[0].resolve('\n\nSierra16D68\nSierra16D69'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); > > await MockSubprocess.resetAndWaitForInvocation(); > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']); >- invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraE)); > >- result = await fetchAndReportPromise; >- assert.equal(result['status'], 'OK'); >+ result = await fetchReportAndUpdatePromise; > const results = await Promise.all([ > db.selectRows('repositories', {'name': 'WebKit'}), > db.selectRows('repositories', {'name': 'JavaScriptCore'}), >@@ -467,6 +724,8 @@ describe('OSBuildFetcher', function() { > const logger = new MockLogger; > const fetcher = new OSBuildFetcher(configWithoutOwnedCommitCommand, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); > const db = TestServer.database(); >+ const resultsForSierraD = {allRevisions: ["Sierra16D68", "Sierra16D69", "Sierra16D10000"], commitsWithTestabilityWarnings: {}}; >+ const resultsForSierraE = {allRevisions: ["Sierra16E32", "Sierra16E33", "Sierra16E33h", "Sierra16E34", "Sierra16E10000"], commitsWithTestabilityWarnings: {}}; > > await addSlaveForReport(emptyReport); > await Promise.all([ >@@ -488,20 +747,19 @@ describe('OSBuildFetcher', function() { > assert.equal(result['commits'][0]['revision'], 'Sierra16E33g'); > assert.equal(result['commits'][0]['order'], 1604003307); > const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >- const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds(); >+ const fetchReportAndUpdatePromise = fetcher.fetchReportAndUpdateBuilds(); > > await waitForInvocationPromise; > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >- invocations[0].resolve('\n\nSierra16D68\nSierra16D69\nSierra16D10000'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); > > await MockSubprocess.resetAndWaitForInvocation(); > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']); >- invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34\nSierra16E10000'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraE)); > >- result = await fetchAndReportPromise; >- assert.equal(result['status'], 'OK'); >+ result = await fetchReportAndUpdatePromise; > const results = await Promise.all([ > db.selectRows('repositories', {'name': 'WebKit'}), > db.selectRows('repositories', {'name': 'JavaScriptCore'}), >@@ -545,6 +803,7 @@ describe('OSBuildFetcher', function() { > const logger = new MockLogger; > const fetcher = new OSBuildFetcher(configTrackingOneOS, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); > const db = TestServer.database(); >+ const resultsForSierraD = {allRevisions: ["Sierra16D68", "Sierra16D69", "Sierra16D100", "Sierra16D100a"], commitsWithTestabilityWarnings: {}}; > > await addSlaveForReport(emptyReport); > await db.insert('repositories', {'id': 10, 'name': 'OSX'}); >@@ -556,14 +815,13 @@ describe('OSBuildFetcher', function() { > assert.equal(result['commits'][0]['order'], 1603010000); > > const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >- const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds(); >+ const fetchAndReportPromise = fetcher.fetchReportAndUpdateBuilds(); > await waitForInvocationPromise; > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >- invocations[0].resolve('\n\nSierra16D68\nSierra16D69\nSierra16D100\nSierra16D100a\n'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); > > result = await fetchAndReportPromise; >- assert.equal(result['status'], 'OK'); > const results = await Promise.all([ > db.selectRows('repositories', {'name': 'WebKit'}), > db.selectRows('repositories', {'name': 'JavaScriptCore'}), >@@ -594,6 +852,7 @@ describe('OSBuildFetcher', function() { > const logger = new MockLogger; > const fetcher = new OSBuildFetcher(configTrackingOneOS, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); > const db = TestServer.database(); >+ const resultsForSierraD = {allRevisions: ["Sierra16D68", "Sierra16D69", "Sierra16D100", "Sierra16D101"], commitsWithTestabilityWarnings: {}}; > > await addSlaveForReport(emptyReport); > await db.insert('repositories', {'id': 10, 'name': 'OSX'}); >@@ -602,14 +861,13 @@ describe('OSBuildFetcher', function() { > assert.equal(result['commits'].length, 0); > > const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >- const fetchAndReportPromise = fetcher.fetchAndReportNewBuilds(); >+ const fetchReportAndUpdatePromise = fetcher.fetchReportAndUpdateBuilds(); > await waitForInvocationPromise; > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >- invocations[0].resolve('\n\nSierra16D68\nSierra16D69\nSierra16D100\nSierra16D101\n'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); > >- result = await fetchAndReportPromise; >- assert.equal(result['status'], 'OK'); >+ result = await fetchReportAndUpdatePromise; > const results = await Promise.all([ > db.selectRows('repositories', {'name': 'WebKit'}), > db.selectRows('repositories', {'name': 'JavaScriptCore'}), >@@ -646,6 +904,8 @@ describe('OSBuildFetcher', function() { > const logger = new MockLogger; > const fetcher = new OSBuildFetcher(config, TestServer.remoteAPI(), slaveAuth, MockSubprocess, logger); > const db = TestServer.database(); >+ const resultsForSierraD = {allRevisions: ["Sierra16D68", "Sierra16D69"], commitsWithTestabilityWarnings: {}}; >+ const resultsForSierraE = {allRevisions: ["Sierra16E32", "Sierra16E33", "Sierra16E33h", "Sierra16E34"], commitsWithTestabilityWarnings: {}}; > let fetchAndReportPromise = null; > > return addSlaveForReport(emptyReport).then(() => { >@@ -671,12 +931,12 @@ describe('OSBuildFetcher', function() { > assert.equal(result['commits'][0]['order'], 1604003307); > > const waitForInvocationPromise = MockSubprocess.waitForInvocation(); >- fetchAndReportPromise = fetcher.fetchAndReportNewBuilds(); >+ fetchAndReportPromise = fetcher.fetchReportAndUpdateBuilds(); > return waitForInvocationPromise; > }).then(() => { > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Dxx builds']); >- invocations[0].resolve('\n\nSierra16D68\nSierra16D69\n'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraD)); > return MockSubprocess.resetAndWaitForInvocation(); > }).then(() => { > assert.equal(invocations.length, 1); >@@ -686,7 +946,7 @@ describe('OSBuildFetcher', function() { > }).then(() => { > assert.equal(invocations.length, 1); > assert.deepEqual(invocations[0].command, ['list', 'all osx 16Exx builds']); >- invocations[0].resolve('\n\nSierra16E32\nSierra16E33\nSierra16E33h\nSierra16E34'); >+ invocations[0].resolve(JSON.stringify(resultsForSierraE)); > return MockSubprocess.resetAndWaitForInvocation(); > }).then(() => { > assert.deepEqual(invocations[0].command, ['list', 'ownedCommit', 'for', 'revision', 'Sierra16E33h']); >diff --git a/Websites/perf.webkit.org/tools/js/os-build-fetcher.js b/Websites/perf.webkit.org/tools/js/os-build-fetcher.js >index 051c29fcb7b86336bf4172d55f7a4986d1714fe1..fb57892af506080fc2e403a0737b9d2697f86e20 100644 >--- a/Websites/perf.webkit.org/tools/js/os-build-fetcher.js >+++ b/Websites/perf.webkit.org/tools/js/os-build-fetcher.js >@@ -22,59 +22,56 @@ class OSBuildFetcher { > this._maxSubmitCount = osConfig['maxSubmitCount'] || 20; > } > >- static fetchAndReportAllInOrder(fetcherList) >+ static async fetchReportAndUpdateCommits(fetcherList) > { >- return mapInSerialPromiseChain(fetcherList, (fetcher) => fetcher.fetchAndReportNewBuilds()); >+ for (const fetcher of fetcherList) >+ await fetcher.fetchReportAndUpdateBuilds(); > } > >- fetchAndReportNewBuilds() >+ async fetchReportAndUpdateBuilds() > { >- return this._fetchAvailableBuilds().then((results) => { >- this._logger.log(`Submitting ${results.length} builds for ${this._osConfig['name']}`); >- if (results.length == 0) >- return this._submitCommits(results); >- >- const splittedResults = []; >- for (let startIndex = 0; startIndex < results.length; startIndex += this._maxSubmitCount) >- splittedResults.push(results.slice(startIndex, startIndex + this._maxSubmitCount)); >- >- return mapInSerialPromiseChain(splittedResults, this._submitCommits.bind(this)).then((responses) => { >- assert(responses.every((response) => response['status'] == 'OK')); >- assert(responses.length > 0); >- return responses[0]; >- }); >- }); >+ const {newCommitsToReport, commitsToUpdate} = await this._fetchAvailableBuilds(); >+ >+ this._logger.log(`Submitting ${newCommitsToReport.length} builds for ${this._osConfig['name']}`); >+ await this._reportToEndPoint('/api/report-commits/', newCommitsToReport); >+ >+ this._logger.log(`Updating ${commitsToUpdate.length} builds for ${this._osConfig['name']}`); >+ await this._reportToEndPoint('/api/update-commits/', commitsToUpdate); > } > >- _fetchAvailableBuilds() >+ async _fetchAvailableBuilds() > { > const config = this._osConfig; > const repositoryName = config['name']; >- let customCommands = config['customCommands']; >+ const newCommitsToReport = []; >+ const commitsToUpdate = []; >+ const customCommands = config['customCommands']; > >- return mapInSerialPromiseChain(customCommands, (command) => { >+ for (const command of customCommands) { > assert(command['minRevision']); > assert(command['maxRevision']); > const minRevisionOrder = this._computeOrder(command['minRevision']); > const maxRevisionOrder = this._computeOrder(command['maxRevision']); > > const url = `/api/commits/${escape(repositoryName)}/last-reported?from=${minRevisionOrder}&to=${maxRevisionOrder}`; >+ const result = await this._remoteAPI.getJSONWithStatus(url); >+ const minOrder = result['commits'].length == 1 ? parseInt(result['commits'][0]['order']) + 1 : minRevisionOrder; > >- return this._remoteAPI.getJSONWithStatus(url).then((result) => { >- const minOrder = result['commits'].length == 1 ? parseInt(result['commits'][0]['order']) + 1 : minRevisionOrder; >- return this._commitsForAvailableBuilds(repositoryName, command['command'], command['linesToIgnore'], minOrder, maxRevisionOrder); >- }).then((commits) => { >- const label = 'name' in command ? `"${command['name']}"` : `"${command['minRevision']}" to "${command['maxRevision']}"`; >- this._logger.log(`Found ${commits.length} builds for ${label}`); >+ const commitInfo = await this._commitsForAvailableBuilds(command['command'], command['linesToIgnore']); >+ const commits = this._commitsWithinRange(commitInfo.allRevisions, repositoryName, minOrder, maxRevisionOrder); > >- if ('ownedCommitCommand' in command) { >- this._logger.log(`Resolving ownedCommits for ${label}`); >- return this._addOwnedCommitsForBuild(commits, command['ownedCommitCommand']); >- } >+ const label = 'name' in command ? `"${command['name']}"` : `"${command['minRevision']}" to "${command['maxRevision']}"`; >+ this._logger.log(`Found ${commits.length} builds for ${label}`); >+ if ('ownedCommitCommand' in command) { >+ this._logger.log(`Resolving ownedCommits for ${label}`); >+ await this._addOwnedCommitsForBuild(commits, command['ownedCommitCommand']); >+ } >+ newCommitsToReport.push(...commits); > >- return commits; >- }); >- }).then((results) => [].concat(...results)); >+ for (const [revision, testabilityWarning] of Object.entries(commitInfo.commitsWithTestabilityWarnings)) >+ commitsToUpdate.push({repository: repositoryName, revision, testabilityWarning}); >+ } >+ return {newCommitsToReport, commitsToUpdate}; > } > > _computeOrder(revision) >@@ -89,17 +86,27 @@ class OSBuildFetcher { > return ((major * 100 + kind) * 10000 + minor) * 100 + variant; > } > >- _commitsForAvailableBuilds(repository, command, linesToIgnore, minOrder, maxOrder) >+ async _commitsForAvailableBuilds(command, linesToIgnore) > { >- return this._subprocess.execute(command).then((output) => { >+ const output = await this._subprocess.execute(command); >+ try { >+ return JSON.parse(output); >+ } catch (error) { >+ if (!(error instanceof SyntaxError)) >+ throw error; > let lines = output.split('\n'); >- if (linesToIgnore){ >+ if (linesToIgnore) { > const regex = new RegExp(linesToIgnore); > lines = lines.filter((line) => !regex.exec(line)); > } >- return lines.map((revision) => ({repository, revision, 'order': this._computeOrder(revision)})) >- .filter((commit) => commit['order'] >= minOrder && commit['order'] <= maxOrder); >- }); >+ return {allRevisions: lines, commitsWithTestabilityWarnings: {}}; >+ } >+ } >+ >+ _commitsWithinRange(revisions, repository, minOrder, maxOrder) >+ { >+ return revisions.map((revision) => ({repository, revision, 'order': this._computeOrder(revision)})) >+ .filter((commit) => commit['order'] >= minOrder && commit['order'] <= maxOrder); > } > > _addOwnedCommitsForBuild(commits, command) >@@ -119,10 +126,16 @@ class OSBuildFetcher { > }); > } > >- _submitCommits(commits) >+ async _reportToEndPoint(endPoint, commitsToPost) > { >- const commitsToReport = {"slaveName": this._slaveAuth['name'], "slavePassword": this._slaveAuth['password'], 'commits': commits}; >- return this._remoteAPI.postJSONWithStatus('/api/report-commits/', commitsToReport); >+ if (!commitsToPost.length) >+ return; >+ >+ for(let commitsToSubmit = commitsToPost.splice(0, this._maxSubmitCount); commitsToSubmit.length; commitsToSubmit = commitsToPost.splice(0, this._maxSubmitCount)) { >+ const report = {"slaveName": this._slaveAuth['name'], "slavePassword": this._slaveAuth['password'], 'commits': commitsToSubmit}; >+ const response = await this._remoteAPI.postJSONWithStatus(endPoint, report); >+ assert(response['status'] === 'OK'); >+ } > } > } > >diff --git a/Websites/perf.webkit.org/tools/sync-os-versions.js b/Websites/perf.webkit.org/tools/sync-os-versions.js >index 77f4a0a7d34381943076b83ec48d5bc90b483586..4fbe582bf0388da4a4b3a75307d2f16b62297c78 100644 >--- a/Websites/perf.webkit.org/tools/sync-os-versions.js >+++ b/Websites/perf.webkit.org/tools/sync-os-versions.js >@@ -29,7 +29,7 @@ function syncLoop(options) > const remoteAPI = new RemoteAPI(serverConfig.server); > > const fetchers = osConfigList.map((osConfig) => new OSBuildFetcher(osConfig, remoteAPI, serverConfig.slave, new Subprocess, console)); >- OSBuildFetcher.fetchAndReportAllInOrder(fetchers).catch((error) => { >+ OSBuildFetcher.fetchReportAndUpdateCommits(fetchers).catch((error) => { > console.error(error); > if (typeof(error.stack) == 'string') { > for (let line of error.stack.split('\n')) >diff --git a/Websites/perf.webkit.org/unit-tests/commit-log-tests.js b/Websites/perf.webkit.org/unit-tests/commit-log-tests.js >index 5f8852492060eea6f3305bbc0f54eb60c010b2a3..9c6edf917d6414def71c8e6bd8a14ca531fecc1b 100644 >--- a/Websites/perf.webkit.org/unit-tests/commit-log-tests.js >+++ b/Websites/perf.webkit.org/unit-tests/commit-log-tests.js >@@ -58,6 +58,18 @@ function osxCommit() > }); > } > >+function osxCommitWithTestabilityWarning() >+{ >+ return new CommitLog(5, { >+ id: 5, >+ repository: MockModels.osx, >+ revision: '10.11.4 15E65', >+ time: null, >+ order: 1504065, >+ testabilityWarning: "Panic on boot" >+ }); >+} >+ > function oldOSXCommit() > { > return new CommitLog(6, { >@@ -417,6 +429,13 @@ describe('CommitLog', function () { > }); > }); > >+ describe('testabilityWarning', () => { >+ it('should return "testabilityWarning" message', () => { >+ const commit = osxCommitWithTestabilityWarning(); >+ assert.equal(commit.testabilityWarning(), 'Panic on boot'); >+ }); >+ }); >+ > const commitsAPIResponse = { > "commits":[{ > "id": "831151", >diff --git a/Websites/perf.webkit.org/unit-tests/commit-set-tests.js b/Websites/perf.webkit.org/unit-tests/commit-set-tests.js >index 39fccc54759f879f1ce0383b0a9b2ce7fc5b9a49..ba6c107d089aec195cb2e9a1a80c9fc258905e32 100644 >--- a/Websites/perf.webkit.org/unit-tests/commit-set-tests.js >+++ b/Websites/perf.webkit.org/unit-tests/commit-set-tests.js >@@ -170,6 +170,18 @@ function anotherCommitWithGitRevision() > }); > } > >+function commitWithTestabilityWarning() >+{ >+ return CommitLog.ensureSingleton(2023, { >+ id: 2023, >+ repository: MockModels.webkitGit, >+ revision: 'f24fc67873a0068fd5a3a9adac595f0036c21315', >+ ownsCommits: false, >+ time: 1456932773000, >+ testabilityWarning: 'Failed compilation' >+ }); >+} >+ > describe('CommitSet', () => { > MockRemoteAPI.inject(null, BrowserPrivilegedAPI); > MockModels.inject(); >@@ -294,6 +306,15 @@ describe('CommitSet', () => { > }); > } > >+ function commitSetWithTestabilityWarning() >+ { >+ return CommitSet.ensureSingleton(16, { >+ revisionItems: [{ commit: commitWithTestabilityWarning(), requiresBuild: false }, >+ { commit: webkitCommit(), requiresBuild: false }], >+ customRoots: [] >+ }); >+ } >+ > function oneMeasurementCommitSet() > { > return MeasurementCommitSet.ensureSingleton(1, [ >@@ -406,6 +427,25 @@ describe('CommitSet', () => { > {'11': { revision: 'webkit-commit-0', ownerRevision: null, patch: null}, customRoots: [456, 458]}]); > }); > }); >+ >+ describe('commitsWithTestabilityWarnings', () => { >+ it('should return commits with testability warning', () => { >+ const commits = commitSetWithTestabilityWarning().commitsWithTestabilityWarnings(); >+ assert.equal(commits.length, 1); >+ assert.equal(commits[0], commitWithTestabilityWarning()); >+ }); >+ >+ it('should return empty list if no commit in commit set contains testablity warning', () => { >+ const commits = commitSetWithTwoCommits().commitsWithTestabilityWarnings(); >+ assert.equal(commits.length, 0); >+ }); >+ }); >+ >+ describe('commits', () => { >+ it('should return all commits in commit set', () => { >+ assert.equal(commitSetWithTwoCommits().commits().length, 2); >+ }); >+ }); > }); > > describe('IntermediateCommitSet', () => { >@@ -629,9 +669,7 @@ describe('IntermediateCommitSet', () => { > assert(!commitSet.commitForRepository(MockModels.webkit)); > }); > }); >- > }); >- > }); > > describe('CustomCommitSet', () => {
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 191557
:
354587
|
357273
|
357308
|
357486
|
357656
|
357803