14
14
from zope.security.proxy import removeSecurityProxy
16
16
from canonical.config import config
17
from canonical.testing.layers import DatabaseFunctionalLayer
17
from canonical.testing.layers import (
18
DatabaseFunctionalLayer,
18
21
from lp.code.interfaces.codehosting import branch_id_alias
19
22
from lp.codehosting.rewrite import BranchRewriter
20
23
from lp.codehosting.vfs import branch_id_to_path
21
24
from lp.services.log.logger import BufferLogger
22
25
from lp.testing import (
24
29
TestCaseWithFactory,
31
from lp.testing.fixture import PGBouncerFixture
28
34
class TestBranchRewriter(TestCaseWithFactory):
246
254
# buffering, write a complete line of output.
247
255
for input_line in input_lines:
248
256
proc.stdin.write(input_line + '\n')
249
output_lines.append(proc.stdout.readline().rstrip('\n'))
258
nonblocking_readline(proc.stdout, 60).rstrip('\n'))
250
259
# If we create a new branch after the branch-rewrite.py script has
251
260
# connected to the database, or edit a branch name that has already
252
261
# been rewritten, both are rewritten successfully.
260
269
'file:///var/tmp/bazaar.launchpad.dev/mirrors/%s/.bzr/README'
261
270
% branch_id_to_path(new_branch.id))
262
271
proc.stdin.write(new_branch_input + '\n')
263
output_lines.append(proc.stdout.readline().rstrip('\n'))
273
nonblocking_readline(proc.stdout, 60).rstrip('\n'))
265
275
edited_branch_input = '/%s/.bzr/README' % edited_branch.unique_name
266
276
expected_lines.append(
267
277
'file:///var/tmp/bazaar.launchpad.dev/mirrors/%s/.bzr/README'
268
278
% branch_id_to_path(edited_branch.id))
269
279
proc.stdin.write(edited_branch_input + '\n')
270
output_lines.append(proc.stdout.readline().rstrip('\n'))
281
nonblocking_readline(proc.stdout, 60).rstrip('\n'))
272
283
os.kill(proc.pid, signal.SIGINT)
273
284
err = proc.stderr.read()
274
285
# The script produces logging output, but not to stderr.
275
286
self.assertEqual('', err)
276
287
self.assertEqual(expected_lines, output_lines)
290
class TestBranchRewriterScriptHandlesDisconnects(TestCase):
291
"""Ensure branch-rewrite.py survives fastdowntime deploys."""
292
layer = DatabaseLayer
295
script_file = os.path.join(
296
config.root, 'scripts', 'branch-rewrite.py')
298
self.rewriter_proc = subprocess.Popen(
299
[script_file], stdin=subprocess.PIPE, stdout=subprocess.PIPE,
300
stderr=subprocess.PIPE, bufsize=0)
302
self.addCleanup(self.rewriter_proc.terminate)
304
def request(self, query):
305
self.rewriter_proc.stdin.write(query + '\n')
306
self.rewriter_proc.stdin.flush()
308
# 60 second timeout as we might need to wait for the script to
309
# finish starting up.
310
result = nonblocking_readline(self.rewriter_proc.stdout, 60)
312
if result.endswith('\n'):
315
"Incomplete line or no result retrieved from subprocess: %s"
316
% repr(result.getvalue()))
318
def test_reconnects_when_disconnected(self):
319
pgbouncer = self.useFixture(PGBouncerFixture())
323
# Everything should be working, and we get valid output.
324
out = self.request('foo')
325
self.assertEndsWith(out, '/foo')
329
# Now with pgbouncer down, we should get NULL messages and
330
# stderr spam, and this keeps happening. We test more than
331
# once to ensure that we will keep trying to reconnect even
332
# after several failures.
333
for count in range(5):
334
out = self.request('foo')
335
self.assertEqual(out, 'NULL')
339
# Everything should be working, and we get valid output.
340
out = self.request('foo')
341
self.assertEndsWith(out, '/foo')
343
def test_starts_with_db_down(self):
344
pgbouncer = self.useFixture(PGBouncerFixture())
346
# Start with the database down.
351
for count in range(5):
352
out = self.request('foo')
353
self.assertEqual(out, 'NULL')
357
out = self.request('foo')
358
self.assertEndsWith(out, '/foo')