22
from cStringIO import StringIO
21
24
from bzrlib.tests import TestCaseWithTransport
22
from bzrlib.util.configobj.configobj import ConfigObj
26
from bzrlib.util.configobj.configobj import ConfigObj
28
from configobj import ConfigObj
23
29
from bzrlib import config
25
31
from loggerhead.apps.branch import BranchWSGIApp
32
from loggerhead.apps.http_head import HeadMiddleware
26
33
from paste.fixture import TestApp
27
from paste.httpexceptions import HTTPExceptionHandler
31
def test_config_root():
32
from loggerhead.apps.config import Root
34
app = TestApp(HTTPExceptionHandler(Root(config)))
36
res.mustcontain('loggerhead branches')
34
from paste.httpexceptions import HTTPExceptionHandler, HTTPMovedPermanently
36
from loggerhead.tests.fixtures import (
39
41
class BasicTests(TestCaseWithTransport):
50
52
branch_app = BranchWSGIApp(self.tree.branch, '', **kw).app
51
53
return TestApp(HTTPExceptionHandler(branch_app))
55
def assertOkJsonResponse(self, app, env):
56
start, content = consume_app(app, env)
57
self.assertEqual('200 OK', start[0])
58
self.assertEqual('application/json', dict(start[1])['Content-Type'])
59
self.assertEqual(None, start[2])
60
simplejson.loads(content)
62
def make_branch_app(self, branch, **kw):
63
branch_app = BranchWSGIApp(branch, friendly_name='friendly-name', **kw)
64
branch_app._environ = {
69
branch_app._url_base = ''
54
73
class TestWithSimpleTree(BasicTests):
57
76
BasicTests.setUp(self)
60
self.filecontents = ('some\nmultiline\ndata\n'
61
'with<htmlspecialchars\n')
62
self.build_tree_contents(
63
[('myfilename', self.filecontents)])
64
self.tree.add('myfilename')
65
self.fileid = self.tree.path2id('myfilename')
66
self.msg = 'a very exciting commit message <'
67
self.revid = self.tree.commit(message=self.msg)
77
self.sample_branch_fixture = SampleBranch(self)
79
# XXX: This could be cleaned up more... -- mbp 2011-11-25
80
self.useFixture(self.sample_branch_fixture)
81
self.tree = self.sample_branch_fixture.tree
82
self.fileid = self.sample_branch_fixture.fileid
83
self.filecontents = self.sample_branch_fixture.filecontents
84
self.msg = self.sample_branch_fixture.msg
86
def test_public_private(self):
87
app = self.make_branch_app(self.tree.branch, private=True)
88
self.assertEqual(app.public_private_css(), 'private')
89
app = self.make_branch_app(self.tree.branch)
90
self.assertEqual(app.public_private_css(), 'public')
69
92
def test_changes(self):
70
93
app = self.setUpLoggerhead()
71
94
res = app.get('/changes')
72
95
res.mustcontain(cgi.escape(self.msg))
97
def test_changes_for_file(self):
98
app = self.setUpLoggerhead()
99
res = app.get('/changes?filter_file_id=myfilename-id')
100
res.mustcontain(cgi.escape(self.msg))
74
102
def test_changes_branch_from(self):
75
103
app = self.setUpLoggerhead(served_url="lp:loggerhead")
76
104
res = app.get('/changes')
77
105
self.failUnless("To get this branch, use:" in res)
78
106
self.failUnless("lp:loggerhead" in res)
79
app = self.setUpLoggerhead(served_url=None)
108
def test_no_empty_download_location(self):
109
"""With no served_url, no instructions how to get it"""
110
app = self.setUpLoggerhead()
80
111
res = app.get('/changes')
81
112
self.failIf("To get this branch, use:" in res)
88
119
def test_annotate(self):
89
120
app = self.setUpLoggerhead()
90
121
res = app.get('/annotate', params={'file_id': self.fileid})
122
# If pygments is installed, it inserts <span class="pyg" content into
123
# the output, to trigger highlighting. And it specifically highlights
124
# the < that we are interested in seeing in the output.
125
# Without pygments we have a simple: 'with<htmlspecialchars'
127
# '<span class='pyg-n'>with</span><span class='pyg-o'><</span>'
128
# '<span class='pyg-n'>htmlspecialchars</span>
129
# So we pre-filter the body, to make sure remove spans of that type.
130
body_no_span = re.sub(r'<span class="pyg-.">', '', res.body)
131
body_no_span = body_no_span.replace('</span>', '')
91
132
for line in self.filecontents.splitlines():
92
res.mustcontain(cgi.escape(line))
133
escaped = cgi.escape(line)
134
self.assertTrue(escaped in body_no_span,
135
"did not find %r in %r" % (escaped, body_no_span))
94
137
def test_inventory(self):
95
138
app = self.setUpLoggerhead()
157
202
res = app.get('/changes', status=404)
205
class TestControllerRedirects(BasicTests):
207
Test that a file under /files redirects to /view,
208
and a directory under /view redirects to /files.
212
BasicTests.setUp(self)
214
self.build_tree(('file', 'folder/', 'folder/file'))
215
self.tree.smart_add([])
218
def test_view_folder(self):
219
app = TestApp(BranchWSGIApp(self.tree.branch, '').app)
221
e = self.assertRaises(HTTPMovedPermanently, app.get, '/view/head:/folder')
222
self.assertEqual(e.location(), '/files/head:/folder')
224
def test_files_file(self):
225
app = TestApp(BranchWSGIApp(self.tree.branch, '').app)
227
e = self.assertRaises(HTTPMovedPermanently, app.get, '/files/head:/folder/file')
228
self.assertEqual(e.location(), '/view/head:/folder/file')
229
e = self.assertRaises(HTTPMovedPermanently, app.get, '/files/head:/file')
230
self.assertEqual(e.location(), '/view/head:/file')
233
class TestHeadMiddleware(BasicTests):
236
BasicTests.setUp(self)
238
self.msg = 'trivial commit message'
239
self.revid = self.tree.commit(message=self.msg)
241
def setUpLoggerhead(self, **kw):
242
branch_app = BranchWSGIApp(self.tree.branch, '', **kw).app
243
return TestApp(HTTPExceptionHandler(HeadMiddleware(branch_app)))
246
app = self.setUpLoggerhead()
247
res = app.get('/changes')
248
res.mustcontain(self.msg)
249
self.assertEqual('text/html', res.header('Content-Type'))
252
app = self.setUpLoggerhead()
253
res = app.get('/changes', extra_environ={'REQUEST_METHOD': 'HEAD'})
254
self.assertEqual('text/html', res.header('Content-Type'))
255
self.assertEqualDiff('', res.body)
258
def consume_app(app, env):
261
def start_response(status, headers, exc_info=None):
262
start.append((status, headers, exc_info))
264
extra_content = list(app(env, start_response))
265
body.writelines(extra_content)
266
return start[0], body.getvalue()
160
270
#class TestGlobalConfig(BasicTests):
162
272
# Test that global config settings are respected