File: test_functional.py

package info (click to toggle)
freedombox 26.2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 82,976 kB
  • sloc: python: 48,504; javascript: 1,736; xml: 481; makefile: 290; sh: 167; php: 32
file content (343 lines) | stat: -rw-r--r-- 13,559 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Functional, browser based tests for gitweb app.
"""
import contextlib
import os
import shutil
import subprocess
import tempfile

import pytest

from plinth.tests import functional

pytestmark = [pytest.mark.apps, pytest.mark.gitweb]

_default_url = functional.config['DEFAULT']['url']


class TestGitwebApp(functional.BaseAppTests):
    app_name = 'gitweb'
    has_service = False
    has_web = True

    def test_all_repos_private(self, session_browser):
        """Test repo accessability when all repos are private."""
        _create_repo(session_browser, 'Test-repo', 'private',
                     ok_if_exists=True)
        _set_all_repos_private(session_browser)
        if not functional.user_exists(session_browser, 'gitweb_user'):
            functional.create_user(session_browser, 'gitweb_user',
                                   groups=['git-access'])
        if not functional.user_exists(session_browser, 'nogroupuser'):
            functional.create_user(session_browser, 'nogroupuser', groups=[])

        functional.login_with_account(session_browser, functional.base_url,
                                      'gitweb_user')
        assert functional.is_available(session_browser, 'gitweb')
        assert len(functional.find_on_front_page(session_browser,
                                                 'gitweb')) == 1

        functional.login_with_account(session_browser, functional.base_url,
                                      'nogroupuser')
        assert not functional.is_available(session_browser, 'gitweb')
        assert len(functional.find_on_front_page(session_browser,
                                                 'gitweb')) == 0

        functional.logout(session_browser)
        functional.access_url(session_browser, 'gitweb')
        assert functional.is_login_prompt(session_browser)
        assert len(functional.find_on_front_page(session_browser,
                                                 'gitweb')) == 0

    @pytest.mark.backups
    def test_backup_restore(self, session_browser):
        """Test backing up and restoring."""
        _create_repo(session_browser, 'Test-repo', ok_if_exists=True)
        functional.backup_create(session_browser, 'gitweb', 'test_gitweb')
        _delete_repo(session_browser, 'Test-repo')
        functional.backup_restore(session_browser, 'gitweb', 'test_gitweb')
        assert _repo_exists(session_browser, 'Test-repo')
        assert functional.is_available(session_browser, 'gitweb')

    @pytest.mark.parametrize('access', ['public', 'private'])
    @pytest.mark.parametrize('repo_name', ['Test-repo', 'Test-repo.git'])
    @pytest.mark.parametrize('app_status', ['enabled', 'disabled'])
    def test_create_delete_repo(self, session_browser, access, repo_name,
                                app_status):
        """Test creating and deleting a repo and accessing with a git
        client."""
        if app_status == "disabled":
            functional.app_disable(session_browser, 'gitweb')

        _delete_repo(session_browser, repo_name, ignore_missing=True)
        _create_repo(session_browser, repo_name, access)

        assert _repo_exists(session_browser, repo_name, access)

        if app_status == "enabled":
            assert _site_repo_exists(session_browser, repo_name)

            if access == "public":
                assert _repo_is_readable(repo_name)
            else:
                assert not _repo_is_readable(repo_name)

            assert not _repo_is_writable(repo_name)
            assert _repo_is_readable(repo_name, with_auth=True)
            assert _repo_is_writable(repo_name, with_auth=True)

        _delete_repo(session_browser, repo_name)
        assert not _repo_exists(session_browser, repo_name)

    def test_both_private_and_public_repo_exist(self, session_browser):
        """Tests when both private and public repo exist."""
        _create_repo(session_browser, 'Test-repo', 'public', True)
        _create_repo(session_browser, 'Test-repo-private', 'private', True)

        functional.logout(session_browser)
        assert _site_repo_exists(session_browser, 'Test-repo')
        assert not _site_repo_exists(session_browser, 'Test-repo-private')

    @pytest.mark.parametrize('app_status', ['enabled', 'disabled'])
    def test_edit_repo_metadata(self, session_browser, app_status):
        """Test edit repo metadata."""
        if app_status == "disabled":
            functional.app_disable(session_browser, 'gitweb')

        _create_repo(session_browser, 'Test-repo2', 'public',
                     ok_if_exists=True)
        _delete_repo(session_browser, 'Test-repo', ignore_missing=True)
        repo_metadata = {
            'name': 'Test-repo',
            'description': 'Test Description',
            'owner': 'Test Owner',
            'access': 'private',
        }
        _edit_repo_metadata(session_browser, 'Test-repo2', repo_metadata)
        assert _get_repo_metadata(session_browser,
                                  "Test-repo") == repo_metadata

        if app_status == "enabled":
            _create_branch('Test-repo', 'branch1')
            _set_default_branch(session_browser, 'Test-repo', 'branch1')

            assert _get_gitweb_site_default_repo_branch(
                session_browser, 'Test-repo') == 'branch1'


def _create_local_repo(path):
    """Create a local repository."""
    shutil.rmtree(path, ignore_errors=True)
    os.mkdir(path)
    create_repo_commands = [
        'git init -q', 'git config http.sslVerify false',
        'git -c "user.name=Tester" -c "user.email=tester" '
        'commit -q --allow-empty --no-gpg-sign -m "test"'
    ]
    for command in create_repo_commands:
        subprocess.check_call(command, shell=True, cwd=path)


def _create_repo(browser, repo, access=None, ok_if_exists=False):
    """Create repository."""
    if not _repo_exists(browser, repo, access):
        _delete_repo(browser, repo, ignore_missing=True)
        browser.links.find_by_href('/plinth/apps/gitweb/create/').first.click()
        browser.find_by_id('id_gitweb-name').fill(repo)
        if access == 'private':
            browser.find_by_id('id_gitweb-is_private').check()
        elif access == 'public':
            browser.find_by_id('id_gitweb-is_private').uncheck()
        functional.submit(browser, form_class='form-gitweb')
    elif not ok_if_exists:
        assert False, 'Repo already exists.'


def _create_branch(repo, branch):
    """Add a branch to the repo."""
    repo_url = _get_repo_url(repo, with_auth=True)

    with _gitweb_temp_directory() as temp_directory:
        repo_path = os.path.join(temp_directory, repo)

        _create_local_repo(repo_path)

        add_branch_commands = [['git', 'checkout', '-q', '-b', branch],
                               [
                                   'git', '-c', 'user.name=Tester', '-c',
                                   'user.email=tester', 'commit', '-q',
                                   '--allow-empty', '--no-gpg-sign', '-m',
                                   'test_branch1'
                               ],
                               ['git', 'push', '-q', '-f', repo_url, branch]]
        for command in add_branch_commands:
            subprocess.check_call(command, cwd=repo_path)


def _delete_repo(browser, repo, ignore_missing=False):
    """Delete repository."""
    functional.nav_to_module(browser, 'gitweb')
    if repo.endswith('.git'):
        repo = repo[:-4]
    delete_link = browser.links.find_by_href(
        '/plinth/apps/gitweb/{}/delete/'.format(repo))
    if delete_link or not ignore_missing:
        delete_link.first.click()
        functional.submit(browser, form_class='form-delete')


def _edit_repo_metadata(browser, repo, metadata):
    """Set repository metadata."""
    functional.nav_to_module(browser, 'gitweb')
    browser.links.find_by_href(
        '/plinth/apps/gitweb/{}/edit/'.format(repo)).first.click()
    browser.find_by_id('id_gitweb-name').fill(metadata['name'])
    browser.find_by_id('id_gitweb-description').fill(metadata['description'])
    browser.find_by_id('id_gitweb-owner').fill(metadata['owner'])
    if metadata['access'] == 'private':
        browser.find_by_id('id_gitweb-is_private').check()
    else:
        browser.find_by_id('id_gitweb-is_private').uncheck()
    functional.submit(browser, form_class='form-gitweb')


def _get_gitweb_site_default_repo_branch(browser, repo):
    functional.nav_to_module(browser, 'gitweb')
    browser.find_by_css('a[href="/gitweb/{0}.git"]'.format(repo)).first.click()

    return browser.find_by_css('.head').first.text


def _get_repo_metadata(browser, repo):
    """Get repository metadata."""
    functional.nav_to_module(browser, 'gitweb')
    browser.links.find_by_href(
        '/plinth/apps/gitweb/{}/edit/'.format(repo)).first.click()
    metadata = {}
    for item in ['name', 'description', 'owner']:
        metadata[item] = browser.find_by_id('id_gitweb-' + item).value
    if browser.find_by_id('id_gitweb-is_private').value:
        metadata['access'] = 'private'
    else:
        metadata['access'] = 'public'
    return metadata


def _get_repo_url(repo, with_auth):
    """"Get repository URL"""
    scheme = 'http'
    if _default_url.startswith('https://'):
        scheme = 'https'
    url = _default_url.split(
        '://')[1] if '://' in _default_url else _default_url
    password = 'gitweb_wrong_password'
    if with_auth:
        password = functional.config['DEFAULT']['password']

    return '{0}://{1}:{2}@{3}/gitweb/{4}'.format(
        scheme, functional.config['DEFAULT']['username'], password, url, repo)


