Skip to content

Commit

Permalink
Migrate tests to syrup (#393)
Browse files Browse the repository at this point in the history
Migrate tests to syrup, avoiding use of pytest-golden which hasn't been
updated for awhile and uses yaml files which are harder to use. The test
commands have been moved into the test fixture parameters which isn't so
bad to maintain, and makes it easy to see all commands run in one place.

The test files were grouped in some small groupings that make it
reasonable to manage the separate ambr files, since everything in one
file might be too hard to deal with.
  • Loading branch information
allenporter authored Nov 22, 2023
1 parent e7ce942 commit d954c91
Show file tree
Hide file tree
Showing 81 changed files with 1,636 additions and 1,024 deletions.
12 changes: 7 additions & 5 deletions .github/workflows/python-package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ jobs:
python-version:
- "3.10"
- "3.11"
pydantic-install:
- "echo"
- "pip3 install pydantic==1.10.11"

steps:
- uses: actions/checkout@v4
Expand All @@ -30,18 +33,17 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Install extra packages
run: |
${{ matrix.pydantic-install }}
- uses: supplypike/setup-bin@v3
with:
uri: https://github.com/kyverno/kyverno/releases/download/v1.9.0/kyverno-cli_v1.9.0_linux_x86_64.tar.gz
name: kyverno-cli
version: v1.9.0
- name: Test with pytest
run: |
SKIP_DIFF_TESTS=1 pytest --cov=flux_local --cov-report=term-missing
- name: Test with pytest pydantic v1
run: |
pip install pydantic==1.10.11
SKIP_DIFF_TESTS=1 pytest --cov=flux_local --cov-report=term-missing
SKIP_DIFF_TESTS=1 pytest --cov=flux_local --cov-report=term-missing --snapshot-warn-unused
- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ repos:
rev: v4.5.0
hooks:
- id: trailing-whitespace
exclude: '^tests/tool/testdata/.*\.yaml$'
exclude: '^tests/.*.ambr$'
- id: end-of-file-fixer
exclude: '^tests/tool/testdata/.*\.yaml$'
exclude: '^tests/.*.ambr$'
- id: check-yaml
args:
- --allow-multiple-documents
Expand All @@ -24,14 +24,14 @@ repos:
rev: v1.33.0
hooks:
- id: yamllint
exclude: '^tests/tool/testdata/.*\.yaml$'
args:
- -c
- ".yaml-lint.yaml"
- repo: https://github.com/psf/black
rev: 23.11.0
hooks:
- id: black
exclude: '^tests/.*.ambr$'
- repo: local
hooks:
- id: mypy
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ To run the tests locally, you can use the following command:
$ pytest
```

Some tests used `pytest-golden` to test against golden files. These can be updated with:
Some tests used `syrup` to test against golden snapshot files. These can be updated with:
```bash
$ pytest --update-goldens
$ pytest --snapshot-update
```

## Documentation
Expand Down
29 changes: 20 additions & 9 deletions flux_local/tool/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import functools
import os
from argparse import ArgumentParser, _SubParsersAction as SubParsersAction
from collections.abc import Iterable
from contextlib import contextmanager
from dataclasses import asdict
import difflib
import logging
import pathlib
import shlex
import tempfile
from typing import cast, Generator, Any, AsyncGenerator
from typing import cast, Generator, Any, AsyncGenerator, TypeVar
import yaml


Expand All @@ -27,18 +28,28 @@

_TRUNCATE = "[Diff truncated by flux-local]"

T = TypeVar("T")


def _unique_keys(k1: dict[T, Any], k2: dict[T, Any]) -> Iterable[T]:
"""Return an ordered set."""
return {
**{k: True for k in k1.keys()},
**{k: True for k in k2.keys()},
}.keys()


def perform_object_diff(
a: ObjectOutput, b: ObjectOutput, n: int, limit_bytes: int
) -> Generator[str, None, None]:
"""Generate diffs between the two output objects."""
for kustomization_key in set(a.content.keys()) | set(b.content.keys()):
for kustomization_key in _unique_keys(a.content, b.content):
_LOGGER.debug(
"Diffing results for Kustomization %s (n=%d)", kustomization_key, n
)
a_resources = a.content.get(kustomization_key, {})
b_resources = b.content.get(kustomization_key, {})
for resource_key in set(a_resources.keys()) | set(b_resources.keys()):
for resource_key in _unique_keys(a_resources, b_resources):
diff_text = difflib.unified_diff(
a=a_resources.get(resource_key, []),
b=b_resources.get(resource_key, []),
Expand All @@ -63,14 +74,14 @@ async def perform_external_diff(
) -> AsyncGenerator[str, None]:
"""Generate diffs between the two output objects."""
with tempfile.TemporaryDirectory() as tmpdir:
for kustomization_key in set(a.content.keys()) | set(b.content.keys()):
for kustomization_key in _unique_keys(a.content, b.content):
_LOGGER.debug(
"Diffing results for Kustomization %s",
kustomization_key,
)
a_resources = a.content.get(kustomization_key, {})
b_resources = b.content.get(kustomization_key, {})
keys = set(a_resources.keys()) | set(b_resources.keys())
keys = _unique_keys(a_resources, b_resources)

a_file = pathlib.Path(tmpdir) / "a.yaml"
a_file.write_text(
Expand Down Expand Up @@ -115,12 +126,12 @@ def perform_yaml_diff(
"""Generate diffs between the two output objects."""

diffs = []
for kustomization_key in set(a.content.keys()) | set(b.content.keys()):
for kustomization_key in _unique_keys(a.content, b.content):
_LOGGER.debug("Diffing results for %s (n=%d)", kustomization_key, n)
a_resources = a.content.get(kustomization_key, {})
b_resources = b.content.get(kustomization_key, {})
resource_diffs = []
for resource_key in set(a_resources.keys()) | set(b_resources.keys()):
for resource_key in _unique_keys(a_resources, b_resources):
diff_text = difflib.unified_diff(
a=a_resources.get(resource_key, []),
b=b_resources.get(resource_key, []),
Expand Down Expand Up @@ -154,12 +165,12 @@ def get_helm_release_diff_keys(
) -> dict[str, list[ResourceKey]]:
"""Return HelmRelease resource keys with diffs, by cluster."""
result: dict[str, list[ResourceKey]] = {}
for kustomization_key in set(a.content.keys()) | set(b.content.keys()):
for kustomization_key in _unique_keys(a.content, b.content):
cluster_path = kustomization_key.cluster_path
_LOGGER.debug("Diffing results for Kustomization %s", kustomization_key)
a_resources = a.content.get(kustomization_key, {})
b_resources = b.content.get(kustomization_key, {})
for resource_key in set(a_resources.keys()) | set(b_resources.keys()):
for resource_key in _unique_keys(a_resources, b_resources):
if resource_key.kind != "HelmRelease":
continue
if a_resources.get(resource_key) != b_resources.get(resource_key):
Expand Down
3 changes: 0 additions & 3 deletions flux_local/tool/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,6 @@ async def run( # type: ignore[no-untyped-def]
str(verbosity),
"--no-header",
"--disable-warnings",
# Disable plugins used by this library that generates warnings
"-p",
"no:pytest-golden",
]
_LOGGER.debug("pytest.main: %s", pytest_args)
retcode = pytest.main(
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ pydantic==2.5.1
pytest==7.4.3
pytest-asyncio==0.21.1
pytest-cov==4.1.0
pytest-golden==0.2.2
python-slugify==8.0.1
PyYAML==6.0.1
ruff==0.1.6
Expand All @@ -22,3 +21,4 @@ typing-extensions==4.8.0
types-python-slugify==8.0.0.3
wheel==0.41.3
yamllint==1.33.0
syrupy==4.6.0
172 changes: 172 additions & 0 deletions tests/__snapshots__/test_kustomize.ambr
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# serializer version: 1
# name: test_build[path0]
'''
apiVersion: v1
data:
CLUSTER: dev
DOMAIN: example.org
kind: ConfigMap
metadata:
name: cluster-settings
namespace: flux-system
---
apiVersion: v1
data:
PWD: secret
kind: Secret
metadata:
name: cluster-secrets
namespace: flux-system

'''
# ---
# name: test_build[path1]
'''
apiVersion: v1
data:
CLUSTER: dev
DOMAIN: example.org
kind: ConfigMap
metadata:
name: cluster-settings
namespace: flux-system
---
apiVersion: v1
data:
PWD: secret
kind: Secret
metadata:
name: cluster-secrets
namespace: flux-system

'''
# ---
# name: test_build_flags
'''
apiVersion: v1
data:
CLUSTER: dev
DOMAIN: example.org
kind: ConfigMap
metadata:
name: cluster-settings
namespace: flux-system
---
apiVersion: v1
data:
PWD: secret
kind: Secret
metadata:
name: cluster-secrets
namespace: flux-system

'''
# ---
# name: test_build_grep[path0]
'''
apiVersion: v1
data:
CLUSTER: dev
DOMAIN: example.org
kind: ConfigMap
metadata:
name: cluster-settings
namespace: flux-system
annotations:
config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'

'''
# ---
# name: test_build_grep[path1]
'''
apiVersion: v1
data:
CLUSTER: dev
DOMAIN: example.org
kind: ConfigMap
metadata:
name: cluster-settings
namespace: flux-system
annotations:
config.kubernetes.io/index: '0'
internal.config.kubernetes.io/index: '0'

'''
# ---
# name: test_grep[path0]
'''
apiVersion: v1
kind: ConfigMap
metadata:
namespace: flux-system
name: cluster-settings
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'cluster-settings.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'cluster-settings.yaml'
data:
CLUSTER: dev
DOMAIN: example.org

'''
# ---
# name: test_grep[path1]
'''
apiVersion: v1
kind: ConfigMap
metadata:
namespace: flux-system
name: cluster-settings
annotations:
config.kubernetes.io/index: '0'
config.kubernetes.io/path: 'cluster-settings.yaml'
internal.config.kubernetes.io/index: '0'
internal.config.kubernetes.io/path: 'cluster-settings.yaml'
data:
CLUSTER: dev
DOMAIN: example.org

'''
# ---
# name: test_objects[path0]
list([
dict({
'apiVersion': 'v1',
'data': dict({
'CLUSTER': 'dev',
'DOMAIN': 'example.org',
}),
'kind': 'ConfigMap',
'metadata': dict({
'annotations': dict({
'config.kubernetes.io/index': '0',
'internal.config.kubernetes.io/index': '0',
}),
'name': 'cluster-settings',
'namespace': 'flux-system',
}),
}),
])
# ---
# name: test_objects[path1]
list([
dict({
'apiVersion': 'v1',
'data': dict({
'CLUSTER': 'dev',
'DOMAIN': 'example.org',
}),
'kind': 'ConfigMap',
'metadata': dict({
'annotations': dict({
'config.kubernetes.io/index': '0',
'internal.config.kubernetes.io/index': '0',
}),
'name': 'cluster-settings',
'namespace': 'flux-system',
}),
}),
])
# ---
Loading

0 comments on commit d954c91

Please sign in to comment.