Skip to content

Commit

Permalink
Add logic for integration package files (#14544)
Browse files Browse the repository at this point in the history
* Add logic for integration package files

* Change to yield

* update

* Update test_core.py

---------

Co-authored-by: Ofek Lev <[email protected]>
  • Loading branch information
yzhan289 and ofek authored Jul 19, 2023
1 parent b560f21 commit f5ceb4a
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 51 deletions.
3 changes: 3 additions & 0 deletions .ddev/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,6 @@ snowflake-connector-python = 'https://github.com/snowflakedb/snowflake-connector
supervisor = 'https://github.com/Supervisor/supervisor'
tuf = 'https://github.com/theupdateframework/python-tuf'
typing = 'https://github.com/python/typing'

[overrides.validate.openmetrics]
exclude = ["openmetrics"]
58 changes: 19 additions & 39 deletions ddev/src/ddev/cli/validate/openmetrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,15 @@
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

import os
from typing import TYPE_CHECKING

import click

if TYPE_CHECKING:
from ddev.cli.application import Application

SKIPPED_INTEGRATIONS = [
"OpenMetrics",
"Datadog Checks Base",
"Datadog Checks Dev",
]


def _validate_openmetrics_integrations(contents, integration, package_file, validation_tracker):
if integration.display_name in SKIPPED_INTEGRATIONS:
return False

# Note: can't include the closing parenthesis since some may include ConfigMixin
if '(OpenMetricsBaseCheckV2' in contents or '(OpenMetricsBaseCheck' in contents:
if 'DEFAULT_METRIC_LIMIT = 0' not in contents:
Expand All @@ -33,27 +23,16 @@ def _validate_openmetrics_integrations(contents, integration, package_file, vali
return False


def _get_python_files(directory):
python_files = []
for root, _, files in os.walk(directory):
for file in files:
if file.endswith(".py"):
python_files.append(os.path.join(root, file))
return python_files


@click.command(short_help='Validate OpenMetrics')
@click.argument('integrations', nargs=-1)
@click.pass_context
def openmetrics(ctx: click.Context, integrations: tuple[str, ...]):
@click.pass_obj
def openmetrics(app: Application, integrations: tuple[str, ...]):
"""Validate OpenMetrics metric limit.
If `check` is specified, only the check will be validated, if check value is 'changed' will only apply to changed
checks, an 'all' or empty `check` value will validate nothing.
"""

app: Application = ctx.obj
validation_tracker = app.create_validation_tracker('OpenMetrics Metric limit')
validation_tracker = app.create_validation_tracker('OpenMetrics metric limit')

app.display_waiting("Validating default metric limit for OpenMetrics integrations ...")
if app.repo.name not in ('core', 'extras'):
Expand All @@ -63,26 +42,27 @@ def openmetrics(ctx: click.Context, integrations: tuple[str, ...]):
)
app.abort()

excluded = set(app.repo.config.get('/overrides/validate/openmetrics/exclude', []))
for integration in app.repo.integrations.iter_packages(integrations):
pass_validation = False
python_files = _get_python_files(integration.package_directory)
if integration.name in excluded or not integration.is_integration:
continue

for file in python_files:
try:
f = open(file)
contents = f.read()
except Exception:
app.display_info(f"Could not open or read file {file}, skipping")
for f in integration.package_files():
contents = f.read_text()

# Note: can't include the closing parenthesis since some may include ConfigMixin
if not ('(OpenMetricsBaseCheckV2' in contents or '(OpenMetricsBaseCheck' in contents):
continue

if 'DEFAULT_METRIC_LIMIT = 0' in contents:
validation_tracker.success()
else:
pass_validation = pass_validation or _validate_openmetrics_integrations(
contents, integration, file, validation_tracker
validation_tracker.error(
(integration.display_name, str(f.relative_to(app.repo.path))),
message="`DEFAULT_METRIC_LIMIT = 0` is missing",
)

if pass_validation:
validation_tracker.success()
validation_tracker.display()

if validation_tracker.errors:
validation_tracker.display()
app.abort()

validation_tracker.display()
11 changes: 9 additions & 2 deletions ddev/src/ddev/integration/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

import os
from functools import cached_property
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Iterator

from ddev.repo.constants import NOT_SHIPPABLE
from ddev.utils.fs import Path

if TYPE_CHECKING:
from ddev.integration.manifest import Manifest
from ddev.repo.config import RepositoryConfig
from ddev.utils.fs import Path


class Integration:
Expand Down Expand Up @@ -59,6 +60,12 @@ def package_directory(self) -> Path:

return self.path / 'datadog_checks' / directory

def package_files(self) -> Iterator[Path]:
for root, _, files in os.walk(self.package_directory):
for f in files:
if f.endswith('.py'):
yield Path(root, f)

@property
def release_tag_pattern(self) -> str:
version_part = r'\d+\.\d+\.\d+'
Expand Down
23 changes: 13 additions & 10 deletions ddev/tests/cli/validate/test_openmetrics.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import pytest


@pytest.mark.usefixtures('repository')
@pytest.mark.parametrize(
"check_name",
"check_name, classes",
[
pytest.param("aerospike", id="Aerospike check.py OpenMetricsV2"),
pytest.param("amazon_msk", id="Amazon MSK amazon_msk.py OpenMetricsV1 and V2"),
pytest.param("aerospike", 1, id="Aerospike check.py OpenMetricsV2"),
pytest.param("amazon_msk", 2, id="Amazon MSK amazon_msk.py OpenMetricsV1 and V2"),
],
)
def test_openmetrics_pass_single_parameter(ddev, repository, check_name, helpers, network_replay):
def test_openmetrics_pass_single_parameter(ddev, helpers, check_name, classes):
result = ddev("validate", "openmetrics", check_name)

assert result.exit_code == 0, result.output

assert helpers.remove_trailing_spaces(result.output) == helpers.dedent(
"""
f"""
Validating default metric limit for OpenMetrics integrations ...
OpenMetrics Metric limit
OpenMetrics metric limit
Passed: 1
Passed: {classes}
"""
)


def test_openmetrics_fail_single_parameter(ddev, helpers, repository, network_replay):
def test_openmetrics_fail_single_parameter(ddev, helpers, repository):
missing_metric_limit = '''
class ArangodbCheck(OpenMetricsBaseCheckV2, ConfigMixin):
__NAMESPACE__ = 'arangodb'
Expand All @@ -44,7 +45,8 @@ def __init__(self, name, init_config, instances):
assert "Errors: 1" in helpers.remove_trailing_spaces(result.output)


def test_openmetrics_skip_openmetrics(ddev, helpers, repository, network_replay):
@pytest.mark.usefixtures('repository')
def test_openmetrics_skip_openmetrics(ddev, helpers):
result = ddev("validate", "openmetrics", "openmetrics")

assert result.exit_code == 0, result.output
Expand All @@ -53,6 +55,7 @@ def test_openmetrics_skip_openmetrics(ddev, helpers, repository, network_replay)
assert "Errors" not in helpers.remove_trailing_spaces(result.output)


@pytest.mark.usefixtures('repository')
@pytest.mark.parametrize(
"repo, expected_message",
[
Expand All @@ -64,7 +67,7 @@ def test_openmetrics_skip_openmetrics(ddev, helpers, repository, network_replay)
),
],
)
def test_openmetrics_validate_repo(repo, repository, expected_message, ddev, helpers, config_file):
def test_openmetrics_validate_repo(repo, expected_message, ddev, helpers, config_file):
config_file.model.repo = repo
config_file.save()

Expand Down
23 changes: 23 additions & 0 deletions ddev/tests/integration/test_core.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# (C) Datadog, Inc. 2022-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
import os

from ddev.repo.core import Repository
from ddev.utils.fs import Path


def test_attributes(local_repo, valid_integration):
Expand Down Expand Up @@ -189,6 +192,26 @@ def test_normalization(self, local_repo):
assert integration.package_directory == local_repo / integration.name / 'datadog_checks' / 'go_metro'


class TestPackageFiles:
def test_base_package_file(self, local_repo):
repo = Repository(local_repo.name, str(local_repo))
integration = repo.integrations.get('datadog_checks_base')

expected_files = []
for root, _, files in os.walk(integration.package_directory):
for f in files:
if f.endswith(".py"):
expected_files.append(Path(root, f))

assert list(integration.package_files()) == expected_files

def test_tile_only_package_file(self, local_repo):
repo = Repository(local_repo.name, str(local_repo))
integration = repo.integrations.get('agent_metrics')

assert not list(integration.package_files())


class TestReleaseTagPattern:
def test_shipped(self, local_repo):
repo = Repository(local_repo.name, str(local_repo))
Expand Down

0 comments on commit f5ceb4a

Please sign in to comment.