Skip to content

added formatting, makefile, updated project structure #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ on:
# disabled pipeline for push events, as we want to run the pipeline only on a schedule or manually
# push:
# branches:
# - pytest-plugin-fork
# - pytest-plugin

name: Terraform Tests
jobs:
Expand All @@ -27,7 +27,7 @@ jobs:
with:
submodules: 'true'
- id: set-matrix
run: echo "matrix=$(python get-services.py ${{ github.event.inputs.services || 'ls-community' }})" >> $GITHUB_OUTPUT
run: echo "matrix=$(python -m terraform_pytest.get-services ${{ github.event.inputs.services || 'ls-community' }})" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}

Expand Down Expand Up @@ -69,16 +69,16 @@ jobs:
run: |
cd terraform-provider-aws && go mod vendor
cd ../
python3 main.py patch
python -m terraform_pytest.main patch

- name: Build ${{ matrix.service }} Binary
run: |
python main.py build -s ${{ matrix.service }}
python -m terraform_pytest.main build -s ${{ matrix.service }}
ls -la terraform-provider-aws/test-bin

- name: Run ${{ matrix.service }} Tests
run: |
pytest --junitxml=target/reports/pytest.xml terraform-provider-aws/internal/service/${{ matrix.service }} -s -v --ls-start --ls-image ${{ github.event.inputs.localstack-image || 'localstack/localstack:latest' }}
python -m pytest --junitxml=target/reports/pytest.xml terraform-provider-aws/internal/service/${{ matrix.service }} -s -v --ls-start --ls-image ${{ github.event.inputs.localstack-image || 'localstack/localstack:latest' }}

- name: Publish ${{ matrix.service }} Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
Expand Down
26 changes: 26 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

VENV_BIN ?= python3 -m venv
VENV_DIR ?= .venv
PIP_CMD ?= pip3

ifeq ($(OS), Windows_NT)
VENV_ACTIVATE = $(VENV_DIR)/Scripts/activate
else
VENV_ACTIVATE = $(VENV_DIR)/bin/activate
endif

$(VENV_ACTIVATE):
test -d $(VENV_DIR) || $(VENV_BIN) $(VENV_DIR)
$(VENV_RUN); $(PIP_CMD) install --upgrade pip setuptools wheel plux
touch $(VENV_ACTIVATE)

VENV_RUN = . $(VENV_ACTIVATE)

venv: $(VENV_ACTIVATE) ## Create a new (empty) virtual environment

install:
$(VENV_RUN); $(PIP_CMD) install -r requirements.txt

format:
$(VENV_RUN); python -m isort .; python -m black .
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,30 @@ This is a test runner for localstack and terraform. It will run a test cases fro
Purpose of this project is to externalize the test cases from the localstack repo and run them against localstack to gather parity metrics.

