Blame tests/test_pagure_repospanner.py

Patrick Uiterwijk 3f97f6
# -*- coding: utf-8 -*-
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
"""
Patrick Uiterwijk 3f97f6
 (c) 2015-2018 - Copyright Red Hat Inc
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
 Authors:
Patrick Uiterwijk 3f97f6
   Patrick Uiterwijk <puiterwijk@redhat.com></puiterwijk@redhat.com>
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
"""
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
from __future__ import unicode_literals
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
__requires__ = ['SQLAlchemy >= 0.8']
Patrick Uiterwijk 3f97f6
import pkg_resources
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
import datetime
Patrick Uiterwijk 3f97f6
import unittest
Patrick Uiterwijk 3f97f6
import shutil
Patrick Uiterwijk 3f97f6
import subprocess
Patrick Uiterwijk 3f97f6
import sys
Patrick Uiterwijk 3f97f6
import tempfile
Patrick Uiterwijk 3f97f6
import time
Patrick Uiterwijk 3f97f6
import os
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
import six
Patrick Uiterwijk 3f97f6
import json
Patrick Uiterwijk 3f97f6
import pygit2
Patrick Uiterwijk 3f97f6
import requests
Patrick Uiterwijk 3f97f6
from requests.adapters import HTTPAdapter
Patrick Uiterwijk 3f97f6
from requests.packages.urllib3.util.retry import Retry
Patrick Uiterwijk 3f97f6
from mock import patch, MagicMock
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
sys.path.insert(0, os.path.join(os.path.dirname(
Patrick Uiterwijk 3f97f6
    os.path.abspath(__file__)), '..'))
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
import pagure.lib
Patrick Uiterwijk 3f97f6
import tests
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
REPOSPANNER_CONFIG_TEMPLATE = """
Patrick Uiterwijk 3f97f6
---
Patrick Uiterwijk 3f97f6
ca:
Patrick Uiterwijk 3f97f6
  path: %(path)s/repospanner/pki
Patrick Uiterwijk 3f97f6
admin:
Patrick Uiterwijk 3f97f6
  url:  https://nodea.regiona.repospanner.local:%(gitport)s/
Patrick Uiterwijk 3f97f6
  ca:   %(path)s/repospanner/pki/ca.crt
Patrick Uiterwijk 3f97f6
  cert: %(path)s/repospanner/pki/admin.crt
Patrick Uiterwijk 3f97f6
  key:  %(path)s/repospanner/pki/admin.key
Patrick Uiterwijk 3f97f6
storage:
Patrick Uiterwijk 3f97f6
  state: %(path)s/repospanner/state
Patrick Uiterwijk 3f97f6
  git:
Patrick Uiterwijk 3f97f6
    type: tree
Patrick Uiterwijk 3f97f6
    clustered: true
Patrick Uiterwijk 3f97f6
    directory: %(path)s/repospanner/git
Patrick Uiterwijk 3f97f6
listen:
Patrick Uiterwijk 3f97f6
  rpc:  127.0.0.1:%(rpcport)s
Patrick Uiterwijk 3f97f6
  http: 127.0.0.1:%(gitport)s
Patrick Uiterwijk 3f97f6
certificates:
Patrick Uiterwijk 3f97f6
  ca: %(path)s/repospanner/pki/ca.crt
Patrick Uiterwijk 3f97f6
  client:
Patrick Uiterwijk 3f97f6
    cert: %(path)s/repospanner/pki/nodea.regiona.crt
Patrick Uiterwijk 3f97f6
    key:  %(path)s/repospanner/pki/nodea.regiona.key
Patrick Uiterwijk 3f97f6
  server:
Patrick Uiterwijk 3f97f6
    default:
Patrick Uiterwijk 3f97f6
      cert: %(path)s/repospanner/pki/nodea.regiona.crt
Patrick Uiterwijk 3f97f6
      key:  %(path)s/repospanner/pki/nodea.regiona.key
Patrick Uiterwijk 3f97f6
hooks:
Patrick Uiterwijk 3f97f6
  bubblewrap:
Patrick Uiterwijk 3f97f6
    enabled: true
Patrick Uiterwijk 3f97f6
    unshare:
Patrick Uiterwijk 3f97f6
    - net
Patrick Uiterwijk 3f97f6
    - ipc
Patrick Uiterwijk 3f97f6
    - pid
Patrick Uiterwijk 3f97f6
    - uts
Patrick Uiterwijk 3f97f6
    share_net: false
Patrick Uiterwijk 3f97f6
    mount_proc: true
Patrick Uiterwijk 3f97f6
    mount_dev: true
Patrick Uiterwijk 3f97f6
    uid:
Patrick Uiterwijk 3f97f6
    gid:
Patrick Uiterwijk 3f97f6
    hostname: myhostname
Patrick Uiterwijk 3f97f6
    bind:
Patrick Uiterwijk 3f97f6
    ro_bind:
Patrick Uiterwijk 3f97f6
      /usr: /usr
Patrick Uiterwijk 3f97f6
    symlink:
Patrick Uiterwijk 3f97f6
      usr/lib64: /lib64
Patrick Uiterwijk 3f97f6
      usr/bin: /bin
Patrick Uiterwijk 3f97f6
  runner: /usr/bin/repohookrunner
Patrick Uiterwijk 3f97f6
  user: 0
Patrick Uiterwijk 3f97f6
"""
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
class PagureRepoSpannerTests(tests.Modeltests):
Patrick Uiterwijk 3f97f6
    """ Tests for repoSpanner integration of pagure """
