~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/tests/test_simple.py

  • Committer: Robert Collins
  • Date: 2012-02-02 07:42:24 UTC
  • Revision ID: robertc@robertcollins.net-20120202074224-ujea2ocm1u1ws1en
    - Make tz calculations consistent and use UTC in the UI everywhere we show
      a precise timestamp. (Robert Collins, #594591)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007, 2008, 2009, 2011 Canonical Ltd.
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
#
 
17
 
1
18
import cgi
2
 
import unittest
3
 
import os
4
 
import tempfile
5
 
import shutil
6
19
import logging
7
 
 
8
 
import bzrlib.bzrdir
9
 
import bzrlib.osutils
10
 
from configobj import ConfigObj
11
 
 
12
 
from loggerhead.history import History
 
20
import re
 
21
import simplejson
 
22
from cStringIO import StringIO
 
23
 
 
24
from bzrlib.tests import TestCaseWithTransport
 
25
try:
 
26
    from bzrlib.util.configobj.configobj import ConfigObj
 
27
except ImportError:
 
28
    from configobj import ConfigObj
 
29
from bzrlib import config
 
30
 
13
31
from loggerhead.apps.branch import BranchWSGIApp
 
32
from loggerhead.apps.http_head import HeadMiddleware
14
33
from paste.fixture import TestApp
15
 
 
16
 
 
17
 
def test_config_root():
18
 
    from loggerhead.apps.config import Root
19
 
    config = ConfigObj()
20
 
    app = TestApp(Root(config))
21
 
    res = app.get('/')
22
 
    res.mustcontain('loggerhead branches')
23
 
 
24
 
 
25
 
class BasicTests(object):
26
 
 
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):
30
 
        self.setUp()
31
 
 
32
 
    def teardown_method(self, meth):
33
 
        self.tearDown()
 
34
from paste.httpexceptions import HTTPExceptionHandler, HTTPMovedPermanently
 
35
 
 
36
from loggerhead.tests.fixtures import (
 
37
    SampleBranch,
 
38
    )
 
39
 
 
40
 
 
41
class BasicTests(TestCaseWithTransport):
34
42
 
35
43
    def setUp(self):
36
 
        logging.basicConfig(level=logging.DEBUG)
37
 
        self.bzrbranch = None
38
 
        self.old_bzrhome = None
 
44
        TestCaseWithTransport.setUp(self)
 
45
        logging.basicConfig(level=logging.ERROR)
 
46
        logging.getLogger('bzr').setLevel(logging.CRITICAL)
39
47
 
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()
46
 
 
47
 
    config_template = """
48
 
    [project]
49
 
        [[branch]]
50
 
            branch_name = 'branch'
51
 
            folder = '%(branch)s'
52
 
    """
53
 
 
54
 
    def makeHistory(self):
55
 
        return History.from_folder(self.bzrbranch)
56
 
 
57
 
    def setUpLoggerhead(self):
58
 
        app = TestApp(BranchWSGIApp(self.bzrbranch).app)
59
 
        return app
60
 
 
61
 
    def tearDown(self):
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('.')
 
50
 
 
51
    def setUpLoggerhead(self, **kw):
 
52
        branch_app = BranchWSGIApp(self.tree.branch, '', **kw).app
 
53
        return TestApp(HTTPExceptionHandler(branch_app))
 
54
 
 
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)
 
61
 
 
62
    def make_branch_app(self, branch, **kw):
 
63
        branch_app = BranchWSGIApp(branch, friendly_name='friendly-name', **kw)
 
64
        branch_app._environ = {
 
65
            'wsgi.url_scheme':'',
 
66
            'SERVER_NAME':'',
 
67
            'SERVER_PORT':'80',
 
68
            }
 
69
        branch_app._url_base = ''
 
70
        return branch_app
65
71
 
66
72
 
67
73
class TestWithSimpleTree(BasicTests):
68
74
 
69
75
    def setUp(self):
70
76
        BasicTests.setUp(self)
71
 
        self.createBranch()
72
 
 
73
 
        f = open(os.path.join(self.bzrbranch, 'myfilename'), 'w')
74
 
        self.filecontents = ('some\nmultiline\ndata\n'
75
 
                             'with<htmlspecialchars\n')
76
 
        try:
77
 
            f.write(self.filecontents)
78
 
        finally:
79
 
            f.close()
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)
84
 
 
 
77
        self.sample_branch_fixture = SampleBranch(self)
 
78
 
 
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
 
