Skip to content
Open
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
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ vendor/
scratch
config.yml
!playground/config.yml
*.pyc

# Project exclusion
site
venv
.cache
# Binaries
cmd/greenmask/greenmask
cmd/greenmask/greenmask

# Allure artifacts
allure-results/
12 changes: 12 additions & 0 deletions .run/v1-list-dumps.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="v1-list-dumps" type="GoApplicationRunConfiguration" factoryName="Go Application">
<module name="v1" />
<working_directory value="$PROJECT_DIR$/v1" />
<parameters value="--config playground/mysql/config.yaml list-dumps" />
<kind value="PACKAGE" />
<package value="github.com/greenmaskio/greenmask/v1/cmd" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/v1/cmd/main.go" />
<method v="2" />
</configuration>
</component>
6 changes: 6 additions & 0 deletions v1/playground/mysql/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
echo "alias mysql='mysql --user $MYSQL_USER --database $ORIGINAL_DB_NAME --host $ORIGINAL_DB_HOST --port $ORIGINAL_DB_PORT'" >> ~/.bashrc
echo "alias mysql_o='mysql --user $MYSQL_USER --database $ORIGINAL_DB_NAME --host $ORIGINAL_DB_HOST --port $ORIGINAL_DB_PORT'" >> ~/.bashrc
echo "alias mysql_t='mysql --user $MYSQL_USER --database $TRANSFORMED_DB_NAME --host $TRANSFORMED_DB_HOST --port $TRANSFORMED_DB_PORT'" >> ~/.bashrc
echo "alias cleanup='/var/lib/playground/cleanup.sh'" >> ~/.bashrc
bash
41 changes: 41 additions & 0 deletions v1/tests/integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Integration Tests

This directory contains Python-based integration tests for Greenmask using `pytest` and `allure`.

## Prerequisites

- Python 3.11+
- Poetry (for dependency management)
- Docker & Docker Compose (for running Greenmask services)

## Setup

1. Install dependencies:
```bash
poetry install
```

2. (Optional) Run Greenmask environment:
Ensure your `greenmask` service or target environment is running.
Export the service URL if different from default:
```bash
export GREENMASK_URL=http://localhost:8080
```

## Running Tests

Run tests with Allure (report data generated in `allure-results`):
```bash
poetry run pytest --alluredir=./allure-results
```

To view the Allure report:
```bash
poetry run allure serve ./allure-results
```

## Structure

- `tests/`: Contains test files.
- `tests/conftest.py`: Fixtures (async client, configuration).
- `pyproject.toml`: Dependency and tool configuration.
9 changes: 9 additions & 0 deletions v1/tests/integration/integration.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.14 virtualenv at ~/gits/greenmaskio/greenmask/v1/tests/integration/venv" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
159 changes: 159 additions & 0 deletions v1/tests/integration/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions v1/tests/integration/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[tool.poetry]
name = "integration"
version = "0.1.0"
description = "Integration tests for Greenmask"
authors = ["Greenmask Team"]
readme = "README.md"
package-mode = false

[tool.poetry.dependencies]
python = "^3.11"
pytest = "^8.0.0"
pytest-asyncio = "^0.23.0"
allure-pytest = "^2.13.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
asyncio_mode = "auto"
Empty file.
37 changes: 37 additions & 0 deletions v1/tests/integration/resources/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright 2025 Greenmask
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

log:
level: "debug"
format: "text"

storage:
type: "directory"
directory:
path: "/tmp/greenmask_backups"

dump:
transformation:
- schema: "public"
name: "users"
transformers:
- name: "RandomPerson"
params:
gender: "Any"
columns:
- name: "username"
template: "{{ .FirstName }}"
engine: "random"

# engine: postgresql # Commenting out to see if it fixes root key error
75 changes: 75 additions & 0 deletions v1/tests/integration/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import pytest
import os
import subprocess
import shutil
import logging
import allure

logger = logging.getLogger(__name__)

@pytest.fixture(scope="session")
def greenmask_bin():
"""Locates the greenmask binary.
Prioritizes GREENMASK_BIN env var.
"""
bin_path = os.getenv("GREENMASK_BIN")
if bin_path:
if not os.path.isfile(bin_path):
pytest.fail(f"GREENMASK_BIN is set to {bin_path} but it does not exist.")
return bin_path

# Assumes greenmask is in PATH if not specified
bin_path = shutil.which("greenmask")
if not bin_path:
pytest.skip("greenmask binary not found in PATH and GREENMASK_BIN is not set.")
return bin_path

@pytest.fixture
def greenmask_config(request, tmp_path):
"""Sets up the configuration environment.
Copies the default config to a temp dir to allow tests to modify it if needed,
or just returns a path to a static config.
"""
# For now, let's just return the path to the resources config
# In the future, we might want to copy it to tmp_path
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
config_path = os.path.join(base_dir, "resources", "config.yaml")

if not os.path.exists(config_path):
pytest.logger.warning(f"Config file not found at {config_path}")

return config_path

@pytest.fixture
def greenmask_cmd(greenmask_bin, greenmask_config):
"""Executes greenmask commands.
"""
@allure.step("Run greenmask {args}")
def _run_greenmask(args, env=None, check=True):
cmd = [greenmask_bin, "--config", greenmask_config] + args

full_env = os.environ.copy()
if env:
full_env.update(env)

logger.info(f"Running command: {' '.join(cmd)}")
result = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
env=full_env,
)

if check and result.returncode != 0:
logger.error(f"Command failed with return code {result.returncode}")
logger.error(f"STDOUT: {result.stdout}")
logger.error(f"STDERR: {result.stderr}")
allure.attach(result.stdout, name="stdout", attachment_type=allure.attachment_type.TEXT)
allure.attach(result.stderr, name="stderr", attachment_type=allure.attachment_type.TEXT)
pytest.fail(f"greenmask command failed: {result.stderr}")

allure.attach(result.stdout, name="stdout", attachment_type=allure.attachment_type.TEXT)
return result

return _run_greenmask
Loading