def _gitweb_git_command_is_successful(command, cwd):
    """Check if a command runs successfully or gives authentication error"""
    # Tell OS not to translate command return messages
    env = os.environ.copy()
    env['LC_ALL'] = 'C'

    process = subprocess.run(command, capture_output=True, cwd=cwd, env=env,
                             check=False)
    if process.returncode != 0:
        if 'Authentication failed' in process.stderr.decode():
            return False

        process.check_returncode()  # Raise exception
    return True


@contextlib.contextmanager
def _gitweb_temp_directory():
    """Create temporary directory"""
    name = tempfile.mkdtemp(prefix='plinth_test_gitweb_')
    yield name
    shutil.rmtree(name)


def _repo_exists(browser, repo, access=None):
    """Check whether the repository exists."""
    functional.nav_to_module(browser, 'gitweb')
    if not repo.endswith('.git'):
        repo = repo + ".git"
    links_found = browser.links.find_by_href('/gitweb/{}'.format(repo))
    access_matches = True
    if links_found and access:
        parent = links_found.first.find_by_xpath('..').first
        private_icon = parent.find_by_css('.repo-private-icon')
        if access == 'private':
            access_matches = bool(private_icon)
        if access == 'public':
            access_matches = not bool(private_icon)
    return bool(links_found) and access_matches


