diff --git a/.dockerignore b/.dockerignore index 03881ecb..e9006fd5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1 +1 @@ -build_output \ No newline at end of file +build_output diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..8ce5ac18 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,55 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + args: [--allow-multiple-documents] + - id: check-ast + - id: check-added-large-files + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-executables-have-shebangs + - id: check-symlinks + - id: check-case-conflict + - id: check-vcs-permalinks + - id: mixed-line-ending + args: [--fix=lf] + - id: name-tests-test + args: [--pytest-test-first] + exclude: ^(tests/settings.py) + - id: no-commit-to-branch + - id: requirements-txt-fixer + - id: fix-byte-order-marker + - id: detect-private-key + - repo: local + hooks: + - id: golang-diff + name: create-go-diff + entry: bash -c 'git diff -p origin/main > /tmp/diff.patch' + language: system + types: [go] + pass_filenames: false + - repo: https://github.com/golangci/golangci-lint + rev: v1.52.2 + hooks: + - id: golangci-lint + args: [--new-from-patch=/tmp/diff.patch] + - repo: https://github.com/asottile/pyupgrade + rev: v3.3.2 + hooks: + - id: pyupgrade + - repo: https://github.com/PyCQA/isort + rev: 5.12.0 + hooks: + - id: isort + - repo: https://github.com/psf/black + rev: 23.3.0 + hooks: + - id: black + +ci: + skip: [golang-diff, golangci-lint] diff --git a/build/postinstall.sh b/build/postinstall.sh old mode 100644 new mode 100755 diff --git a/build/postremove.sh b/build/postremove.sh old mode 100644 new mode 100755 diff --git a/build/preremove.sh b/build/preremove.sh old mode 100644 new mode 100755 diff --git a/examples/azure.md b/examples/azure.md index 5f9395ef..2dfd4c0f 100644 --- a/examples/azure.md +++ b/examples/azure.md @@ -49,4 +49,4 @@ upstreams: * `max_conns` – The maximum number of simultaneous active connections to an upstream server. Default value is 0, meaning there is no limit. * `max_fails` – The number of unsuccessful attempts to communicate with an upstream server that should happen in the duration set by the `fail-timeout` to consider the server unavailable. Default value is 1. The zero value disables the accounting of attempts. * `fail_timeout` – The time during which the specified number of unsuccessful attempts to communicate with an upstream server should happen to consider the server unavailable. Default value is 10s. - * `slow_start` – The slow start allows an upstream server to gradually recover its weight from 0 to its nominal value after it has been recovered or became available or when the server becomes available after a period of time it was considered unavailable. By default, the slow start is disabled. \ No newline at end of file + * `slow_start` – The slow start allows an upstream server to gradually recover its weight from 0 to its nominal value after it has been recovered or became available or when the server becomes available after a period of time it was considered unavailable. By default, the slow start is disabled. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..0f5f9d3b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,13 @@ +[tool.black] +line-length = 120 +target-version = ['py311'] +extend-exclude = '.*pb2.*' + +[tool.isort] +atomic = true +profile = "black" +line_length = 120 +skip_gitignore = true +balanced_wrapping = true +filter_files = true +skip_glob = ['*pb2*'] diff --git a/tests/.dockerignore b/tests/.dockerignore index 69c5b0ee..00c1dcd3 100644 --- a/tests/.dockerignore +++ b/tests/.dockerignore @@ -1,2 +1,2 @@ # Ignore pytest cache -.pytest_cache \ No newline at end of file +.pytest_cache diff --git a/tests/.flake8 b/tests/.flake8 index bf3c1b12..b1d2afea 100644 --- a/tests/.flake8 +++ b/tests/.flake8 @@ -2,4 +2,4 @@ format = pylint max-complexity = 10 max-line-length = 170 -exclude = .git,__pycache__,data,.idea,.pytest_cache \ No newline at end of file +exclude = .git,__pycache__,data,.idea,.pytest_cache diff --git a/tests/Makefile b/tests/Makefile index 386df633..456b3e96 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -9,4 +9,4 @@ build: docker build -t $(PREFIX):$(TAG) -f docker/Dockerfile .. run-tests: build - docker run --rm -v $(AWS_CREDENTIALS):/root/.aws/credentials $(PREFIX):$(TAG) --nginx-api=$(NGINX_API) --aws-region=$(AWS_REGION) $(PYTEST_ARGS) \ No newline at end of file + docker run --rm -v $(AWS_CREDENTIALS):/root/.aws/credentials $(PREFIX):$(TAG) --nginx-api=$(NGINX_API) --aws-region=$(AWS_REGION) $(PYTEST_ARGS) diff --git a/tests/README.md b/tests/README.md index 61ca6baf..172a3ded 100644 --- a/tests/README.md +++ b/tests/README.md @@ -10,8 +10,8 @@ Below you will find the instructions on how to run the tests against a cloud pro ### Prerequisites: -* AWS stack prepared. -* AWS access key and AWS secret access key. +* AWS stack prepared. +* AWS access key and AWS secret access key. * Python3 or Docker. #### Step 1 - Set up the environment @@ -19,7 +19,7 @@ Below you will find the instructions on how to run the tests against a cloud pro * Either create|update ~/.aws/credentials file or set the AWS_SHARED_CREDENTIALS_FILE environment variable pointing to your own location. This file is an INI formatted file with section names corresponding to profiles. Tests use 'default' profile. The file [credentials](data/credentials) is a minimal example of such a file. #### Step 2 - Run the Tests - + Run the tests: * Use local Python3 installation: ```bash @@ -44,4 +44,4 @@ The table below shows various configuration options for the tests. If you use Py | `--aws-region` | `AWS_REGION` | The AWS stack region. | `us-east-2` | | `N/A` | `PYTEST_ARGS` | Any additional pytest command-line arguments (i.e `-k TestSmoke`) | `""` | -If you would like to use an IDE (such as PyCharm) to run the tests, use the [pytest.ini](pytest.ini) file to set the command-line arguments. \ No newline at end of file +If you would like to use an IDE (such as PyCharm) to run the tests, use the [pytest.ini](pytest.ini) file to set the command-line arguments. diff --git a/tests/conftest.py b/tests/conftest.py index a5001370..d427b95e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,7 +13,12 @@ def pytest_addoption(parser) -> None: :return: """ parser.addoption("--nginx-api", action="store", default="", help="The NGINX Plus API url.") - parser.addoption("--aws-region", action="store", default=DEFAULT_AWS_REGION, help="The AWS region name.") + parser.addoption( + "--aws-region", + action="store", + default=DEFAULT_AWS_REGION, + help="The AWS region name.", + ) class CLIArguments: @@ -24,6 +29,7 @@ class CLIArguments: nginx_api (str): NGINX Plus API url aws_region (str): AWS region name """ + def __init__(self, nginx_api: str, aws_region: str): self.nginx_api = nginx_api self.aws_region = aws_region @@ -57,6 +63,5 @@ def autoscaling_client(cli_arguments) -> BaseClient: :param cli_arguments: a set of command-line arguments :return: """ - session = Session(profile_name='default', - region_name=cli_arguments.aws_region) - return session.client('autoscaling') + session = Session(profile_name="default", region_name=cli_arguments.aws_region) + return session.client("autoscaling") diff --git a/tests/data/credentials b/tests/data/credentials index ea3db8a5..6cc56363 100644 --- a/tests/data/credentials +++ b/tests/data/credentials @@ -1,3 +1,3 @@ [default] aws_access_key_id=foo -aws_secret_access_key=bar \ No newline at end of file +aws_secret_access_key=bar diff --git a/tests/docker/Dockerfile b/tests/docker/Dockerfile index 2974989c..eeac2e23 100644 --- a/tests/docker/Dockerfile +++ b/tests/docker/Dockerfile @@ -10,4 +10,4 @@ WORKDIR /workspace/tests RUN pip install -r requirements.txt -ENTRYPOINT [ "python3", "-m", "pytest"] \ No newline at end of file +ENTRYPOINT [ "python3", "-m", "pytest"] diff --git a/tests/pytest.ini b/tests/pytest.ini index 4e7b7158..1d27b5ab 100644 --- a/tests/pytest.ini +++ b/tests/pytest.ini @@ -1,3 +1,3 @@ [pytest] addopts = --tb=native -r fsxX --disable-warnings -log_cli=true \ No newline at end of file +log_cli=true diff --git a/tests/requirements.txt b/tests/requirements.txt index 019fe6dd..46ac1fa3 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,3 +1,3 @@ -requests==2.29.0 boto3==1.26.5 -pytest==7.3.1 \ No newline at end of file +pytest==7.3.1 +requests==2.29.0 diff --git a/tests/settings.py b/tests/settings.py index 41e7b8fb..78110995 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Describe project settings""" import os diff --git a/tests/suite/test_smoke.py b/tests/suite/test_smoke.py index 73d5e8c8..109df6b6 100644 --- a/tests/suite/test_smoke.py +++ b/tests/suite/test_smoke.py @@ -1,18 +1,18 @@ -import pytest -import time -import requests import json +import time +import pytest +import requests from botocore.waiter import WaiterModel, create_waiter_with_client -from tests.settings import RECONFIGURATION_DELAY, NGINX_API_VERSION +from tests.settings import NGINX_API_VERSION, RECONFIGURATION_DELAY def wait_for_changes_in_api(req_url, desired_capacity) -> None: resp = requests.get(req_url) nginx_upstream = json.loads(resp.text) counter = 0 - while len(nginx_upstream['peers']) != desired_capacity and counter < 10: + while len(nginx_upstream["peers"]) != desired_capacity and counter < 10: time.sleep(RECONFIGURATION_DELAY) counter = counter + 1 resp = requests.get(req_url) @@ -20,9 +20,11 @@ def wait_for_changes_in_api(req_url, desired_capacity) -> None: def wait_for_changes_in_aws(autoscaling_client, group_name, desired_capacity) -> None: - waiter_name = 'autoscaling_completed' - argument = f"contains(AutoScalingGroups[?(starts_with(AutoScalingGroupName, `{group_name}`) == `true`)]." \ - f"[length(Instances[?LifecycleState=='InService']) == `{desired_capacity}`][], `false`)" + waiter_name = "autoscaling_completed" + argument = ( + f"contains(AutoScalingGroups[?(starts_with(AutoScalingGroupName, `{group_name}`) == `true`)]." + f"[length(Instances[?LifecycleState=='InService']) == `{desired_capacity}`][], `false`)" + ) waiter_config = { "version": 2, "waiters": { @@ -32,20 +34,20 @@ def wait_for_changes_in_aws(autoscaling_client, group_name, desired_capacity) -> "argument": argument, "expected": True, "matcher": "path", - "state": "success" + "state": "success", }, { "argument": argument, "expected": False, "matcher": "path", - "state": "retry" - } + "state": "retry", + }, ], "delay": 5, "maxAttempts": 20, - "operation": "DescribeAutoScalingGroups" + "operation": "DescribeAutoScalingGroups", } - } + }, } waiter_model = WaiterModel(waiter_config) custom_waiter = create_waiter_with_client(waiter_name, waiter_model, autoscaling_client) @@ -78,41 +80,89 @@ def get_aws_group_name(autoscaling_client, group_name) -> str: :param group_name: :return: str """ - groups = autoscaling_client.describe_auto_scaling_groups()['AutoScalingGroups'] - return list(filter(lambda group: group_name in group['AutoScalingGroupName'], groups))[0]['AutoScalingGroupName'] + groups = autoscaling_client.describe_auto_scaling_groups()["AutoScalingGroups"] + return list(filter(lambda group: group_name in group["AutoScalingGroupName"], groups))[0]["AutoScalingGroupName"] class TestSmoke: - @pytest.mark.parametrize("test_data", [ - pytest.param({'group_name': 'WebserverGroup1', 'api_url': '/http/upstreams/backend1'}, id="backend1"), - pytest.param({'group_name': 'WebserverGroup2', 'api_url': '/http/upstreams/backend2'}, id="backend2"), - pytest.param({'group_name': 'WebserverGroup3', 'api_url': '/stream/upstreams/tcp-backend'}, id="tcp-backend") - ]) + @pytest.mark.parametrize( + "test_data", + [ + pytest.param( + { + "group_name": "WebserverGroup1", + "api_url": "/http/upstreams/backend1", + }, + id="backend1", + ), + pytest.param( + { + "group_name": "WebserverGroup2", + "api_url": "/http/upstreams/backend2", + }, + id="backend2", + ), + pytest.param( + { + "group_name": "WebserverGroup3", + "api_url": "/stream/upstreams/tcp-backend", + }, + id="tcp-backend", + ), + ], + ) def test_aws_scale_up(self, cli_arguments, autoscaling_client, test_data): desired_capacity = 5 - group_name = get_aws_group_name(autoscaling_client, test_data['group_name']) + group_name = get_aws_group_name(autoscaling_client, test_data["group_name"]) scale_aws_group(autoscaling_client, group_name, desired_capacity) wait_for_changes_in_aws(autoscaling_client, group_name, desired_capacity) - wait_for_changes_in_api(f"{cli_arguments.nginx_api}/{NGINX_API_VERSION}{test_data['api_url']}", - desired_capacity) + wait_for_changes_in_api( + f"{cli_arguments.nginx_api}/{NGINX_API_VERSION}{test_data['api_url']}", + desired_capacity, + ) resp = requests.get(f"{cli_arguments.nginx_api}/{NGINX_API_VERSION}{test_data['api_url']}") nginx_upstream = json.loads(resp.text) - assert len(nginx_upstream['peers']) == desired_capacity,\ - f"Expected {desired_capacity} servers, found: {nginx_upstream['peers']}" + assert ( + len(nginx_upstream["peers"]) == desired_capacity + ), f"Expected {desired_capacity} servers, found: {nginx_upstream['peers']}" - @pytest.mark.parametrize("test_data", [ - pytest.param({'group_name': 'WebserverGroup1', 'api_url': '/http/upstreams/backend1'}, id="backend1"), - pytest.param({'group_name': 'WebserverGroup2', 'api_url': '/http/upstreams/backend2'}, id="backend2"), - pytest.param({'group_name': 'WebserverGroup3', 'api_url': '/stream/upstreams/tcp-backend'}, id="tcp-backend") - ]) + @pytest.mark.parametrize( + "test_data", + [ + pytest.param( + { + "group_name": "WebserverGroup1", + "api_url": "/http/upstreams/backend1", + }, + id="backend1", + ), + pytest.param( + { + "group_name": "WebserverGroup2", + "api_url": "/http/upstreams/backend2", + }, + id="backend2", + ), + pytest.param( + { + "group_name": "WebserverGroup3", + "api_url": "/stream/upstreams/tcp-backend", + }, + id="tcp-backend", + ), + ], + ) def test_aws_scale_down(self, cli_arguments, autoscaling_client, test_data): desired_capacity = 1 - group_name = get_aws_group_name(autoscaling_client, test_data['group_name']) + group_name = get_aws_group_name(autoscaling_client, test_data["group_name"]) scale_aws_group(autoscaling_client, group_name, desired_capacity) wait_for_changes_in_aws(autoscaling_client, group_name, desired_capacity) - wait_for_changes_in_api(f"{cli_arguments.nginx_api}/{NGINX_API_VERSION}{test_data['api_url']}", - desired_capacity) + wait_for_changes_in_api( + f"{cli_arguments.nginx_api}/{NGINX_API_VERSION}{test_data['api_url']}", + desired_capacity, + ) resp = requests.get(f"{cli_arguments.nginx_api}/{NGINX_API_VERSION}{test_data['api_url']}") nginx_upstream = json.loads(resp.text) - assert len(nginx_upstream['peers']) == desired_capacity,\ - f"Expected {desired_capacity} servers, found: {nginx_upstream['peers']}" + assert ( + len(nginx_upstream["peers"]) == desired_capacity + ), f"Expected {desired_capacity} servers, found: {nginx_upstream['peers']}"