Merge lp:~mwhudson/launchpad/pull-mirror-branches-separately-bug-520107 into lp:launchpad
- pull-mirror-branches-separately-bug-520107
- Merge into devel
Proposed by
Michael Hudson-Doyle
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Hudson-Doyle | ||||
Approved revision: | not available | ||||
Merged at revision: | not available | ||||
Proposed branch: | lp:~mwhudson/launchpad/pull-mirror-branches-separately-bug-520107 | ||||
Merge into: | lp:launchpad | ||||
Prerequisite: | lp:~mwhudson/launchpad/remove-old-puller-xmlrpc-methods | ||||
Diff against target: |
527 lines (+144/-46) 14 files modified
cronscripts/supermirror-pull.py (+3/-1) lib/lp/code/errors.py (+5/-0) lib/lp/code/interfaces/branch.py (+0/-4) lib/lp/code/interfaces/branchpuller.py (+3/-1) lib/lp/code/interfaces/codehosting.py (+4/-1) lib/lp/code/model/branchpuller.py (+5/-2) lib/lp/code/model/tests/test_branchpuller.py (+47/-9) lib/lp/code/xmlrpc/codehosting.py (+11/-2) lib/lp/code/xmlrpc/tests/test_codehosting.py (+17/-9) lib/lp/codehosting/inmemory.py (+12/-2) lib/lp/codehosting/puller/scheduler.py (+3/-2) lib/lp/codehosting/puller/tests/test_acceptance.py (+19/-2) lib/lp/codehosting/puller/tests/test_scheduler.py (+14/-10) lib/lp/testing/factory.py (+1/-1) |
||||
To merge this branch: | bzr merge lp:~mwhudson/launchpad/pull-mirror-branches-separately-bug-520107 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Penhey (community) | Approve | ||
Review via email:
|
Commit message
Allow an invocation of supermirror-pull.py to only pull certain branch types.
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Hudson-Doyle (mwhudson) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Tim Penhey (thumper) wrote : | # |
Good except test_type_
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'cronscripts/supermirror-pull.py' | |||
2 | --- cronscripts/supermirror-pull.py 2009-10-13 14:38:07 +0000 | |||
3 | +++ cronscripts/supermirror-pull.py 2010-02-24 19:04:21 +0000 | |||
4 | @@ -38,12 +38,14 @@ | |||
5 | 38 | if __name__ == '__main__': | 38 | if __name__ == '__main__': |
6 | 39 | parser = OptionParser() | 39 | parser = OptionParser() |
7 | 40 | logger_options(parser) | 40 | logger_options(parser) |
8 | 41 | parser.add_option('--branch-type', action='append', default=[]) | ||
9 | 41 | (options, arguments) = parser.parse_args() | 42 | (options, arguments) = parser.parse_args() |
10 | 42 | if arguments: | 43 | if arguments: |
11 | 43 | parser.error("Unhandled arguments %s" % repr(arguments)) | 44 | parser.error("Unhandled arguments %s" % repr(arguments)) |
12 | 44 | log = set_up_logging_for_script(options, 'supermirror_puller') | 45 | log = set_up_logging_for_script(options, 'supermirror_puller') |
13 | 45 | manager = scheduler.JobScheduler( | 46 | manager = scheduler.JobScheduler( |
15 | 46 | LoggingProxy(config.codehosting.branch_puller_endpoint, log), log) | 47 | LoggingProxy(config.codehosting.branch_puller_endpoint, log), log, |
16 | 48 | options.branch_type) | ||
17 | 47 | 49 | ||
18 | 48 | reactor.callWhenRunning(run_mirror, log, manager) | 50 | reactor.callWhenRunning(run_mirror, log, manager) |
19 | 49 | reactor.run() | 51 | reactor.run() |
20 | 50 | 52 | ||
21 | === modified file 'lib/lp/code/errors.py' | |||
22 | --- lib/lp/code/errors.py 2009-12-14 06:41:18 +0000 | |||
23 | +++ lib/lp/code/errors.py 2010-02-24 19:04:21 +0000 | |||
24 | @@ -11,6 +11,7 @@ | |||
25 | 11 | 'ClaimReviewFailed', | 11 | 'ClaimReviewFailed', |
26 | 12 | 'InvalidBranchMergeProposal', | 12 | 'InvalidBranchMergeProposal', |
27 | 13 | 'ReviewNotPending', | 13 | 'ReviewNotPending', |
28 | 14 | 'UnknownBranchTypeError', | ||
29 | 14 | 'UserHasExistingReview', | 15 | 'UserHasExistingReview', |
30 | 15 | 'UserNotBranchReviewer', | 16 | 'UserNotBranchReviewer', |
31 | 16 | 'WrongBranchMergeProposal', | 17 | 'WrongBranchMergeProposal', |
32 | @@ -59,3 +60,7 @@ | |||
33 | 59 | 60 | ||
34 | 60 | class WrongBranchMergeProposal(Exception): | 61 | class WrongBranchMergeProposal(Exception): |
35 | 61 | """The comment requested is not associated with this merge proposal.""" | 62 | """The comment requested is not associated with this merge proposal.""" |
36 | 63 | |||
37 | 64 | |||
38 | 65 | class UnknownBranchTypeError(Exception): | ||
39 | 66 | """Raised when the user specifies an unrecognized branch type.""" | ||
40 | 62 | 67 | ||
41 | === modified file 'lib/lp/code/interfaces/branch.py' | |||
42 | --- lib/lp/code/interfaces/branch.py 2010-02-18 16:00:24 +0000 | |||
43 | +++ lib/lp/code/interfaces/branch.py 2010-02-24 19:04:21 +0000 | |||
44 | @@ -119,10 +119,6 @@ | |||
45 | 119 | """The branch cannot be deleted at this time.""" | 119 | """The branch cannot be deleted at this time.""" |
46 | 120 | 120 | ||
47 | 121 | 121 | ||
48 | 122 | class UnknownBranchTypeError(Exception): | ||
49 | 123 | """Raised when the user specifies an unrecognized branch type.""" | ||
50 | 124 | |||
51 | 125 | |||
52 | 126 | class BranchCreationForbidden(BranchCreationException): | 122 | class BranchCreationForbidden(BranchCreationException): |
53 | 127 | """A Branch visibility policy forbids branch creation. | 123 | """A Branch visibility policy forbids branch creation. |
54 | 128 | 124 | ||
55 | 129 | 125 | ||
56 | === modified file 'lib/lp/code/interfaces/branchpuller.py' | |||
57 | --- lib/lp/code/interfaces/branchpuller.py 2010-02-24 01:22:28 +0000 | |||
58 | +++ lib/lp/code/interfaces/branchpuller.py 2010-02-24 19:04:21 +0000 | |||
59 | @@ -23,9 +23,11 @@ | |||
60 | 23 | MIRROR_TIME_INCREMENT = Attribute( | 23 | MIRROR_TIME_INCREMENT = Attribute( |
61 | 24 | "How frequently we mirror branches.") | 24 | "How frequently we mirror branches.") |
62 | 25 | 25 | ||
64 | 26 | def acquireBranchToPull(): | 26 | def acquireBranchToPull(*branch_types): |
65 | 27 | """Return a Branch to pull and mark it as mirror-started. | 27 | """Return a Branch to pull and mark it as mirror-started. |
66 | 28 | 28 | ||
67 | 29 | :param branch_types: Only return branches of these types. Passing no | ||
68 | 30 | types means consider all types (apart from REMOTE). | ||
69 | 29 | :return: The branch object to pull next, or ``None`` if there is no | 31 | :return: The branch object to pull next, or ``None`` if there is no |
70 | 30 | branch to pull. | 32 | branch to pull. |
71 | 31 | """ | 33 | """ |
72 | 32 | 34 | ||
73 | === modified file 'lib/lp/code/interfaces/codehosting.py' | |||
74 | --- lib/lp/code/interfaces/codehosting.py 2010-02-24 01:57:35 +0000 | |||
75 | +++ lib/lp/code/interfaces/codehosting.py 2010-02-24 19:04:21 +0000 | |||
76 | @@ -58,9 +58,12 @@ | |||
77 | 58 | Published at 'branch_puller' on the private XML-RPC server. | 58 | Published at 'branch_puller' on the private XML-RPC server. |
78 | 59 | """ | 59 | """ |
79 | 60 | 60 | ||
81 | 61 | def acquireBranchToPull(): | 61 | def acquireBranchToPull(branch_type_names): |
82 | 62 | """Return a Branch to pull and mark it as mirror-started. | 62 | """Return a Branch to pull and mark it as mirror-started. |
83 | 63 | 63 | ||
84 | 64 | :param branch_type_names: Only consider branches of these type names. | ||
85 | 65 | An empty list means consider HOSTED, MIRRORED and IMPORTED | ||
86 | 66 | branches. | ||
87 | 64 | :return: A 5-tuple:: | 67 | :return: A 5-tuple:: |
88 | 65 | 68 | ||
89 | 66 | (branch_id, pull_url, unique_name, default_branch, branch_type) | 69 | (branch_id, pull_url, unique_name, default_branch, branch_type) |
90 | 67 | 70 | ||
91 | === modified file 'lib/lp/code/model/branchpuller.py' | |||
92 | --- lib/lp/code/model/branchpuller.py 2010-02-24 01:22:28 +0000 | |||
93 | +++ lib/lp/code/model/branchpuller.py 2010-02-24 19:04:21 +0000 | |||
94 | @@ -28,13 +28,16 @@ | |||
95 | 28 | MAXIMUM_MIRROR_FAILURES = 5 | 28 | MAXIMUM_MIRROR_FAILURES = 5 |
96 | 29 | MIRROR_TIME_INCREMENT = timedelta(hours=6) | 29 | MIRROR_TIME_INCREMENT = timedelta(hours=6) |
97 | 30 | 30 | ||
99 | 31 | def acquireBranchToPull(self): | 31 | def acquireBranchToPull(self, *branch_types): |
100 | 32 | """See `IBranchPuller`.""" | 32 | """See `IBranchPuller`.""" |
101 | 33 | if not branch_types: | ||
102 | 34 | branch_types = ( | ||
103 | 35 | BranchType.HOSTED, BranchType.MIRRORED, BranchType.IMPORTED) | ||
104 | 33 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) | 36 | store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR) |
105 | 34 | branch = store.find( | 37 | branch = store.find( |
106 | 35 | Branch, | 38 | Branch, |
107 | 36 | Branch.next_mirror_time <= UTC_NOW, | 39 | Branch.next_mirror_time <= UTC_NOW, |
109 | 37 | Branch.branch_type != BranchType.REMOTE).order_by( | 40 | Branch.branch_type.is_in(branch_types)).order_by( |
110 | 38 | Branch.next_mirror_time).first() | 41 | Branch.next_mirror_time).first() |
111 | 39 | if branch is not None: | 42 | if branch is not None: |
112 | 40 | branch.startMirroring() | 43 | branch.startMirroring() |
113 | 41 | 44 | ||
114 | === modified file 'lib/lp/code/model/tests/test_branchpuller.py' | |||
115 | --- lib/lp/code/model/tests/test_branchpuller.py 2010-02-24 01:22:28 +0000 | |||
116 | +++ lib/lp/code/model/tests/test_branchpuller.py 2010-02-24 19:04:21 +0000 | |||
117 | @@ -169,12 +169,22 @@ | |||
118 | 169 | and `startMirroring` as appropriate. | 169 | and `startMirroring` as appropriate. |
119 | 170 | """ | 170 | """ |
120 | 171 | 171 | ||
123 | 172 | def assertNoBranchIsAquired(self): | 172 | def assertNoBranchIsAquired(self, *branch_types): |
124 | 173 | """Assert that there is no branch to pull.""" | 173 | """Assert that there is no branch to pull. |
125 | 174 | |||
126 | 175 | :param branch_types: A list of branch types to pass to | ||
127 | 176 | acquireBranchToPull. Passing none means consider all types of | ||
128 | 177 | branch. | ||
129 | 178 | """ | ||
130 | 174 | raise NotImplementedError(self.assertNoBranchIsAquired) | 179 | raise NotImplementedError(self.assertNoBranchIsAquired) |
131 | 175 | 180 | ||
134 | 176 | def assertBranchIsAquired(self, branch): | 181 | def assertBranchIsAquired(self, branch, *branch_types): |
135 | 177 | """Assert that ``branch`` is the next branch to be pulled.""" | 182 | """Assert that ``branch`` is the next branch to be pulled. |
136 | 183 | |||
137 | 184 | :param branch_types: A list of branch types to pass to | ||
138 | 185 | acquireBranchToPull. Passing none means consider all types of | ||
139 | 186 | branch. | ||
140 | 187 | """ | ||
141 | 178 | raise NotImplementedError(self.assertBranchIsAquired) | 188 | raise NotImplementedError(self.assertBranchIsAquired) |
142 | 179 | 189 | ||
143 | 180 | def startMirroring(self, branch): | 190 | def startMirroring(self, branch): |
144 | @@ -202,7 +212,6 @@ | |||
145 | 202 | removeSecurityProxy(branch).branch_type = BranchType.REMOTE | 212 | removeSecurityProxy(branch).branch_type = BranchType.REMOTE |
146 | 203 | self.assertNoBranchIsAquired() | 213 | self.assertNoBranchIsAquired() |
147 | 204 | 214 | ||
148 | 205 | |||
149 | 206 | def test_private(self): | 215 | def test_private(self): |
150 | 207 | # If there is a private branch that needs mirroring, | 216 | # If there is a private branch that needs mirroring, |
151 | 208 | # acquireBranchToPull returns that. | 217 | # acquireBranchToPull returns that. |
152 | @@ -232,6 +241,33 @@ | |||
153 | 232 | naked_second_branch.next_mirror_time -= timedelta(seconds=50) | 241 | naked_second_branch.next_mirror_time -= timedelta(seconds=50) |
154 | 233 | self.assertBranchIsAquired(naked_first_branch) | 242 | self.assertBranchIsAquired(naked_first_branch) |
155 | 234 | 243 | ||
156 | 244 | def test_type_filter_hosted_returns_hosted(self): | ||
157 | 245 | branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED) | ||
158 | 246 | branch.requestMirror() | ||
159 | 247 | self.assertBranchIsAquired(branch, BranchType.HOSTED) | ||
160 | 248 | |||
161 | 249 | def test_type_filter_hosted_does_not_return_mirrored(self): | ||
162 | 250 | branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED) | ||
163 | 251 | branch.requestMirror() | ||
164 | 252 | self.assertNoBranchIsAquired(BranchType.HOSTED) | ||
165 | 253 | |||
166 | 254 | def test_type_filter_mirrored_does_not_return_hosted(self): | ||
167 | 255 | branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED) | ||
168 | 256 | branch.requestMirror() | ||
169 | 257 | self.assertNoBranchIsAquired(BranchType.MIRRORED) | ||
170 | 258 | |||
171 | 259 | def test_type_filter_hosted_imported_returns_hosted(self): | ||
172 | 260 | branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED) | ||
173 | 261 | branch.requestMirror() | ||
174 | 262 | self.assertBranchIsAquired( | ||
175 | 263 | branch, BranchType.HOSTED, BranchType.IMPORTED) | ||
176 | 264 | |||
177 | 265 | def test_type_filter_hosted_imported_returns_imported(self): | ||
178 | 266 | branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED) | ||
179 | 267 | branch.requestMirror() | ||
180 | 268 | self.assertBranchIsAquired( | ||
181 | 269 | branch, BranchType.HOSTED, BranchType.IMPORTED) | ||
182 | 270 | |||
183 | 235 | 271 | ||
184 | 236 | class TestAcquireBranchToPullDirectly(TestCaseWithFactory, | 272 | class TestAcquireBranchToPullDirectly(TestCaseWithFactory, |
185 | 237 | AcquireBranchToPullTests): | 273 | AcquireBranchToPullTests): |
186 | @@ -239,14 +275,16 @@ | |||
187 | 239 | 275 | ||
188 | 240 | layer = DatabaseFunctionalLayer | 276 | layer = DatabaseFunctionalLayer |
189 | 241 | 277 | ||
191 | 242 | def assertNoBranchIsAquired(self): | 278 | def assertNoBranchIsAquired(self, *branch_types): |
192 | 243 | """See `AcquireBranchToPullTests`.""" | 279 | """See `AcquireBranchToPullTests`.""" |
194 | 244 | acquired_branch = getUtility(IBranchPuller).acquireBranchToPull() | 280 | acquired_branch = getUtility(IBranchPuller).acquireBranchToPull( |
195 | 281 | *branch_types) | ||
196 | 245 | self.assertEqual(None, acquired_branch) | 282 | self.assertEqual(None, acquired_branch) |
197 | 246 | 283 | ||
199 | 247 | def assertBranchIsAquired(self, branch): | 284 | def assertBranchIsAquired(self, branch, *branch_types): |
200 | 248 | """See `AcquireBranchToPullTests`.""" | 285 | """See `AcquireBranchToPullTests`.""" |
202 | 249 | acquired_branch = getUtility(IBranchPuller).acquireBranchToPull() | 286 | acquired_branch = getUtility(IBranchPuller).acquireBranchToPull( |
203 | 287 | *branch_types) | ||
204 | 250 | login_person(removeSecurityProxy(branch).owner) | 288 | login_person(removeSecurityProxy(branch).owner) |
205 | 251 | self.assertEqual(branch, acquired_branch) | 289 | self.assertEqual(branch, acquired_branch) |
206 | 252 | self.assertIsNot(None, acquired_branch.last_mirror_attempt) | 290 | self.assertIsNot(None, acquired_branch.last_mirror_attempt) |
207 | 253 | 291 | ||
208 | === modified file 'lib/lp/code/xmlrpc/codehosting.py' | |||
209 | --- lib/lp/code/xmlrpc/codehosting.py 2010-02-24 01:22:28 +0000 | |||
210 | +++ lib/lp/code/xmlrpc/codehosting.py 2010-02-24 19:04:21 +0000 | |||
211 | @@ -23,6 +23,7 @@ | |||
212 | 23 | from zope.security.proxy import removeSecurityProxy | 23 | from zope.security.proxy import removeSecurityProxy |
213 | 24 | 24 | ||
214 | 25 | from canonical.launchpad.ftests import login_person, logout | 25 | from canonical.launchpad.ftests import login_person, logout |
215 | 26 | from lp.code.errors import UnknownBranchTypeError | ||
216 | 26 | from lp.code.enums import BranchType | 27 | from lp.code.enums import BranchType |
217 | 27 | from lp.code.interfaces.branch import BranchCreationException | 28 | from lp.code.interfaces.branch import BranchCreationException |
218 | 28 | from lp.code.interfaces.branchlookup import IBranchLookup | 29 | from lp.code.interfaces.branchlookup import IBranchLookup |
219 | @@ -54,9 +55,17 @@ | |||
220 | 54 | 55 | ||
221 | 55 | implements(IBranchPuller) | 56 | implements(IBranchPuller) |
222 | 56 | 57 | ||
224 | 57 | def acquireBranchToPull(self): | 58 | def acquireBranchToPull(self, branch_type_names): |
225 | 58 | """See `IBranchPuller`.""" | 59 | """See `IBranchPuller`.""" |
227 | 59 | branch = getUtility(branchpuller.IBranchPuller).acquireBranchToPull() | 60 | branch_types = [] |
228 | 61 | for branch_type_name in branch_type_names: | ||
229 | 62 | try: | ||
230 | 63 | branch_types.append(BranchType.items[branch_type_name]) | ||
231 | 64 | except KeyError: | ||
232 | 65 | raise UnknownBranchTypeError( | ||
233 | 66 | 'Unknown branch type: %r' % (branch_type_name,)) | ||
234 | 67 | branch = getUtility(branchpuller.IBranchPuller).acquireBranchToPull( | ||
235 | 68 | *branch_types) | ||
236 | 60 | if branch is not None: | 69 | if branch is not None: |
237 | 61 | branch = removeSecurityProxy(branch) | 70 | branch = removeSecurityProxy(branch) |
238 | 62 | default_branch = branch.target.default_stacked_on_branch | 71 | default_branch = branch.target.default_stacked_on_branch |
239 | 63 | 72 | ||
240 | === modified file 'lib/lp/code/xmlrpc/tests/test_codehosting.py' | |||
241 | --- lib/lp/code/xmlrpc/tests/test_codehosting.py 2010-02-24 01:57:35 +0000 | |||
242 | +++ lib/lp/code/xmlrpc/tests/test_codehosting.py 2010-02-24 19:04:21 +0000 | |||
243 | @@ -30,6 +30,7 @@ | |||
244 | 30 | from canonical.testing import DatabaseFunctionalLayer, FunctionalLayer | 30 | from canonical.testing import DatabaseFunctionalLayer, FunctionalLayer |
245 | 31 | 31 | ||
246 | 32 | from lp.code.enums import BranchType | 32 | from lp.code.enums import BranchType |
247 | 33 | from lp.code.errors import UnknownBranchTypeError | ||
248 | 33 | from lp.code.interfaces.branch import BRANCH_NAME_VALIDATION_ERROR_MESSAGE | 34 | from lp.code.interfaces.branch import BRANCH_NAME_VALIDATION_ERROR_MESSAGE |
249 | 34 | from lp.code.interfaces.branchlookup import IBranchLookup | 35 | from lp.code.interfaces.branchlookup import IBranchLookup |
250 | 35 | from lp.code.interfaces.branchtarget import IBranchTarget | 36 | from lp.code.interfaces.branchtarget import IBranchTarget |
251 | @@ -409,15 +410,17 @@ | |||
252 | 409 | self.storage = frontend.getPullerEndpoint() | 410 | self.storage = frontend.getPullerEndpoint() |
253 | 410 | self.factory = frontend.getLaunchpadObjectFactory() | 411 | self.factory = frontend.getLaunchpadObjectFactory() |
254 | 411 | 412 | ||
256 | 412 | def assertNoBranchIsAquired(self): | 413 | def assertNoBranchIsAquired(self, *branch_types): |
257 | 413 | """See `AcquireBranchToPullTests`.""" | 414 | """See `AcquireBranchToPullTests`.""" |
259 | 414 | pull_info = self.storage.acquireBranchToPull() | 415 | branch_types = tuple(branch_type.name for branch_type in branch_types) |
260 | 416 | pull_info = self.storage.acquireBranchToPull(branch_types) | ||
261 | 415 | self.assertEqual((), pull_info) | 417 | self.assertEqual((), pull_info) |
262 | 416 | 418 | ||
264 | 417 | def assertBranchIsAquired(self, branch): | 419 | def assertBranchIsAquired(self, branch, *branch_types): |
265 | 418 | """See `AcquireBranchToPullTests`.""" | 420 | """See `AcquireBranchToPullTests`.""" |
266 | 419 | branch = removeSecurityProxy(branch) | 421 | branch = removeSecurityProxy(branch) |
268 | 420 | pull_info = self.storage.acquireBranchToPull() | 422 | branch_types = tuple(branch_type.name for branch_type in branch_types) |
269 | 423 | pull_info = self.storage.acquireBranchToPull(branch_types) | ||
270 | 421 | default_branch = branch.target.default_stacked_on_branch | 424 | default_branch = branch.target.default_stacked_on_branch |
271 | 422 | if default_branch: | 425 | if default_branch: |
272 | 423 | default_branch_name = default_branch | 426 | default_branch_name = default_branch |
273 | @@ -437,21 +440,21 @@ | |||
274 | 437 | def test_branch_type_returned_hosted(self): | 440 | def test_branch_type_returned_hosted(self): |
275 | 438 | branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED) | 441 | branch = self.factory.makeAnyBranch(branch_type=BranchType.HOSTED) |
276 | 439 | branch.requestMirror() | 442 | branch.requestMirror() |
278 | 440 | pull_info = self.storage.acquireBranchToPull() | 443 | pull_info = self.storage.acquireBranchToPull(()) |
279 | 441 | _, _, _, _, branch_type = pull_info | 444 | _, _, _, _, branch_type = pull_info |
280 | 442 | self.assertEqual('HOSTED', branch_type) | 445 | self.assertEqual('HOSTED', branch_type) |
281 | 443 | 446 | ||
282 | 444 | def test_branch_type_returned_mirrored(self): | 447 | def test_branch_type_returned_mirrored(self): |
283 | 445 | branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED) | 448 | branch = self.factory.makeAnyBranch(branch_type=BranchType.MIRRORED) |
284 | 446 | branch.requestMirror() | 449 | branch.requestMirror() |
286 | 447 | pull_info = self.storage.acquireBranchToPull() | 450 | pull_info = self.storage.acquireBranchToPull(()) |
287 | 448 | _, _, _, _, branch_type = pull_info | 451 | _, _, _, _, branch_type = pull_info |
288 | 449 | self.assertEqual('MIRRORED', branch_type) | 452 | self.assertEqual('MIRRORED', branch_type) |
289 | 450 | 453 | ||
290 | 451 | def test_branch_type_returned_import(self): | 454 | def test_branch_type_returned_import(self): |
291 | 452 | branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED) | 455 | branch = self.factory.makeAnyBranch(branch_type=BranchType.IMPORTED) |
292 | 453 | branch.requestMirror() | 456 | branch.requestMirror() |
294 | 454 | pull_info = self.storage.acquireBranchToPull() | 457 | pull_info = self.storage.acquireBranchToPull(()) |
295 | 455 | _, _, _, _, branch_type = pull_info | 458 | _, _, _, _, branch_type = pull_info |
296 | 456 | self.assertEqual('IMPORTED', branch_type) | 459 | self.assertEqual('IMPORTED', branch_type) |
297 | 457 | 460 | ||
298 | @@ -459,7 +462,7 @@ | |||
299 | 459 | branch = self.factory.makeProductBranch() | 462 | branch = self.factory.makeProductBranch() |
300 | 460 | self.factory.enableDefaultStackingForProduct(branch.product) | 463 | self.factory.enableDefaultStackingForProduct(branch.product) |
301 | 461 | branch.requestMirror() | 464 | branch.requestMirror() |
303 | 462 | pull_info = self.storage.acquireBranchToPull() | 465 | pull_info = self.storage.acquireBranchToPull(()) |
304 | 463 | _, _, _, default_stacked_on_branch, _ = pull_info | 466 | _, _, _, default_stacked_on_branch, _ = pull_info |
305 | 464 | self.assertEqual( | 467 | self.assertEqual( |
306 | 465 | default_stacked_on_branch, | 468 | default_stacked_on_branch, |
307 | @@ -475,11 +478,16 @@ | |||
308 | 475 | mirrored_branch = self.factory.makeProductBranch( | 478 | mirrored_branch = self.factory.makeProductBranch( |
309 | 476 | branch_type=BranchType.MIRRORED, product=product) | 479 | branch_type=BranchType.MIRRORED, product=product) |
310 | 477 | mirrored_branch.requestMirror() | 480 | mirrored_branch.requestMirror() |
312 | 478 | pull_info = self.storage.acquireBranchToPull() | 481 | pull_info = self.storage.acquireBranchToPull(()) |
313 | 479 | _, _, _, default_stacked_on_branch, _ = pull_info | 482 | _, _, _, default_stacked_on_branch, _ = pull_info |
314 | 480 | self.assertEqual( | 483 | self.assertEqual( |
315 | 481 | '', default_stacked_on_branch) | 484 | '', default_stacked_on_branch) |
316 | 482 | 485 | ||
317 | 486 | def test_unknown_branch_type_name_raises(self): | ||
318 | 487 | self.assertRaises( | ||
319 | 488 | UnknownBranchTypeError, self.storage.acquireBranchToPull, | ||
320 | 489 | ('NO_SUCH_TYPE',)) | ||
321 | 490 | |||
322 | 483 | 491 | ||
323 | 484 | class BranchFileSystemTest(TestCaseWithFactory): | 492 | class BranchFileSystemTest(TestCaseWithFactory): |
324 | 485 | """Tests for the implementation of `IBranchFileSystem`.""" | 493 | """Tests for the implementation of `IBranchFileSystem`.""" |
325 | 486 | 494 | ||
326 | === modified file 'lib/lp/codehosting/inmemory.py' | |||
327 | --- lib/lp/codehosting/inmemory.py 2010-02-24 01:57:35 +0000 | |||
328 | +++ lib/lp/codehosting/inmemory.py 2010-02-24 19:04:21 +0000 | |||
329 | @@ -18,6 +18,7 @@ | |||
330 | 18 | from zope.interface import implementer | 18 | from zope.interface import implementer |
331 | 19 | 19 | ||
332 | 20 | from canonical.database.constants import UTC_NOW | 20 | from canonical.database.constants import UTC_NOW |
333 | 21 | from lp.code.errors import UnknownBranchTypeError | ||
334 | 21 | from lp.code.model.branchnamespace import BranchNamespaceSet | 22 | from lp.code.model.branchnamespace import BranchNamespaceSet |
335 | 22 | from lp.code.model.branchtarget import ( | 23 | from lp.code.model.branchtarget import ( |
336 | 23 | PackageBranchTarget, ProductBranchTarget) | 24 | PackageBranchTarget, ProductBranchTarget) |
337 | @@ -442,11 +443,20 @@ | |||
338 | 442 | self._branch_set = branch_set | 443 | self._branch_set = branch_set |
339 | 443 | self._script_activity_set = script_activity_set | 444 | self._script_activity_set = script_activity_set |
340 | 444 | 445 | ||
342 | 445 | def acquireBranchToPull(self): | 446 | def acquireBranchToPull(self, branch_type_names): |
343 | 447 | if not branch_type_names: | ||
344 | 448 | branch_type_names = 'HOSTED', 'MIRRORED', 'IMPORTED' | ||
345 | 449 | branch_types = [] | ||
346 | 450 | for branch_type_name in branch_type_names: | ||
347 | 451 | try: | ||
348 | 452 | branch_types.append(BranchType.items[branch_type_name]) | ||
349 | 453 | except KeyError: | ||
350 | 454 | raise UnknownBranchTypeError( | ||
351 | 455 | 'Unknown branch type: %r' % (branch_type_name,)) | ||
352 | 446 | branches = sorted( | 456 | branches = sorted( |
353 | 447 | [branch for branch in self._branch_set | 457 | [branch for branch in self._branch_set |
354 | 448 | if branch.next_mirror_time is not None | 458 | if branch.next_mirror_time is not None |
356 | 449 | and branch.branch_type != BranchType.REMOTE], | 459 | and branch.branch_type in branch_types], |
357 | 450 | key=operator.attrgetter('next_mirror_time')) | 460 | key=operator.attrgetter('next_mirror_time')) |
358 | 451 | if branches: | 461 | if branches: |
359 | 452 | branch = branches[-1] | 462 | branch = branches[-1] |
360 | 453 | 463 | ||
361 | === modified file 'lib/lp/codehosting/puller/scheduler.py' | |||
362 | --- lib/lp/codehosting/puller/scheduler.py 2009-12-22 00:26:49 +0000 | |||
363 | +++ lib/lp/codehosting/puller/scheduler.py 2010-02-24 19:04:21 +0000 | |||
364 | @@ -417,9 +417,10 @@ | |||
365 | 417 | branches. | 417 | branches. |
366 | 418 | """ | 418 | """ |
367 | 419 | 419 | ||
369 | 420 | def __init__(self, branch_puller_endpoint, logger): | 420 | def __init__(self, branch_puller_endpoint, logger, branch_type_names): |
370 | 421 | self.branch_puller_endpoint = branch_puller_endpoint | 421 | self.branch_puller_endpoint = branch_puller_endpoint |
371 | 422 | self.logger = logger | 422 | self.logger = logger |
372 | 423 | self.branch_type_names = branch_type_names | ||
373 | 423 | self.actualLock = None | 424 | self.actualLock = None |
374 | 424 | self.name = 'branch-puller' | 425 | self.name = 'branch-puller' |
375 | 425 | self.lockfilename = '/var/lock/launchpad-%s.lock' % self.name | 426 | self.lockfilename = '/var/lock/launchpad-%s.lock' % self.name |
376 | @@ -455,7 +456,7 @@ | |||
377 | 455 | 456 | ||
378 | 456 | def _poll(self): | 457 | def _poll(self): |
379 | 457 | deferred = self.branch_puller_endpoint.callRemote( | 458 | deferred = self.branch_puller_endpoint.callRemote( |
381 | 458 | 'acquireBranchToPull') | 459 | 'acquireBranchToPull', self.branch_type_names) |
382 | 459 | deferred.addCallback(self._turnJobTupleIntoTask) | 460 | deferred.addCallback(self._turnJobTupleIntoTask) |
383 | 460 | return deferred | 461 | return deferred |
384 | 461 | 462 | ||
385 | 462 | 463 | ||
386 | === modified file 'lib/lp/codehosting/puller/tests/test_acceptance.py' | |||
387 | --- lib/lp/codehosting/puller/tests/test_acceptance.py 2010-01-20 20:56:29 +0000 | |||
388 | +++ lib/lp/codehosting/puller/tests/test_acceptance.py 2010-02-24 19:04:21 +0000 | |||
389 | @@ -122,7 +122,7 @@ | |||
390 | 122 | output, error = process.communicate() | 122 | output, error = process.communicate() |
391 | 123 | return process.returncode, output, error | 123 | return process.returncode, output, error |
392 | 124 | 124 | ||
394 | 125 | def runPuller(self): | 125 | def runPuller(self, *args): |
395 | 126 | """Run the puller script for the given branch type. | 126 | """Run the puller script for the given branch type. |
396 | 127 | 127 | ||
397 | 128 | :param branch_type: One of 'upload', 'mirror' or 'import' | 128 | :param branch_type: One of 'upload', 'mirror' or 'import' |
398 | @@ -132,7 +132,7 @@ | |||
399 | 132 | stdout and stderr respectively. | 132 | stdout and stderr respectively. |
400 | 133 | """ | 133 | """ |
401 | 134 | command = [ | 134 | command = [ |
403 | 135 | '%s/bin/py' % config.root, self._puller_script, '-q'] | 135 | '%s/bin/py' % config.root, self._puller_script, '-q'] + list(args) |
404 | 136 | retcode, output, error = self.runSubprocess(command) | 136 | retcode, output, error = self.runSubprocess(command) |
405 | 137 | return command, retcode, output, error | 137 | return command, retcode, output, error |
406 | 138 | 138 | ||
407 | @@ -430,6 +430,23 @@ | |||
408 | 430 | command, retcode, output, error = self.runPuller() | 430 | command, retcode, output, error = self.runPuller() |
409 | 431 | self.assertRanSuccessfully(command, retcode, output, error) | 431 | self.assertRanSuccessfully(command, retcode, output, error) |
410 | 432 | 432 | ||
411 | 433 | def test_type_filtering(self): | ||
412 | 434 | # When run with --branch-type arguments, the puller only mirrors those | ||
413 | 435 | # branches of the specified types. | ||
414 | 436 | hosted_branch = self.factory.makeAnyBranch( | ||
415 | 437 | branch_type=BranchType.HOSTED) | ||
416 | 438 | mirrored_branch = self.factory.makeAnyBranch( | ||
417 | 439 | branch_type=BranchType.MIRRORED) | ||
418 | 440 | mirrored_branch.requestMirror() | ||
419 | 441 | transaction.commit() | ||
420 | 442 | self.pushBranch(hosted_branch) | ||
421 | 443 | command, retcode, output, error = self.runPuller( | ||
422 | 444 | '--branch-type', 'HOSTED') | ||
423 | 445 | self.assertRanSuccessfully(command, retcode, output, error) | ||
424 | 446 | self.assertMirrored(hosted_branch) | ||
425 | 447 | self.assertIsNot( | ||
426 | 448 | None, mirrored_branch.next_mirror_time) | ||
427 | 449 | |||
428 | 433 | def test_records_script_activity(self): | 450 | def test_records_script_activity(self): |
429 | 434 | # A record gets created in the ScriptActivity table. | 451 | # A record gets created in the ScriptActivity table. |
430 | 435 | script_activity_set = getUtility(IScriptActivitySet) | 452 | script_activity_set = getUtility(IScriptActivitySet) |
431 | 436 | 453 | ||
432 | === modified file 'lib/lp/codehosting/puller/tests/test_scheduler.py' | |||
433 | --- lib/lp/codehosting/puller/tests/test_scheduler.py 2010-01-08 03:07:25 +0000 | |||
434 | +++ lib/lp/codehosting/puller/tests/test_scheduler.py 2010-02-24 19:04:21 +0000 | |||
435 | @@ -8,7 +8,6 @@ | |||
436 | 8 | from datetime import datetime | 8 | from datetime import datetime |
437 | 9 | import logging | 9 | import logging |
438 | 10 | import os | 10 | import os |
439 | 11 | import sys | ||
440 | 12 | import textwrap | 11 | import textwrap |
441 | 13 | import unittest | 12 | import unittest |
442 | 14 | 13 | ||
443 | @@ -42,8 +41,7 @@ | |||
444 | 42 | 41 | ||
445 | 43 | class FakePullerEndpointProxy: | 42 | class FakePullerEndpointProxy: |
446 | 44 | 43 | ||
449 | 45 | def __init__(self, branch_queues=None): | 44 | def __init__(self): |
448 | 46 | self.branch_queues = branch_queues | ||
450 | 47 | self.calls = [] | 45 | self.calls = [] |
451 | 48 | 46 | ||
452 | 49 | def callRemote(self, method_name, *args): | 47 | def callRemote(self, method_name, *args): |
453 | @@ -58,8 +56,8 @@ | |||
454 | 58 | def _default(self, *args): | 56 | def _default(self, *args): |
455 | 59 | return defer.succeed(None) | 57 | return defer.succeed(None) |
456 | 60 | 58 | ||
459 | 61 | def _remote_getBranchPullQueue(self, branch_type): | 59 | def _remote_acquireBranchToPull(self, *args): |
460 | 62 | return defer.succeed(self.branch_queues[branch_type]) | 60 | return defer.succeed(0) |
461 | 63 | 61 | ||
462 | 64 | def _remote_setStackedOn(self, branch_id, stacked_on_location): | 62 | def _remote_setStackedOn(self, branch_id, stacked_on_location): |
463 | 65 | if stacked_on_location == 'raise-branch-not-found': | 63 | if stacked_on_location == 'raise-branch-not-found': |
464 | @@ -70,7 +68,7 @@ | |||
465 | 70 | return defer.succeed(None) | 68 | return defer.succeed(None) |
466 | 71 | 69 | ||
467 | 72 | 70 | ||
469 | 73 | class TestJobScheduler(unittest.TestCase): | 71 | class TestJobScheduler(TrialTestCase): |
470 | 74 | 72 | ||
471 | 75 | def setUp(self): | 73 | def setUp(self): |
472 | 76 | self.masterlock = 'master.lock' | 74 | self.masterlock = 'master.lock' |
473 | @@ -80,8 +78,9 @@ | |||
474 | 80 | if os.path.exists(self.masterlock): | 78 | if os.path.exists(self.masterlock): |
475 | 81 | os.unlink(self.masterlock) | 79 | os.unlink(self.masterlock) |
476 | 82 | 80 | ||
479 | 83 | def makeJobScheduler(self): | 81 | def makeJobScheduler(self, branch_type_names=()): |
480 | 84 | return scheduler.JobScheduler(None, logging.getLogger()) | 82 | return scheduler.JobScheduler( |
481 | 83 | FakePullerEndpointProxy(), logging.getLogger(), branch_type_names) | ||
482 | 85 | 84 | ||
483 | 86 | def testManagerCreatesLocks(self): | 85 | def testManagerCreatesLocks(self): |
484 | 87 | manager = self.makeJobScheduler() | 86 | manager = self.makeJobScheduler() |
485 | @@ -100,6 +99,13 @@ | |||
486 | 100 | self.failUnless(os.path.exists(self.masterlock)) | 99 | self.failUnless(os.path.exists(self.masterlock)) |
487 | 101 | manager.unlock() | 100 | manager.unlock() |
488 | 102 | 101 | ||
489 | 102 | def test_run_calls_acquireBranchToPull(self): | ||
490 | 103 | manager = self.makeJobScheduler(('HOSTED',)) | ||
491 | 104 | manager.run() | ||
492 | 105 | self.assertEqual( | ||
493 | 106 | [('acquireBranchToPull', ('HOSTED',))], | ||
494 | 107 | manager.branch_puller_endpoint.calls) | ||
495 | 108 | |||
496 | 103 | 109 | ||
497 | 104 | class TestPullerWireProtocol(TrialTestCase): | 110 | class TestPullerWireProtocol(TrialTestCase): |
498 | 105 | """Tests for the `PullerWireProtocol`. | 111 | """Tests for the `PullerWireProtocol`. |
499 | @@ -516,7 +522,6 @@ | |||
500 | 516 | layer = TwistedLayer | 522 | layer = TwistedLayer |
501 | 517 | 523 | ||
502 | 518 | def setUp(self): | 524 | def setUp(self): |
503 | 519 | from twisted.internet import reactor | ||
504 | 520 | self.factory = ObjectFactory() | 525 | self.factory = ObjectFactory() |
505 | 521 | self.available_oops_prefixes = set(['foo']) | 526 | self.available_oops_prefixes = set(['foo']) |
506 | 522 | self.eventHandler = self.makePullerMaster( | 527 | self.eventHandler = self.makePullerMaster( |
507 | @@ -526,7 +531,6 @@ | |||
508 | 526 | self.commands_spawned = [] | 531 | self.commands_spawned = [] |
509 | 527 | 532 | ||
510 | 528 | def tearDown(self): | 533 | def tearDown(self): |
511 | 529 | from twisted.internet import reactor | ||
512 | 530 | reactor.spawnProcess = self._realSpawnProcess | 534 | reactor.spawnProcess = self._realSpawnProcess |
513 | 531 | 535 | ||
514 | 532 | def makePullerMaster(self, branch_type_name, default_stacked_on_url=None, | 536 | def makePullerMaster(self, branch_type_name, default_stacked_on_url=None, |
515 | 533 | 537 | ||
516 | === modified file 'lib/lp/testing/factory.py' | |||
517 | --- lib/lp/testing/factory.py 2010-02-23 20:02:07 +0000 | |||
518 | +++ lib/lp/testing/factory.py 2010-02-24 19:04:21 +0000 | |||
519 | @@ -93,7 +93,7 @@ | |||
520 | 93 | BranchType, CodeImportMachineState, CodeImportReviewStatus, | 93 | BranchType, CodeImportMachineState, CodeImportReviewStatus, |
521 | 94 | CodeImportResultStatus, CodeReviewNotificationLevel, | 94 | CodeImportResultStatus, CodeReviewNotificationLevel, |
522 | 95 | RevisionControlSystems) | 95 | RevisionControlSystems) |
524 | 96 | from lp.code.interfaces.branch import UnknownBranchTypeError | 96 | from lp.code.errors import UnknownBranchTypeError |
525 | 97 | from lp.code.interfaces.branchmergequeue import IBranchMergeQueueSet | 97 | from lp.code.interfaces.branchmergequeue import IBranchMergeQueueSet |
526 | 98 | from lp.code.interfaces.branchnamespace import get_branch_namespace | 98 | from lp.code.interfaces.branchnamespace import get_branch_namespace |
527 | 99 | from lp.code.interfaces.codeimport import ICodeImportSet | 99 | from lp.code.interfaces.codeimport import ICodeImportSet |
Mirrored branches are inherently less reliable to access than hosted or imported branches, so it makes sense to be able to handle them in a separate process, and that's what this branch does.
The default behavior is kept the same, we can coordinate with the LOSAs after rollout to set up two different cronjobs.