Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug-1909870: Make system test cases independent of each other. #3005

Merged
merged 1 commit into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion systemtests/lib/fake_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ def __init__(

self.file_name: Optional[str] = None
self.members: list[FakeSymFile] = []
self.uploaded = False

def create(self, tmp_dir: os.PathLike):
LOGGER.info(
Expand Down
24 changes: 9 additions & 15 deletions systemtests/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import logging
import os
import tempfile
from typing import Generator
from typing import Callable, Generator

import pytest

Expand Down Expand Up @@ -143,21 +143,15 @@ def fake_data_bucket(pytestconfig: pytest.Config) -> FakeDataBucket:
return FakeDataBucket(bucket_name, public_url, credentials_path)


@pytest.fixture(scope="class")
def zip_archive(
request: pytest.FixtureRequest,
) -> Generator[FakeZipArchive, None, None]:
size, platform = request.param
sym_file_size = size // 2
zip = FakeZipArchive(size, sym_file_size, platform)
@pytest.fixture
def create_zip_archive() -> Generator[Callable[[int, str], FakeZipArchive], None, None]:
os.makedirs(TMP_DIR, exist_ok=True)
with tempfile.TemporaryDirectory(dir=TMP_DIR) as tmp_dir:
zip.create(tmp_dir)
yield zip

def _create_zip_archive(size: int, platform: str) -> FakeZipArchive:
sym_file_size = size // 2
zip = FakeZipArchive(size, sym_file_size, platform)
zip.create(tmp_dir)
return zip

@pytest.fixture(scope="class")
def zip_archive_url(
zip_archive: FakeZipArchive, fake_data_bucket: FakeDataBucket
) -> str:
return fake_data_bucket.upload_scratch(zip_archive.file_name)
yield _create_zip_archive
235 changes: 117 additions & 118 deletions systemtests/tests/test_direct_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

from typing import Callable
from unittest.mock import ANY
from urllib.parse import unquote

Expand All @@ -14,129 +15,127 @@
# Mark all tests in this module as upload tests
pytestmark = pytest.mark.upload

small_archive_param = pytest.param((2**19, "windows"), id="small")
large_archive_param = pytest.param(
(2**30, "linux"), id="large", marks=pytest.mark.large_files
)

small_and_large_archives = pytest.mark.parametrize(
"zip_archive", [small_archive_param, large_archive_param], indirect=True
)
small_archive = pytest.mark.parametrize(
"zip_archive", [small_archive_param], indirect=True
)
# Upload sizes
SMALL = 2**16
LARGE = 2**30


class TestDirectUpload:
# Tests within a class scope are executed in definition order.

@small_and_large_archives
def test_upload(self, tecken_client: TeckenClient, zip_archive: FakeZipArchive):
response = tecken_client.upload(zip_archive.file_name)
assert response.status_code == 201
zip_archive.uploaded = True

@small_and_large_archives
def test_download(self, tecken_client: TeckenClient, zip_archive: FakeZipArchive):
if not zip_archive.uploaded:
pytest.skip("upload failed")

for sym_file in zip_archive.members:
response = tecken_client.download(sym_file.key())
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302

@small_archive
def test_head_request(
self, tecken_client: TeckenClient, zip_archive: FakeZipArchive
):
if not zip_archive.uploaded:
pytest.skip("upload failed")

for sym_file in zip_archive.members:
response = tecken_client.download(sym_file.key(), method="HEAD")
assert response.status_code == 200
assert not response.history

@small_archive
@pytest.mark.nginx
def test_headers(self, tecken_client: TeckenClient, zip_archive: FakeZipArchive):
if not zip_archive.uploaded:
pytest.skip("upload failed")

# These are exclusively security headers added by nginx
expected_tecken_headers = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Content-Security-Policy": ANY,
"Strict-Transport-Security": "max-age=31536000",
}
# These are headers sent by the storage backend (S3 or GCS)
expected_storage_headers = {
"Content-Encoding": "gzip",
"Content-Length": ANY,
}
response = tecken_client.download(zip_archive.members[0].key())
@pytest.mark.parametrize(
["size", "platform"],
[
pytest.param(SMALL, "windows", id="small"),
pytest.param(LARGE, "linux", id="large", marks=pytest.mark.large_files),
],
)
def test_upload_and_download(
size: int,
platform: str,
tecken_client: TeckenClient,
create_zip_archive: Callable[[int, str], FakeZipArchive],
):
zip_archive = create_zip_archive(size, platform)
response = tecken_client.upload(zip_archive.file_name)
assert response.status_code == 201

for sym_file in zip_archive.members:
response = tecken_client.download(sym_file.key())
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302


def test_head_request(
tecken_client: TeckenClient,
create_zip_archive: Callable[[int, str], FakeZipArchive],
):
zip_archive = create_zip_archive(SMALL, "windows")
response = tecken_client.upload(zip_archive.file_name)
response.raise_for_status()

for sym_file in zip_archive.members:
response = tecken_client.download(sym_file.key(), method="HEAD")
assert response.status_code == 200
assert not response.history


@pytest.mark.nginx
def test_headers(
tecken_client: TeckenClient,
create_zip_archive: Callable[[int, str], FakeZipArchive],
):
zip_archive = create_zip_archive(SMALL, "windows")
response = tecken_client.upload(zip_archive.file_name)
response.raise_for_status()

# These are exclusively security headers added by nginx
expected_tecken_headers = {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Content-Security-Policy": ANY,
"Strict-Transport-Security": "max-age=31536000",
}
# These are headers sent by the storage backend (S3 or GCS)
expected_storage_headers = {
"Content-Encoding": "gzip",
"Content-Length": ANY,
}
response = tecken_client.download(zip_archive.members[0].key())
[redirect] = response.history

actual_tecken_headers = {
name: redirect.headers[name] for name in expected_tecken_headers
}
assert actual_tecken_headers == expected_tecken_headers

actual_storage_headers = {
name: response.headers[name] for name in expected_storage_headers
}
assert actual_storage_headers == expected_storage_headers


def test_code_info_lookup(
tecken_client: TeckenClient,
create_zip_archive: Callable[[int, str], FakeZipArchive],
):
zip_archive = create_zip_archive(SMALL, "windows")
response = tecken_client.upload(zip_archive.file_name)
response.raise_for_status()

for sym_file in zip_archive.members:
response = tecken_client.download(
sym_file.code_info_key(), allow_redirects=False
)
assert response.status_code == 302
redirect_key = unquote(response.headers["location"])[1:]
assert redirect_key == sym_file.key()


def test_try_upload_and_download(
tecken_client: TeckenClient,
create_zip_archive: Callable[[int, str], FakeZipArchive],
):
zip_archive = create_zip_archive(SMALL, "windows")
response = tecken_client.upload(zip_archive.file_name, try_storage=True)
assert response.status_code == 201

for sym_file in zip_archive.members:
# regular download should fail
key = sym_file.key()
response = tecken_client.download(key)
assert response.status_code == 404

# download using `?try` query parameter
response = tecken_client.download(key, try_storage=True)
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302

actual_tecken_headers = {
name: redirect.headers[name] for name in expected_tecken_headers
}
assert actual_tecken_headers == expected_tecken_headers

actual_storage_headers = {
name: response.headers[name] for name in expected_storage_headers
}
assert actual_storage_headers == expected_storage_headers

@small_archive
def test_code_info_lookup(
self, tecken_client: TeckenClient, zip_archive: FakeZipArchive
):
if not zip_archive.uploaded:
pytest.skip("upload failed")

for sym_file in zip_archive.members:
response = tecken_client.download(
sym_file.code_info_key(), allow_redirects=False
)
assert response.status_code == 302
redirect_key = unquote(response.headers["location"])[1:]
assert redirect_key == sym_file.key()


class TestDirectTryUpload:
# Tests within a class scope are executed in definition order.

@small_archive
def test_upload(self, tecken_client: TeckenClient, zip_archive: FakeZipArchive):
response = tecken_client.upload(zip_archive.file_name, try_storage=True)
assert response.status_code == 201
zip_archive.uploaded = True

@small_archive
def test_download(self, tecken_client: TeckenClient, zip_archive: FakeZipArchive):
if not zip_archive.uploaded:
pytest.skip("upload failed")

for sym_file in zip_archive.members:
# regular download should fail
key = sym_file.key()
response = tecken_client.download(key)
assert response.status_code == 404

# download using `?try` query parameter
response = tecken_client.download(key, try_storage=True)
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302

# download by prefixing the key with try/
response = tecken_client.download(f"try/{key}")
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302
# download by prefixing the key with try/
response = tecken_client.download(f"try/{key}")
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302


def test_no_token(tecken_client: TeckenClient):
Expand Down
64 changes: 29 additions & 35 deletions systemtests/tests/test_upload_by_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,47 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

from typing import Callable
import pytest

from systemtests.lib.fake_data import FakeZipArchive
from systemtests.lib.fake_data import FakeDataBucket, FakeZipArchive
from systemtests.lib.tecken_client import TeckenClient


# Mark all tests in this module as upload tests
pytestmark = pytest.mark.upload

small_archive_param = pytest.param((2**19, "windows"), id="small")
large_archive_param = pytest.param(
(3 * 2**30, "linux"), id="large", marks=pytest.mark.large_files
)

small_and_large_archives = pytest.mark.parametrize(
"zip_archive", [small_archive_param, large_archive_param], indirect=True
)
small_archive = pytest.mark.parametrize(
"zip_archive", [small_archive_param], indirect=True
)
# Upload sizes
SMALL = 2**16
LARGE = 2**30


@pytest.mark.parametrize(
["size", "platform"],
[
pytest.param(SMALL, "windows", id="small"),
pytest.param(LARGE, "linux", id="large", marks=pytest.mark.large_files),
],
)
@pytest.mark.write_bucket
class TestUploadByDownload:
# Tests within a class scope are executed in definition order.

@small_and_large_archives
def test_upload(
self,
tecken_client: TeckenClient,
zip_archive: FakeZipArchive,
zip_archive_url: str,
):
response = tecken_client.upload_by_download(zip_archive_url)
assert response.status_code == 201
zip_archive.uploaded = True

@small_and_large_archives
def test_download(self, tecken_client: TeckenClient, zip_archive: FakeZipArchive):
if not zip_archive.uploaded:
pytest.skip("upload failed")

for sym_file in zip_archive.members:
response = tecken_client.download(sym_file.key())
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302
def test_upload_and_download(
size: int,
platform: str,
tecken_client: TeckenClient,
create_zip_archive: Callable[[int, str], FakeZipArchive],
fake_data_bucket: FakeDataBucket,
):
zip_archive = create_zip_archive(size, platform)
url = fake_data_bucket.upload_scratch(zip_archive.file_name)
response = tecken_client.upload_by_download(url)
assert response.status_code == 201

for sym_file in zip_archive.members:
response = tecken_client.download(sym_file.key())
assert response.status_code == 200
[redirect] = response.history
assert redirect.status_code == 302


def test_disallowed_domain(tecken_client: TeckenClient):
Expand Down