## Installation
1. Clone the repository
2. Run `python -m virtualenv venv` to create a virtual environment
3. Run `source venv/bin/activate` to activate the virtual environment
4. Run `pip install -r requirements.txt` to install the dependencies
1. Clone the repository with submodules`
2. Run `make venv` to create a virtual environment
3. Run `make install` to install the dependencies

## How to run?
1. Run `python main.py patch` to apply the patch to the terraform provider aws
2. Now you are ready to use `pytest` commands to list and run test cases from golang
1. Run `python -m terraform_pytest.main patch` to apply the patch to the terraform provider aws
2. Run `python -m terraform_pytest.main build -s s3` to build testing binary for the golang module
3Now you are ready to use `python -m pytest` commands to list and run test cases from golang

## How to run test cases?
- To list down all the test case from a specific service, run `pytest terraform-provider-aws/internal/service/<service> --collect-only -q`
- To run a specific test case, run `pytest terraform-provider-aws/internal/service/<service>/<test-file> -k <test-case-name> --ls-start` or `pytest terraform-provider-aws/internal/service/<service>/<test-file>::<test-case-name> --ls-start`
- Additional environment variables can be added by appending it in the start of the command, i.e. `AWS_ALTERNATE_REGION='us-west-2' pytest terraform-provider-aws/internal/service/<service>/<test-file>::<test-case-name> --ls-start`
- To list down all the test case from a specific service, run `python -m pytest terraform-provider-aws/internal/service/<service> --collect-only -q`
- To run a specific test case, run `python -m pytest terraform-provider-aws/internal/service/<service>/<test-file> -k <test-case-name> --ls-start` or `python -m pytest terraform-provider-aws/internal/service/<service>/<test-file>::<test-case-name> --ls-start`
- Additional environment variables can be added by appending it in the start of the command, i.e. `AWS_ALTERNATE_REGION='us-west-2' python -m pytest terraform-provider-aws/internal/service/<service>/<test-file>::<test-case-name> --ls-start`

## Default environment variables
- **TF_LOG**: ``debug``,
- **TF_ACC**: ``1``,
- **AWS_ACCESS_KEY_ID**: ``test``,
- **AWS_SECRET_ACCESS_KEY**: ``test``,
- **AWS_DEFAULT_REGION**: ``'us-east-1``'
- **TF_ACC**: `1`
- **AWS_ACCESS_KEY_ID**: `test`
- **AWS_SECRET_ACCESS_KEY**: `test`
- **AWS_DEFAULT_REGION**: `us-west-1`
- **AWS_ALTERNATE_ACCESS_KEY_ID**: `test`
- **AWS_ALTERNATE_SECRET_ACCESS_KEY**: `test`
- **AWS_ALTERNATE_SECRET_ACCESS_KEY**: `test`
- **AWS_ALTERNATE_REGION**: `us-east-2`
- **AWS_THIRD_REGION**: `eu-west-1`

## Options
- `--ls-start`: Start localstack instance before running the test cases
Expand Down
135 changes: 74 additions & 61 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
import os
import re
import pytest
from os.path import dirname, realpath, relpath
from pathlib import Path

import docker
import pytest
import requests
from requests.adapters import HTTPAdapter, Retry
from pathlib import Path
import os
from os.path import realpath, relpath, dirname
from utils import execute_command, build_test_bin

from terraform_pytest.utils import execute_command


def pytest_addoption(parser):
parser.addoption(
'--ls-image', action='store', default='localstack/localstack:latest', help='Base URL for the API tests'
"--ls-image",
action="store",
default="localstack/localstack:latest",
help="Base URL for the API tests",
)
parser.addoption(
'--ls-start', action='store_true', default=False, help='Start localstack service'
"--ls-start", action="store_true", default=False, help="Start localstack service"
)


def pytest_collect_file(parent, file_path):
if file_path.suffix == '.go' and file_path.name.endswith('_test.go'):
if file_path.suffix == ".go" and file_path.name.endswith("_test.go"):
return GoFile.from_parent(parent, path=file_path)


class GoFile(pytest.File):
def collect(self):
raw = self.path.open().read()
fa = re.findall(r'^(func (TestAcc.*))\(.*\).*', raw, re.MULTILINE)
fa = re.findall(r"^(func (TestAcc.*))\(.*\).*", raw, re.MULTILINE)
for _, name in fa:
yield GoItem.from_parent(self, name=name)

Expand All @@ -41,41 +46,43 @@ def runtest(self):
service = service_path.split(os.sep)[-1]

env = dict(os.environ)
env.update({
'TF_ACC': '1',
'AWS_ACCESS_KEY_ID': 'test',
'AWS_SECRET_ACCESS_KEY': 'test',
'AWS_DEFAULT_REGION': 'us-west-2',
'AWS_ALTERNATE_ACCESS_KEY_ID': 'test',
'AWS_ALTERNATE_SECRET_ACCESS_KEY': 'test',
'AWS_ALTERNATE_SECRET_ACCESS_KEY': 'test',
'AWS_ALTERNATE_REGION': 'us-east-2',
'AWS_THIRD_REGION': 'eu-west-1',
})
env.update(
{
"TF_ACC": "1",
"AWS_ACCESS_KEY_ID": "test",
"AWS_SECRET_ACCESS_KEY": "test",
"AWS_DEFAULT_REGION": "us-west-1",
"AWS_ALTERNATE_ACCESS_KEY_ID": "test",
"AWS_ALTERNATE_SECRET_ACCESS_KEY": "test",
"AWS_ALTERNATE_SECRET_ACCESS_KEY": "test",
"AWS_ALTERNATE_REGION": "us-east-2",
"AWS_THIRD_REGION": "eu-west-1",
}
)

cmd = [
f'./test-bin/{service}.test',
'-test.v',
'-test.parallel=1',
'-test.count=1',
'-test.timeout=60m',
f'-test.run={self.name}',
f"./test-bin/{service}.test",
"-test.v",
"-test.parallel=1",
"-test.count=1",
"-test.timeout=60m",
f"-test.run={self.name}",
]
return_code, stdout = execute_command(cmd, env, tf_root_path)
if return_code != 0:
raise GoException(returncode=return_code, stderr=stdout)

def repr_failure(self, excinfo, **kwargs):
if isinstance(excinfo.value, GoException):
return '\n'.join(
return "\n".join(
[
f'Execution failed with return code: {excinfo.value.returncode}',
f'Failure Reason:\n{excinfo.value.stderr}',
f"Execution failed with return code: {excinfo.value.returncode}",
f"Failure Reason:\n{excinfo.value.stderr}",
]
)

def reportinfo(self):
return self.path, 0, f'Test Case: {self.name}'
return self.path, 0, f"Test Case: {self.name}"


class ReprCrash:
Expand All @@ -97,10 +104,10 @@ def pytest_runtest_makereport(item, call):
outcome = yield
report = outcome.get_result()
if report.failed:
splits = report.longrepr.split('\n', 1)
splits = report.longrepr.split("\n", 1)
longrepr = LongRepr(splits[0], splits[1])
delattr(report, 'longrepr')
setattr(report, 'longrepr', longrepr)
delattr(report, "longrepr")
setattr(report, "longrepr", longrepr)


class GoException(Exception):
Expand All @@ -111,58 +118,64 @@ def __init__(self, returncode, stderr):

def _docker_service_health(client):
if not client.ping():
print('\nPlease start docker daemon and try again')
raise Exception('Docker is not running')
print("\nPlease start docker daemon and try again")
raise Exception("Docker is not running")


def _start_docker_container(client, config, localstack_image):
env_vars = ['DEBUG=1', 'PROVIDER_OVERRIDE_S3=asf']
env_vars = ["DEBUG=1", "PROVIDER_OVERRIDE_S3=asf"]
port_mappings = {
'53/tcp': ('127.0.0.1', 53),
'53/udp': ('127.0.0.1', 53),
'443': ('127.0.0.1', 443),
'4566': ('127.0.0.1', 4566),
'4571': ('127.0.0.1', 4571),
"53/tcp": ("127.0.0.1", 53),
"53/udp": ("127.0.0.1", 53),
"443": ("127.0.0.1", 443),
"4566": ("127.0.0.1", 4566),
"4571": ("127.0.0.1", 4571),
}
volumes = ['/var/run/docker.sock:/var/run/docker.sock']
localstack_container = client.containers.run(image=localstack_image, detach=True, ports=port_mappings,
name='localstack_main', volumes=volumes, auto_remove=True,
environment=env_vars)
setattr(config, 'localstack_container_id', localstack_container.id)
volumes = ["/var/run/docker.sock:/var/run/docker.sock"]
localstack_container = client.containers.run(
image=localstack_image,
detach=True,
ports=port_mappings,
name="localstack_main",
volumes=volumes,
auto_remove=True,
environment=env_vars,
)
setattr(config, "localstack_container_id", localstack_container.id)


def _stop_docker_container(client, config):
client.containers.get(getattr(config, 'localstack_container_id')).stop()
print('LocalStack is stopped')
client.containers.get(getattr(config, "localstack_container_id")).stop()
print("LocalStack is stopped")


def _localstack_health_check():
localstack_health_url = 'http://localhost:4566/health'
localstack_health_url = "http://localhost:4566/health"
session = requests.Session()
retry = Retry(connect=3, backoff_factor=2)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)
session.mount("http://", adapter)
session.mount("https://", adapter)
session.get(localstack_health_url)
session.close()


def _pull_docker_image(client, localstack_image):
docker_image_list = client.images.list(name=localstack_image)
if len(docker_image_list) == 0:
print(f'Pulling image {localstack_image}')
print(f"Pulling image {localstack_image}")
client.images.pull(localstack_image)
docker_image_list = client.images.list(name=localstack_image)
print(f'Using LocalStack image: {docker_image_list[0].id}')
print(f"Using LocalStack image: {docker_image_list[0].id}")


def pytest_configure(config):
is_collect_only = config.getoption(name='--collect-only')
is_localstack_start = config.getoption(name='--ls-start')
localstack_image = config.getoption(name='--ls-image')
is_collect_only = config.getoption(name="--collect-only")
is_localstack_start = config.getoption(name="--ls-start")
localstack_image = config.getoption(name="--ls-image")

if not is_collect_only and is_localstack_start:
print('\nStarting LocalStack...')
print("\nStarting LocalStack...")

client = docker.from_env()
_docker_service_health(client)
Expand All @@ -171,15 +184,15 @@ def pytest_configure(config):
_localstack_health_check()
client.close()

print('LocalStack is ready...')
print("LocalStack is ready...")


def pytest_unconfigure(config):
is_collect_only = config.getoption(name='--collect-only')
is_localstack_start = config.getoption(name='--ls-start')
is_collect_only = config.getoption(name="--collect-only")
is_localstack_start = config.getoption(name="--ls-start")

if not is_collect_only and is_localstack_start:
print('\nStopping LocalStack...')
print("\nStopping LocalStack...")
client = docker.from_env()
_stop_docker_container(client, config)
client.close()
16 changes: 0 additions & 16 deletions docker-compose.yml

This file was deleted.

Loading