def _repo_is_readable(repo, with_auth=False):
    """Check if a git repo is readable with git client."""
    url = _get_repo_url(repo, with_auth)
    git_command = ['git', 'clone', '-c', 'http.sslverify=false', url]
    with _gitweb_temp_directory() as cwd:
        return _gitweb_git_command_is_successful(git_command, cwd)


def _repo_is_writable(repo, with_auth=False):
    """Check if a git repo is writable with git client."""
    url = _get_repo_url(repo, with_auth)
    with _gitweb_temp_directory() as temp_directory:
        repo_directory = os.path.join(temp_directory, 'test-project')
        _create_local_repo(repo_directory)
        git_push_command = [
            'git', '-c', 'push.default=current', 'push', '-qf', url
        ]
        return _gitweb_git_command_is_successful(git_push_command,
                                                 repo_directory)


def _set_all_repos_private(browser):
    """Set all repositories private"""
    functional.nav_to_module(browser, 'gitweb')
    public_repos = []
    for element in browser.find_by_css('#gitweb-repo-list .list-group-item'):
        if not element.find_by_css('.repo-private-icon'):
            repo = element.find_by_css('.repo-label').first.text
            public_repos.append(repo)
    for repo in public_repos:
        _set_repo_access(browser, repo, 'private')


def _set_default_branch(browser, repo, branch):
    """Set default branch of the repository."""
    functional.nav_to_module(browser, 'gitweb')
    browser.links.find_by_href(
        '/plinth/apps/gitweb/{}/edit/'.format(repo)).first.click()
    browser.find_by_id('id_gitweb-default_branch').select(branch)
    functional.submit(browser, form_class='form-gitweb')


def _set_repo_access(browser, repo, access):
    """Set repository as public or private."""
    functional.nav_to_module(browser, 'gitweb')
    browser.links.find_by_href(
        '/plinth/apps/gitweb/{}/edit/'.format(repo)).first.click()
    if access == 'private':
        browser.find_by_id('id_gitweb-is_private').check()
    else:
        browser.find_by_id('id_gitweb-is_private').uncheck()
    functional.submit(browser, form_class='form-gitweb')


def _site_repo_exists(browser, repo):
    """Check whether the repository exists on Gitweb site."""
    browser.visit('{}/gitweb'.format(_default_url))
    if not repo.endswith('.git'):
        repo = repo + ".git"
    return bool(browser.find_by_css('a[href="/gitweb/{0}"]'.format(repo)))