diff options
author | John L. Villalovos <john@sodarock.com> | 2021-12-28 20:56:21 -0800 |
---|---|---|
committer | John L. Villalovos <john@sodarock.com> | 2021-12-28 20:56:21 -0800 |
commit | 05d5bdc49a0fd46e5064feb190b4069296059232 (patch) | |
tree | 6275028a114775e79c36a98c46317b86d6df59f0 | |
parent | f26bf7d3a86e4d5d1a43423476a46a381e62e8f9 (diff) | |
download | gitlab-jlvillal/gitlab-ee.tar.gz |
chore: enable using GitLab EE in functional testsjlvillal/gitlab-ee
Enable using GitLab Enterprise Edition (EE) in the functional tests.
This will allow us to add functional tests for EE only features in the
functional tests.
-rw-r--r-- | pyproject.toml | 7 | ||||
-rw-r--r-- | tests/functional/conftest.py | 176 | ||||
-rw-r--r-- | tests/functional/fixtures/.env | 7 | ||||
-rw-r--r-- | tests/functional/fixtures/Dockerfile | 8 | ||||
-rwxr-xr-x | tests/functional/fixtures/build-dockerfile.sh | 17 | ||||
-rw-r--r-- | tests/functional/fixtures/create_license.rb | 51 | ||||
-rw-r--r-- | tests/functional/fixtures/docker-compose.yml | 3 | ||||
-rw-r--r-- | tox.ini | 2 |
8 files changed, 222 insertions, 49 deletions
diff --git a/pyproject.toml b/pyproject.toml index 2aa5b1d..5b738de 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,3 +87,10 @@ disable = [ "useless-object-inheritance", ] + +[tool.pytest.ini_options] +log_cli = true +log_cli_level = "INFO" +log_cli_format = "%(asctime)s.%(msecs)03d [%(levelname)8s] (%(filename)s:%(funcName)s:L%(lineno)s) %(message)s" +log_cli_date_format = "%Y-%m-%d %H:%M:%S" +addopts = "--color=yes" diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py index 7c4e584..0185609 100644 --- a/tests/functional/conftest.py +++ b/tests/functional/conftest.py @@ -1,3 +1,4 @@ +import logging import tempfile import time import uuid @@ -10,7 +11,7 @@ import gitlab import gitlab.base SLEEP_INTERVAL = 0.1 -TIMEOUT = 60 # seconds before timeout will occur +TIMEOUT = 3 * 60 # seconds before timeout will occur @pytest.fixture(scope="session") @@ -18,49 +19,6 @@ def fixture_dir(test_dir): return test_dir / "functional" / "fixtures" -def reset_gitlab(gl): - # previously tools/reset_gitlab.py - for project in gl.projects.list(): - for deploy_token in project.deploytokens.list(): - deploy_token.delete() - project.delete() - for group in gl.groups.list(): - for deploy_token in group.deploytokens.list(): - deploy_token.delete() - group.delete() - for variable in gl.variables.list(): - variable.delete() - for user in gl.users.list(): - if user.username != "root": - user.delete(hard_delete=True) - - max_iterations = int(TIMEOUT / SLEEP_INTERVAL) - - # Ensure everything has been reset - start_time = time.perf_counter() - - def wait_for_maximum_list_length( - rest_manager: gitlab.base.RESTManager, description: str, max_length: int = 0 - ) -> None: - """Wait for the list() length to be no greater than expected maximum or fail - test if timeout is exceeded""" - for _ in range(max_iterations): - if len(rest_manager.list()) <= max_length: - break - time.sleep(SLEEP_INTERVAL) - assert len(rest_manager.list()) <= max_length, ( - f"Did not delete required items for {description}. " - f"Elapsed_time: {time.perf_counter() - start_time}" - ) - - wait_for_maximum_list_length(rest_manager=gl.projects, description="projects") - wait_for_maximum_list_length(rest_manager=gl.groups, description="groups") - wait_for_maximum_list_length(rest_manager=gl.variables, description="variables") - wait_for_maximum_list_length( - rest_manager=gl.users, description="users", max_length=1 - ) - - def set_token(container, fixture_dir): set_token_rb = fixture_dir / "set_token.rb" @@ -163,9 +121,11 @@ def gitlab_config(check_is_alive, docker_ip, docker_services, temp_dir, fixture_ config_file = temp_dir / "python-gitlab.cfg" port = docker_services.port_for("gitlab", 80) + logging.info("Waiting for GitLab container to come up...") docker_services.wait_until_responsive( - timeout=200, pause=5, check=lambda: check_is_alive("gitlab-test") + timeout=300, pause=5, check=lambda: check_is_alive("gitlab-test") ) + logging.info("GitLab container is now up") token = set_token("gitlab-test", fixture_dir=fixture_dir) @@ -188,12 +148,136 @@ api_version = 4""" def gl(gitlab_config): """Helper instance to make fixtures and asserts directly via the API.""" + logging.info("Create python-gitlab gitlab.Gitlab object") instance = gitlab.Gitlab.from_config("local", [gitlab_config]) - reset_gitlab(instance) + + # wait for any running busy sidekiq processes to complete + for count in range(TIMEOUT): + time.sleep(SLEEP_INTERVAL) + busy = False + processes = instance.sidekiq.process_metrics()["processes"] + for process in processes: + if process["busy"]: + logging.info(f"sidekiq: count: {count} process_busy: {process['busy']}") + busy = True + if not busy: + logging.info(f"sidekiq idle check completed after {count} iterations") + break + + if is_gitlab_ee(instance): + logging.info("GitLab EE detected") + # NOTE(jlvillal): By default in GitLab EE it will wait 7 days before + # deleting a group. Change it to 0 days. + settings = instance.settings.get() + if settings.deletion_adjourned_period != 0: + settings.deletion_adjourned_period = 0 + settings.save() + # Clean up any extraneous resources which may exist + for project in instance.projects.list(): + logging.info(f"Mark for deletion project: {project.name!r}") + for deploy_token in project.deploytokens.list(): + logging.info( + f"Mark for deletion token: {deploy_token.name!r} in " + f"project: {project.name!r}" + ) + deploy_token.delete() + project.delete() + for group in instance.groups.list(): + logging.info(f"Mark for deletion group: {group.name!r}") + for deploy_token in group.deploytokens.list(): + logging.info( + f"Mark for deletion token: {deploy_token.name!r} in " + f"group: {group.name!r}" + ) + deploy_token.delete() + group.delete() + for variable in instance.variables.list(): + logging.info(f"Mark for deletion variable: {variable.name!r}") + variable.delete() + for user in instance.users.list(): + if user.username != "root": + logging.info(f"Mark for deletion user: {user.username!r}") + user.delete(hard_delete=True) + + timeout = TIMEOUT + sleep_interval = 0.5 + max_iterations = int(timeout / sleep_interval) + + # Ensure everything has been reset + start_time = time.perf_counter() + + def wait_for_maximum_list_length( + rest_manager: gitlab.base.RESTManager, + description: str, + max_length: int = 0, + should_delete_func=lambda x: True, + ) -> None: + """Wait for the list() length to be no greater than expected maximum or fail + test if timeout is exceeded""" + for count in range(max_iterations): + items = rest_manager.list() + logging.info( + f"Iteration: {count}: items in {description}: {[x.name for x in items]}" + ) + for item in items: + if should_delete_func(item): + logging.info( + f"Marking again for deletion {description}: {item.name!r}" + ) + try: + item.delete() + except gitlab.exceptions.GitlabDeleteError as exc: + logging.info( + f"Already marked for deletion: {item.name!r} {exc}" + ) + if len(items) <= max_length: + break + time.sleep(sleep_interval) + items = rest_manager.list() + elapsed_time = time.perf_counter() - start_time + if len(items) > max_length: + logging.error( + f"Too many items still remaining and timeout exceeded: {elapsed_time}" + ) + assert len(items) <= max_length, ( + f"Did not delete required items for {description}. " + f"Elapsed_time: {time.perf_counter() - start_time}\n" + f"items: {[str(x) for x in items]!r}" + ) + + wait_for_maximum_list_length(rest_manager=instance.projects, description="projects") + wait_for_maximum_list_length(rest_manager=instance.groups, description="groups") + wait_for_maximum_list_length( + rest_manager=instance.variables, description="variables" + ) + + def should_delete_user(user): + if user.username == "root": + return False + return True + + wait_for_maximum_list_length( + rest_manager=instance.users, + description="users", + max_length=1, + should_delete_func=should_delete_user, + ) return instance +def is_gitlab_ee(gl: gitlab.Gitlab) -> bool: + """Determine if we are running with GitLab EE as opposed to GitLab CE""" + try: + license = gl.get_license() + except gitlab.exceptions.GitlabLicenseError: + license = None + # If we have a license then we assume we are running on GitLab EE + if license: + return True + return False + + @pytest.fixture(scope="session") def gitlab_runner(gl): container = "gitlab-runner-test" diff --git a/tests/functional/fixtures/.env b/tests/functional/fixtures/.env index 30abd5c..980316c 100644 --- a/tests/functional/fixtures/.env +++ b/tests/functional/fixtures/.env @@ -1,2 +1,5 @@ -GITLAB_IMAGE=gitlab/gitlab-ce -GITLAB_TAG=14.5.2-ce.0 +GITLAB_IMAGE=gitlab/gitlab-ee +GITLAB_TAG=14.5.2-ee.0 + +GITLAB_CI_IMAGE=localhost/gitlab-ci +GITLAB_CI_TAG=latest diff --git a/tests/functional/fixtures/Dockerfile b/tests/functional/fixtures/Dockerfile new file mode 100644 index 0000000..c6a9423 --- /dev/null +++ b/tests/functional/fixtures/Dockerfile @@ -0,0 +1,8 @@ +ARG GITLAB_IMAGE=get_this_from_env +ARG GITLAB_TAG=get_this_from_env +FROM ${GITLAB_IMAGE}:${GITLAB_TAG} + +COPY create_license.rb / +RUN ruby /create_license.rb + +CMD ["/assets/wrapper"] diff --git a/tests/functional/fixtures/build-dockerfile.sh b/tests/functional/fixtures/build-dockerfile.sh new file mode 100755 index 0000000..5fa0381 --- /dev/null +++ b/tests/functional/fixtures/build-dockerfile.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -u +set -e + +TOP_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) + +cd "${TOP_DIR}" || exit 1 + +source .env + +docker build \ + -t "${GITLAB_CI_IMAGE}:${GITLAB_CI_TAG}" \ + --build-arg GITLAB_IMAGE="${GITLAB_IMAGE}" \ + --build-arg GITLAB_TAG="${GITLAB_TAG}" \ + --no-cache \ + "${TOP_DIR}" diff --git a/tests/functional/fixtures/create_license.rb b/tests/functional/fixtures/create_license.rb new file mode 100644 index 0000000..7de67b1 --- /dev/null +++ b/tests/functional/fixtures/create_license.rb @@ -0,0 +1,51 @@ +# NOTE: As of 2021-12-26 the GitLab Enterprise Edition License has the following +# section: +# Notwithstanding the foregoing, you may copy and modify the Software for development +# and testing purposes, without requiring a subscription. +# +# https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/LICENSE +# +# This code is strictly intended for use in the testing framework of python-gitlab + +# Code inspired by MIT licensed code at: https://github.com/CONIGUERO/gitlab-license.git + +require 'openssl' +require 'gitlab/license' + +# Generate a 2048 bit key pair. +license_encryption_key = OpenSSL::PKey::RSA.generate(2048) + +# Save the private key +File.open("/.license_encryption_key", "w") { |f| f.write(license_encryption_key.to_pem) } +# Save the public key +public_key = license_encryption_key.public_key +File.open("/.license_encryption_key.pub", "w") { |f| f.write(public_key.to_pem) } +File.open("/opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub", "w") { |f| f.write(public_key.to_pem) } + +Gitlab::License.encryption_key = license_encryption_key + +# Build a new license. +license = Gitlab::License.new + +license.licensee = { + "Name" => "python-gitlab-ci", + "Company" => "python-gitlab-ci", + "Email" => "python-gitlab-ci@example.com", +} + +# The date the license starts. +license.starts_at = Date.today +# Want to make sure we get at least 1 day of usage. Do two days after because if CI +# started at 23:59 we could be expired in one minute if we only did one next_day. +license.expires_at = Date.today.next_day.next_day + +# Use 'ultimate' plan so that we can test all features in the CI +license.restrictions = { + :plan => "ultimate", + :id => rand(1000..99999999) +} + +# Export the license, which encrypts and encodes it. +data = license.export + +File.open("/python-gitlab-ci.gitlab-license", 'w') { |file| file.write(data) } diff --git a/tests/functional/fixtures/docker-compose.yml b/tests/functional/fixtures/docker-compose.yml index e4869fb..1fc1248 100644 --- a/tests/functional/fixtures/docker-compose.yml +++ b/tests/functional/fixtures/docker-compose.yml @@ -6,7 +6,7 @@ networks: services: gitlab: - image: '${GITLAB_IMAGE}:${GITLAB_TAG}' + image: '${GITLAB_CI_IMAGE}:${GITLAB_CI_TAG}' container_name: 'gitlab-test' hostname: 'gitlab.test' privileged: true # Just in case https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/1350 @@ -31,6 +31,7 @@ services: gitlab_exporter['enable'] = false grafana['enable'] = false letsencrypt['enable'] = false + gitlab_rails['initial_license_file'] = "/python-gitlab-ci.gitlab-license" ports: - '8080:80' - '2222:22' @@ -95,11 +95,13 @@ exclude_lines = [testenv:cli_func_v4] deps = -r{toxinidir}/requirements-docker.txt commands = + {toxinidir}/tests/functional/fixtures/build-dockerfile.sh pytest --script-launch-mode=subprocess --cov --cov-report xml tests/functional/cli {posargs} [testenv:py_func_v4] deps = -r{toxinidir}/requirements-docker.txt commands = + {toxinidir}/tests/functional/fixtures/build-dockerfile.sh pytest --cov --cov-report xml tests/functional/api {posargs} [testenv:smoke] |