Patrick Uiterwijk 3f97f6
    repospanner_binary = None
Patrick Uiterwijk 3f97f6
    repospanner_runlog = None
Patrick Uiterwijk 3f97f6
    repospanner_proc = None
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    def run_cacmd(self, logfile, *args):
Patrick Uiterwijk 3f97f6
        """ Run a repoSpanner CA command. """
Patrick Uiterwijk 3f97f6
        subprocess.check_call(
Patrick Uiterwijk 3f97f6
            [self.repospanner_binary,
Patrick Uiterwijk 3f97f6
             '--config',
Patrick Uiterwijk 3f97f6
             os.path.join(self.path, 'repospanner', 'config.yml'),
Patrick Uiterwijk 3f97f6
             # NEVER use this in a production system! It makes repeatable keys
Patrick Uiterwijk 3f97f6
             'ca'] + list(args) + ['--very-insecure-weak-keys'],
Patrick Uiterwijk 3f97f6
            stdout=logfile,
Patrick Uiterwijk 3f97f6
            stderr=subprocess.STDOUT,
Patrick Uiterwijk 3f97f6
        )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    def setUp(self):
Patrick Uiterwijk 3f97f6
        """ set up the environment. """
Patrick Uiterwijk 3f97f6
        possible_paths = [
Patrick Uiterwijk 3f97f6
            './repospanner',
Patrick Uiterwijk 3f97f6
            '/usr/bin/repospanner',
Patrick Uiterwijk 3f97f6
        ]
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        for option in possible_paths:
Patrick Uiterwijk 3f97f6
            option = os.path.abspath(option)
Patrick Uiterwijk 3f97f6
            if os.path.exists(option):
Patrick Uiterwijk 3f97f6
                self.repospanner_binary = option
Patrick Uiterwijk 3f97f6
                break
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        if not self.repospanner_binary:
Patrick Uiterwijk 3f97f6
            raise unittest.SkipTest('repoSpanner not found')
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        # Only run the setUp() function if we are actually going ahead and run
Patrick Uiterwijk 3f97f6
        # this test. The reason being that otherwise, setUp will set up a
Patrick Uiterwijk 3f97f6
        # database, but because we "error out" from setUp, the tearDown()
Patrick Uiterwijk 3f97f6
        # function never gets called, leaving it behind.
Patrick Uiterwijk 3f97f6
        super(PagureRepoSpannerTests, self).setUp()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        # TODO: Find free ports
Patrick Uiterwijk 3f97f6
        configvals = {
Patrick Uiterwijk 3f97f6
            'path': self.path,
Patrick Uiterwijk 3f97f6
            'gitport': 8443,
Patrick Uiterwijk 3f97f6
            'rpcport': 8444,
Patrick Uiterwijk 3f97f6
        }
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        os.mkdir(os.path.join(self.path, 'repospanner'))
Patrick Uiterwijk 3f97f6
        cfgpath = os.path.join(self.path, 'repospanner', 'config.yml')
Patrick Uiterwijk 3f97f6
        with open(cfgpath, 'w') as cfg:
Patrick Uiterwijk 3f97f6
            cfg.write(REPOSPANNER_CONFIG_TEMPLATE % configvals)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        with open(os.path.join(self.path, 'repospanner', 'keylog'),
Patrick Uiterwijk 3f97f6
                  'w') as keylog:
Patrick Uiterwijk 3f97f6
            # Create the CA
Patrick Uiterwijk 3f97f6
            self.run_cacmd(keylog, 'init', 'repospanner.local')
