diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000000000000000000000000000000000000..a529cce01dc7b64e37c0b2532fd77aa9cca02e55 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 88 +ignore = E203, E731 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 082ccae7fc5d91ca0a9e044a9b13d88b2045f9fd..9771ddf32b2c3bcdfda5a4d4dbb94993f6a277b8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,11 +8,10 @@ variables: PUBLISH_URL: ota.ecloud.global DOCKER_TLS_CERTDIR: "/certs" -services: -- docker:19.03.1-dind - build: stage: build + services: + - docker:19.03.1-dind script: - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME || true - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY @@ -21,6 +20,52 @@ build: - if [ "${CI_COMMIT_REF_NAME}" = master ] ; then docker push $CI_REGISTRY_IMAGE:latest ; fi tags: - generic_privileged + rules: + - if: '$CI_PIPELINE_SOURCE != "schedule"' + +check:rules:tests: + stage: build + image: python:3.11-slim + before_script: + - pip install black==22.10.0 flake8==5.0.4 isort==5.10.1 + script: + - cd tests/functional + - black --check . + - flake8 . + - isort --check . + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + changes: + - tests/functional/* + +.tests:functional: + stage: test + image: python:3.11-slim + variables: + PYTEST_ADDOPTS: "--junitxml=report.xml" + before_script: + - cd tests/functional/ + - pip install -r requirements.txt + rules: + - if: '$CI_PIPELINE_SOURCE == "schedule"' + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + changes: + - tests/functional/* + artifacts: + when: always + reports: + junit: tests/functional/report.xml + + +tests:functional:staging: + extends: .tests:functional + script: + - pytest --ota-domain "test.${PUBLISH_URL}" + +tests:functional:production: + extends: .tests:functional + script: + - pytest --ota-domain "${PUBLISH_URL}" # Deploy stage .deploy:image: @@ -44,15 +89,17 @@ build: deploy:staging: extends: .deploy:image - when: manual + rules: + - if: '$CI_COMMIT_REF_NAME != "production" && $CI_PIPELINE_SOURCE != "schedule"' + when: manual environment: name: staging url: https://ota.eeo.one deploy:production: extends: .deploy:image - only: - - production + rules: + - if: '$CI_COMMIT_REF_NAME == "production" && $CI_PIPELINE_SOURCE != "schedule"' environment: name: production url: https://ota.ecloud.global diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py new file mode 100644 index 0000000000000000000000000000000000000000..15b01544cdac319afbd2006f463539639737ee50 --- /dev/null +++ b/tests/functional/conftest.py @@ -0,0 +1,28 @@ +import pytest + + +class Context: + def __init__(self, config): + self.domain = config.getoption("--ota-domain") + assert self.domain is not None, "OTA server domain has to be defined" + self.device = config.getoption("--ota-device") + self.channel = config.getoption("--ota-channel") + self.url = f"https://{self.domain}" + + +def pytest_addoption(parser): + parser.addoption( + "--ota-domain", action="store", default=None, help="OTA server domain" + ) + parser.addoption( + "--ota-device", action="store", default="FP3", help="OTA device name" + ) + parser.addoption( + "--ota-channel", action="store", default="stable", help="OTA channel name" + ) + + +@pytest.fixture +def ctx(request): + context = Context(request.config) + yield context diff --git a/tests/functional/requirements.txt b/tests/functional/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..65a64119a6db32f128471e7b4cc2cf1408056170 --- /dev/null +++ b/tests/functional/requirements.txt @@ -0,0 +1,2 @@ +pytest==7.2.0 +httpx==0.23.1 diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py new file mode 100644 index 0000000000000000000000000000000000000000..8b266b82feb4ba1f6776f39927328b7ae8ced999 --- /dev/null +++ b/tests/functional/test_api.py @@ -0,0 +1,69 @@ +import httpx +import pytest + + +@pytest.fixture +def ctx(ctx): + ctx.cli = httpx.Client(base_url=f"{ctx.url}/api/v1", timeout=60) + yield ctx + + +def test_list_device_builds(ctx): + res = ctx.cli.get(f"/{ctx.device}/{ctx.channel}") + assert res.status_code == httpx.codes.OK + data = res.json() + assert not data["error"] + assert len(data["response"]) + build = data["response"][-1] + assert build["channel"] == ctx.channel + assert build["romtype"] == ctx.channel + assert build["url"].startswith(ctx.url) + assert build["filename"].startswith("e-") + + +def test_list_build_with_incremental_update_field(ctx): + # list and sort all builds by datetime + res = ctx.cli.get(f"/{ctx.device}/{ctx.channel}") + assert res.status_code == httpx.codes.OK + data = sorted(res.json()["response"], key=lambda d: d["datetime"]) + assert len(data) >= 2 + + # list build with incremental field + build = data[-2] + res = ctx.cli.get(f"/{ctx.device}/{ctx.channel}/{build['incremental']}") + assert res.status_code == httpx.codes.OK + data = res.json() + assert len(data["response"]) == 1 + + +def test_FP4_upgrade_from_given_build(ctx): + """FP4 A12 upgrade is allowed only from 1.5-r build""" + # create a map about /e/OS builds + res = ctx.cli.get("/FP4/stable") + assert res.status_code == httpx.codes.OK + assert len(res.json()["response"]) + builds = { + f"{d['version']}-{d['pre_version']}-{d['android_version']}": d + for d in res.json()["response"] + } + + # ensure that A12 builds are not listed with version <= 1.4-r + build14r = builds["1.4--11"] + res = ctx.cli.get(f"/FP4/stable/{build14r['incremental']}") + assert res.status_code == httpx.codes.OK + data = res.json()["response"] + a12builds = [d for d in data if d["android_version"] == "12"] + assert len(a12builds) == 0 + + # ensure that A12 builds are listed with version == 1.5-r + build15r = builds["1.5--11"] + res = ctx.cli.get( + f"/FP4/stable/{build15r['incremental']}", + headers={"User-Agent": "eOS v1.5"}, + ) + assert res.status_code == httpx.codes.OK + data = res.json()["response"] + a12builds = [d for d in data if d["android_version"] == "12"] + a11builds = [d for d in data if d["android_version"] == "11"] + assert len(a11builds) == 0 + assert len(a12builds) >= 1