summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn L. Villalovos <john@sodarock.com>2021-12-28 20:56:21 -0800
committerJohn L. Villalovos <john@sodarock.com>2021-12-28 20:56:21 -0800
commit05d5bdc49a0fd46e5064feb190b4069296059232 (patch)
tree6275028a114775e79c36a98c46317b86d6df59f0
parentf26bf7d3a86e4d5d1a43423476a46a381e62e8f9 (diff)
downloadgitlab-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.toml7
-rw-r--r--tests/functional/conftest.py176
-rw-r--r--tests/functional/fixtures/.env7
-rw-r--r--tests/functional/fixtures/Dockerfile8
-rwxr-xr-xtests/functional/fixtures/build-dockerfile.sh17
-rw-r--r--tests/functional/fixtures/create_license.rb51
-rw-r--r--tests/functional/fixtures/docker-compose.yml3
-rw-r--r--tox.ini2
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'
diff --git a/tox.ini b/tox.ini
index 1606471..6c87e2c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -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]