85
 
 
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')
85
91
 
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))
90
96
 
 
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))
 
101
 
 
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)
 
107
 
 
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)
 
113
 
91
114
    def test_changes_search(self):
92
115
        app = self.setUpLoggerhead()
93
116
        res = app.get('/changes', params={'q': 'foo'})
95
118
 
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 &lt; that we are interested in seeing in the output.
 
125
        # Without pygments we have a simple: 'with&lt;htmlspecialchars'
 
126
        # With it, we have
 
127
        # '<span class='pyg-n'>with</span><span class='pyg-o'>&lt;</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))
101
136
 
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')
 
149
 
 
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)
 
154
 
 
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)
106
159
 
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&lt;')
110
165
        res.mustcontain('myfilename')
111
166
 
112
167
 
113
168
class TestEmptyBranch(BasicTests):
 
169
    """Test that an empty branch doesn't break"""
114
170
 
115
171
    def setUp(self):
116
172
        BasicTests.setUp(self)
121
177
        res = app.get('/changes')
122
178
        res.mustcontain('No revisions!')
123
179
 
 
180
    def test_inventory(self):
 
181
        app = self.setUpLoggerhead()
 
182
        res = app.get('/files')
 
183
        res.mustcontain('No revisions!')
 
184
 
 
185
 
 
186
class TestHiddenBranch(BasicTests):
 
187
    """
 
188
    Test that hidden branches aren't shown
 
189
    FIXME: not tested that it doesn't show up on listings
 
190
    """
 
191
 
 
192
    def setUp(self):
 
193
        BasicTests.setUp(self)
 
194
        self.createBranch()
 
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,))
 
199
 
 
200
    def test_no_access(self):
 
201
        app = self.setUpLoggerhead()
 
202
        res = app.get('/changes', status=404)
 
203
 
 
204
 
 
205
class TestControllerRedirects(BasicTests):
 
206
    """
 
207
    Test that a file under /files redirects to /view,
 
208
    and a directory under /view redirects to /files.
 
209
    """
 
210
 
 
211
    def setUp(self):
 
212
        BasicTests.setUp(self)
 
213
        self.createBranch()
 
214
        self.build_tree(('file', 'folder/', 'folder/file'))
 
215
        self.tree.smart_add([])
 
216
        self.tree.commit('')
 
217
 
 
218
    def test_view_folder(self):
 
219
        app = TestApp(BranchWSGIApp(self.tree.branch, '').app)
 
220
 
 
221
        e = self.assertRaises(HTTPMovedPermanently, app.get, '/view/head:/folder')
 
222
        self.assertEqual(e.location(), '/files/head:/folder')
 
223
 
 
224
    def test_files_file(self):
 
225
        app = TestApp(BranchWSGIApp(self.tree.branch, '').app)
 
226
 
 
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')
 
231
 
 
232
 
 
233
class TestHeadMiddleware(BasicTests):
 
234
 
 
235
    def setUp(self):
 
236
        BasicTests.setUp(self)
 
237
        self.createBranch()
 
238
        self.msg = 'trivial commit message'
 
239
        self.revid = self.tree.commit(message=self.msg)
 
240
 
 
241
    def setUpLoggerhead(self, **kw):
 
242
        branch_app = BranchWSGIApp(self.tree.branch, '', **kw).app
 
243
        return TestApp(HTTPExceptionHandler(HeadMiddleware(branch_app)))
 
244
 
 
245
    def test_get(self):
 
246
        app = self.setUpLoggerhead()
 
247
        res = app.get('/changes')
 
248
        res.mustcontain(self.msg)
 
249
        self.assertEqual('text/html', res.header('Content-Type'))
 
250
 
 
251
    def test_head(self):
 
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)
 
256
 
 
257
 
 
258
def consume_app(app, env):
 
259
    body = StringIO()
 
260
    start = []
 
261
    def start_response(status, headers, exc_info=None):
 
262
        start.append((status, headers, exc_info))
 
263
        return body.write
 
264
    extra_content = list(app(env, start_response))
 
265
    body.writelines(extra_content)
 
266
    return start[0], body.getvalue()
 
267
 
 
268
 
 
269
 
 
270
#class TestGlobalConfig(BasicTests):
 
271
#    """
 
272
#    Test that global config settings are respected
 
273
#    """
 
274
 
 
275
#    def setUp(self):
 
276
#        BasicTests.setUp(self)
 
277
#        self.createBranch()
 
278
#        config.GlobalConfig().set_user_option('http_version', 'True')
 
279
 
 
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)