Skip to content

Commit

Permalink
ci: add pytest test support on windows runners
Browse files Browse the repository at this point in the history
also:
change: add `meltano elt` guidance for windows users
  • Loading branch information
visch committed Jun 28, 2022
1 parent a558c1e commit 64fda9f
Show file tree
Hide file tree
Showing 27 changed files with 304 additions and 21 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/test.yml
Expand Up @@ -20,6 +20,10 @@ jobs:
- { python-version: "3.8", os: "ubuntu-latest", backend-db: postgresql }
- { python-version: "3.9", os: "ubuntu-latest", backend-db: postgresql }
- { python-version: "3.10", os: "ubuntu-latest", backend-db: postgresql }
- { python-version: "3.7", os: "windows-latest", backend-db: sqlite } # We'd like to run Windows tests for all backend-dbs see https://github.com/meltano/meltano/issues/6281
- { python-version: "3.8", os: "windows-latest", backend-db: sqlite }
- { python-version: "3.9", os: "windows-latest", backend-db: sqlite }
- { python-version: "3.10", os: "windows-latest", backend-db: sqlite }
fail-fast: false

name: "Pytest on py${{ matrix.python-version }} (OS: ${{ matrix.os }}, DB: ${{ matrix.backend-db }})"
Expand Down Expand Up @@ -86,7 +90,7 @@ jobs:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: pytest_warehouse
run: |
poetry run coverage run --parallel -m pytest -m "$PYTEST_MARKERS"
poetry run coverage run --parallel -m pytest -m "${{ env.PYTEST_MARKERS }}"
- name: Upload coverage data
if: always() && (matrix.python-version == '3.9')
Expand Down
7 changes: 6 additions & 1 deletion src/meltano/cli/elt.py
Expand Up @@ -2,6 +2,7 @@

import datetime
import logging
import platform
from contextlib import asynccontextmanager, contextmanager

