Blame tests/__init__.py

Pierre-Yves Chibon 33b534
# -*- coding: utf-8 -*-
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
"""
Pierre-Yves Chibon 517d69
 (c) 2015-2018 - Copyright Red Hat Inc
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
 Authors:
Pierre-Yves Chibon 413073
   Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
"""
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 67d1cc
from __future__ import unicode_literals, absolute_import
Aurélien Bompard 626417
Aurélien Bompard 626417
import imp
Aurélien Bompard f61bb3
import json
Pierre-Yves Chibon 59df6f
import logging
Pierre-Yves Chibon 59e3b9
import os
Pierre-Yves Chibon 59e3b9
import re
Pierre-Yves Chibon 59e3b9
import resource
Pierre-Yves Chibon 59d644
import shutil
Patrick Uiterwijk 55e7e0
import subprocess
Pierre-Yves Chibon 413073
import sys
Pierre-Yves Chibon c27b0d
import tempfile
Patrick Uiterwijk 114ca2
import time
Pierre-Yves Chibon 59e3b9
import unittest
Aurélien Bompard 619e2a
from io import open, StringIO
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 59df6f
logging.basicConfig(stream=sys.stderr)
Pierre-Yves Chibon 413073
Aurélien Bompard 626417
from bs4 import BeautifulSoup
Pierre-Yves Chibon a324b4
from contextlib import contextmanager
Pierre-Yves Chibon 413073
from datetime import date
Pierre-Yves Chibon 21f499
from datetime import datetime
Pierre-Yves Chibon 413073
from datetime import timedelta
Pierre-Yves Chibon 413073
from functools import wraps
Aurélien Bompard 626417
from six.moves.urllib.parse import urlparse, parse_qs
Pierre-Yves Chibon 413073
Pierre-Yves Chibon a324b4
import mock
Pierre-Yves Chibon 4e9b76
import pygit2
Aurélien Bompard 00115d
import redis
Aurélien Bompard 626417
import six
Pierre-Yves Chibon 4e9b76
Pierre-Yves Chibon 675b89
from bs4 import BeautifulSoup
Aurélien Bompard 00115d
from celery.app.task import EagerResult
Pierre-Yves Chibon 413073
from sqlalchemy import create_engine
Pierre-Yves Chibon 413073
from sqlalchemy.orm import sessionmaker
Pierre-Yves Chibon 413073
from sqlalchemy.orm import scoped_session
Pierre-Yves Chibon 413073
Aurélien Bompard 626417
if six.PY2:
Aurélien Bompard 626417
    # Always enable performance counting for tests
Pierre-Yves Chibon 73d120
    os.environ["PAGURE_PERFREPO"] = "true"
Aurélien Bompard 626417
Pierre-Yves Chibon 73d120
sys.path.insert(
Pierre-Yves Chibon 73d120
    0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
Pierre-Yves Chibon 73d120
)
Pierre-Yves Chibon 413073
Pierre-Yves Chibon fe5017
import pagure
Pierre-Yves Chibon b130e5
import pagure.api
Patrick Uiterwijk 3f97f6
from pagure.api.ci import jenkins
Pierre-Yves Chibon b130e5
import pagure.flask_app
Pierre-Yves Chibon 6fdafd
import pagure.lib.git
Pierre-Yves Chibon fe5017
import pagure.lib.model
Pierre-Yves Chibon 930073
import pagure.lib.query
Patrick Uiterwijk 4012dc
import pagure.lib.tasks_mirror
Patrick Uiterwijk fcd520
import pagure.perfrepo as perfrepo
Aurélien Bompard e78d79
from pagure.config import config as pagure_config, reload_config
Pierre-Yves Chibon b130e5
from pagure.lib.repo import PagureRepo
Pierre-Yves Chibon 413073
Pierre-Yves Chibon f62635
HERE = os.path.join(os.path.dirname(os.path.abspath(__file__)))
Pierre-Yves Chibon b73de8
LOG = logging.getLogger(__name__)
Pierre-Yves Chibon b130e5
LOG.setLevel(logging.INFO)
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
PAGLOG = logging.getLogger("pagure")
Pierre-Yves Chibon b73de8
PAGLOG.setLevel(logging.CRITICAL)
Pierre-Yves Chibon b73de8
PAGLOG.handlers = []
Pierre-Yves Chibon b73de8
Pierre-Yves Chibon 73d120
if "PYTHONPATH" not in os.environ:
Pierre-Yves Chibon 73d120
    os.environ["PYTHONPATH"] = os.path.normpath(os.path.join(HERE, "../"))
Patrick Uiterwijk b2cb9c
Patrick Uiterwijk 55e7e0
CONFIG_TEMPLATE = """
Patrick Uiterwijk 55e7e0
GIT_FOLDER = '%(path)s/repos'
Aurélien Bompard e78d79
ENABLE_DOCS = %(enable_docs)s
Aurélien Bompard e78d79
ENABLE_TICKETS = %(enable_tickets)s
Patrick Uiterwijk 55e7e0
REMOTE_GIT_FOLDER = '%(path)s/remotes'
Patrick Uiterwijk 55e7e0
DB_URL = '%(dburl)s'
Patrick Uiterwijk 7b9080
ALLOW_PROJECT_DOWAIT = True
Aurélien Bompard e78d79
PAGURE_CI_SERVICES = ['jenkins']
Aurélien Bompard e78d79
EMAIL_SEND = False
Aurélien Bompard e78d79
TESTING = True
Aurélien Bompard e78d79
GIT_FOLDER = '%(path)s/repos'
Aurélien Bompard e78d79
REQUESTS_FOLDER = '%(path)s/repos/requests'
Aurélien Bompard e78d79
TICKETS_FOLDER = %(tickets_folder)r
Aurélien Bompard e78d79
DOCS_FOLDER = %(docs_folder)r
Patrick Uiterwijk 3f97f6
REPOSPANNER_PSEUDO_FOLDER = '%(path)s/repos/pseudo'
Aurélien Bompard e78d79
ATTACHMENTS_FOLDER = '%(path)s/attachments'
Aurélien Bompard e78d79
BROKER_URL = 'redis+socket://%(global_path)s/broker'
Aurélien Bompard 00115d
CELERY_CONFIG = {
Aurélien Bompard 00115d
    "task_always_eager": True,
Aurélien Bompard 626417
    #"task_eager_propagates": True,
Aurélien Bompard 00115d
}
Patrick Uiterwijk b2cb9c
GIT_AUTH_BACKEND = '%(authbackend)s'
Patrick Uiterwijk b2cb9c
TEST_AUTH_STATUS = '%(path)s/testauth_status.json'
Patrick Uiterwijk 8174a4
REPOBRIDGE_BINARY = '%(repobridge_binary)s'
Patrick Uiterwijk 3f97f6
REPOSPANNER_NEW_REPO = %(repospanner_new_repo)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_NEW_REPO_ADMIN_OVERRIDE = %(repospanner_admin_override)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_NEW_FORK = %(repospanner_new_fork)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_ADMIN_MIGRATION = %(repospanner_admin_migration)s
Patrick Uiterwijk 3f97f6
REPOSPANNER_REGIONS = {
Patrick Uiterwijk 9b2de7
    'default': {'url': 'https://repospanner.localhost.localdomain:%(repospanner_gitport)s',
Patrick Uiterwijk 3f97f6
                'repo_prefix': 'pagure/',
Patrick Uiterwijk d29158
                'hook': None,
Patrick Uiterwijk 3f97f6
                'ca': '%(path)s/repospanner/pki/ca.crt',
Patrick Uiterwijk 3f97f6
                'admin_cert': {'cert': '%(path)s/repospanner/pki/admin.crt',
Patrick Uiterwijk 3f97f6
                               'key': '%(path)s/repospanner/pki/admin.key'},
Patrick Uiterwijk 3f97f6
                'push_cert': {'cert': '%(path)s/repospanner/pki/pagure.crt',
Patrick Uiterwijk 3f97f6
                              'key': '%(path)s/repospanner/pki/pagure.key'}}
Patrick Uiterwijk 3f97f6
}
Patrick Uiterwijk 55e7e0
"""
Aurélien Bompard 00115d
# The Celery docs warn against using task_always_eager:
Aurélien Bompard 00115d
# http://docs.celeryproject.org/en/latest/userguide/testing.html
Aurélien Bompard 00115d
# but that warning is only valid when testing the async nature of the task, not
Aurélien Bompard 00115d
# what the task actually does.
Patrick Uiterwijk 55e7e0
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
LOG.info("BUILD_ID: %s", os.environ.get("BUILD_ID"))
Pierre-Yves Chibon 413073
Patrick Uiterwijk 114ca2
Karsten Hopp b310af
WAIT_REGEX = re.compile(r"""var _url = '(\/wait\/[a-z0-9-]+\??.*)'""")
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 73d120
Patrick Uiterwijk 114ca2
def get_wait_target(html):
Patrick Uiterwijk 114ca2
    """ This parses the window.location out of the HTML for the wait page. """
Patrick Uiterwijk 114ca2
    found = WAIT_REGEX.findall(html)
Pierre-Yves Chibon f341aa
    if len(found) == 0:
Patrick Uiterwijk 114ca2
        raise Exception("Not able to get wait target in %s" % html)
Pierre-Yves Chibon f341aa
    return found[-1]
Patrick Uiterwijk 114ca2
Patrick Uiterwijk 114ca2
Pierre-Yves Chibon 517d69
def get_post_target(html):
Pierre-Yves Chibon 675b89
    """ This parses the wait page form to get the POST url. """
Pierre-Yves Chibon 73d120
    soup = BeautifulSoup(html, "html.parser")
Pierre-Yves Chibon 73d120
    form = soup.find(id="waitform")
Pierre-Yves Chibon 675b89
    if not form:
