22
from cStringIO import StringIO
24
21
from bzrlib.tests import TestCaseWithTransport
26
from bzrlib.util.configobj.configobj import ConfigObj
28
from configobj import ConfigObj
22
from bzrlib.util.configobj.configobj import ConfigObj
29
23
from bzrlib import config
31
25
from loggerhead.apps.branch import BranchWSGIApp
32
from loggerhead.apps.http_head import HeadMiddleware
33
26
from paste.fixture import TestApp
34
from paste.httpexceptions import HTTPExceptionHandler, HTTPMovedPermanently
36
from loggerhead.tests.fixtures import (
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')
41
39
class BasicTests(TestCaseWithTransport):
52
50
branch_app = BranchWSGIApp(self.tree.branch, '', **kw).app
53
51
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 = ''
73
54
class TestWithSimpleTree(BasicTests):
76
57
BasicTests.setUp(self)
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')
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)
92
69
def test_changes(self):
93
70
app = self.setUpLoggerhead()
94
71
res = app.get('/changes')
95
72
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))
102
74
def test_changes_branch_from(self):
103
75
app = self.setUpLoggerhead(served_url="lp:loggerhead")
104
76
res = app.get('/changes')
105
77
self.failUnless("To get this branch, use:" in res)
106
78
self.failUnless("lp:loggerhead" in res)
108
def test_no_empty_download_location(self):
109
"""With no served_url, no instructions how to get it"""
110
app = self.setUpLoggerhead()
79
app = self.setUpLoggerhead(served_url=None)
111
80
res = app.get('/changes')
112
81
self.failIf("To get this branch, use:" in res)
119
88
def test_annotate(self):
120
89
app = self.setUpLoggerhead()
121
90
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>', '')
132
91
for line in self.filecontents.splitlines():
133
escaped = cgi.escape(line)
134
self.assertTrue(escaped in body_no_span,
135
"did not find %r in %r" % (escaped, body_no_span))
92
res.mustcontain(cgi.escape(line))
137
94
def test_inventory(self):
138
95
app = self.setUpLoggerhead()
202
157
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()
270
160
#class TestGlobalConfig(BasicTests):
272
162
# Test that global config settings are respected