def test_new_wpt_pr(env, git_gecko, git_wpt, pull_request, set_pr_status, mock_mach, mock_wpt): pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") mock_mach.set_data( "file-info", """Testing :: web-platform-tests testing/web-platform/tests/README """) mock_wpt.set_data("files-changed", "README\n") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = load.get_pr_sync(git_gecko, git_wpt, pr["number"]) env.gh_wpt.set_status(pr["number"], "success", "http://test/", "description", "continuous-integration/travis-ci/pr") assert sync is not None assert sync.status == "open" assert len(sync.gecko_commits) == 1 assert len(sync.wpt_commits) == 1 assert sync.gecko_commits[0].metadata == { "wpt-pr": str(pr["number"]), "wpt-commit": pr["head"] } assert "Creating a bug in component Testing :: web-platform" in env.bz.output.getvalue( )
def test_metadata_update(env, git_gecko, git_wpt, pull_request, pull_request_commit): from conftest import gecko_changes, git_commit pr = pull_request([("Test commit", {"README": "Example change\n"})], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = load.get_pr_sync(git_gecko, git_wpt, pr["number"]) assert len(sync.gecko_commits) == 1 with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): gecko_work = sync.gecko_worktree.get() changes = gecko_changes(env, meta_changes={"example.ini": "Example change"}) git_commit(gecko_work, """Update metadata wpt-pr: %s wpt-type: metadata """ % pr.number, changes) assert len(sync.gecko_commits) == 2 assert sync.gecko_commits[-1].metadata.get("wpt-type") == "metadata" metadata_commit = sync.gecko_commits[-1] head_sha = pull_request_commit(pr.number, [("fixup! Test commit", {"README": "Example change 1\n"})]) downstream.update_repositories(git_gecko, git_wpt) sync.update_commits() assert len(sync.gecko_commits) == 3 assert sync.gecko_commits[-1].metadata.get("wpt-type") == "metadata" assert sync.gecko_commits[-1].msg == metadata_commit.msg assert sync.gecko_commits[-2].metadata.get("wpt-commit") == head_sha
def test_revert_pr(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, pull_request_fn, set_pr_status, wpt_worktree): pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = load.get_pr_sync(git_gecko, git_wpt, pr["number"]) commit = sync.wpt_commits[0] sync.wpt_commits.base = sync.data[ "wpt-base"] = git_wpt_upstream.head.commit.hexsha git_wpt_upstream.git.merge(commit.sha1) def revert_fn(): git_wpt.remotes["origin"].fetch() wpt_work = wpt_worktree() wpt_work.git.revert(commit.sha1, no_edit=True) wpt_work.git.push("origin", "HEAD:refs/heads/revert") git_wpt_upstream.commit("revert") return "revert" pr_revert = pull_request_fn(revert_fn, title="Revert Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr_revert) sync_revert = load.get_pr_sync(git_gecko, git_wpt, pr_revert["number"]) # Refresh the instance data sync.data._load() assert sync.skip assert sync_revert.skip
def test_dependent_commit(env, git_gecko, git_wpt, pull_request, upstream_wpt_commit, pull_request_commit): upstream_wpt_commit("First change", {"README": "Example change\n"}) pr = pull_request([("Test change", { "README": "Example change 1\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = load.get_pr_sync(git_gecko, git_wpt, pr["number"]) assert len(sync.gecko_commits) == 2 assert sync.gecko_commits[0].msg.splitlines()[0] == "First change" assert sync.gecko_commits[0].metadata["wpt-type"] == "dependency" assert sync.gecko_commits[1].metadata.get("wpt-type") is None assert "Test change" in sync.gecko_commits[1].msg.splitlines()[0] old_gecko_commits = sync.gecko_commits[:] # Check that rerunning doesn't affect anything sync.update_commits() assert [item.sha1 for item in sync.gecko_commits ] == [item.sha1 for item in old_gecko_commits] head_sha = pull_request_commit(pr.number, [("fixup! Test change", { "README": "Example change 2\n" })]) downstream.update_repositories(git_gecko, git_wpt) sync.update_commits() assert len(sync.gecko_commits) == 3 assert ([item.sha1 for item in sync.gecko_commits[:2] ] == [item.sha1 for item in old_gecko_commits]) assert sync.gecko_commits[-1].metadata["wpt-commit"] == head_sha
def test_relanding_unchanged_upstreamed_pr(env, git_gecko, git_wpt, hg_gecko_upstream, pull_request, upstream_gecko_commit, mock_mach, set_pr_status, git_wpt_upstream): trypush.Mach = mock_mach # Create an unrelated PR that didn't come from Gecko pr0 = pull_request([(b"Non Gecko PR", {"SOMEFILE": b"Made changes"})]) unrelated_rev = pr0._commits[0]["sha"] downstream.new_wpt_pr(git_gecko, git_wpt, pr0) downstream_sync = set_pr_status(pr0.number, 'success') git_wpt_upstream.head.commit = unrelated_rev git_wpt.remotes.origin.fetch() sync = create_and_upstream_gecko_bug(env, git_gecko, git_wpt, hg_gecko_upstream, upstream_gecko_commit) # 'Merge' this upstream PR pr = env.gh_wpt.get_pull(sync.pr) pr["user"]["login"] = "******" with SyncLock.for_process(sync.process_name) as upstream_sync_lock: with sync.as_mut(upstream_sync_lock): sync.push_commits() assert str(git_wpt_upstream.active_branch) == "master" git_wpt_upstream.git.merge('gecko/1234') # TODO avoid hardcoding? # Create a ref on the upstream to simulate the pr than GH would setup git_wpt_upstream.create_head( 'pr/%d' % pr['number'], commit=git_wpt_upstream.refs['gecko/1234'].commit.hexsha) git_wpt.remotes.origin.fetch() pr['merge_commit_sha'] = str(git_wpt_upstream.active_branch.commit.hexsha) pr['base'] = {'sha': unrelated_rev} env.gh_wpt.commit_prs[pr['merge_commit_sha']] = pr['number'] # Update landing, the Non Gecko PR should be applied but not the Gecko one we upstreamed def mock_create(repo, msg, metadata, author=None, amend=False, allow_empty=False): # This commit should not be making it this far, should've been dropped earlier assert b'Bug 1234 [wpt PR 2] - [Gecko Bug 1234]' not in msg return DEFAULT m = Mock(side_effect=mock_create, wraps=sync_commit.Commit.create) with patch('sync.commit.Commit.create', m): landing_sync = landing.update_landing(git_gecko, git_wpt, include_incomplete=True) commits = landing_sync.gecko_commits._commits # Check that the upstreamed gecko PR didnt get pushed to try assert not any([c.bug == sync.bug for c in commits]) # Check that our unrelated PR got pushed to try assert any([c.bug == downstream_sync.bug for c in commits])
def test_landing_pr_on_central(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, upstream_gecko_commit, mock_mach): # Ensure we handle the case where a PR already identical changes on central trypush.Mach = mock_mach test_changes = {"example/test.html": b"Change test\n"} more_changes = {"LICENSE": b"Change license\n"} for changes in [test_changes, more_changes]: pr = pull_request([(b"Test commit", changes)]) downstream.new_wpt_pr(git_gecko, git_wpt, pr) downstream_sync = set_pr_status(pr.number, "success") head_rev = pr._commits[0]["sha"] git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) with SyncLock.for_process(downstream_sync.process_name) as downstream_lock: with downstream_sync.as_mut(downstream_lock): downstream_sync.data["force-metadata-ready"] = True # Repeat the changes in m-c upstream_gecko_commit(test_changes=test_changes, bug=1234, message=b"Change README") tree.is_open = lambda x: True sync = landing.update_landing(git_gecko, git_wpt) assert len(sync.wpt_commits) == 2 assert len(sync.gecko_commits) == 3 assert sync.gecko_commits[0].is_empty() assert sync.gecko_commits[-1].is_landing
def try_push(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_try, mock_mach): pr = pull_request([(b"Test commit", {"README": b"example_change", "LICENSE": b"Some change"})]) head_rev = pr._commits[0]["sha"] trypush.Mach = mock_mach with patch("sync.tree.is_open", Mock(return_value=True)): downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr.number, "success") with SyncLock.for_process(sync.process_name) as sync_lock: git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) with sync.as_mut(sync_lock): env.gh_wpt.get_pull(sync.pr).merged = True sync.data["affected-tests"] = {"Example": "affected"} sync.next_try_push() sync.data["force-metadata-ready"] = True try_push = sync.latest_try_push with try_push.as_mut(sync_lock): try_push.taskgroup_id = "abcdef" return sync.latest_try_push
def test_land_commit(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_try, mock_mach, mock_tasks): pr = pull_request([(b"Test commit", {"README": b"example_change"})]) head_rev = pr._commits[0]["sha"] trypush.Mach = mock_mach downstream.new_wpt_pr(git_gecko, git_wpt, pr) downstream_sync = set_pr_status(pr.number, "success") git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) with SyncLock.for_process(downstream_sync.process_name) as downstream_lock: with downstream_sync.as_mut(downstream_lock): downstream_sync.data["force-metadata-ready"] = True tree.is_open = lambda x: True sync = landing.update_landing(git_gecko, git_wpt) assert ("Setting bug %s add_blocks %s" % (sync.bug, downstream_sync.bug) in env.bz.output.getvalue()) try_push = sync.latest_try_push with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock), try_push.as_mut(lock): try_push.taskgroup_id = "abcdef" with patch.object(try_push, "download_logs", Mock(return_value=[])): with patch.object(tc.TaskGroup, "tasks", property(Mock(return_value=mock_tasks(completed=["foo"])))): landing.try_push_complete(git_gecko, git_wpt, try_push, sync) assert "Pushed to try (stability)" in env.bz.output.getvalue() assert try_push.status == "complete" assert sync.status == "open" try_push = sync.latest_try_push with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock), try_push.as_mut(lock): try_push.taskgroup_id = "abcdef2" with patch.object(try_push, "download_logs", Mock(return_value=[])): with patch.object(tc.TaskGroup, "tasks", property(Mock(return_value=mock_tasks(completed=["foo"])))): landing.try_push_complete(git_gecko, git_wpt, try_push, sync) new_head = git_gecko.remotes.mozilla.refs["bookmarks/mozilla/autoland"].commit assert "Update web-platform-tests to %s" % head_rev in new_head.message assert (new_head.tree["testing/web-platform/tests/README"].data_stream.read() == b"example_change") sync_point = landing.load_sync_point(git_gecko, git_wpt) assert sync_point["upstream"] == head_rev # Update central to contain the landing git_gecko.refs["mozilla/bookmarks/mozilla/central"].commit = new_head with patch("sync.landing.start_next_landing") as start_next_landing: landing.gecko_push(git_gecko, git_wpt, "mozilla-central", git_gecko.cinnabar.git2hg(new_head)) assert start_next_landing.call_count == 1 assert sync.status == "complete"
def test_downstream_move(git_gecko, git_wpt, pull_request, set_pr_status, hg_gecko_try, local_gecko_commit, sample_gecko_metadata, initial_wpt_content, mock_mach): local_gecko_commit(message="Add wpt metadata", meta_changes=sample_gecko_metadata) pr = pull_request([("Test commit", {"example/test.html": None, "example/test1.html": initial_wpt_content["example/test.html"]})], "Test PR") with patch("sync.tree.is_open", Mock(return_value=True)), patch("sync.trypush.Mach", mock_mach): downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") assert sync.gecko_commits[-1].metadata["wpt-type"] == "metadata"
def test_wpt_pr_status_success(git_gecko, git_wpt, pull_request, set_pr_status, hg_gecko_try, mock_wpt, mock_mach): with patch("sync.trypush.Mach", mock_mach): mock_wpt.set_data("tests-affected", "") pr = pull_request([("Test commit", {"README": "Example change\n"})], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) with patch("sync.tree.is_open", Mock(return_value=True)): sync = set_pr_status(pr, "success") try_push = sync.latest_try_push assert sync.last_pr_check == {"state": "success", "sha": pr.head} assert try_push is None # No Try push for the status check passing.
def test_downstream_move(git_gecko, git_wpt, pull_request, set_pr_status, hg_gecko_try, local_gecko_commit, sample_gecko_metadata, initial_wpt_content): local_gecko_commit(message="Add wpt metadata", meta_changes=sample_gecko_metadata) pr = pull_request( [("Test commit", { "example/test.html": None, "example/test1.html": initial_wpt_content["example/test.html"] })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") assert sync.gecko_commits[-1].metadata["wpt-type"] == "metadata"
def test_next_try_push(git_gecko, git_wpt, pull_request, set_pr_status, MockTryCls, hg_gecko_try, pull_request_commit): pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") assert sync.next_try_push() is None assert sync.metadata_ready is False # No affected tests and one try push, means we should be ready sync.data["affected-tests"] = [] assert sync.requires_try assert not sync.requires_stability_try try_push = trypush.TryPush.create(sync, try_cls=MockTryCls) try_push.status = "complete" assert try_push.wpt_head == sync.wpt_commits.head.sha1 assert sync.metadata_ready assert sync.next_try_push() is None sync.data["affected-tests"] = ["example"] assert sync.requires_stability_try assert not sync.metadata_ready new_try_push = sync.next_try_push(try_cls=MockTryCls) assert new_try_push is not None assert new_try_push.stability assert not sync.metadata_ready new_try_push.status = "complete" assert sync.metadata_ready assert not sync.next_try_push() pull_request_commit(pr.number, [("Second test commit", { "README": "Another change\n" })]) git_wpt.remotes.origin.fetch() sync.update_commits() assert sync.latest_try_push is not None assert sync.latest_valid_try_push is None assert not sync.metadata_ready updated_try_push = sync.next_try_push(try_cls=MockTryCls) assert not updated_try_push.stability
def test_land_try(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_try, mock_mach): pr = pull_request([(b"Test commit", { "README": b"example_change", "resources/testdriver_vendor.js": b"Some change" })]) head_rev = pr._commits[0]["sha"] trypush.Mach = mock_mach downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr.number, "success") git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) with SyncLock.for_process(sync.process_name) as downstream_lock: with sync.as_mut(downstream_lock): sync.data["force-metadata-ready"] = True tree.is_open = lambda x: True landing_sync = landing.update_landing(git_gecko, git_wpt) assert landing_sync is not None with SyncLock("landing", None) as lock: with landing_sync.as_mut(lock): worktree = landing_sync.gecko_worktree.get() # Check that files we shouldn't move aren't assert not os.path.exists( os.path.join(worktree.working_dir, env.config["gecko"]["path"]["wpt"], ".git")) with open( os.path.join(worktree.working_dir, env.config["gecko"]["path"]["wpt"], "resources/testdriver_vendor.js"), "rb") as f: assert f.read() == b"Initial testdriver_vendor\n" try_push = sync.latest_try_push assert try_push is None mach_command = mock_mach.get_log()[-1] assert mach_command["command"] == "mach" assert mach_command["args"] == ("try", "fuzzy", "-q", "web-platform-tests !ccov !shippable", "-q", "web-platform-tests linux-32 shippable", "-q", "web-platform-tests mac !debug shippable", "--disable-target-task-filter", "--artifact")
def test_wpt_pr_status_success(git_gecko, git_wpt, pull_request, set_pr_status, hg_gecko_try, mock_wpt): mock_wpt.set_data("tests-affected", "") pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") try_push = sync.latest_try_push assert sync.last_pr_check == {"state": "success", "sha": pr.head} assert try_push is not None assert try_push.status == "open" assert try_push.try_rev == hg_gecko_try.log("-l1", "--template={node}") assert try_push.stability is False
def test_next_try_push_infra_fail(env, git_gecko, git_wpt, pull_request, set_pr_status, MockTryCls, hg_gecko_try, mock_mach, mock_taskgroup): taskgroup = mock_taskgroup("taskgroup-complete-build-failed.json") try_tasks = trypush.TryPushTasks(taskgroup) pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) try_patch = patch("sync.trypush.TryPush.tasks", Mock(return_value=try_tasks)) tree_open_patch = patch("sync.tree.is_open", Mock(return_value=True)) taskgroup_patch = patch("sync.tc.TaskGroup", Mock(return_value=taskgroup)) mach_patch = patch("sync.trypush.Mach", mock_mach) with tree_open_patch, try_patch, taskgroup_patch, mach_patch: sync = set_pr_status(pr, "success") env.gh_wpt.get_pull(sync.pr).merged = True with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): assert len(sync.try_pushes()) == 0 sync.data["affected-tests"] = {"testharness": ["example"]} try_push = sync.next_try_push(try_cls=MockTryCls) with try_push.as_mut(lock): try_push["taskgroup-id"] = taskgroup.taskgroup_id try_push.status = "complete" try_push.infra_fail = True # This try push still has completed builds and tests, so we say metadata is ready. assert sync.next_action == downstream.DownstreamAction.ready assert sync.next_try_push(try_cls=MockTryCls) is None # There should be a comment to flag failed builds msg = "There were infrastructure failures for the Try push (%s):\nbuild-win32/opt\nbuild-win32/debug\nbuild-win64/opt\nbuild-win64/debug\n" % try_push.treeherder_url # noqa: E501 assert msg in env.bz.output.getvalue() # Replace the taskgroup with one where there were no completed tests taskgroup = mock_taskgroup( "taskgroup-no-tests-build-failed.json") try_tasks = trypush.TryPushTasks(taskgroup) # The next action should flag for manual fix now assert sync.next_action == downstream.DownstreamAction.manual_fix
def test_land_commit(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_try, mock_mach, mock_tasks): pr = pull_request([("Test commit", {"README": "example_change"})]) head_rev = pr._commits[0]["sha"] trypush.Mach = mock_mach downstream.new_wpt_pr(git_gecko, git_wpt, pr) downstream_sync = set_pr_status(pr, "success") git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) downstream_sync.data["force-metadata-ready"] = True tree.is_open = lambda x: True sync = landing.update_landing(git_gecko, git_wpt) # Set the landing sync point to current central sync.last_sync_point(git_gecko, "mozilla-central", env.config["gecko"]["refs"]["central"]) try_push = sync.latest_try_push try_push.taskgroup_id = "abcdef" with patch.object(try_push, "download_logs", Mock(return_value=[])): with patch.object( tc.TaskGroup, "tasks", property(Mock(return_value=mock_tasks(completed=["foo"])))): landing.try_push_complete(git_gecko, git_wpt, try_push, sync) assert sync.status == "open" new_head = git_gecko.remotes.mozilla.refs[ "bookmarks/mozilla/inbound"].commit assert "Update web-platform-tests to %s" % head_rev in new_head.message assert new_head.tree["testing/web-platform/tests/README"].data_stream.read( ) == "example_change" sync_point = landing.load_sync_point(git_gecko, git_wpt) assert sync_point["local"] == new_head.parents[0].hexsha assert sync_point["upstream"] == head_rev # Update central to contain the landing git_gecko.refs["mozilla/bookmarks/mozilla/central"].commit = new_head with patch("sync.landing.tasks.land.apply_async") as mock_apply: landing.gecko_push(git_gecko, git_wpt, "mozilla-central", git_gecko.cinnabar.git2hg(new_head)) assert mock_apply.call_count == 1 assert sync.status == "complete"
def test_github_label_on_error(env, git_gecko, git_wpt, pull_request): pr = pull_request([("Testing", {"README": "Example change\n"})], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = load.get_pr_sync(git_gecko, git_wpt, pr["number"]) with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): sync.error = "Infrastructure Failed" assert env.gh_wpt.get_pull( pr["number"])["labels"] == ["mozilla:gecko-blocked"] with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): sync.update_commits() assert env.gh_wpt.get_pull(pr["number"])["labels"] == []
def test_landing_metadata(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_try, mock_mach): from conftest import create_file_data, gecko_changes trypush.Mach = mock_mach pr = pull_request([("Test commit", { "example/test1.html": "example_change" })]) head_rev = pr._commits[0]["sha"] downstream.new_wpt_pr(git_gecko, git_wpt, pr) downstream_sync = set_pr_status(pr, "success") # Create a metadata commit with SyncLock.for_process(downstream_sync.process_name) as downstream_lock: with downstream_sync.as_mut(downstream_lock): git_work = downstream_sync.gecko_worktree.get() changes = gecko_changes(env, meta_changes={ "example/test1.html": "[test1.html]\n expected: FAIL" }) file_data, _ = create_file_data(changes, git_work.working_dir) downstream_sync.ensure_metadata_commit() git_work.index.add(file_data) downstream_sync._commit_metadata() assert downstream_sync.metadata_commit is not None downstream_sync.data["force-metadata-ready"] = True git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) tree.is_open = lambda x: True landing_sync = landing.update_landing(git_gecko, git_wpt) assert len(landing_sync.gecko_commits) == 3 assert landing_sync.gecko_commits[-1].metadata["wpt-type"] == "landing" assert landing_sync.gecko_commits[-2].metadata["wpt-type"] == "metadata" for item in file_data: assert item in landing_sync.gecko_commits[-2].commit.stats.files
def test_wpt_pr_approved(env, git_gecko, git_wpt, pull_request, set_pr_status, hg_gecko_try, mock_wpt, mock_tasks, mock_mach): mock_wpt.set_data("tests-affected", "") pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") pr._approved = False with patch("sync.tree.is_open", Mock(return_value=True)), patch("sync.trypush.Mach", mock_mach): downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): sync.data["affected-tests"] = {"testharness": ["example"]} assert sync.latest_try_push is None assert sync.last_pr_check == {"state": "success", "sha": pr.head} pr._approved = True # A Try push is not run after approval. assert sync.latest_try_push is None # If we 'merge' the PR, then we will see a stability try push handlers.handle_pr( git_gecko, git_wpt, { "action": "closed", "number": pr.number, "pull_request": { "number": pr.number, "merge_commit_sha": "a" * 25, "base": { "sha": "b" * 25 }, "merged": True, "state": "closed", "merged_by": { "login": "******" } } }) try_push = sync.latest_try_push assert try_push.stability
def test_try_push_expiration(git_gecko, git_wpt, pull_request, set_pr_status, MockTryCls, hg_gecko_try): pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") today = datetime.today().date() downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") try_push = sync.latest_valid_try_push created_date = datetime.strptime(try_push.created, tc._DATE_FMT) assert today == created_date.date() assert not try_push.expired() try_push.created = taskcluster.fromNowJSON("-15 days") assert try_push.expired() try_push.created = None with patch("sync.trypush.tc.get_task", return_value={"created": taskcluster.fromNowJSON("-5 days")}): assert not try_push.expired()
def test_update_metadata(env, git_gecko, git_wpt, pull_request, git_wpt_metadata, mock_mach): results_obj = fx_only_failure() pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = load.get_pr_sync(git_gecko, git_wpt, pr["number"]) mock_mach.set_data( "wpt-test-paths", json.dumps(bugs.fallback_test_ids_to_paths(["/test/test.html"]))) with patch( "sync.notify.bugs.components_for_wpt_paths", return_value={"Testing :: web-platform-tests": ["test/test.html"]}): with patch("sync.notify.bugs.Mach", return_value=mock_mach(None)): with patch("sync.meta.Metadata.github") as mock_github: with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): bug_data = bugs.for_sync(sync, results_obj) bugs.update_metadata(sync, bug_data) assert mock_github.create_pull.called head = mock_github.method_calls[0].args[-1] bugs_filed = bug_data.keys() assert len(bugs_filed) == 1 bug = bugs_filed[0] metadata = meta.Metadata(sync.process_name, branch=head) links = list(metadata.iterbugs("/test/test.html")) assert len(links) == 1 link = links[0] assert link.url == "%s/show_bug.cgi?id=%s" % (env.bz.bz_url, bug) assert link.test_id == "/test/test.html" assert link.product == "firefox" assert link.subtest is None assert link.status is None
def test_gecko_rebase(env, git_gecko, git_wpt, pull_request): pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = load.get_pr_sync(git_gecko, git_wpt, pr["number"]) assert len(sync.gecko_commits) == 1 with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): assert sync.data[ "gecko-base"] == downstream.DownstreamSync.gecko_landing_branch( ) sync.gecko_rebase( downstream.DownstreamSync.gecko_integration_branch()) assert sync.data[ "gecko-base"] == downstream.DownstreamSync.gecko_integration_branch( )
def test_land_try(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_try, mock_mach): pr = pull_request([("Test commit", { "README": "example_change", "LICENSE": "Some change" })]) head_rev = pr._commits[0]["sha"] trypush.Mach = mock_mach downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) sync.data["force-metadata-ready"] = True tree.is_open = lambda x: True landing_sync = landing.update_landing(git_gecko, git_wpt) assert landing_sync is not None worktree = landing_sync.gecko_worktree.get() # Check that files we shouldn't move aren't assert not os.path.exists( os.path.join(worktree.working_dir, env.config["gecko"]["path"]["wpt"], ".git")) with open( os.path.join(worktree.working_dir, env.config["gecko"]["path"]["wpt"], "LICENSE")) as f: assert f.read() == "Initial license\n" try_push = sync.latest_try_push assert try_push is not None assert try_push.status == "open" assert try_push.stability is False mach_command = mock_mach.get_log()[-1] assert mach_command["command"] == "mach" assert mach_command["args"] == ("try", "fuzzy", "-q", "web-platform-tests !pgo !ccov !msvc", "--artifact")
def test_next_try_push(git_gecko, git_wpt, pull_request, set_pr_status, MockTryCls, hg_gecko_try, pull_request_commit, mock_mach): pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) with patch("sync.tree.is_open", Mock(return_value=True)), patch("sync.trypush.Mach", mock_mach): sync = set_pr_status(pr, "success") with SyncLock.for_process(sync.process_name) as lock: with sync.as_mut(lock): assert sync.next_try_push() is None assert sync.metadata_ready is False # No affected tests and one try push, means we should be ready sync.data["affected-tests"] = {} assert sync.requires_try assert not sync.requires_stability_try sync.data["affected-tests"] = {"testharness": ["example"]} assert sync.requires_stability_try assert not sync.metadata_ready # The PR has not yet been merged, so no Try push should happen assert sync.next_try_push() is None pr.merged = True new_try_push = sync.next_try_push(try_cls=MockTryCls) assert new_try_push is not None assert new_try_push.stability assert not sync.metadata_ready with new_try_push.as_mut(lock): new_try_push.status = "complete" assert sync.metadata_ready assert not sync.next_try_push()
def try_push(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_try, mock_mach): pr = pull_request([("Test commit", { "README": "example_change", "LICENSE": "Some change" })]) head_rev = pr._commits[0]["sha"] trypush.Mach = mock_mach downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) sync.data["force-metadata-ready"] = True tree.is_open = lambda x: True sync.latest_try_push.taskgroup_id = "abcdef" return sync.latest_try_push
def test_wpt_pr_approved(git_gecko, git_wpt, pull_request, set_pr_status, hg_gecko_try, mock_wpt, mock_tasks): mock_wpt.set_data("tests-affected", "") pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") pr._approved = False tree.is_open = lambda x: True downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") sync.data["affected-tests"] = ["example"] try_push = sync.latest_try_push try_push.taskgroup_id = "abcdef" assert sync.last_pr_check == {"state": "success", "sha": pr.head} try_push.success = lambda: True tasks = Mock(return_value=mock_tasks(completed=["foo", "bar"] * 5)) with patch.object(tc.TaskGroup, 'tasks', property(tasks)): downstream.try_push_complete(git_gecko, git_wpt, try_push, sync) assert try_push.status == "complete" assert sync.latest_try_push == try_push pr._approved = True handlers.handle_pull_request_review( git_gecko, git_wpt, { "action": "submitted", "review": { "state": "approved" }, "pull_request": { "number": pr.number } }) assert sync.latest_try_push != try_push assert sync.latest_try_push.stability
def test_landable_skipped(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, mock_mach): prev_wpt_head = git_wpt_upstream.head.commit pr = pull_request([(b"Test commit", {"README": b"example_change"})]) head_rev = pr._commits[0]["sha"] trypush.Mach = mock_mach downstream.new_wpt_pr(git_gecko, git_wpt, pr) downstream_sync = set_pr_status(pr.number, "success") with SyncLock.for_process(downstream_sync.process_name) as downstream_lock: with downstream_sync.as_mut(downstream_lock): downstream_sync.skip = True git_wpt_upstream.head.commit = head_rev git_wpt.remotes.origin.fetch() landing.wpt_push(git_gecko, git_wpt, [head_rev], create_missing=False) wpt_head, landable_commits = landing.landable_commits(git_gecko, git_wpt, prev_wpt_head.hexsha) assert len(landable_commits) == 1 assert landable_commits[0][0] == pr.number assert landable_commits[0][1] == downstream_sync
def test_next_try_push_infra_fail(git_gecko, git_wpt, pull_request, set_pr_status, MockTryCls, hg_gecko_try): pr = pull_request([("Test commit", { "README": "Example change\n" })], "Test PR") downstream.new_wpt_pr(git_gecko, git_wpt, pr) sync = set_pr_status(pr, "success") assert len(sync.try_pushes()) == 1 # no stability try push needed sync.data["affected-tests"] = [] try_push = sync.latest_valid_try_push try_push.status = "complete" try_push.infra_fail = True for i in range(4): another_try_push = sync.next_try_push(try_cls=MockTryCls) assert not sync.metadata_ready assert another_try_push is not None another_try_push.infra_fail = True another_try_push.status = "complete" assert len(sync.latest_busted_try_pushes()) == 5 another_try_push.infra_fail = False # Now most recent try push isn't busted, so count goes back to 0 assert len(sync.latest_busted_try_pushes()) == 0 # Reset back to 5 another_try_push.infra_fail = True # After sixth consecutive infra_failure, we should get sync error another_try_push = sync.next_try_push(try_cls=MockTryCls) another_try_push.infra_fail = True another_try_push.status = "complete" another_try_push = sync.next_try_push(try_cls=MockTryCls) assert another_try_push is None assert sync.next_action == downstream.DownstreamAction.manual_fix
def test_landing_reapply(env, git_gecko, git_wpt, git_wpt_upstream, pull_request, set_pr_status, hg_gecko_upstream, upstream_gecko_commit, upstream_wpt_commit, hg_gecko_try, mock_mach, mock_tasks): # Test that we reapply the correct commits when landing patches on upstream # First we need to create 3 gecko commits: # Two that are landed # One that is still a PR # Then we create a landing that points at the first gecko commit that is landed # upstream. Locally we expect the code to reapply the two other gecko commits, so # we should end up with no overall change. trypush.Mach = mock_mach # Add first gecko change test_changes = {"change1": b"CHANGE1\n"} rev = upstream_gecko_commit(test_changes=test_changes, bug=1111, message=b"Add change1 file") update_repositories(git_gecko, git_wpt, wait_gecko_commit=rev) pushed, _, _ = upstream.gecko_push(git_gecko, git_wpt, "autoland", rev, raise_on_error=True) sync_1 = pushed.pop() # Update central hg_gecko_upstream.bookmark("mozilla/central", "-r", rev) # Merge the upstream change with SyncLock.for_process(sync_1.process_name) as lock: with sync_1.as_mut(lock): remote_branch = sync_1.remote_branch git_wpt_upstream.git.checkout(remote_branch) git_wpt_upstream.git.rebase("master") git_wpt_upstream.git.checkout("master") git_wpt_upstream.git.merge(remote_branch, ff_only=True) sync_1.finish() # Add second gecko change test_changes = {"change2": b"CHANGE2\n"} rev = upstream_gecko_commit(test_changes=test_changes, bug=1112, message=b"Add change2 file") update_repositories(git_gecko, git_wpt, wait_gecko_commit=rev) pushed, _, _ = upstream.gecko_push(git_gecko, git_wpt, "autoland", rev, raise_on_error=True) sync_2 = pushed.pop() hg_gecko_upstream.bookmark("mozilla/central", "-r", rev) # Merge the gecko change remote_branch = sync_2.remote_branch git_wpt_upstream.git.checkout(remote_branch) git_wpt_upstream.git.rebase("master") git_wpt_upstream.git.checkout("master") git_wpt_upstream.git.merge(remote_branch, ff_only=True) # Add an upstream commit that has metadata pr = pull_request([(b"Upstream change 1", {"upstream1": b"UPSTREAM1\n"})]) head_rev = pr._commits[0]["sha"] downstream.new_wpt_pr(git_gecko, git_wpt, pr) downstream_sync = set_pr_status(pr.number, "success") git_wpt_upstream.head.commit = head_rev git_wpt_upstream.git.reset(hard=True) with SyncLock.for_process(downstream_sync.process_name) as downstream_lock: with downstream_sync.as_mut(downstream_lock): downstream_sync.data["force-metadata-ready"] = True # This is the commit we should land to landing_rev = git_wpt_upstream.git.rev_parse("HEAD") # Add an upstream commit that doesn't have metadata pr = pull_request([(b"Upstream change 2", {"upstream2": b"UPSTREAM2\n"})]) head_rev = pr._commits[0]["sha"] downstream.new_wpt_pr(git_gecko, git_wpt, pr) downstream_sync = set_pr_status(pr.number, "success") git_wpt_upstream.head.commit = head_rev git_wpt_upstream.git.reset(hard=True) # Add third gecko change test_changes = {"change3": b"CHANGE3\n"} rev = upstream_gecko_commit(test_changes=test_changes, bug=1113, message=b"Add change3 file") update_repositories(git_gecko, git_wpt, wait_gecko_commit=rev) pushed, _, _ = upstream.gecko_push(git_gecko, git_wpt, "autoland", rev, raise_on_error=True) # Now start a landing tree.is_open = lambda x: True sync = landing.update_landing(git_gecko, git_wpt) assert sync is not None for i in xrange(2): with SyncLock.for_process(sync.process_name) as lock: try_push = sync.latest_try_push with sync.as_mut(lock), try_push.as_mut(lock): try_push.taskgroup_id = "abcde" + str(i) try_push.download_logs = Mock(return_value=[]) with patch.object(tc.TaskGroup, "tasks", property(Mock(return_value=mock_tasks(completed=["foo"])))): landing.try_push_complete(git_gecko, git_wpt, try_push, sync) hg_gecko_upstream.update() gecko_root = hg_gecko_upstream.root().strip().decode("utf8") assert (hg_gecko_upstream .log("-l1", "--template={desc|firstline}") .strip() .endswith(b"[wpt-sync] Update web-platform-tests to %s, a=testonly" % landing_rev.encode("utf8"))) for file in ["change1", "change2", "change3", "upstream1"]: path = os.path.join(gecko_root, env.config["gecko"]["path"]["wpt"], file) assert os.path.exists(path) with open(path) as f: assert f.read() == file.upper() + "\n" assert not os.path.exists(os.path.join(gecko_root, env.config["gecko"]["path"]["wpt"], "upstream2")) sync_point = landing.load_sync_point(git_gecko, git_wpt) assert sync_point["upstream"] == landing_rev