Pierre-Yves Chibon 517d69
        raise Exception("Not able to get the POST url in %s" % html)
Pierre-Yves Chibon 73d120
    return form.get("action")
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
def get_post_args(html):
Pierre-Yves Chibon 675b89
    """ This parses the wait page for the hidden arguments of the form. """
Pierre-Yves Chibon 73d120
    soup = BeautifulSoup(html, "html.parser")
Pierre-Yves Chibon 517d69
    output = {}
Pierre-Yves Chibon 73d120
    inputs = soup.find_all("input")
Pierre-Yves Chibon 675b89
    if not inputs:
Pierre-Yves Chibon 675b89
        raise Exception("Not able to get the POST arguments in %s" % html)
Pierre-Yves Chibon 675b89
    for inp in inputs:
Pierre-Yves Chibon 73d120
        if inp.get("type") == "hidden":
Pierre-Yves Chibon 73d120
            output[inp.get("name")] = inp.get("value")
Pierre-Yves Chibon 517d69
    return output
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
Patrick Uiterwijk 114ca2
def create_maybe_waiter(method, getter):
Patrick Uiterwijk 114ca2
    def maybe_waiter(*args, **kwargs):
Patrick Uiterwijk 114ca2
        """ A wrapper for self.app.get()/.post() that will resolve wait's """
Patrick Uiterwijk 114ca2
        result = method(*args, **kwargs)
Pierre-Yves Chibon 517d69
Pierre-Yves Chibon 517d69
        # Handle the POST wait case
Pierre-Yves Chibon 517d69
        form_url = None
Pierre-Yves Chibon 517d69
        form_args = None
Aurélien Bompard 626417
        try:
Aurélien Bompard 626417
            result_text = result.get_data(as_text=True)
Aurélien Bompard 626417
        except UnicodeDecodeError:
Aurélien Bompard 626417
            return result
Aurélien Bompard 626417
        if 'id="waitform"' in result_text:
Aurélien Bompard 626417
            form_url = get_post_target(result_text)
Aurélien Bompard 626417
            form_args = get_post_args(result_text)
Pierre-Yves Chibon 73d120
            form_args["csrf_token"] = result_text.split(
Pierre-Yves Chibon 73d120
                'name="csrf_token" type="hidden" value="'
Pierre-Yves Chibon 73d120
            )[1].split('">')[0]
Pierre-Yves Chibon 517d69
Patrick Uiterwijk 114ca2
        count = 0
Pierre-Yves Chibon 73d120
        while "We are waiting for your task to finish." in result_text:
Patrick Uiterwijk 114ca2
            # Resolve wait page
Aurélien Bompard 626417
            target_url = get_wait_target(result_text)
Patrick Uiterwijk 114ca2
            if count > 10:
Patrick Uiterwijk 114ca2
                time.sleep(0.5)
Patrick Uiterwijk 114ca2
            else:
Patrick Uiterwijk 114ca2
                time.sleep(0.1)
Patrick Uiterwijk 114ca2
            result = getter(target_url, follow_redirects=True)
Aurélien Bompard 626417
            try:
Aurélien Bompard 626417
                result_text = result.get_data(as_text=True)
Aurélien Bompard 626417
            except UnicodeDecodeError:
Aurélien Bompard 626417
                return result
Patrick Uiterwijk 114ca2
            if count > 50:
Pierre-Yves Chibon 73d120
                raise Exception("Had to wait too long")
Patrick Uiterwijk 114ca2
        else:
Pierre-Yves Chibon 517d69
            if form_url and form_args:
Pierre-Yves Chibon 517d69
                return method(form_url, data=form_args, follow_redirects=True)
Patrick Uiterwijk 114ca2
            return result
Pierre-Yves Chibon 73d120
Patrick Uiterwijk 114ca2
    return maybe_waiter
Patrick Uiterwijk 114ca2
Patrick Uiterwijk 114ca2
Pierre-Yves Chibon 413073
@contextmanager
Patrick Uiterwijk 3d2cb5
def user_set(APP, user, keep_get_user=False):
Pierre-Yves Chibon 413073
    """ Set the provided user as fas_user in the provided application."""
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    # Hack used to remove the before_request function set by
Pierre-Yves Chibon 413073
    # flask.ext.fas_openid.FAS which otherwise kills our effort to set a
Pierre-Yves Chibon 413073
    # flask.g.fas_user.
Pierre-Yves Chibon 413073
    from flask import appcontext_pushed, g
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 4ad0bb
    keep = []
Pierre-Yves Chibon 4ad0bb
    for meth in APP.before_request_funcs[None]:
Pierre-Yves Chibon 73d120
        if "flask_fas_openid.FAS" in str(meth):
Pierre-Yves Chibon 4ad0bb
            continue
Pierre-Yves Chibon 4ad0bb
        keep.append(meth)
Pierre-Yves Chibon 4ad0bb
    APP.before_request_funcs[None] = keep
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    def handler(sender, **kwargs):
Pierre-Yves Chibon 413073
        g.fas_user = user
Pierre-Yves Chibon 73d120
        g.fas_session_id = b"123"
Pierre-Yves Chibon 392277
        g.authenticated = True
Pierre-Yves Chibon 73d120
Patrick Uiterwijk 3d2cb5
    old_get_user = pagure.flask_app._get_user
Patrick Uiterwijk 3d2cb5
    if not keep_get_user:
Patrick Uiterwijk 3d2cb5
        pagure.flask_app._get_user = mock.MagicMock(
Pierre-Yves Chibon 73d120
            return_value=pagure.lib.model.User()
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    with appcontext_pushed.connected_to(handler, APP):
Pierre-Yves Chibon 413073
        yield
Pierre-Yves Chibon 413073
Patrick Uiterwijk 3d2cb5
    pagure.flask_app._get_user = old_get_user
Patrick Uiterwijk 3d2cb5
Slavek Kabrda 7713cf
Aurélien Bompard e78d79
tests_state = {
Pierre-Yves Chibon 73d120
    "path": tempfile.mkdtemp(prefix="pagure-tests-"),
Aurélien Bompard e78d79
    "broker": None,
Aurélien Bompard 00115d
    "broker_client": None,
Aurélien Bompard 00115d
    "results": {},
Aurélien Bompard e78d79
}
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
Aurélien Bompard e78d79
def _populate_db(session):
Slavek Kabrda 7713cf
    # Create a couple of users
Slavek Kabrda 7713cf
    item = pagure.lib.model.User(
Pierre-Yves Chibon 73d120
        user="pingou",
Pierre-Yves Chibon 73d120
        fullname="PY C",
Pierre-Yves Chibon 73d120
        password=b"foo",
Pierre-Yves Chibon 73d120
        default_email="bar@pingou.com",
Slavek Kabrda 7713cf
    )
Slavek Kabrda 7713cf
    session.add(item)
Pierre-Yves Chibon 73d120
    item = pagure.lib.model.UserEmail(user_id=1, email="bar@pingou.com")
Slavek Kabrda 7713cf
    session.add(item)
Pierre-Yves Chibon 73d120
    item = pagure.lib.model.UserEmail(user_id=1, email="foo@pingou.com")
Slavek Kabrda 7713cf
    session.add(item)
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
    item = pagure.lib.model.User(
Pierre-Yves Chibon 73d120
        user="foo",
Pierre-Yves Chibon 73d120
        fullname="foo bar",
Pierre-Yves Chibon 73d120
        password=b"foo",
Pierre-Yves Chibon 73d120
        default_email="foo@bar.com",
Slavek Kabrda 7713cf
    )
Slavek Kabrda 7713cf
    session.add(item)
Pierre-Yves Chibon 73d120
    item = pagure.lib.model.UserEmail(user_id=2, email="foo@bar.com")
Slavek Kabrda 7713cf
    session.add(item)
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
    session.commit()
Slavek Kabrda 7713cf
Slavek Kabrda 7713cf
Aurélien Bompard 00115d
def store_eager_results(*args, **kwargs):
Aurélien Bompard 00115d
    """A wrapper for EagerResult that stores the instance."""
Aurélien Bompard 00115d
    result = EagerResult(*args, **kwargs)
Aurélien Bompard 00115d
    tests_state["results"][result.id] = result
Aurélien Bompard 00115d
    return result
Slavek Kabrda 7713cf
Aurélien Bompard e78d79
Aurélien Bompard e78d79
def setUp():
Aurélien Bompard e78d79
    # In order to save time during local test execution, we create sqlite DB
Aurélien Bompard e78d79
    # file only once and then we populate it and empty it for every test case
Aurélien Bompard e78d79
    # (as opposed to creating DB file for every test case).
Aurélien Bompard e78d79
    session = pagure.lib.model.create_tables(
Pierre-Yves Chibon 73d120
        "sqlite:///%s/db.sqlite" % tests_state["path"],
Pierre-Yves Chibon 73d120
        acls=pagure_config.get("ACLS", {}),
Aurélien Bompard e78d79
    )
Aurélien Bompard e78d79
    tests_state["db_session"] = session
Slavek Kabrda 7713cf
Slavek Kabrda 3cb529
    # Create a broker
Pierre-Yves Chibon 73d120
    broker_url = os.path.join(tests_state["path"], "broker")
Aurélien Bompard e78d79
Aurélien Bompard e78d79
    tests_state["broker"] = broker = subprocess.Popen(
Pierre-Yves Chibon 73d120
        [
Pierre-Yves Chibon 73d120
            "/usr/bin/redis-server",
Pierre-Yves Chibon 73d120
            "--unixsocket",
Pierre-Yves Chibon 73d120
            broker_url,
Pierre-Yves Chibon 73d120
            "--port",
Pierre-Yves Chibon 73d120
            "0",
Pierre-Yves Chibon 73d120
            "--loglevel",
Pierre-Yves Chibon 73d120
            "warning",
Pierre-Yves Chibon 73d120
            "--logfile",
Pierre-Yves Chibon 73d120
            "/dev/null",
Pierre-Yves Chibon 73d120
        ],
Pierre-Yves Chibon 73d120
        stdout=None,
Pierre-Yves Chibon 73d120
        stderr=None,
Pierre-Yves Chibon 73d120
    )
Slavek Kabrda 3cb529
    broker.poll()
Slavek Kabrda 3cb529
    if broker.returncode is not None:
Pierre-Yves Chibon 73d120
        raise Exception("Broker failed to start")
Aurélien Bompard 00115d
    tests_state["broker_client"] = redis.Redis(unix_socket_path=broker_url)
Aurélien Bompard 00115d
Aurélien Bompard 00115d
    # Store the EagerResults to be able to retrieve them later
Pierre-Yves Chibon 73d120
    tests_state["eg_patcher"] = mock.patch("celery.app.task.EagerResult")
Aurélien Bompard 00115d
    eg_mock = tests_state["eg_patcher"].start()
Aurélien Bompard 00115d
    eg_mock.side_effect = store_eager_results
Slavek Kabrda 7713cf
Pierre-Yves Chibon 2d5c52
Slavek Kabrda 3cb529
def tearDown():
Aurélien Bompard e78d79
    tests_state["db_session"].close()
Aurélien Bompard 00115d
    tests_state["eg_patcher"].stop()
Aurélien Bompard e78d79
    broker = tests_state["broker"]
Slavek Kabrda 3cb529
    broker.kill()
Slavek Kabrda 3cb529
    broker.wait()
Aurélien Bompard e78d79
    shutil.rmtree(tests_state["path"])
Pierre-Yves Chibon 59e3b9
Pierre-Yves Chibon 59e3b9
Clement Verna 109c4b
class SimplePagureTest(unittest.TestCase):
Clement Verna 109c4b
    """
Clement Verna 109c4b
    Simple Test class that does not set a broker/worker
Clement Verna 109c4b
    """
Pierre-Yves Chibon 413073
Aurélien Bompard e78d79
    populate_db = True
Aurélien Bompard e78d79
    config_values = {}
Aurélien Bompard e78d79
Pierre-Yves Chibon 73d120
    @mock.patch("pagure.lib.notify.fedmsg_publish", mock.MagicMock())
Pierre-Yves Chibon 73d120
    def __init__(self, method_name="runTest"):
Pierre-Yves Chibon 413073
        """ Constructor. """
Pierre-Yves Chibon 413073
        unittest.TestCase.__init__(self, method_name)
Pierre-Yves Chibon 413073
        self.session = None
Jeremy Cline 20109f
        self.path = None
Pierre-Yves Chibon 3a4d42
        self.gitrepo = None
Pierre-Yves Chibon 619b9a
        self.gitrepos = None
Pierre-Yves Chibon 413073
Patrick Uiterwijk fcd520
    def perfMaxWalks(self, max_walks, max_steps):
Patrick Uiterwijk fcd520
        """ Check that we have not performed too many walks/steps. """
Patrick Uiterwijk fcd520
        num_walks = 0
Patrick Uiterwijk fcd520
        num_steps = 0
Patrick Uiterwijk fcd520
        for reqstat in perfrepo.REQUESTS:
Pierre-Yves Chibon 73d120
            for walk in reqstat["walks"].values():
Patrick Uiterwijk fcd520
                num_walks += 1
Pierre-Yves Chibon 73d120
                num_steps += walk["steps"]
Pierre-Yves Chibon 73d120
        self.assertLessEqual(
Pierre-Yves Chibon 73d120
            num_walks,
Pierre-Yves Chibon 73d120
            max_walks,
Pierre-Yves Chibon 73d120
            "%s git repo walks performed, at most %s allowed"
Pierre-Yves Chibon 73d120
            % (num_walks, max_walks),
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon 73d120
        self.assertLessEqual(
Pierre-Yves Chibon 73d120
            num_steps,
Pierre-Yves Chibon 73d120
            max_steps,
Pierre-Yves Chibon 73d120
            "%s git repo steps performed, at most %s allowed"
Pierre-Yves Chibon 73d120
            % (num_steps, max_steps),
Pierre-Yves Chibon 73d120
        )
Patrick Uiterwijk fcd520
Patrick Uiterwijk fcd520
    def perfReset(self):
Patrick Uiterwijk fcd520
        """ Reset perfrepo stats. """
Patrick Uiterwijk fcd520
        perfrepo.reset_stats()
Patrick Uiterwijk fcd520
        perfrepo.REQUESTS = []
Patrick Uiterwijk fcd520
Clement Verna 109c4b
    def setUp(self):
Patrick Uiterwijk 8a2282
        if self.path:
Patrick Uiterwijk 8a2282
            # This prevents test state leakage.
Patrick Uiterwijk 8a2282
            # This should be None if the previous runs' tearDown didn't finish,
Patrick Uiterwijk 8a2282
            # leaving behind a self.path.
Patrick Uiterwijk 8a2282
            # If we continue in this case, not only did the previous worker and
Patrick Uiterwijk 8a2282
            # redis instances not exit, we also might accidentally use the
Patrick Uiterwijk 8a2282
            # old database connection.
Patrick Uiterwijk 8a2282
            # @pingou, don't delete this again... :)
Pierre-Yves Chibon 73d120
            raise Exception("Previous test failed!")
Patrick Uiterwijk 8a2282
Clement Verna 109c4b
        self.perfReset()
Patrick Uiterwijk fcd520
Pierre-Yves Chibon 73d120
        self.path = tempfile.mkdtemp(prefix="pagure-tests-path-")
Pierre-Yves Chibon 8b2c5c
Pierre-Yves Chibon 73d120
        LOG.debug("Testdir: %s", self.path)
Pierre-Yves Chibon 73d120
        for folder in ["repos", "forks", "releases", "remotes", "attachments"]:
Jeremy Cline 20109f
            os.mkdir(os.path.join(self.path, folder))
Pierre-Yves Chibon 58e731
Pierre-Yves Chibon 73d120
        if hasattr(pagure.lib.query, "REDIS") and pagure.lib.query.REDIS:
Pierre-Yves Chibon 930073
            pagure.lib.query.REDIS.connection_pool.disconnect()
Pierre-Yves Chibon 930073
            pagure.lib.query.REDIS = None
Slavek Kabrda afb8f6
Aurélien Bompard e78d79
        # Database
Aurélien Bompard e78d79
        self._prepare_db()
Patrick Uiterwijk 55e7e0
Patrick Uiterwijk 55e7e0
        # Write a config file
Aurélien Bompard e78d79
        config_values = {
Pierre-Yves Chibon 73d120
            "path": self.path,
Pierre-Yves Chibon 73d120
            "dburl": self.dbpath,
Pierre-Yves Chibon 73d120
            "enable_docs": True,
Pierre-Yves Chibon 73d120
            "docs_folder": "%s/repos/docs" % self.path,
Pierre-Yves Chibon 73d120
            "enable_tickets": True,
Pierre-Yves Chibon 73d120
            "tickets_folder": "%s/repos/tickets" % self.path,
Pierre-Yves Chibon 73d120
            "global_path": tests_state["path"],
Pierre-Yves Chibon 73d120
            "authbackend": "gitolite3",
Pierre-Yves Chibon 73d120
            "repobridge_binary": "/usr/libexec/repobridge",
Pierre-Yves Chibon 73d120
            "repospanner_gitport": str(8443 + sys.version_info.major),
Pierre-Yves Chibon 73d120
            "repospanner_new_repo": "None",
Pierre-Yves Chibon 73d120
            "repospanner_admin_override": "False",
Pierre-Yves Chibon 73d120
            "repospanner_new_fork": "True",
Pierre-Yves Chibon 73d120
            "repospanner_admin_migration": "False",
Aurélien Bompard e78d79
        }
Aurélien Bompard e78d79
        config_values.update(self.config_values)
Pierre-Yves Chibon 30c623
        self.config_values = config_values
Pierre-Yves Chibon 73d120
        config_path = os.path.join(self.path, "config")
Pierre-Yves Chibon 8b2c5c
        if not os.path.exists(config_path):
Pierre-Yves Chibon 73d120
            with open(config_path, "w") as f:
Pierre-Yves Chibon 30c623
                f.write(CONFIG_TEMPLATE % self.config_values)
Aurélien Bompard e78d79
        os.environ["PAGURE_CONFIG"] = config_path
Aurélien Bompard e78d79
        pagure_config.update(reload_config())
Patrick Uiterwijk 55e7e0
Aurélien Bompard 626417
        imp.reload(pagure.lib.tasks)
Pierre-Yves Chibon 893d4f
        imp.reload(pagure.lib.tasks_mirror)
Aurélien Bompard 626417
        imp.reload(pagure.lib.tasks_services)
Pierre-Yves Chibon b130e5
Pierre-Yves Chibon 73d120
        self._app = pagure.flask_app.create_app({"DB_URL": self.dbpath})
Pierre-Yves Chibon b130e5
Slavek Kabrda 3675ce
        self.app = self._app.test_client()
Pierre-Yves Chibon 73d120
        self.gr_patcher = mock.patch("pagure.lib.tasks.get_result")
Aurélien Bompard 00115d
        gr_mock = self.gr_patcher.start()
Aurélien Bompard 00115d
        gr_mock.side_effect = lambda tid: tests_state["results"][tid]
Pierre-Yves Chibon 564e63
Pierre-Yves Chibon b3d8b5
        # Refresh the DB session
Pierre-Yves Chibon b3d8b5
        self.session = pagure.lib.query.create_session(self.dbpath)
Pierre-Yves Chibon b3d8b5
Clement Verna 109c4b
    def tearDown(self):
Aurélien Bompard 00115d
        self.gr_patcher.stop()
Aurélien Bompard e78d79
        self.session.rollback()
Aurélien Bompard e78d79
        self._clear_database()
Pierre-Yves Chibon 7cbc4e
Patrick Uiterwijk 55e7e0
        # Remove testdir
Pierre-Yves Chibon e49b79
        try:
Pierre-Yves Chibon e49b79
            shutil.rmtree(self.path)
Pierre-Yves Chibon e49b79
        except:
Pierre-Yves Chibon e49b79
            # Sometimes there is a race condition that makes deleting the folder
Pierre-Yves Chibon e49b79
            # fail during the first attempt. So just try a second time if that's
Pierre-Yves Chibon e49b79
            # the case.
Pierre-Yves Chibon e49b79
            shutil.rmtree(self.path)
Patrick Uiterwijk 55e7e0
        self.path = None
Patrick Uiterwijk 55e7e0
Slavek Kabrda 3675ce
        del self.app
Slavek Kabrda 3675ce
        del self._app
Slavek Kabrda 3675ce
Aurélien Bompard f61bb3
    def shortDescription(self):
Aurélien Bompard 00115d
        doc = self.__str__() + ": " + self._testMethodDoc
Aurélien Bompard 00115d
        return doc or None
Aurélien Bompard f61bb3
Aurélien Bompard e78d79
    def _prepare_db(self):
Pierre-Yves Chibon 73d120
        self.dbpath = "sqlite:///%s" % os.path.join(
Pierre-Yves Chibon 73d120
            tests_state["path"], "db.sqlite"
Pierre-Yves Chibon 73d120
        )
Aurélien Bompard e78d79
        self.session = tests_state["db_session"]
Aurélien Bompard e78d79
        pagure.lib.model.create_default_status(
Pierre-Yves Chibon 73d120
            self.session, acls=pagure_config.get("ACLS", {})
Pierre-Yves Chibon 73d120
        )
Aurélien Bompard e78d79
        if self.populate_db:
Aurélien Bompard e78d79
            _populate_db(self.session)
Aurélien Bompard e78d79
Aurélien Bompard e78d79
    def _clear_database(self):
Pierre-Yves Chibon 930073
        tables = reversed(pagure.lib.model_base.BASE.metadata.sorted_tables)
Pierre-Yves Chibon 73d120
        if self.dbpath.startswith("postgresql"):
Pierre-Yves Chibon 73d120
            self.session.execute(
Pierre-Yves Chibon 73d120
                "TRUNCATE %s CASCADE" % ", ".join([t.name for t in tables])
Pierre-Yves Chibon 73d120
            )
Pierre-Yves Chibon 73d120
        elif self.dbpath.startswith("sqlite"):
Aurélien Bompard e78d79
            for table in tables:
Aurélien Bompard e78d79
                self.session.execute("DELETE FROM %s" % table.name)
Pierre-Yves Chibon 73d120
        elif self.dbpath.startswith("mysql"):
Aurélien Bompard e78d79
            self.session.execute("SET FOREIGN_KEY_CHECKS = 0")
Aurélien Bompard e78d79
            for table in tables:
Aurélien Bompard e78d79
                self.session.execute("TRUNCATE %s" % table.name)
Aurélien Bompard e78d79
            self.session.execute("SET FOREIGN_KEY_CHECKS = 1")
Aurélien Bompard e78d79
        self.session.commit()
Aurélien Bompard e78d79
Patrick Uiterwijk b2cb9c
    def set_auth_status(self, value):
Patrick Uiterwijk b2cb9c
        """ Set the return value for the test auth """
Pierre-Yves Chibon 73d120
        with open(
Pierre-Yves Chibon 73d120
            os.path.join(self.path, "testauth_status.json"), "w"
Pierre-Yves Chibon 73d120
        ) as statusfile:
Patrick Uiterwijk b2cb9c
            statusfile.write(six.u(json.dumps(value)))
Patrick Uiterwijk b2cb9c
Pierre-Yves Chibon 73d120
    def get_csrf(self, url="/new", output=None):
Pierre-Yves Chibon d596a9
        """Retrieve a CSRF token from given URL."""
Pierre-Yves Chibon a754ea
        if output is None:
Pierre-Yves Chibon a754ea
            output = self.app.get(url)
Pierre-Yves Chibon a754ea
            self.assertEqual(output.status_code, 200)
Pierre-Yves Chibon d596a9
Pierre-Yves Chibon 73d120
        return (
Pierre-Yves Chibon 73d120
            output.get_data(as_text=True)
Pierre-Yves Chibon 73d120
            .split('name="csrf_token" type="hidden" value="')[1]
Pierre-Yves Chibon 73d120
            .split('">')[0]
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon d596a9
Pierre-Yves Chibon 3e9b1d
    def get_wtforms_version(self):
Pierre-Yves Chibon 3e9b1d
        """Returns the wtforms version as a tuple."""
Pierre-Yves Chibon 3e9b1d
        import wtforms
Pierre-Yves Chibon 73d120
Pierre-Yves Chibon 73d120
        wtforms_v = wtforms.__version__.split(".")
Pierre-Yves Chibon 3e9b1d
        for idx, val in enumerate(wtforms_v):
Pierre-Yves Chibon 3e9b1d
            try:
Pierre-Yves Chibon 3e9b1d
                val = int(val)
Pierre-Yves Chibon 3e9b1d
            except ValueError:
Pierre-Yves Chibon 3e9b1d
                pass
Pierre-Yves Chibon 3e9b1d
            wtforms_v[idx] = val
Pierre-Yves Chibon 3e9b1d
        return tuple(wtforms_v)
Pierre-Yves Chibon 3e9b1d
Aurélien Bompard f61bb3
    def assertURLEqual(self, url_1, url_2):
Aurélien Bompard f61bb3
        url_parsed_1 = list(urlparse(url_1))
Aurélien Bompard f61bb3
        url_parsed_1[4] = parse_qs(url_parsed_1[4])
Aurélien Bompard f61bb3
        url_parsed_2 = list(urlparse(url_2))
Aurélien Bompard f61bb3
        url_parsed_2[4] = parse_qs(url_parsed_2[4])
Aurélien Bompard f61bb3
        return self.assertListEqual(url_parsed_1, url_parsed_2)
Aurélien Bompard f61bb3
Aurélien Bompard f61bb3
    def assertJSONEqual(self, json_1, json_2):
Aurélien Bompard f61bb3
        return self.assertEqual(json.loads(json_1), json.loads(json_2))
Aurélien Bompard f61bb3
Pierre-Yves Chibon b130e5
Clement Verna 109c4b
class Modeltests(SimplePagureTest):
Clement Verna 109c4b
    """ Model tests. """
Clement Verna 109c4b
Pierre-Yves Chibon 73d120
    def setUp(self):  # pylint: disable=invalid-name
Clement Verna 109c4b
        """ Set up the environnment, ran before every tests. """
Clement Verna 109c4b
        # Clean up test performance info
Clement Verna 109c4b
        super(Modeltests, self).setUp()
Clement Verna 109c4b
        self.app.get = create_maybe_waiter(self.app.get, self.app.get)
Clement Verna 109c4b
        self.app.post = create_maybe_waiter(self.app.post, self.app.get)
Clement Verna 109c4b
Pierre-Yves Chibon 19ab90
        # Refresh the DB session
Pierre-Yves Chibon 19ab90
        self.session = pagure.lib.query.create_session(self.dbpath)
Pierre-Yves Chibon 19ab90
Pierre-Yves Chibon 73d120
    def tearDown(self):  # pylint: disable=invalid-name
Clement Verna 109c4b
        """ Remove the test.db database if there is one. """
Aurélien Bompard 00115d
        tests_state["broker_client"].flushall()
Aurélien Bompard e78d79
        super(Modeltests, self).tearDown()
Clement Verna 109c4b
Patrick Uiterwijk 390193
    def create_project_full(self, projectname, extra=None):
Patrick Uiterwijk b2cb9c
        """ Create a project via the API.
Patrick Uiterwijk b2cb9c
Patrick Uiterwijk b2cb9c
        This makes sure that the repo is fully setup the way a normal new
Patrick Uiterwijk b2cb9c
        project would be, with hooks and all setup.
Patrick Uiterwijk b2cb9c
        """
Patrick Uiterwijk b2cb9c
Pierre-Yves Chibon 73d120
        headers = {"Authorization": "token aaabbbcccddd"}
Pierre-Yves Chibon 73d120
        data = {"name": projectname, "description": "A test repo"}
Patrick Uiterwijk 390193
        if extra:
Patrick Uiterwijk 390193
            data.update(extra)
Patrick Uiterwijk b2cb9c
Patrick Uiterwijk b2cb9c
        # Valid request
Pierre-Yves Chibon 73d120
        output = self.app.post("/api/0/new/", data=data, headers=headers)
Patrick Uiterwijk b2cb9c
        self.assertEqual(output.status_code, 200)
Patrick Uiterwijk b2cb9c
        data = json.loads(output.get_data(as_text=True))
Patrick Uiterwijk b2cb9c
        self.assertDictEqual(
Pierre-Yves Chibon 73d120
            data, {"message": 'Project "%s" created' % projectname}
Patrick Uiterwijk b2cb9c
        )
Patrick Uiterwijk b2cb9c
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
class FakeGroup(object):  # pylint: disable=too-few-public-methods
Pierre-Yves Chibon 413073
    """ Fake object used to make the FakeUser object closer to the
Pierre-Yves Chibon 413073
    expectations.
Pierre-Yves Chibon 413073
    """
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    def __init__(self, name):
Pierre-Yves Chibon 413073
        """ Constructor.
Pierre-Yves Chibon 413073
        :arg name: the name given to the name attribute of this object.
Pierre-Yves Chibon 413073
        """
Pierre-Yves Chibon 413073
        self.name = name
Pierre-Yves Chibon 73d120
        self.group_type = "cla"
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
class FakeUser(object):  # pylint: disable=too-few-public-methods
Pierre-Yves Chibon 413073
    """ Fake user used to test the fedocallib library. """
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 73d120
    def __init__(
Pierre-Yves Chibon 73d120
        self, groups=None, username="username", cla_done=True, id=None
Pierre-Yves Chibon 73d120
    ):
Pierre-Yves Chibon 413073
        """ Constructor.
Pierre-Yves Chibon 413073
        :arg groups: list of the groups in which this fake user is
Pierre-Yves Chibon 413073
            supposed to be.
Pierre-Yves Chibon 413073
        """
Aurélien Bompard 626417
        if isinstance(groups, six.string_types):
Pierre-Yves Chibon 413073
            groups = [groups]
Pierre-Yves Chibon ad2b94
        self.id = id
Pierre-Yves Chibon a71ef5
        self.groups = groups or []
Pierre-Yves Chibon ad2b94
        self.user = username
Pierre-Yves Chibon 413073
        self.username = username
Pierre-Yves Chibon 413073
        self.name = username
Pierre-Yves Chibon 73d120
        self.email = "foo@bar.com"
Pierre-Yves Chibon 73d120
        self.default_email = "foo@bar.com"
Ryan Lerch 5682fd
Pierre-Yves Chibon 413073
        self.approved_memberships = [
Pierre-Yves Chibon 73d120
            FakeGroup("packager"),
Pierre-Yves Chibon 73d120
            FakeGroup("design-team"),
Pierre-Yves Chibon 413073
        ]
Pierre-Yves Chibon 413073
        self.dic = {}
Pierre-Yves Chibon 73d120
        self.dic["timezone"] = "Europe/Paris"
Pierre-Yves Chibon 9fe7c1
        self.login_time = datetime.utcnow()
Pierre-Yves Chibon 413073
        self.cla_done = cla_done
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
    def __getitem__(self, key):
Pierre-Yves Chibon 413073
        return self.dic[key]
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
Patrick Uiterwijk 3f97f6
def create_locks(session, project):
Pierre-Yves Chibon 73d120
    for ltype in ("WORKER", "WORKER_TICKET", "WORKER_REQUEST"):
Patrick Uiterwijk 3f97f6
        lock = pagure.lib.model.ProjectLock(
Pierre-Yves Chibon 73d120
            project_id=project.id, lock_type=ltype
Pierre-Yves Chibon 73d120
        )
Patrick Uiterwijk 3f97f6
        session.add(lock)
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Pierre-Yves Chibon 73d120
def create_projects(session, is_fork=False, user_id=1, hook_token_suffix=""):
Pierre-Yves Chibon 413073
    """ Create some projects in the database. """
Pierre-Yves Chibon fe5017
    item = pagure.lib.model.Project(
Pierre-Yves Chibon 11d019
        user_id=user_id,  # pingou
Pierre-Yves Chibon 73d120
        name="test",
Pierre-Yves Chibon 11d019
        is_fork=is_fork,
Pierre-Yves Chibon 11d019
        parent_id=1 if is_fork else None,
Pierre-Yves Chibon 73d120
        description="test project #1",
Pierre-Yves Chibon 73d120
        hook_token="aaabbbccc" + hook_token_suffix,
Pierre-Yves Chibon 413073
    )
Pierre-Yves Chibon 73d120
    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
Pierre-Yves Chibon 413073
    session.add(item)
Patrick Uiterwijk 3f97f6
    session.flush()
Patrick Uiterwijk 3f97f6
    create_locks(session, item)
Pierre-Yves Chibon 413073
Pierre-Yves Chibon fe5017
    item = pagure.lib.model.Project(
Pierre-Yves Chibon 11d019
        user_id=user_id,  # pingou
Pierre-Yves Chibon 73d120
        name="test2",
Pierre-Yves Chibon 11d019
        is_fork=is_fork,
Pierre-Yves Chibon 11d019
        parent_id=2 if is_fork else None,
Pierre-Yves Chibon 73d120
        description="test project #2",
Pierre-Yves Chibon 73d120
        hook_token="aaabbbddd" + hook_token_suffix,
Pierre-Yves Chibon 413073
    )
Pierre-Yves Chibon 73d120
    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
Pierre-Yves Chibon 413073
    session.add(item)
Pierre-Yves Chibon 930073
    session.flush()
Pierre-Yves Chibon 930073
    create_locks(session, item)
Pierre-Yves Chibon 413073
clime afed57
    item = pagure.lib.model.Project(
Pierre-Yves Chibon 11d019
        user_id=user_id,  # pingou
Pierre-Yves Chibon 73d120
        name="test3",
Pierre-Yves Chibon 11d019
        is_fork=is_fork,
Pierre-Yves Chibon 11d019
        parent_id=3 if is_fork else None,
Pierre-Yves Chibon 73d120
        description="namespaced test project",
Pierre-Yves Chibon 73d120
        hook_token="aaabbbeee" + hook_token_suffix,
Pierre-Yves Chibon 73d120
        namespace="somenamespace",
clime afed57
    )
Pierre-Yves Chibon 73d120
    item.close_status = ["Invalid", "Insufficient data", "Fixed", "Duplicate"]
clime afed57
    session.add(item)
Pierre-Yves Chibon 930073
    session.flush()
Pierre-Yves Chibon 930073
    create_locks(session, item)
Pierre-Yves Chibon 413073
    session.commit()
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 413073
Pierre-Yves Chibon 05b648
def create_projects_git(folder, bare=False):
Pierre-Yves Chibon 4e9b76
    """ Create some projects in the database. """
Pierre-Yves Chibon 4e9b76
    repos = []
Pierre-Yves Chibon 73d120
    for project in [
Pierre-Yves Chibon 73d120
        "test.git",
Pierre-Yves Chibon 73d120
        "test2.git",
Pierre-Yves Chibon 73d120
        os.path.join("somenamespace", "test3.git"),
Pierre-Yves Chibon 73d120
    ]:
Pierre-Yves Chibon 4e9b76
        repo_path = os.path.join(folder, project)
Pierre-Yves Chibon 4e9b76
        repos.append(repo_path)
Pierre-Yves Chibon 63d161
        if not os.path.exists(repo_path):
Pierre-Yves Chibon 63d161
            os.makedirs(repo_path)
Pierre-Yves Chibon 05b648
        pygit2.init_repository(repo_path, bare=bare)
Pierre-Yves Chibon 4e9b76
    return repos
Pierre-Yves Chibon 4e9b76
Pierre-Yves Chibon 4e9b76
Pierre-Yves Chibon a14636
def create_tokens(session, user_id=1, project_id=1):
Pierre-Yves Chibon c0b635
    """ Create some tokens for the project in the database. """
Pierre-Yves Chibon c0b635
    item = pagure.lib.model.Token(
Pierre-Yves Chibon 73d120
        id="aaabbbcccddd",
Pierre-Yves Chibon c0b635
        user_id=user_id,
Pierre-Yves Chibon a14636
        project_id=project_id,
Pierre-Yves Chibon 73d120
        expiration=datetime.utcnow() + timedelta(days=30),
Pierre-Yves Chibon c0b635
    )
Pierre-Yves Chibon c0b635
    session.add(item)
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon c0b635
    item = pagure.lib.model.Token(
Pierre-Yves Chibon 73d120
        id="foo_token",
Pierre-Yves Chibon c0b635
        user_id=user_id,
Pierre-Yves Chibon a14636
        project_id=project_id,
Pierre-Yves Chibon 73d120
        expiration=datetime.utcnow() + timedelta(days=30),
Pierre-Yves Chibon c0b635
    )
Pierre-Yves Chibon c0b635
    session.add(item)
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon c0b635
    item = pagure.lib.model.Token(
Pierre-Yves Chibon 73d120
        id="expired_token",
Pierre-Yves Chibon c0b635
        user_id=user_id,
Pierre-Yves Chibon a14636
        project_id=project_id,
Pierre-Yves Chibon 73d120
        expiration=datetime.utcnow() - timedelta(days=1),
Pierre-Yves Chibon c0b635
    )
Pierre-Yves Chibon c0b635
    session.add(item)
Pierre-Yves Chibon c0b635
    session.commit()
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon c0b635
Pierre-Yves Chibon 73d120
def create_tokens_acl(session, token_id="aaabbbcccddd", acl_name=None):
Matt Prahl 30f8b1
    """ Create some ACLs for the token. If acl_name is not set, the token will
Matt Prahl 30f8b1
    have all the ACLs enabled.
Matt Prahl 30f8b1
    """
Matt Prahl 30f8b1
    if acl_name is None:
Pierre-Yves Chibon 73d120
        for aclid in range(len(pagure_config["ACLS"])):
Matt Prahl 30f8b1
            token_acl = pagure.lib.model.TokenAcl(
Pierre-Yves Chibon 73d120
                token_id=token_id, acl_id=aclid + 1
Matt Prahl 30f8b1
            )
Matt Prahl 30f8b1
            session.add(token_acl)
Matt Prahl 30f8b1
    else:
Pierre-Yves Chibon 73d120
        acl = (
Pierre-Yves Chibon 73d120
            session.query(pagure.lib.model.ACL).filter_by(name=acl_name).one()
Pierre-Yves Chibon 955beb
        )
Pierre-Yves Chibon 73d120
        token_acl = pagure.lib.model.TokenAcl(token_id=token_id, acl_id=acl.id)
Matt Prahl 30f8b1
        session.add(token_acl)
Pierre-Yves Chibon 955beb
Pierre-Yves Chibon 955beb
    session.commit()
Pierre-Yves Chibon 955beb
Pierre-Yves Chibon 955beb
Pierre-Yves Chibon 8a76fa
def _clone_and_top_commits(folder, branch, branch_ref=False):
Pierre-Yves Chibon 8a76fa
    """ Clone the repository, checkout the specified branch and return
Pierre-Yves Chibon 8a76fa
    the top commit of that branch if there is one.
Pierre-Yves Chibon 8a76fa
    Returns the repo, the path to the clone and the top commit(s) in a tuple
Pierre-Yves Chibon 8a76fa
    or the repo, the path to the clone and the reference to the branch
Pierre-Yves Chibon 8a76fa
    object if branch_ref is True.
Pierre-Yves Chibon 8a76fa
    """
Pierre-Yves Chibon f0ad75
    if not os.path.exists(folder):
Pierre-Yves Chibon f0ad75
        os.makedirs(folder)
Pierre-Yves Chibon 128dfb
    brepo = pygit2.init_repository(folder, bare=True)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 73d120
    newfolder = tempfile.mkdtemp(prefix="pagure-tests")
Pierre-Yves Chibon 128dfb
    repo = pygit2.clone_repository(folder, newfolder)
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 6fdafd
    branch_ref_obj = None
Pierre-Yves Chibon 6fdafd
    if "origin/%s" % branch in repo.listall_branches(pygit2.GIT_BRANCH_ALL):
Pierre-Yves Chibon 6fdafd
        branch_ref_obj = pagure.lib.git.get_branch_ref(repo, branch)
Pierre-Yves Chibon 6fdafd
        repo.checkout(branch_ref_obj)
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 8a76fa
    if branch_ref:
Pierre-Yves Chibon 8a76fa
        return (repo, newfolder, branch_ref_obj)
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon a71c8d
    parents = []
Pierre-Yves Chibon a71c8d
    commit = None
Pierre-Yves Chibon a71c8d
    try:
Pierre-Yves Chibon 6fdafd
        if branch_ref_obj:
Pierre-Yves Chibon 29ff0a
            commit = repo[branch_ref_obj.peel().hex]
Pierre-Yves Chibon 6fdafd
        else:
Pierre-Yves Chibon 73d120
            commit = repo.revparse_single("HEAD")
Pierre-Yves Chibon a71c8d
    except KeyError:
Pierre-Yves Chibon a71c8d
        pass
Pierre-Yves Chibon a71c8d
    if commit:
Pierre-Yves Chibon a71c8d
        parents = [commit.oid.hex]
Pierre-Yves Chibon a71c8d
Pierre-Yves Chibon 8a76fa
    return (repo, newfolder, parents)
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon 73d120
def add_content_git_repo(folder, branch="master", append=None):
Pierre-Yves Chibon 8a76fa
    """ Create some content for the specified git repo. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, parents = _clone_and_top_commits(folder, branch)
Pierre-Yves Chibon 8a76fa
Pierre-Yves Chibon 6fdafd
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    filename = os.path.join(newfolder, "sources")
Pierre-Yves Chibon 73d120
    content = "foo\n bar"
Pierre-Yves Chibon 6fdafd
    if os.path.exists(filename):
Pierre-Yves Chibon 73d120
        content = "foo\n bar\nbaz"
Pierre-Yves Chibon 6fdafd
    if append:
Pierre-Yves Chibon 6fdafd
        content += append
Pierre-Yves Chibon 73d120
    with open(filename, "w") as stream:
Pierre-Yves Chibon 6fdafd
        stream.write(content)
Pierre-Yves Chibon 73d120
    repo.index.add("sources")
Pierre-Yves Chibon 6fdafd
    repo.index.write()
Pierre-Yves Chibon 6fdafd
Pierre-Yves Chibon f0ad75
    # Commits the files added
Pierre-Yves Chibon f0ad75
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6fdafd
    commit = repo.create_commit(
Pierre-Yves Chibon 73d120
        "refs/heads/%s" % branch,  # the name of the reference to update
Pierre-Yves Chibon f0ad75
        author,
Pierre-Yves Chibon f0ad75
        committer,
Pierre-Yves Chibon 73d120
        "Add sources file for testing",
Pierre-Yves Chibon f0ad75
        # binary string representing the tree object ID
Pierre-Yves Chibon f0ad75
        tree,
Pierre-Yves Chibon f0ad75
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon a71c8d
        parents,
Pierre-Yves Chibon f0ad75
    )
Pierre-Yves Chibon a71c8d
Pierre-Yves Chibon a71c8d
    if commit:
Pierre-Yves Chibon 6fdafd
        parents = [commit.hex]
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 73d120
    subfolder = os.path.join("folder1", "folder2")
Pierre-Yves Chibon 128dfb
    if not os.path.exists(os.path.join(newfolder, subfolder)):
Pierre-Yves Chibon 128dfb
        os.makedirs(os.path.join(newfolder, subfolder))
Pierre-Yves Chibon f0ad75
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, subfolder, "file"), "w") as stream:
Pierre-Yves Chibon 73d120
        stream.write("foo\n bar\nbaz")
Pierre-Yves Chibon 73d120
    repo.index.add(os.path.join(subfolder, "file"))
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, subfolder, "fileŠ"), "w") as stream:
Pierre-Yves Chibon 73d120
        stream.write("foo\n bar\nbaz")
Pierre-Yves Chibon 73d120
    repo.index.add(os.path.join(subfolder, "fileŠ"))
Pierre-Yves Chibon f0ad75
    repo.index.write()
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon f0ad75
    # Commits the files added
Pierre-Yves Chibon f0ad75
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 73d120
    commit = repo.create_commit(
Pierre-Yves Chibon 73d120
        "refs/heads/%s" % branch,  # the name of the reference to update
Pierre-Yves Chibon f0ad75
        author,
Pierre-Yves Chibon f0ad75
        committer,
Pierre-Yves Chibon 73d120
        "Add some directory and a file for more testing",
Pierre-Yves Chibon f0ad75
        # binary string representing the tree object ID
Pierre-Yves Chibon f0ad75
        tree,
Pierre-Yves Chibon f0ad75
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon f0ad75
    )
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 62e16b
    master_ref = repo.lookup_reference(
Pierre-Yves Chibon 73d120
        "HEAD" if branch == "master" else "refs/heads/%s" % branch
Pierre-Yves Chibon 73d120
    ).resolve()
Pierre-Yves Chibon 73d120
    refname = "%s:%s" % (master_ref.name, master_ref.name)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 27a73d
    PagureRepo.push(ori_remote, refname)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon f0ad75
Pierre-Yves Chibon 73d120
def add_readme_git_repo(folder, readme_name="README.rst", branch="master"):
Pierre-Yves Chibon 87ffe2
    """ Create a README file for the specified git repo. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, parents = _clone_and_top_commits(folder, branch)
Pierre-Yves Chibon 6fdafd
Pierre-Yves Chibon 73d120
    if readme_name == "README.rst":
Karsten Hopp 5192eb
        content = """Pagure
Pierre-Yves Chibon 87ffe2
======
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
:Author: Pierre-Yves Chibon <pingou@pingoured.fr></pingou@pingoured.fr>
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon fe5017
Pagure is a light-weight git-centered forge based on pygit2.
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon fe5017
Currently, Pagure offers a web-interface for git repositories, a ticket
Pierre-Yves Chibon fe5017
system and possibilities to create new projects, fork existing ones and
Pierre-Yves Chibon fe5017
create/merge pull-requests across or within projects.
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon fe5017
Homepage: https://github.com/pypingou/pagure
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
Dev instance: http://209.132.184.222/ (/!\\ May change unexpectedly, it's a dev instance ;-))
Pierre-Yves Chibon 87ffe2
"""
Karsten Hopp 5192eb
    else:
Pierre-Yves Chibon 73d120
        content = (
Pierre-Yves Chibon 73d120
            """Pagure
Karsten Hopp 5192eb
======
Karsten Hopp 5192eb
Pierre-Yves Chibon 73d120
This is a placeholder """
Pierre-Yves Chibon 73d120
            + readme_name
Pierre-Yves Chibon 73d120
            + """
Karsten Hopp 5192eb
that should never get displayed on the website if there is a README.rst in the repo.
Karsten Hopp 5192eb
"""
Pierre-Yves Chibon 73d120
        )
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, readme_name), "w") as stream:
Pierre-Yves Chibon 87ffe2
        stream.write(content)
Karsten Hopp 5192eb
    repo.index.add(readme_name)
Pierre-Yves Chibon 87ffe2
    repo.index.write()
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 87ffe2
    # Commits the files added
Pierre-Yves Chibon 87ffe2
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6fdafd
    branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 87ffe2
    repo.create_commit(
Pierre-Yves Chibon 6fdafd
        branch_ref,  # the name of the reference to update
Pierre-Yves Chibon 87ffe2
        author,
Pierre-Yves Chibon 87ffe2
        committer,
Pierre-Yves Chibon 73d120
        "Add a README file",
Pierre-Yves Chibon 87ffe2
        # binary string representing the tree object ID
Pierre-Yves Chibon 87ffe2
        tree,
Pierre-Yves Chibon 87ffe2
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon 87ffe2
    )
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 87ffe2
Pierre-Yves Chibon 73d120
def add_commit_git_repo(
Pierre-Yves Chibon 73d120
    folder, ncommits=10, filename="sources", branch="master", symlink_to=None
Pierre-Yves Chibon 73d120
):
Pierre-Yves Chibon 595b4e
    """ Create some more commits for the specified git repo. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, branch_ref_obj = _clone_and_top_commits(
Pierre-Yves Chibon 73d120
        folder, branch, branch_ref=True
Pierre-Yves Chibon 73d120
    )
Pierre-Yves Chibon 6fdafd
Pierre-Yves Chibon 595b4e
    for index in range(ncommits):
Pierre-Yves Chibon 595b4e
        # Create a file in that git repo
Slavek Kabrda dade63
        if symlink_to:
Pierre-Yves Chibon 73d120
            os.symlink(symlink_to, os.path.join(newfolder, filename))
Slavek Kabrda dade63
        else:
Pierre-Yves Chibon 73d120
            with open(os.path.join(newfolder, filename), "a") as stream:
Pierre-Yves Chibon 73d120
                stream.write("Row %s\n" % index)
Pierre-Yves Chibon a48463
        repo.index.add(filename)
Pierre-Yves Chibon 595b4e
        repo.index.write()
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 595b4e
        parents = []
Pierre-Yves Chibon 595b4e
        commit = None
Pierre-Yves Chibon 595b4e
        try:
Pierre-Yves Chibon 6fdafd
            if branch_ref_obj:
Pierre-Yves Chibon 29ff0a
                commit = repo[branch_ref_obj.peel().hex]
Pierre-Yves Chibon 6fdafd
            else:
Pierre-Yves Chibon 73d120
                commit = repo.revparse_single("HEAD")
Pierre-Yves Chibon 6fdafd
        except (KeyError, AttributeError):
Pierre-Yves Chibon 595b4e
            pass
Pierre-Yves Chibon 595b4e
        if commit:
Pierre-Yves Chibon 595b4e
            parents = [commit.oid.hex]
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 595b4e
        # Commits the files added
Pierre-Yves Chibon 595b4e
        tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
        author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
        committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6fdafd
        branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 595b4e
        repo.create_commit(
Pierre-Yves Chibon 6fdafd
            branch_ref,
Pierre-Yves Chibon 595b4e
            author,
Pierre-Yves Chibon 595b4e
            committer,
Pierre-Yves Chibon 73d120
            "Add row %s to %s file" % (index, filename),
Pierre-Yves Chibon 595b4e
            # binary string representing the tree object ID
Pierre-Yves Chibon 595b4e
            tree,
Pierre-Yves Chibon 595b4e
            # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 595b4e
            parents,
Pierre-Yves Chibon 595b4e
        )
Pierre-Yves Chibon 6fdafd
        branch_ref_obj = pagure.lib.git.get_branch_ref(repo, branch)
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
Slavek Kabrda be430b
def add_tag_git_repo(folder, tagname, obj_hash, message):
Slavek Kabrda be430b
    """ Add a tag to the given object of the given repo annotated by given message. """
Slavek Kabrda be430b
    repo, newfolder, branch_ref_obj = _clone_and_top_commits(
Pierre-Yves Chibon 73d120
        folder, "master", branch_ref=True
Pierre-Yves Chibon 73d120
    )
Slavek Kabrda be430b
Slavek Kabrda be430b
    tag_sha = repo.create_tag(
Slavek Kabrda be430b
        tagname,
Slavek Kabrda be430b
        obj_hash,
Slavek Kabrda be430b
        repo.get(obj_hash).type,
Pierre-Yves Chibon 73d120
        pygit2.Signature("Alice Author", "alice@authors.tld"),
Slavek Kabrda be430b
        message,
Slavek Kabrda be430b
    )
Slavek Kabrda be430b
Slavek Kabrda be430b
    # Push to origin
Slavek Kabrda be430b
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    PagureRepo.push(
Pierre-Yves Chibon 73d120
        ori_remote, "refs/tags/%s:refs/tags/%s" % (tagname, tagname)
Pierre-Yves Chibon 73d120
    )
Slavek Kabrda be430b
Slavek Kabrda be430b
    shutil.rmtree(newfolder)
Slavek Kabrda be430b
    return tag_sha
Slavek Kabrda be430b
Slavek Kabrda be430b
Pierre-Yves Chibon ec5e38
def add_content_to_git(
Julen Landa Alustiza c95aa4
    folder,
Julen Landa Alustiza c95aa4
    branch="master",
Julen Landa Alustiza c95aa4
    filename="sources",
Julen Landa Alustiza c95aa4
    content="foo",
Julen Landa Alustiza c95aa4
    message=None,
Julen Landa Alustiza c95aa4
    author=("Alice Author", "alice@authors.tld"),
Julen Landa Alustiza c95aa4
    commiter=("Cecil Committer", "cecil@committers.tld"),
Pierre-Yves Chibon 73d120
):
Pierre-Yves Chibon 1cd41d
    """ Create some more commits for the specified git repo. """
Pierre-Yves Chibon ec5e38
    repo, newfolder, branch_ref_obj = _clone_and_top_commits(
Pierre-Yves Chibon 73d120
        folder, branch, branch_ref=True
Pierre-Yves Chibon 73d120
    )
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(
Pierre-Yves Chibon 73d120
        os.path.join(newfolder, filename), "a", encoding="utf-8"
Pierre-Yves Chibon 73d120
    ) as stream:
Pierre-Yves Chibon 73d120
        stream.write("%s\n" % content)
Pierre-Yves Chibon 1cd41d
    repo.index.add(filename)
Pierre-Yves Chibon 1cd41d
    repo.index.write()
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon ec5e38
    parents = []
Pierre-Yves Chibon ec5e38
    commit = None
Pierre-Yves Chibon ec5e38
    try:
Pierre-Yves Chibon ec5e38
        if branch_ref_obj:
Pierre-Yves Chibon 29ff0a
            commit = repo[branch_ref_obj.peel().hex]
Pierre-Yves Chibon ec5e38
        else:
Pierre-Yves Chibon 73d120
            commit = repo.revparse_single("HEAD")
Pierre-Yves Chibon ec5e38
    except (KeyError, AttributeError):
Pierre-Yves Chibon ec5e38
        pass
Pierre-Yves Chibon ec5e38
    if commit:
Pierre-Yves Chibon ec5e38
        parents = [commit.oid.hex]
Pierre-Yves Chibon ec5e38
Pierre-Yves Chibon 1cd41d
    # Commits the files added
Pierre-Yves Chibon 1cd41d
    tree = repo.index.write_tree()
Julen Landa Alustiza c95aa4
    author = pygit2.Signature(*author)
Julen Landa Alustiza c95aa4
    committer = pygit2.Signature(*commiter)
Pierre-Yves Chibon ec5e38
    branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 73d120
    message = message or "Add content to file %s" % (filename)
Pierre-Yves Chibon 1cd41d
    repo.create_commit(
Pierre-Yves Chibon ec5e38
        branch_ref,  # the name of the reference to update
Pierre-Yves Chibon 1cd41d
        author,
Pierre-Yves Chibon 1cd41d
        committer,
Pierre-Yves Chibon 722f04
        message,
Pierre-Yves Chibon 1cd41d
        # binary string representing the tree object ID
Pierre-Yves Chibon 1cd41d
        tree,
Pierre-Yves Chibon 1cd41d
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 1cd41d
        parents,
Pierre-Yves Chibon 1cd41d
    )
Pierre-Yves Chibon 1cd41d
Pierre-Yves Chibon 1cd41d
    # Push to origin
Pierre-Yves Chibon 1cd41d
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 595b4e
Pierre-Yves Chibon 6e857b
def add_binary_git_repo(folder, filename):
Pierre-Yves Chibon 6e857b
    """ Create a fake image file for the specified git repo. """
Pierre-Yves Chibon 73d120
    repo, newfolder, parents = _clone_and_top_commits(folder, "master")
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 945241
    content = b"""\x00\x00\x01\x00\x01\x00\x18\x18\x00\x00\x01\x00 \x00\x88
Pierre-Yves Chibon 945241
\t\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x18\x00x00\x00\x01\x00 \x00\x00\x00
Pierre-Yves Chibon 945241
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
Pierre-Yves Chibon 945241
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7lM\x01\xa6kM\t\xa6kM\x01
Pierre-Yves Chibon 945241
\xa4fF\x04\xa2dE\x95\xa2cD8\xa1a
Pierre-Yves Chibon 6e857b
"""
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 6e857b
    # Create a file in that git repo
Pierre-Yves Chibon 73d120
    with open(os.path.join(newfolder, filename), "wb") as stream:
Pierre-Yves Chibon 6e857b
        stream.write(content)
Pierre-Yves Chibon 6e857b
    repo.index.add(filename)
Pierre-Yves Chibon 6e857b
    repo.index.write()
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 6e857b
    # Commits the files added
Pierre-Yves Chibon 6e857b
    tree = repo.index.write_tree()
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 6e857b
    repo.create_commit(
Pierre-Yves Chibon 73d120
        "refs/heads/master",  # the name of the reference to update
Pierre-Yves Chibon 6e857b
        author,
Pierre-Yves Chibon 6e857b
        committer,
Pierre-Yves Chibon 73d120
        "Add a fake image file",
Pierre-Yves Chibon 6e857b
        # binary string representing the tree object ID
Pierre-Yves Chibon 6e857b
        tree,
Pierre-Yves Chibon 6e857b
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon 6e857b
    )
Pierre-Yves Chibon 6e857b
Pierre-Yves Chibon 128dfb
    # Push to origin
Pierre-Yves Chibon 128dfb
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 73d120
    master_ref = repo.lookup_reference("HEAD").resolve()
Pierre-Yves Chibon 73d120
    refname = "%s:%s" % (master_ref.name, master_ref.name)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 27a73d
    PagureRepo.push(ori_remote, refname)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 128dfb
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 128dfb
Pierre-Yves Chibon 652aff
Pierre-Yves Chibon 73d120
def remove_file_git_repo(folder, filename, branch="master"):
Pierre-Yves Chibon 3470e1
    """ Delete the specified file on the give git repo and branch. """
Pierre-Yves Chibon 8a76fa
    repo, newfolder, parents = _clone_and_top_commits(folder, branch)
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    # Remove file
Pierre-Yves Chibon 3470e1
    repo.index.remove(filename)
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    # Write the change and commit it
Pierre-Yves Chibon 3470e1
    tree = repo.index.write_tree()
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 73d120
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Pierre-Yves Chibon 73d120
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Pierre-Yves Chibon 3470e1
    branch_ref = "refs/heads/%s" % branch
Pierre-Yves Chibon 3470e1
    repo.create_commit(
Pierre-Yves Chibon 3470e1
        branch_ref,  # the name of the reference to update
Pierre-Yves Chibon 3470e1
        author,
Pierre-Yves Chibon 3470e1
        committer,
Pierre-Yves Chibon 73d120
        "Remove file %s" % filename,
Pierre-Yves Chibon 3470e1
        # binary string representing the tree object ID
Pierre-Yves Chibon 3470e1
        tree,
Pierre-Yves Chibon 3470e1
        # list of binary strings representing parents of the new commit
Pierre-Yves Chibon 73d120
        parents,
Pierre-Yves Chibon 3470e1
    )
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    # Push to origin
Pierre-Yves Chibon 3470e1
    ori_remote = repo.remotes[0]
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 73d120
    PagureRepo.push(ori_remote, "%s:%s" % (branch_ref, branch_ref))
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
    shutil.rmtree(newfolder)
Pierre-Yves Chibon 3470e1
Pierre-Yves Chibon 3470e1
Julen Landa Alustiza 064be0
def add_pull_request_git_repo(
Julen Landa Alustiza 064be0
    folder,
Julen Landa Alustiza 064be0
    session,
Julen Landa Alustiza 064be0
    repo,
Julen Landa Alustiza 064be0
    fork,
Julen Landa Alustiza 064be0
    branch_from="feature",
Julen Landa Alustiza 064be0
    user="pingou",
Julen Landa Alustiza 064be0
    allow_rebase=False,
Julen Landa Alustiza 064be0
):
Julen Landa Alustiza 064be0
    """ Set up the git repo and create the corresponding PullRequest
Julen Landa Alustiza 064be0
        object.
Julen Landa Alustiza 064be0
        """
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Clone the main repo
Julen Landa Alustiza 064be0
    gitrepo = os.path.join(folder, "repos", repo.path)
Julen Landa Alustiza 064be0
    newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
Julen Landa Alustiza 064be0
    repopath = os.path.join(newpath, "test")
Julen Landa Alustiza 064be0
    clone_repo = pygit2.clone_repository(gitrepo, repopath)
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Create a file in that git repo
Julen Landa Alustiza 064be0
    with open(os.path.join(repopath, "sources"), "w") as stream:
Julen Landa Alustiza 064be0
        stream.write("foo\n bar")
Julen Landa Alustiza 064be0
    clone_repo.index.add("sources")
Julen Landa Alustiza 064be0
    clone_repo.index.write()
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Commits the files added
Julen Landa Alustiza 064be0
    tree = clone_repo.index.write_tree()
Julen Landa Alustiza 064be0
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Julen Landa Alustiza 064be0
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Julen Landa Alustiza 064be0
    clone_repo.create_commit(
Julen Landa Alustiza 064be0
        "refs/heads/master",  # the name of the reference to update
Julen Landa Alustiza 064be0
        author,
Julen Landa Alustiza 064be0
        committer,
Julen Landa Alustiza 064be0
        "Add sources file for testing",
Julen Landa Alustiza 064be0
        # binary string representing the tree object ID
Julen Landa Alustiza 064be0
        tree,
Julen Landa Alustiza 064be0
        # list of binary strings representing parents of the new commit
Julen Landa Alustiza 064be0
        [],
Julen Landa Alustiza 064be0
    )
Julen Landa Alustiza 064be0
    refname = "refs/heads/master:refs/heads/master"
Julen Landa Alustiza 064be0
    ori_remote = clone_repo.remotes[0]
Julen Landa Alustiza 064be0
    PagureRepo.push(ori_remote, refname)
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    first_commit = clone_repo.revparse_single("HEAD")
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Set the second repo
Julen Landa Alustiza 064be0
    repopath = os.path.join(folder, "repos", fork.path)
Julen Landa Alustiza 064be0
    new_gitrepo = os.path.join(newpath, "fork_test")
Julen Landa Alustiza 064be0
    clone_repo = pygit2.clone_repository(repopath, new_gitrepo)
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Add the main project as remote repo
Julen Landa Alustiza 064be0
    upstream_path = os.path.join(folder, "repos", repo.path)
Julen Landa Alustiza 064be0
    remote = clone_repo.create_remote("upstream", upstream_path)
Julen Landa Alustiza 064be0
    remote.fetch()
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Edit the sources file again
Julen Landa Alustiza 064be0
    with open(os.path.join(new_gitrepo, "sources"), "w") as stream:
Julen Landa Alustiza 064be0
        stream.write("foo\n bar\nbaz\n boose")
Julen Landa Alustiza 064be0
    clone_repo.index.add("sources")
Julen Landa Alustiza 064be0
    clone_repo.index.write()
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Commits the files added
Julen Landa Alustiza 064be0
    tree = clone_repo.index.write_tree()
Julen Landa Alustiza 064be0
    author = pygit2.Signature("Alice Author", "alice@authors.tld")
Julen Landa Alustiza 064be0
    committer = pygit2.Signature("Cecil Committer", "cecil@committers.tld")
Julen Landa Alustiza 064be0
    clone_repo.create_commit(
Julen Landa Alustiza 064be0
        "refs/heads/%s" % branch_from,
Julen Landa Alustiza 064be0
        author,
Julen Landa Alustiza 064be0
        committer,
Julen Landa Alustiza 064be0
        "A commit on branch %s" % branch_from,
Julen Landa Alustiza 064be0
        tree,
Julen Landa Alustiza 064be0
        [first_commit.oid.hex],
Julen Landa Alustiza 064be0
    )
Julen Landa Alustiza 064be0
    refname = "refs/heads/%s" % (branch_from)
Julen Landa Alustiza 064be0
    ori_remote = clone_repo.remotes[0]
Julen Landa Alustiza 064be0
    PagureRepo.push(ori_remote, refname)
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    # Create a PR for these changes
Julen Landa Alustiza 064be0
    project = pagure.lib.query.get_authorized_project(session, "test")
Julen Landa Alustiza 064be0
    req = pagure.lib.query.new_pull_request(
Julen Landa Alustiza 064be0
        session=session,
Julen Landa Alustiza 064be0
        repo_from=fork,
Julen Landa Alustiza 064be0
        branch_from=branch_from,
Julen Landa Alustiza 064be0
        repo_to=project,
Julen Landa Alustiza 064be0
        branch_to="master",
Julen Landa Alustiza 064be0
        title="PR from the %s branch" % branch_from,
Julen Landa Alustiza 064be0
        allow_rebase=allow_rebase,
Julen Landa Alustiza 064be0
        user=user,
Julen Landa Alustiza 064be0
    )
Julen Landa Alustiza 064be0
    session.commit()
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
    return req
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
def clean_pull_requests_path():
Julen Landa Alustiza 064be0
    newpath = tempfile.mkdtemp(prefix="pagure-fork-test")
Julen Landa Alustiza 064be0
    shutil.rmtree(newpath)
Julen Landa Alustiza 064be0
Julen Landa Alustiza 064be0
Aurélien Bompard a29742
@contextmanager
Aurélien Bompard a29742
def capture_output(merge_stderr=True):
Aurélien Bompard a29742
    oldout, olderr = sys.stdout, sys.stderr
Aurélien Bompard a29742
    try:
Aurélien Bompard a29742
        out = StringIO()
Aurélien Bompard a29742
        err = StringIO()
Aurélien Bompard a29742
        if merge_stderr:
Aurélien Bompard a29742
            sys.stdout = sys.stderr = out
Aurélien Bompard a29742
            yield out
Aurélien Bompard a29742
        else:
Aurélien Bompard a29742
            sys.stdout, sys.stderr = out, err
Aurélien Bompard a29742
            yield out, err
Aurélien Bompard a29742
    finally:
Aurélien Bompard a29742
        sys.stdout, sys.stderr = oldout, olderr
Aurélien Bompard a29742
Aurélien Bompard a29742
Aurélien Bompard 626417
def get_alerts(html):
Aurélien Bompard 626417
    soup = BeautifulSoup(html, "html.parser")
Aurélien Bompard 626417
    alerts = []
Aurélien Bompard 626417
    for element in soup.find_all("div", class_="alert"):
Aurélien Bompard 626417
        severity = None
Aurélien Bompard 626417
        for class_ in element["class"]:
Aurélien Bompard 626417
            if not class_.startswith("alert-"):
Aurélien Bompard 626417
                continue
Aurélien Bompard 626417
            if class_ == "alert-dismissible":
Aurélien Bompard 626417
                continue
Pierre-Yves Chibon 73d120
            severity = class_[len("alert-") :]
Aurélien Bompard 626417
            break
Aurélien Bompard 626417
        element.find("button").decompose()  # close button
Pierre-Yves Chibon 73d120
        alerts.append(
Pierre-Yves Chibon 73d120
            dict(severity=severity, text="".join(element.stripped_strings))
Pierre-Yves Chibon 73d120
        )
Aurélien Bompard 626417
    return alerts
Aurélien Bompard 626417
Aurélien Bompard 626417
Patrick Uiterwijk 3f97f6
def definitely_wait(result):
Patrick Uiterwijk 3f97f6
    """ Helper function for definitely waiting in _maybe_wait. """
Patrick Uiterwijk 3f97f6
    result.wait()
Patrick Uiterwijk 3f97f6
Patrick Uiterwijk 3f97f6
Pierre-Yves Chibon 73d120
if __name__ == "__main__":
Pierre-Yves Chibon 413073
    SUITE = unittest.TestLoader().loadTestsFromTestCase(Modeltests)
Pierre-Yves Chibon 413073
    unittest.TextTestRunner(verbosity=2).run(SUITE)