diff options
author | Nejc Habjan <nejc.habjan@siemens.com> | 2020-09-05 00:15:04 +0200 |
---|---|---|
committer | Nejc Habjan <nejc.habjan@siemens.com> | 2020-09-15 22:05:48 +0200 |
commit | 79489c775141c4ddd1f7aecae90dae8061d541fe (patch) | |
tree | 7c8f45e232049e0cad13af57e05b7ccbd8c6bb82 /tools | |
parent | 0d89a6e61bd4ae244c1545463272ef830d72dda9 (diff) | |
download | gitlab-79489c775141c4ddd1f7aecae90dae8061d541fe.tar.gz |
test(env): replace custom scripts with pytest and docker-compose
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/build_test_env.sh | 158 | ||||
-rw-r--r-- | tools/functional/api/test_gitlab.py | 8 | ||||
-rw-r--r-- | tools/functional/cli/conftest.py | 4 | ||||
-rw-r--r-- | tools/functional/conftest.py | 99 | ||||
-rwxr-xr-x | tools/functional/ee-test.py (renamed from tools/ee-test.py) | 0 | ||||
-rw-r--r-- | tools/functional/fixtures/avatar.png (renamed from tools/avatar.png) | bin | 592 -> 592 bytes | |||
-rw-r--r-- | tools/functional/fixtures/docker-compose.yml | 31 | ||||
-rw-r--r-- | tools/functional/fixtures/set_token.rb | 9 | ||||
-rw-r--r-- | tools/functional/python_test_v4.py (renamed from tools/python_test_v4.py) | 17 | ||||
-rwxr-xr-x | tools/functional_tests.sh | 21 | ||||
-rwxr-xr-x | tools/generate_token.py | 51 | ||||
-rwxr-xr-x | tools/py_functional_tests.sh | 22 | ||||
-rwxr-xr-x | tools/reset_gitlab.py | 20 |
13 files changed, 155 insertions, 285 deletions
diff --git a/tools/build_test_env.sh b/tools/build_test_env.sh deleted file mode 100755 index a7b64b6..0000000 --- a/tools/build_test_env.sh +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/sh -# Copyright (C) 2016 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -pecho() { printf %s\\n "$*"; } -log() { - [ "$#" -eq 0 ] || { pecho "$@"; return 0; } - while IFS= read -r log_line || [ -n "${log_line}" ]; do - log "${log_line}" - done -} -error() { log "ERROR: $@" >&2; } -fatal() { error "$@"; exit 1; } -try() { "$@" || fatal "'$@' failed"; } - -REUSE_CONTAINER= -NOVENV= -API_VER=4 -DEFAULT_GITLAB_IMAGE=gitlab/gitlab-ce -DEFAULT_GITLAB_TAG=13.3.6-ce.0 -GITLAB_IMAGE="${GITLAB_IMAGE:-$DEFAULT_GITLAB_IMAGE}" -GITLAB_TAG="${GITLAB_TAG:-$DEFAULT_GITLAB_TAG}" -VENV_CMD="python3 -m venv" -while getopts :knp:a:i:t: opt "$@"; do - case $opt in - k) REUSE_CONTAINER=1;; - n) NOVENV=1;; - a) API_VER=$OPTARG;; - i) GITLAB_IMAGE=$OPTARG;; - t) GITLAB_TAG=$OPTARG;; - :) fatal "Option -${OPTARG} requires a value";; - '?') fatal "Unknown option: -${OPTARG}";; - *) fatal "Internal error: opt=${opt}";; - esac -done - -case $API_VER in - 4) ;; - *) fatal "Wrong API version (4 only)";; -esac - -for req in \ - curl \ - docker \ - ; -do - command -v "${req}" >/dev/null 2>&1 || fatal "${req} is required" -done - -VENV=$(pwd)/.venv || exit 1 -CONFIG=/tmp/python-gitlab.cfg - -cleanup() { - rm -f "${CONFIG}" - log "Deactivating Python virtualenv..." - command -v deactivate >/dev/null 2>&1 && deactivate || true - log "Deleting python virtualenv..." - rm -rf "$VENV" - if [ -z "$REUSE_CONTAINER" ]; then - log "Stopping gitlab-test docker container..." - docker rm -f gitlab-test >/dev/null - fi - log "Done." -} -[ -z "${BUILD_TEST_ENV_AUTO_CLEANUP+set}" ] || { - trap cleanup EXIT - trap 'exit 1' HUP INT TERM -} - -if [ -z "$REUSE_CONTAINER" ] || ! docker top gitlab-test >/dev/null 2>&1; then - try docker pull "$GITLAB_IMAGE:$GITLAB_TAG" - GITLAB_OMNIBUS_CONFIG="external_url 'http://gitlab.test' -gitlab_rails['initial_root_password'] = '5iveL!fe' -gitlab_rails['initial_shared_runners_registration_token'] = 'sTPNtWLEuSrHzoHP8oCU' -registry['enable'] = false -nginx['redirect_http_to_https'] = false -nginx['listen_port'] = 80 -nginx['listen_https'] = false -pages_external_url 'http://pages.gitlab.lxd' -gitlab_pages['enable'] = true -gitlab_pages['inplace_chroot'] = true -prometheus['enable'] = false -alertmanager['enable'] = false -node_exporter['enable'] = false -redis_exporter['enable'] = false -postgres_exporter['enable'] = false -pgbouncer_exporter['enable'] = false -gitlab_exporter['enable'] = false -grafana['enable'] = false -letsencrypt['enable'] = false -" - try docker run --name gitlab-test --detach --publish 8080:80 \ - --publish 2222:22 --env "GITLAB_OMNIBUS_CONFIG=$GITLAB_OMNIBUS_CONFIG" \ - "$GITLAB_IMAGE:$GITLAB_TAG" >/dev/null -fi - -if [ -z "$NOVENV" ]; then - log "Creating Python virtualenv..." - try $VENV_CMD "$VENV" - . "$VENV"/bin/activate || fatal "failed to activate Python virtual environment" - - log "Installing dependencies into virtualenv..." - try pip install -r requirements.txt - - log "Installing into virtualenv..." - try pip install -e . - - # to run generate_token.py - pip install requests-html pytest-console-scripts -fi - -log "Waiting for gitlab to come online... " -I=0 -while :; do - sleep 1 - docker top gitlab-test >/dev/null 2>&1 || fatal "docker failed to start" - sleep 4 - docker logs gitlab-test 2>&1 | grep "gitlab Reconfigured!" \ - && break - I=$((I+5)) - log "Waiting for GitLab to reconfigure.. (${I}s)" - [ "$I" -lt 180 ] || fatal "timed out" -done - -# Get the token -TOKEN=$($(dirname $0)/generate_token.py) - -cat > $CONFIG << EOF -[global] -default = local -timeout = 30 - -[local] -url = http://localhost:8080 -private_token = $TOKEN -api_version = $API_VER -EOF - -log "Config file content ($CONFIG):" -log <$CONFIG - -if [ ! -z "$REUSE_CONTAINER" ]; then - echo reset gitlab - $(dirname $0)/reset_gitlab.py -fi -log "Test environment initialized." diff --git a/tools/functional/api/test_gitlab.py b/tools/functional/api/test_gitlab.py new file mode 100644 index 0000000..5cf3418 --- /dev/null +++ b/tools/functional/api/test_gitlab.py @@ -0,0 +1,8 @@ +""" +Temporary module to run legacy tests as a single pytest test case +as they're all plain asserts at module level. +""" + + +def test_api_v4(gl): + from tools.functional import python_test_v4 diff --git a/tools/functional/cli/conftest.py b/tools/functional/cli/conftest.py index 13c3096..ba94dcb 100644 --- a/tools/functional/cli/conftest.py +++ b/tools/functional/cli/conftest.py @@ -2,7 +2,7 @@ import pytest @pytest.fixture -def gitlab_cli(script_runner, CONFIG): +def gitlab_cli(script_runner, gitlab_config): """Wrapper fixture to help make test cases less verbose.""" def _gitlab_cli(subcommands): @@ -10,7 +10,7 @@ def gitlab_cli(script_runner, CONFIG): Return a script_runner.run method that takes a default gitlab command, and subcommands passed as arguments inside test cases. """ - command = ["gitlab", "--config-file", CONFIG] + command = ["gitlab", "--config-file", gitlab_config] for subcommand in subcommands: # ensure we get strings (e.g from IDs) diff --git a/tools/functional/conftest.py b/tools/functional/conftest.py index e60fa39..ec0d08b 100644 --- a/tools/functional/conftest.py +++ b/tools/functional/conftest.py @@ -1,6 +1,8 @@ +import time import tempfile from pathlib import Path from random import randint +from subprocess import check_output import pytest @@ -8,6 +10,7 @@ import gitlab TEMP_DIR = tempfile.gettempdir() +TEST_DIR = Path(__file__).resolve().parent def random_id(): @@ -20,15 +23,103 @@ def random_id(): return randint(9, 9999) +def reset_gitlab(gl): + # previously tools/reset_gitlab.py + for project in gl.projects.list(): + project.delete() + for group in gl.groups.list(): + group.delete() + for variable in gl.variables.list(): + variable.delete() + for user in gl.users.list(): + if user.username != "root": + user.delete() + + +def set_token(container): + set_token_rb = TEST_DIR / "fixtures" / "set_token.rb" + + with open(set_token_rb, "r") as f: + set_token_command = f.read().strip() + + rails_command = [ + "docker", + "exec", + container, + "gitlab-rails", + "runner", + set_token_command, + ] + output = check_output(rails_command).decode().strip() + + return output + + @pytest.fixture(scope="session") -def CONFIG(): - return Path(TEMP_DIR) / "python-gitlab.cfg" +def docker_compose_file(): + return TEST_DIR / "fixtures" / "docker-compose.yml" @pytest.fixture(scope="session") -def gl(CONFIG): +def check_is_alive(request): + """ + Return a healthcheck function fixture for the GitLab container spinup. + """ + start = time.time() + + # Temporary manager to disable capsys in a session-scoped fixture + # so people know it takes a while for GitLab to spin up + # https://github.com/pytest-dev/pytest/issues/2704 + capmanager = request.config.pluginmanager.getplugin("capturemanager") + + def _check(container): + delay = int(time.time() - start) + + with capmanager.global_and_fixture_disabled(): + print(f"Waiting for GitLab to reconfigure.. (~{delay}s)") + + logs = ["docker", "logs", container] + output = check_output(logs).decode() + + return "gitlab Reconfigured!" in output + + return _check + + +@pytest.fixture(scope="session") +def gitlab_config(check_is_alive, docker_ip, docker_services): + config_file = Path(TEMP_DIR) / "python-gitlab.cfg" + port = docker_services.port_for("gitlab", 80) + + docker_services.wait_until_responsive( + timeout=180, pause=5, check=lambda: check_is_alive("gitlab-test") + ) + + token = set_token("gitlab-test") + + config = f"""[global] +default = local +timeout = 60 + +[local] +url = http://{docker_ip}:{port} +private_token = {token} +api_version = 4""" + + with open(config_file, "w") as f: + f.write(config) + + return config_file + + +@pytest.fixture(scope="session") +def gl(gitlab_config): """Helper instance to make fixtures and asserts directly via the API.""" - return gitlab.Gitlab.from_config("local", [CONFIG]) + + instance = gitlab.Gitlab.from_config("local", [gitlab_config]) + reset_gitlab(instance) + + return instance @pytest.fixture(scope="module") diff --git a/tools/ee-test.py b/tools/functional/ee-test.py index 3f75655..3f75655 100755 --- a/tools/ee-test.py +++ b/tools/functional/ee-test.py diff --git a/tools/avatar.png b/tools/functional/fixtures/avatar.png Binary files differindex a3a767c..a3a767c 100644 --- a/tools/avatar.png +++ b/tools/functional/fixtures/avatar.png diff --git a/tools/functional/fixtures/docker-compose.yml b/tools/functional/fixtures/docker-compose.yml new file mode 100644 index 0000000..5dd9d90 --- /dev/null +++ b/tools/functional/fixtures/docker-compose.yml @@ -0,0 +1,31 @@ +version: '3' +services: + gitlab: + image: 'gitlab/gitlab-ce:latest' + container_name: 'gitlab-test' + hostname: 'gitlab.test' + privileged: true # Just in case https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/1350 + environment: + GITLAB_OMNIBUS_CONFIG: | + external_url 'http://gitlab.test' + gitlab_rails['initial_root_password'] = '5iveL!fe' + gitlab_rails['initial_shared_runners_registration_token'] = 'sTPNtWLEuSrHzoHP8oCU' + registry['enable'] = false + nginx['redirect_http_to_https'] = false + nginx['listen_port'] = 80 + nginx['listen_https'] = false + pages_external_url 'http://pages.gitlab.lxd' + gitlab_pages['enable'] = true + gitlab_pages['inplace_chroot'] = true + prometheus['enable'] = false + alertmanager['enable'] = false + node_exporter['enable'] = false + redis_exporter['enable'] = false + postgres_exporter['enable'] = false + pgbouncer_exporter['enable'] = false + gitlab_exporter['enable'] = false + grafana['enable'] = false + letsencrypt['enable'] = false + ports: + - '8080:80' + - '2222:22' diff --git a/tools/functional/fixtures/set_token.rb b/tools/functional/fixtures/set_token.rb new file mode 100644 index 0000000..735dcd5 --- /dev/null +++ b/tools/functional/fixtures/set_token.rb @@ -0,0 +1,9 @@ +# https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html#programmatically-creating-a-personal-access-token + +user = User.find_by_username('root') + +token = user.personal_access_tokens.create(scopes: [:api, :sudo], name: 'default'); +token.set_token('python-gitlab-token'); +token.save! + +puts token.token diff --git a/tools/python_test_v4.py b/tools/functional/python_test_v4.py index 7ff97b6..6c90fe6 100644 --- a/tools/python_test_v4.py +++ b/tools/functional/python_test_v4.py @@ -1,6 +1,7 @@ import base64 -import os +import tempfile import time +from pathlib import Path import requests @@ -56,11 +57,11 @@ nxs4TLO3kZjUTgWKdhpgRNF5hwaz51ZjpebaRf/ZqRuNyX4lIRolDxzOn/+O1o8L qG2ZdhHHmSK2LaQLFiSprUkikStNU9BqSQ== =5OGa -----END PGP PUBLIC KEY BLOCK-----""" -AVATAR_PATH = os.path.join(os.path.dirname(__file__), "avatar.png") - +AVATAR_PATH = Path(__file__).resolve().parent / "fixtures" / "avatar.png" +TEMP_DIR = Path(tempfile.gettempdir()) # token authentication from config file -gl = gitlab.Gitlab.from_config(config_files=["/tmp/python-gitlab.cfg"]) +gl = gitlab.Gitlab.from_config(config_files=[TEMP_DIR / "python-gitlab.cfg"]) gl.auth() assert isinstance(gl.user, gitlab.v4.objects.CurrentUser) @@ -388,7 +389,7 @@ assert export.message == "202 Accepted" # We cannot check for export_status with group export API time.sleep(10) -import_archive = "/tmp/gitlab-group-export.tgz" +import_archive = TEMP_DIR / "gitlab-group-export.tgz" import_path = "imported_group" import_name = "Imported Group" @@ -1062,11 +1063,13 @@ while ex.export_status != "finished": count += 1 if count == 10: raise Exception("Project export taking too much time") -with open("/tmp/gitlab-export.tgz", "wb") as f: +with open(TEMP_DIR / "gitlab-export.tgz", "wb") as f: ex.download(streamed=True, action=f.write) output = gl.projects.import_project( - open("/tmp/gitlab-export.tgz", "rb"), "imported_project", name="Imported Project" + open(TEMP_DIR / "gitlab-export.tgz", "rb"), + "imported_project", + name="Imported Project", ) project_import = gl.projects.get(output["id"], lazy=True).imports.get() diff --git a/tools/functional_tests.sh b/tools/functional_tests.sh deleted file mode 100755 index 9b91f0f..0000000 --- a/tools/functional_tests.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# Copyright (C) 2015 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -setenv_script=$(dirname "$0")/build_test_env.sh || exit 1 -BUILD_TEST_ENV_AUTO_CLEANUP=true -. "$setenv_script" "$@" || exit 1 - -pytest --script-launch-mode=subprocess "$(dirname "$0")/functional/cli" diff --git a/tools/generate_token.py b/tools/generate_token.py deleted file mode 100755 index 89909bd..0000000 --- a/tools/generate_token.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python - -from urllib.parse import urljoin -from requests_html import HTMLSession - -ENDPOINT = "http://localhost:8080" -LOGIN = "root" -PASSWORD = "5iveL!fe" - - -class GitlabSession(HTMLSession): - def __init__(self, endpoint, *args, **kwargs): - super().__init__(*args, **kwargs) - self.endpoint = endpoint - self.csrf = None - - def find_csrf_token(self, html): - param = html.find("meta[name=csrf-param]")[0].attrs["content"] - token = html.find("meta[name=csrf-token]")[0].attrs["content"] - self.csrf = {param: token} - - def obtain_csrf_token(self): - r = self.get(urljoin(self.endpoint, "/")) - self.find_csrf_token(r.html) - - def sign_in(self, login, password): - data = {"user[login]": login, "user[password]": password, **self.csrf} - r = self.post(urljoin(self.endpoint, "/users/sign_in"), data=data) - self.find_csrf_token(r.html) - - def obtain_personal_access_token(self, name): - data = { - "personal_access_token[name]": name, - "personal_access_token[scopes][]": ["api", "sudo"], - **self.csrf, - } - r = self.post( - urljoin(self.endpoint, "/profile/personal_access_tokens"), data=data - ) - return r.html.find("#created-personal-access-token")[0].attrs["value"] - - -def main(): - with GitlabSession(ENDPOINT) as s: - s.obtain_csrf_token() - s.sign_in(LOGIN, PASSWORD) - print(s.obtain_personal_access_token("default")) - - -if __name__ == "__main__": - main() diff --git a/tools/py_functional_tests.sh b/tools/py_functional_tests.sh deleted file mode 100755 index 1009cb9..0000000 --- a/tools/py_functional_tests.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -# Copyright (C) 2015 Gauvain Pocentek <gauvain@pocentek.net> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -setenv_script=$(dirname "$0")/build_test_env.sh || exit 1 -BUILD_TEST_ENV_AUTO_CLEANUP=true -. "$setenv_script" "$@" || exit 1 - -try python "$(dirname "$0")"/python_test_v${API_VER}.py -pytest "$(dirname "$0")/functional/api" diff --git a/tools/reset_gitlab.py b/tools/reset_gitlab.py deleted file mode 100755 index 64668a9..0000000 --- a/tools/reset_gitlab.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python - -import sys - -from gitlab import Gitlab - - -def main(): - with Gitlab.from_config(config_files=["/tmp/python-gitlab.cfg"]) as gl: - for project in gl.projects.list(): - project.delete() - for group in gl.groups.list(): - group.delete() - for user in gl.users.list(): - if user.username != "root": - user.delete() - - -if __name__ == "__main__": - sys.exit(main()) |