Patrick Uiterwijk 3f97f6
            # Create the node cert
Patrick Uiterwijk 3f97f6
            self.run_cacmd(keylog, 'node', 'regiona', 'nodea')
Patrick Uiterwijk 3f97f6
            # Create the admin cert
Patrick Uiterwijk 3f97f6
            self.run_cacmd(keylog, 'leaf', 'admin',
Patrick Uiterwijk 3f97f6
                           '--admin', '--region', '*', '--repo', '*')
Patrick Uiterwijk 3f97f6
            # Create the Pagure cert
Patrick Uiterwijk 3f97f6
            self.run_cacmd(keylog, 'leaf', 'pagure',
Patrick Uiterwijk 3f97f6
                           '--read', '--write',
Patrick Uiterwijk 3f97f6
                           '--region', '*', '--repo', '*')
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        with open(os.path.join(self.path, 'repospanner', 'spawnlog'),
Patrick Uiterwijk 3f97f6
                  'w') as spawnlog:
Patrick Uiterwijk 3f97f6
            # Initialize state
Patrick Uiterwijk 3f97f6
            subprocess.check_call(
Patrick Uiterwijk 3f97f6
                [self.repospanner_binary,
Patrick Uiterwijk 3f97f6
                 '--config', cfgpath,
Patrick Uiterwijk 3f97f6
                 'serve', '--spawn'],
Patrick Uiterwijk 3f97f6
                stdout=spawnlog,
Patrick Uiterwijk 3f97f6
                stderr=subprocess.STDOUT,
Patrick Uiterwijk 3f97f6
            )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        self.repospanner_runlog = open(
Patrick Uiterwijk 3f97f6
            os.path.join(self.path, 'repospanner', 'runlog'), 'w')
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        try:
Patrick Uiterwijk 3f97f6
            self.repospanner_proc = subprocess.Popen(
Patrick Uiterwijk 3f97f6
                [self.repospanner_binary,
Patrick Uiterwijk 3f97f6
                 '--config', cfgpath,
Patrick Uiterwijk 3f97f6
                 'serve', '--debug'],
Patrick Uiterwijk 3f97f6
                stdout=self.repospanner_runlog,
Patrick Uiterwijk 3f97f6
                stderr=subprocess.STDOUT,
Patrick Uiterwijk 3f97f6
            )
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            # Give repoSpanner time to start
Patrick Uiterwijk 3f97f6
            time.sleep(1)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            # Wait for the instance to become available
Patrick Uiterwijk 3f97f6
            resp = requests.get(
Patrick Uiterwijk 3f97f6
                'https://nodea.regiona.repospanner.local:%d/'
Patrick Uiterwijk 3f97f6
                % configvals['gitport'],
Patrick Uiterwijk 3f97f6
                verify=os.path.join(self.path, 'repospanner', 'pki', 'ca.crt'),
Patrick Uiterwijk 3f97f6
                cert=(
Patrick Uiterwijk 3f97f6
                    os.path.join(self.path, 'repospanner', 'pki', 'pagure.crt'),
Patrick Uiterwijk 3f97f6
                    os.path.join(self.path, 'repospanner', 'pki', 'pagure.key'),
Patrick Uiterwijk 3f97f6
                )
Patrick Uiterwijk 3f97f6
            )
Patrick Uiterwijk 3f97f6
            resp.raise_for_status()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            print('repoSpanner identification: %s' % resp.text)
Patrick Uiterwijk 3f97f6
        except:
Patrick Uiterwijk 3f97f6
            # Make sure to clean up repoSpanner, since we did start it
Patrick Uiterwijk 3f97f6
            self.tearDown()
Patrick Uiterwijk 3f97f6
            raise
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    def tearDown(self):
Patrick Uiterwijk 3f97f6
        """ Tear down the repoSpanner instance. """
Patrick Uiterwijk 3f97f6
        if self.repospanner_proc:
Patrick Uiterwijk 3f97f6
            # Tear down
Patrick Uiterwijk 3f97f6
            self.repospanner_proc.terminate()
Patrick Uiterwijk 3f97f6
            exitcode = self.repospanner_proc.wait()
Patrick Uiterwijk 3f97f6
            if exitcode != 0:
Patrick Uiterwijk 3f97f6
                print('repoSpanner exit code: %d' % exitcode)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        if self.repospanner_runlog:
Patrick Uiterwijk 3f97f6
            self.repospanner_runlog.close()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        super(PagureRepoSpannerTests, self).tearDown()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
