diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..3bd26b2 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,22 @@ +name: Build and publish to PyPi +on: + release: + types: [created] + +jobs: + build-n-publish: + name: Build and publish to PyPi + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@master + - uses: actions/setup-python@v2 + - name: Install dependencies + run: | + python -m pip install --upgrade setuptools wheel + - name: Build + run: | + python setup.py sdist bdist_wheel + - name: Publish + uses: pypa/gh-action-pypi-publish@master + with: + password: ${{ secrets.TEST_PYPI_API_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..edbab1e --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,30 @@ +name: Tests + +on: [push, pull_request] + +jobs: + build: + runs-on: ${{ matrix.platform }} + strategy: + max-parallel: 4 + matrix: + # https://help.github.com/articles/virtual-environments-for-github-actions + platform: + - ubuntu-16.04 + - ubuntu-latest # ubuntu-18.04 + - macos-latest # macOS-10.14 + - windows-latest # windows-2019 + python-version: [3.6, 3.7, 3.8, 3.9] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade setuptools pip wheel pytest mock requests + - name: Test with pytest + run: pytest -rp + diff --git a/dynatrace/environment_v1/custom_device.py b/dynatrace/environment_v1/custom_device.py index c3229ea..2da8e7e 100644 --- a/dynatrace/environment_v1/custom_device.py +++ b/dynatrace/environment_v1/custom_device.py @@ -1,5 +1,5 @@ from datetime import datetime, timedelta, timezone -from collections import MutableSequence +from collections.abc import MutableSequence from typing import Optional, List, Dict, Tuple diff --git a/dynatrace/http_client.py b/dynatrace/http_client.py index 02cffa4..0305459 100644 --- a/dynatrace/http_client.py +++ b/dynatrace/http_client.py @@ -56,7 +56,7 @@ def __init__( total=retries, backoff_factor=retry_delay_s, status_forcelist=[400, 401, 403, 413, 429, 500, 502, 503, 504], - method_whitelist=["TRACE", "PUT", "DELETE", "OPTIONS", "HEAD", "GET", "POST"], + allowed_methods=["TRACE", "PUT", "DELETE", "OPTIONS", "HEAD", "GET", "POST"], raise_on_status=False, ) diff --git a/requirements.txt b/requirements.txt index 3b87e26..0c49162 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -requests>=2.24 \ No newline at end of file +requests>=2.21 \ No newline at end of file diff --git a/requirements_dev.txt b/requirements_dev.txt new file mode 100644 index 0000000..3d8fd6e --- /dev/null +++ b/requirements_dev.txt @@ -0,0 +1,4 @@ +requests>=2.21 +pytest>=6.2.3 +mock +tox \ No newline at end of file diff --git a/setup.py b/setup.py index fa8e9c4..82b3aaf 100644 --- a/setup.py +++ b/setup.py @@ -2,9 +2,10 @@ setup( name="dtapi", - version="1.1.10", + version="1.1.11", packages=find_packages(), install_requires=["requests>=2.21"], + tests_require=["pytest", "mock", "tox"], python_requires=">=3.6", author="David Lopes", author_email="davidribeirolopes@gmail.com", diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/configuration_v1/__init__.py b/test/configuration_v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/configuration_v1/test_alerting_profiles.py b/test/configuration_v1/test_alerting_profiles.py new file mode 100644 index 0000000..9374701 --- /dev/null +++ b/test/configuration_v1/test_alerting_profiles.py @@ -0,0 +1,30 @@ +from dynatrace import Dynatrace +from dynatrace.configuration_v1.alerting_profiles import AlertingProfileStub, AlertingProfile, AlertingProfileSeverityRule +from dynatrace.pagination import PaginatedList + + +def test_list(dt: Dynatrace): + alert_profiles = dt.alerting_profiles.list() + assert isinstance(alert_profiles, PaginatedList) + + list_alert_profiles = list(alert_profiles) + assert len(list_alert_profiles) == 6 + + first = list_alert_profiles[0] + assert isinstance(first, AlertingProfileStub) + + assert first.id == "b1f379d9-98b4-4efe-be38-0289609c9295" + assert first.name == "deployment_change_autoremediation" + + +def test_get_full_configuration(dt: Dynatrace): + alert_profiles = dt.alerting_profiles.list() + list_alert_profiles = list(alert_profiles) + first = list_alert_profiles[0] + + full = first.get_full_configuration() + assert isinstance(full, AlertingProfile) + assert full.id == "b1f379d9-98b4-4efe-be38-0289609c9295" + assert full.display_name == "deployment_change_autoremediation" + assert isinstance(full.rules, list) + assert isinstance(full.rules[0], AlertingProfileSeverityRule) diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000..a117a19 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,36 @@ +import os +from pathlib import Path +from typing import Optional, Dict +from unittest import mock +import json + +import pytest + +from dynatrace import Dynatrace +from dynatrace.http_client import HttpClient + +current_file_path = os.path.dirname(os.path.realpath(__file__)) + + +class MockResponse: + def __init__(self, json_data): + self.json_data = json_data + self.headers = {} + + def json(self): + return self.json_data + + +def local_make_request(self, path: str, params: Optional[Dict] = None, headers: Optional[Dict] = None, method="GET", data=None) -> MockResponse: + file_name = f'{path.replace("/", "_").lstrip("_")}.json' + file_path = Path(current_file_path, "mock_data", file_name) + with open(file_path) as f: + json_data = json.load(f) + return MockResponse(json_data) + + +@pytest.fixture(autouse=True) +def dt(): + with mock.patch.object(HttpClient, "make_request", new=local_make_request): + dt = Dynatrace("mock_tenant", "mock_token") + yield dt diff --git a/test/mock_data/api_config_v1_alertingProfiles.json b/test/mock_data/api_config_v1_alertingProfiles.json new file mode 100644 index 0000000..e39420d --- /dev/null +++ b/test/mock_data/api_config_v1_alertingProfiles.json @@ -0,0 +1,28 @@ +{ + "values": [ + { + "id": "b1f379d9-98b4-4efe-be38-0289609c9295", + "name": "deployment_change_autoremediation" + }, + { + "id": "c21f969b-5f03-333d-83e0-4f8f136e7682", + "name": "Default" + }, + { + "id": "142e6edb-280a-4e9c-85b1-e01f5d2ee829", + "name": "dbslowdwon_autoremediation" + }, + { + "id": "b68e03c2-8a28-45a1-a516-4abce33317e7", + "name": "process_crash_autoremediation" + }, + { + "id": "caa901e6-8163-413c-ac64-5de723a400ab", + "name": "rguerrero" + }, + { + "id": "ebb53f45-6cc6-4efa-a271-1a9657a433c0", + "name": "Keptn" + } + ] +} \ No newline at end of file diff --git a/test/mock_data/api_config_v1_alertingProfiles_b1f379d9-98b4-4efe-be38-0289609c9295.json b/test/mock_data/api_config_v1_alertingProfiles_b1f379d9-98b4-4efe-be38-0289609c9295.json new file mode 100644 index 0000000..a227a46 --- /dev/null +++ b/test/mock_data/api_config_v1_alertingProfiles_b1f379d9-98b4-4efe-be38-0289609c9295.json @@ -0,0 +1,32 @@ +{ + "metadata": { + "currentConfigurationVersions": [ + "0" + ], + "configurationVersions": [], + "clusterVersion": "1.214.112.20210409-064503" + }, + "id": "b1f379d9-98b4-4efe-be38-0289609c9295", + "displayName": "deployment_change_autoremediation", + "rules": [ + { + "severityLevel": "PERFORMANCE", + "tagFilter": { + "includeMode": "NONE", + "tagFilters": [] + }, + "delayInMinutes": 15 + }, + { + "severityLevel": "AVAILABILITY", + "tagFilter": { + "includeMode": "NONE", + "tagFilters": [] + }, + "delayInMinutes": 10 + } + ], + "managementZoneId": null, + "mzId": null, + "eventTypeFilters": [] +} \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..7a69aa1 --- /dev/null +++ b/tox.ini @@ -0,0 +1,9 @@ +[tox] +envlist = py{36,37,38,39} + +[testenv] +deps = + pytest + mock +commands = + pytest -rp