blob: 57806be9701b2d387ed6bea8a3f61ce91203b7df [file] [log] [blame]
Lann Martin4fbdf202018-08-30 12:02:52 -06001# -*- coding: utf-8 -*-
2# Copyright 2018 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Tests for scripts/repo_sync_manifest."""
7
8from __future__ import print_function
9
10import mock
11import os
12
13from chromite.lib import cros_build_lib
14from chromite.lib import cros_test_lib
15from chromite.lib import git
16from chromite.lib import osutils
17from chromite.lib import parallel_unittest
18from chromite.lib import repo_util
19from chromite.lib import repo_manifest
20from chromite.lib import repo_manifest_unittest
21from chromite.scripts import create_manifest_snapshot
22
23
24MANIFEST_XML = """<?xml version="1.0" encoding="UTF-8"?>
25<manifest>
26 <remote name="origin"/>
27 <default remote="origin"/>
28 <project name="project/a" revision="f01dab1e"/>
29 <project name="project/b" revision="cafe1234" upstream="short"/>
30 <project name="project/c" revision="deadbeef" upstream="refs/heads/master"/>
31 <project name="dupe" revision="d1" upstream="dupe"/>
32 <project name="dupe" revision="d2" upstream="dupe"/>
33</manifest>
34"""
35
36
37class CreateManifestSnapshotTest(cros_test_lib.MockTempDirTestCase,
38 repo_manifest_unittest.XMLTestCase):
39 """Unit tests for create_manifest_snapshot."""
40
41 # pylint: disable=protected-access
42
43 def setUp(self):
44 self.manifest = repo_manifest.Manifest.FromString(MANIFEST_XML)
45 self.project_a = self.manifest.GetUniqueProject('project/a')
46 self.project_b = self.manifest.GetUniqueProject('project/b')
47 self.project_c = self.manifest.GetUniqueProject('project/c')
48 self.dupes = [x for x in self.manifest.Projects() if x.name == 'dupe']
49
50 self.mock_is_reachable = self.PatchObject(git, 'IsReachable')
51 self.mock_git_push = self.PatchObject(git, 'GitPush')
52
53 self.repo_root = os.path.join(self.tempdir, 'root')
54 os.makedirs(os.path.join(self.repo_root, '.repo'))
55 self.output_file = os.path.join(self.tempdir, 'snapshot.xml')
56 self.main_args = ['--repo-path', self.repo_root,
57 '--log-level', 'fatal',
58 '--jobs', '1',
59 '--output-file', self.output_file]
60 self.PatchObject(repo_util.Repository, 'Manifest',
61 return_value=self.manifest)
62
63 def testGetUpstreamBranchNoUpstream(self):
64 """Test _GetUpstreamBranch with no upstream."""
65 branch = create_manifest_snapshot._GetUpstreamBranch(self.project_a)
66 self.assertIsNone(branch)
67
68 def testGetUpstreamBranchShortUpstream(self):
69 """Test _GetUpstreamBranch with short upstream ref."""
70 branch = create_manifest_snapshot._GetUpstreamBranch(self.project_b)
71 self.assertEqual(branch, 'short')
72
73 def testGetUpstreamBranchFullUpstream(self):
74 """Test _GetUpstreamBranch with full upstream ref."""
75 branch = create_manifest_snapshot._GetUpstreamBranch(self.project_c)
76 self.assertEqual(branch, 'master')
77
78 def testNeedsSnapshotReachable(self):
79 """Test _NeedsSnapshot with revision reachable from upstream."""
80 self.mock_is_reachable.return_value = True
81 result = create_manifest_snapshot._NeedsSnapshot('root', self.project_c)
82 self.assertFalse(result)
83 self.mock_is_reachable.assert_called_with(
84 'root/project/c', 'deadbeef', 'refs/remotes/origin/master')
85
86 def testNeedsSnapshotUnreachable(self):
87 """Test _NeedsSnapshot with revision reachable from upstream."""
88 self.mock_is_reachable.return_value = False
89 result = create_manifest_snapshot._NeedsSnapshot('root', self.project_b)
90 self.assertTrue(result)
91 self.mock_is_reachable.assert_called_with(
92 'root/project/b', 'cafe1234', 'refs/remotes/origin/short')
93
94 def testNeedsSnapshotNoUpstream(self):
95 """Test _NeedsSnapshot with no project upstream."""
96 create_manifest_snapshot._NeedsSnapshot('root', self.project_a)
97 self.mock_is_reachable.assert_called_with(
98 'root/project/a', 'f01dab1e', 'refs/remotes/origin/master')
99
100 def testNeedsSnapshotIsReachableFailure(self):
101 """Test _NeedsSnapshot with no project upstream."""
102 self.mock_is_reachable.side_effect = cros_build_lib.RunCommandError('', '')
103 result = create_manifest_snapshot._NeedsSnapshot('root', self.project_a)
104 self.assertTrue(result)
105
106 def testMakeUniqueRefMaster(self):
107 """Test _MakeUniqueRef with upstream master."""
108 used = set()
109 ref1 = create_manifest_snapshot._MakeUniqueRef(self.project_c, 'base', used)
110 ref2 = create_manifest_snapshot._MakeUniqueRef(self.project_c, 'base', used)
111 ref3 = create_manifest_snapshot._MakeUniqueRef(self.project_c, 'base', used)
112 self.assertEqual(ref1, 'base')
113 self.assertEqual(ref2, 'base/1')
114 self.assertEqual(ref3, 'base/2')
115
116 def testMakeUniqueRefNonMaster(self):
117 """Test _MakeUniqueRef with non-master upstream."""
118 used = set()
119 ref1 = create_manifest_snapshot._MakeUniqueRef(self.project_b, 'base', used)
120 ref2 = create_manifest_snapshot._MakeUniqueRef(self.project_b, 'base', used)
121 self.assertEqual(ref1, 'base/short')
122 self.assertEqual(ref2, 'base/short/1')
123
124 def testGitPushProjectUpstream(self):
125 """Test _GitPushProjectUpstream."""
126 create_manifest_snapshot._GitPushProjectUpstream(
127 'root', self.project_b, False)
128 self.mock_git_push.assert_called_with(
129 'root/project/b', 'cafe1234', git.RemoteRef('origin', 'short'),
130 dry_run=False)
131
132 def testGitPushProjectUpstreamDryRun(self):
133 """Test _GitPushProjectUpstream with dry_run=True."""
134 create_manifest_snapshot._GitPushProjectUpstream(
135 'root', self.project_b, True)
136 self.mock_git_push.assert_called_with(
137 'root/project/b', 'cafe1234', git.RemoteRef('origin', 'short'),
138 dry_run=True)
139
140 def testMainNoSnapshots(self):
141 """Test main with projects that don't need snapshots."""
142 self.mock_is_reachable.return_value = True
143 create_manifest_snapshot.main(self.main_args)
144 snapshot_xml = osutils.ReadFile(self.output_file)
145 self.AssertXMLAlmostEqual(snapshot_xml, MANIFEST_XML)
146
147 def testMainSnapshots(self):
148 """Test main with projects that need snapshots."""
149 self.mock_is_reachable.return_value = False
150 args = self.main_args + ['--snapshot-ref', 'refs/snap']
151 with parallel_unittest.ParallelMock():
152 create_manifest_snapshot.main(args)
153 snapshot_xml = osutils.ReadFile(self.output_file)
154
155 self.mock_git_push.assert_has_calls([
156 mock.call(os.path.join(self.repo_root, 'project/a'),
157 'f01dab1e', git.RemoteRef('origin', 'refs/snap'),
158 dry_run=False),
159 mock.call(os.path.join(self.repo_root, 'project/b'),
160 'cafe1234', git.RemoteRef('origin', 'refs/snap'),
161 dry_run=False),
162 mock.call(os.path.join(self.repo_root, 'project/c'),
163 'deadbeef', git.RemoteRef('origin', 'refs/snap'),
164 dry_run=False),
165 mock.call(os.path.join(self.repo_root, 'dupe'),
166 'd1', git.RemoteRef('origin', 'refs/snap/dupe'),
167 dry_run=False),
168 mock.call(os.path.join(self.repo_root, 'dupe'),
169 'd2', git.RemoteRef('origin', 'refs/snap/dupe/1'),
170 dry_run=False),
171 ], any_order=True)
172
173 expected = repo_manifest.Manifest.FromString(MANIFEST_XML)
174 for project in expected.Projects():
175 if project.name == 'dupe':
176 if project.revision == 'd1':
177 project.upstream = 'refs/snap/dupe'
178 else:
179 project.upstream = 'refs/snap/dupe/1'
180 else:
181 project.upstream = 'refs/snap'
182 expected_xml = repo_manifest_unittest.ManifestToString(expected)
183 self.AssertXMLAlmostEqual(snapshot_xml, expected_xml)
184
185 def testMainNeedsSnapshotNoSnapshotRef(self):
186 """Test main with projects that need snapshots but no --snapshot-ref."""
187 self.mock_is_reachable.return_value = False
188 with self.assertRaises(SystemExit):
189 create_manifest_snapshot.main(self.main_args)