class PagureRepoSpannerTestsNewRepoDefault(PagureRepoSpannerTests):
Patrick Uiterwijk 3f97f6
    config_values = {
Patrick Uiterwijk 3f97f6
        'repospanner_new_repo': "'default'"
Patrick Uiterwijk 3f97f6
    }
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
    @patch('pagure.ui.app.admin_session_timedout')
Patrick Uiterwijk 3f97f6
    def test_new_project(self, ast):
Patrick Uiterwijk 3f97f6
        """ Test creating a new repo by default on repoSpanner works. """
Patrick Uiterwijk 3f97f6
        ast.return_value = False
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        user = tests.FakeUser(username='foo')
Patrick Uiterwijk 3f97f6
        with tests.user_set(self.app.application, user):
Patrick Uiterwijk 3f97f6
            output = self.app.get('/new/')
Patrick Uiterwijk 3f97f6
            self.assertEqual(output.status_code, 200)
Patrick Uiterwijk 3f97f6
            output_text = output.get_data(as_text=True)
Patrick Uiterwijk 3f97f6
            self.assertIn(
Patrick Uiterwijk 3f97f6
                'Create new Project', output_text)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            csrf_token = output_text.split(
Patrick Uiterwijk 3f97f6
                'name="csrf_token" type="hidden" value="')[1].split('">')[0]
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            data = {
Patrick Uiterwijk 3f97f6
                'name': 'project-1',
Patrick Uiterwijk 3f97f6
                'description': 'Project #1',
Patrick Uiterwijk 3f97f6
                'create_readme': 'y',
Patrick Uiterwijk 3f97f6
                'csrf_token': csrf_token,
Patrick Uiterwijk 3f97f6
            }
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            output = self.app.post('/new/', data=data, follow_redirects=True)
Patrick Uiterwijk 3f97f6
            self.assertEqual(output.status_code, 200)
Patrick Uiterwijk 3f97f6
            output_text = output.get_data(as_text=True)
Patrick Uiterwijk 3f97f6
            self.assertIn(
Patrick Uiterwijk 3f97f6
                '
\nProject #1',
Patrick Uiterwijk 3f97f6
                output_text)
Patrick Uiterwijk 3f97f6
            self.assertIn(
Patrick Uiterwijk 3f97f6
                '<title>Overview - project-1 - Pagure</title>', output_text)
Patrick Uiterwijk 3f97f6
            self.assertIn('Added the README', output_text)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            output = self.app.get('/project-1/settings')
Patrick Uiterwijk 3f97f6
            self.assertIn(
Patrick Uiterwijk 3f97f6
                'This repository is on repoSpanner region default',
Patrick Uiterwijk 3f97f6
                output.get_data(as_text=True))
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        with tests.user_set(self.app.application, tests.FakeUser(username='pingou')):
Patrick Uiterwijk 3f97f6
            csrf_token = self.get_csrf()
Patrick Uiterwijk 3f97f6
            data = {
Patrick Uiterwijk 3f97f6
                'csrf_token': csrf_token,
Patrick Uiterwijk 3f97f6
            }
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            output = self.app.post(
Patrick Uiterwijk 3f97f6
                '/do_fork/project-1', data=data,
Patrick Uiterwijk 3f97f6
                follow_redirects=True)
Patrick Uiterwijk 3f97f6
            self.assertEqual(output.status_code, 200)
Patrick Uiterwijk 3f97f6
            output_text = output.get_data(as_text=True)
Patrick Uiterwijk 3f97f6
            self.assertIn(
Patrick Uiterwijk 3f97f6
                '
\nProject #1',
Patrick Uiterwijk 3f97f6
                output_text)
Patrick Uiterwijk 3f97f6
            self.assertIn(
Patrick Uiterwijk 3f97f6
                '<title>Overview - project-1 - Pagure</title>', output_text)
Patrick Uiterwijk 3f97f6
            self.assertIn('Added the README', output_text)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
            output = self.app.get('/fork/pingou/project-1/settings')
Patrick Uiterwijk 3f97f6
            self.assertIn(
Patrick Uiterwijk 3f97f6
                'This repository is on repoSpanner region default',
Patrick Uiterwijk 3f97f6
                output.get_data(as_text=True))
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
        # Verify that only pseudo repos exist, and no on-disk repos got created
Patrick Uiterwijk 3f97f6
        repodirlist = os.listdir(os.path.join(self.path, 'repos'))
Patrick Uiterwijk 3f97f6
        self.assertEqual(repodirlist, ['pseudo'])
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
if __name__ == '__main__':
Patrick Uiterwijk 3f97f6
    unittest.main(verbosity=2)