1
# Copyright (C) 2007, 2008, 2009, 2011 Canonical Ltd.
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
10
from configobj import ConfigObj
12
from loggerhead.history import History
22
from cStringIO import StringIO
24
from bzrlib.tests import TestCaseWithTransport
26
from bzrlib.util.configobj.configobj import ConfigObj
28
from configobj import ConfigObj
29
from bzrlib import config
13
31
from loggerhead.apps.branch import BranchWSGIApp
32
from loggerhead.apps.http_head import HeadMiddleware
14
33
from paste.fixture import TestApp
17
def test_config_root():
18
from loggerhead.apps.config import Root
20
app = TestApp(Root(config))
22
res.mustcontain('loggerhead branches')
25
class BasicTests(object):
27
# setup_method and teardown_method are so i can run the tests with
28
# py.test and take advantage of the error reporting.
29
def setup_method(self, meth):
32
def teardown_method(self, meth):
34
from paste.httpexceptions import HTTPExceptionHandler, HTTPMovedPermanently
36
from loggerhead.tests.fixtures import (
41
class BasicTests(TestCaseWithTransport):
36
logging.basicConfig(level=logging.DEBUG)
38
self.old_bzrhome = None
44
TestCaseWithTransport.setUp(self)
45
logging.basicConfig(level=logging.ERROR)
46
logging.getLogger('bzr').setLevel(logging.CRITICAL)
40
48
def createBranch(self):
41
self.old_bzrhome = bzrlib.osutils.set_or_unset_env('BZR_HOME', '')
42
self.bzrbranch = tempfile.mkdtemp()
43
self.branch = bzrlib.bzrdir.BzrDir.create_branch_convenience(
44
self.bzrbranch, force_new_tree=True)
45
self.tree = self.branch.bzrdir.open_workingtree()
50
branch_name = 'branch'
54
def makeHistory(self):
55
return History.from_folder(self.bzrbranch)
57
def setUpLoggerhead(self):
58
app = TestApp(BranchWSGIApp(self.bzrbranch).app)
62
if self.bzrbranch is not None:
63
shutil.rmtree(self.bzrbranch)
64
bzrlib.osutils.set_or_unset_env('BZR_HOME', self.old_bzrhome)
49
self.tree = self.make_branch_and_tree('.')
51
def setUpLoggerhead(self, **kw):
52
branch_app = BranchWSGIApp(self.tree.branch, '', **kw).app
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 = ''
67
73
class TestWithSimpleTree(BasicTests):
70
76
BasicTests.setUp(self)
73
f = open(os.path.join(self.bzrbranch, 'myfilename'), 'w')
74
self.filecontents = ('some\nmultiline\ndata\n'
75
'with<htmlspecialchars\n')
77
f.write(self.filecontents)
80
self.tree.add('myfilename')
81
self.fileid = self.tree.path2id('myfilename')
82
self.msg = 'a very exciting commit message <'
83
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')
86
92
def test_changes(self):
87
93
app = self.setUpLoggerhead()
88
94
res = app.get('/changes')
89
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))
102
def test_changes_branch_from(self):
103
app = self.setUpLoggerhead(served_url="lp:loggerhead")
104
res = app.get('/changes')
105
self.failUnless("To get this branch, use:" in res)
106
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()
111
res = app.get('/changes')
112
self.failIf("To get this branch, use:" in res)
91
114
def test_changes_search(self):
92
115
app = self.setUpLoggerhead()
93
116
res = app.get('/changes', params={'q': 'foo'})
96
119
def test_annotate(self):
97
120
app = self.setUpLoggerhead()
98
res = app.get('/annotate', params={'file_id':self.fileid})
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>', '')
99
132
for line in self.filecontents.splitlines():
100
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))
102
137
def test_inventory(self):
103
138
app = self.setUpLoggerhead()
104
139
res = app.get('/files')
105
140
res.mustcontain('myfilename')
141
res = app.get('/files/')
142
res.mustcontain('myfilename')
143
res = app.get('/files/1')
144
res.mustcontain('myfilename')
145
res = app.get('/files/1/')
146
res.mustcontain('myfilename')
147
res = app.get('/files/1/?file_id=' + self.tree.path2id(''))
148
res.mustcontain('myfilename')
150
def test_inventory_bad_rev_404(self):
151
app = self.setUpLoggerhead()
152
res = app.get('/files/200', status=404)
153
res = app.get('/files/invalid-revid', status=404)
155
def test_inventory_bad_path_404(self):
156
app = self.setUpLoggerhead()
157
res = app.get('/files/1/hooha', status=404)
158
res = app.get('/files/1?file_id=dssadsada', status=404)
107
160
def test_revision(self):
108
161
app = self.setUpLoggerhead()
109
162
res = app.get('/revision/1')
163
res.mustcontain(no=['anotherfile<'])
164
res.mustcontain('anotherfile<')
110
165
res.mustcontain('myfilename')
113
168
class TestEmptyBranch(BasicTests):
169
"""Test that an empty branch doesn't break"""
116
172
BasicTests.setUp(self)
121
177
res = app.get('/changes')
122
178
res.mustcontain('No revisions!')
180
def test_inventory(self):
181
app = self.setUpLoggerhead()
182
res = app.get('/files')
183
res.mustcontain('No revisions!')
186
class TestHiddenBranch(BasicTests):
188
Test that hidden branches aren't shown
189
FIXME: not tested that it doesn't show up on listings
193
BasicTests.setUp(self)
195
locations = config.locations_config_filename()
196
config.ensure_config_dir_exists()
197
open(locations, 'wb').write('[%s]\nhttp_serve = False'
198
% (self.tree.branch.base,))
200
def test_no_access(self):
201
app = self.setUpLoggerhead()
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()
270
#class TestGlobalConfig(BasicTests):
272
# Test that global config settings are respected
276
# BasicTests.setUp(self)
277
# self.createBranch()
278
# config.GlobalConfig().set_user_option('http_version', 'True')
280
# def test_setting_respected(self):
281
#FIXME: Figure out how to test this properly
282
# app = self.setUpLoggerhead()
283
# res = app.get('/changes', status=200)