import click
Expand Down Expand Up @@ -104,6 +105,11 @@ async def elt(
\b\nRead more at https://docs.meltano.com/reference/command-line-interface#elt
"""
if platform.system() == "Windows":
raise CliError(
"ELT command not supported on Windows. Please use the Run command as documented here https://docs.meltano.com/reference/command-line-interface#run"
)

tracker = Tracker(project)
legacy_tracker = LegacyTracker(project, context_overrides=tracker.contexts)

Expand Down Expand Up @@ -135,7 +141,6 @@ async def elt(
job_id=state_id
or f'{datetime.datetime.utcnow().strftime("%Y-%m-%dT%H%M%S")}--{extractor}--{loader}'
)

_, Session = project_engine(project) # noqa: N806
session = Session()
try:
Expand Down
2 changes: 0 additions & 2 deletions tests/fixtures/cli.py
Expand Up @@ -2,7 +2,6 @@

import logging
import os
import shutil
from pathlib import Path
from typing import TYPE_CHECKING, Any

Expand Down Expand Up @@ -60,5 +59,4 @@ def project_files_cli(test_dir, compatible_copy_tree):
finally:
Project.deactivate()
os.chdir(test_dir)
shutil.rmtree(project.root)
logging.debug(f"Cleaned project at {project.root}")
13 changes: 2 additions & 11 deletions tests/fixtures/core.py
Expand Up @@ -2,7 +2,6 @@
import itertools
import logging
import os
import shutil
from collections import defaultdict, namedtuple
from copy import deepcopy
from pathlib import Path
Expand Down Expand Up @@ -39,8 +38,6 @@
from meltano.core.task_sets_service import TaskSetsService
from meltano.core.utils import merge

PROJECT_NAME = "a_meltano_project"


@pytest.fixture(scope="class")
def discovery(): # noqa: WPS213
Expand Down Expand Up @@ -238,8 +235,8 @@ def locked_definition_service(project):


@pytest.fixture(scope="class")
def project_init_service():
return ProjectInitService(PROJECT_NAME)
def project_init_service(request):
return ProjectInitService(f"project_{request.node.name}")


@pytest.fixture(scope="class")
Expand Down Expand Up @@ -455,10 +452,6 @@ def job_logging_service(project):

@pytest.fixture(scope="class")
def project(test_dir, project_init_service):
# Clean up whatever might be left behind. Nothing should be left, but some fixtures
# occasionally do not clean up after themselves properly.
shutil.rmtree(test_dir / PROJECT_NAME, ignore_errors=True)

project = project_init_service.init(add_discovery=True)
logging.debug(f"Created new project at {project.root}")

Expand All @@ -476,7 +469,6 @@ def project(test_dir, project_init_service):
finally:
Project.deactivate()
os.chdir(test_dir)
shutil.rmtree(project.root)
logging.debug(f"Cleaned project at {project.root}")


Expand All @@ -499,7 +491,6 @@ def project_files(test_dir, compatible_copy_tree):
finally:
Project.deactivate()
os.chdir(test_dir)
shutil.rmtree(project.root)
logging.debug(f"Cleaned project at {project.root}")


Expand Down
9 changes: 9 additions & 0 deletions tests/meltano/cli/test_add.py
@@ -1,4 +1,5 @@
import os
import platform
import shutil

import mock
Expand Down Expand Up @@ -166,6 +167,10 @@ def test_add_files_with_updates(
project_plugins_service,
plugin_settings_service_factory,
):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
# if plugin is locked, we actually wouldn't expect it to update.
# So we must remove lockfile
shutil.rmtree("plugins/files", ignore_errors=True)
Expand Down Expand Up @@ -215,6 +220,10 @@ def test_add_files_without_updates(
def test_add_files_that_already_exists(
self, project, cli_runner, project_plugins_service
):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
# dbt lockfile was created in an upstream test. Need to remove.
shutil.rmtree(project.root_dir("plugins/files"), ignore_errors=True)
project.root_dir("transform/dbt_project.yml").write_text("Exists!")
Expand Down
10 changes: 10 additions & 0 deletions tests/meltano/cli/test_config.py
@@ -1,5 +1,7 @@
import json
import platform

import pytest
from mock import AsyncMock, mock

from asserts import assert_cli_runner
Expand All @@ -12,6 +14,10 @@ def test_config(self, project, cli_runner, tap, project_plugins_service):
"meltano.cli.config.ProjectPluginsService",
return_value=project_plugins_service,
):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
result = cli_runner.invoke(cli, ["config", tap.name])
assert_cli_runner(result)

Expand All @@ -34,6 +40,10 @@ def test_config_env(self, project, cli_runner, tap, project_plugins_service):
"meltano.cli.config.ProjectPluginsService",
return_value=project_plugins_service,
):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
result = cli_runner.invoke(cli, ["config", "--format=env", tap.name])
assert_cli_runner(result)

Expand Down
43 changes: 42 additions & 1 deletion tests/meltano/cli/test_elt.py
@@ -1,5 +1,6 @@
import asyncio
import json
import platform
from typing import List, Optional

import pytest
Expand Down Expand Up @@ -76,7 +77,7 @@ def assert_lines(output, *lines):


def exception_logged(result_output: str, exc: Exception) -> bool:
"""Small utility to search click result output for a specific excpetion .
"""Small utility to search click result output for a specific exception.
Args:
result_output: The click result output string to search.
Expand Down Expand Up @@ -217,6 +218,38 @@ def dbt_process(process_mock_factory, dbt):
return dbt


class TestWindowsELT:
@pytest.mark.skipif(
platform.system() != "Windows",
reason="Test is only for Windows",
)
@pytest.mark.backend("sqlite")
@mock.patch.object(LegacyTracker, "track_event", return_value=None)
@mock.patch(
"meltano.core.logging.utils.default_config", return_value=test_log_config
)
def test_elt_windows(
self,
google_tracker,
default_config,
cli_runner,
tap,
target,
):
args = ["elt", tap.name, target.name]
result = cli_runner.invoke(cli, args)
assert result.exit_code == 1
# Didn't use exception_logged() as result.stderr doensn't contain the error for some reason
assert (
"ELT command not supported on Windows. Please use the Run command as documented here https://docs.meltano.com/reference/command-line-interface#run"
in str(result.exception)
)


@pytest.mark.skipif(
platform.system() == "Windows",
reason="ELT is not supported on Windows",
)
class TestCliEltScratchpadOne:
@pytest.mark.backend("sqlite")
@mock.patch.object(LegacyTracker, "track_event", return_value=None)
Expand Down Expand Up @@ -1006,6 +1039,10 @@ def test_dump_loader_config(
)


@pytest.mark.skipif(
platform.system() == "Windows",
reason="ELT is not supported on Windows",
)
class TestCliEltScratchpadTwo:
@pytest.mark.backend("sqlite")
@mock.patch.object(LegacyTracker, "track_event", return_value=None)
Expand Down Expand Up @@ -1173,6 +1210,10 @@ def test_elt_transform_run_dbt_failure(
)


@pytest.mark.skipif(
platform.system() == "Windows",
reason="ELT is not supported on Windows",
)
class TestCliEltScratchpadThree:
@pytest.mark.backend("sqlite")
@mock.patch.object(LegacyTracker, "track_event", return_value=None)
Expand Down
6 changes: 6 additions & 0 deletions tests/meltano/cli/test_invoke.py
@@ -1,5 +1,6 @@
import asyncio
import json
import platform

import mock
import pytest
Expand Down Expand Up @@ -89,6 +90,11 @@ def test_invoke_command_containerized( # noqa: WPS210
cli_runner,
mock_invoke_containers,
):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)

async def async_generator(*args, **kwargs):
yield "Line 1"
yield "Line 2" # noqa: WPS354
Expand Down
7 changes: 6 additions & 1 deletion tests/meltano/cli/test_state.py
@@ -1,5 +1,6 @@
import json
import os
import platform
import sys

import mock
Expand Down Expand Up @@ -148,6 +149,10 @@ def test_merge_from_string(self, state_service, state_ids, cli_runner):
def test_merge_from_file(
self, tmp_path, state_service, state_ids, payloads, cli_runner
):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
with mock.patch("meltano.cli.state.StateService", return_value=state_service):
job_pairs = []
for idx in range(0, len(state_ids) - 1, 2):
Expand Down Expand Up @@ -200,7 +205,7 @@ def test_copy_to_new(self, state_service, state_ids, cli_runner):
with mock.patch("meltano.cli.state.StateService", return_value=state_service):
for job_src_id in state_ids:
job_src_state = state_service.get_state(job_src_id)
job_dst_id = "{0}-test-copy".format(job_src_id)
job_dst_id = f"{job_src_id}-test-copy"
result = cli_runner.invoke(
cli,
["state", "copy", job_src_id, job_dst_id, "--force"],
Expand Down
14 changes: 14 additions & 0 deletions tests/meltano/cli/test_upgrade.py
@@ -1,13 +1,19 @@
import platform
import shutil

import mock
import pytest

from asserts import assert_cli_runner
from meltano.cli import cli


class TestCliUpgrade:
def test_upgrade(self, project, cli_runner):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
result = cli_runner.invoke(cli, ["upgrade"])
assert_cli_runner(result)

Expand Down Expand Up @@ -35,6 +41,10 @@ def test_upgrade_skip_package(self, project, cli_runner):
assert "Your Meltano project has been upgraded!" in result.output

def test_upgrade_package(self, project, cli_runner):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
result = cli_runner.invoke(cli, ["upgrade", "package"])
assert_cli_runner(result)

Expand All @@ -46,6 +56,10 @@ def test_upgrade_package(self, project, cli_runner):
def test_upgrade_files(
self, session, project, cli_runner, config_service, meltano_hub_service
):
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
result = cli_runner.invoke(cli, ["upgrade", "files"])
assert_cli_runner(result)

Expand Down
5 changes: 5 additions & 0 deletions tests/meltano/core/container/test_container_spec.py
@@ -1,5 +1,6 @@
"""Test container commands."""

import platform
from collections import defaultdict

import pytest
Expand Down Expand Up @@ -61,5 +62,9 @@ class TestContainerService:
@pytest.mark.asyncio
async def test_docker_config(self, spec: ContainerSpec, payload: dict):
"""Check Docker container config from container spec."""
if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/3444"
)
config = spec.get_docker_config()
assert config == payload
11 changes: 11 additions & 0 deletions tests/meltano/core/job/test_job.py
@@ -1,4 +1,5 @@
import asyncio
import platform
import signal
import uuid
from datetime import datetime, timedelta
Expand Down Expand Up @@ -89,6 +90,11 @@ async def test_run_failed(self, session):

@pytest.mark.asyncio
async def test_run_interrupted(self, session):

if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/2842"
)
subject = self.sample_job({"original_state": 1}).save(session)

with pytest.raises(KeyboardInterrupt):
Expand All @@ -102,6 +108,11 @@ async def test_run_interrupted(self, session):

@pytest.mark.asyncio
async def test_run_terminated(self, session):

if platform.system() == "Windows":
pytest.xfail(
"Doesn't pass on windows, this is currently being tracked here https://github.com/meltano/meltano/issues/2842"
)
subject = self.sample_job({"original_state": 1}).save(session)

with pytest.raises(SystemExit):
Expand Down

0 comments on commit 64fda9f

Please sign in to comment.