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
119 changes: 119 additions & 0 deletions app-tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import pytest
import os
import subprocess
import time
import requests
import docker
import shutil
from pathlib import Path


@pytest.fixture(scope="session")
def generate_opal_keys():
"""Generate OPAL keys and create an .env file."""
print("- Generating OPAL keys")

opal_private_key_passphrase = "123456"
subprocess.run([
"ssh-keygen", "-q", "-t", "rsa", "-b", "4096", "-m", "pem",
"-f", "opal_crypto_key", "-N", opal_private_key_passphrase
], check=True)

with open("opal_crypto_key.pub") as f:
opal_auth_public_key = f.read().strip()
with open("opal_crypto_key") as f:
opal_auth_private_key = f.read().replace('\n', '_')

os.remove("opal_crypto_key.pub")
os.remove("opal_crypto_key")

opal_auth_master_token = subprocess.run(
["openssl", "rand", "-hex", "16"], capture_output=True, text=True
).stdout.strip()

env_vars = {
"OPAL_AUTH_PRIVATE_KEY_PASSPHRASE": opal_private_key_passphrase,
"OPAL_AUTH_MASTER_TOKEN": opal_auth_master_token,
"OPAL_AUTH_JWT_AUDIENCE": "https://api.opal.ac/v1/",
"OPAL_AUTH_JWT_ISSUER": "https://opal.ac/",
"OPAL_REPO_WATCHER_ENABLED": "0",
"OPAL_STATISTICS_ENABLED": "true"
}

opal_server = subprocess.Popen(["opal-server", "run"], env={**os.environ, **env_vars})
time.sleep(2)

opal_client_token = subprocess.run(
["opal-client", "obtain-token", opal_auth_master_token, "--type", "client"],
capture_output=True, text=True
).stdout.strip()

opal_data_source_token = subprocess.run(
["opal-client", "obtain-token", opal_auth_master_token, "--type", "datasource"],
capture_output=True, text=True
).stdout.strip()

opal_server.terminate()
opal_server.wait()
time.sleep(5)

# Create .env file
with open(".env", "w") as f:
f.write(f"OPAL_AUTH_PUBLIC_KEY=\"{opal_auth_public_key}\"\n")
f.write(f"OPAL_AUTH_PRIVATE_KEY=\"{opal_auth_private_key}\"\n")
f.write(f"OPAL_AUTH_MASTER_TOKEN=\"{opal_auth_master_token}\"\n")
f.write(f"OPAL_CLIENT_TOKEN=\"{opal_client_token}\"\n")
f.write(f"OPAL_AUTH_PRIVATE_KEY_PASSPHRASE=\"{opal_private_key_passphrase}\"\n")
f.write("OPAL_STATISTICS_ENABLED=true\n")

os.environ["OPAL_STATISTICS_ENABLED"] = "true"
yield

if Path(".env").exists():
os.remove(".env")


@pytest.fixture(scope="session")
def prepare_policy_repo():
"""Clone and configure the policy repo for testing."""
print("- Setting up policy repository")
repo_url = os.getenv("OPAL_POLICY_REPO_URL", "[email protected]:permitio/opal-tests-policy-repo.git")
policy_repo_branch = f"test-{os.getpid()}"

if os.path.exists("opal-tests-policy-repo"):
shutil.rmtree("opal-tests-policy-repo")

result = subprocess.run(["git", "clone", repo_url, "opal-tests-policy-repo"], capture_output=True, text=True)

if result.returncode != 0:
print("❌ Error cloning repository:", result.stderr)
pytest.fail("Failed to clone the policy repo")

os.chdir("opal-tests-policy-repo")
subprocess.run(["git", "checkout", "-b", policy_repo_branch], check=True)
subprocess.run(["git", "push", "--set-upstream", "origin", policy_repo_branch], check=True)
os.chdir("..")

yield policy_repo_branch

os.chdir("opal-tests-policy-repo")
subprocess.run(["git", "push", "-d", "origin", policy_repo_branch], check=True)
os.chdir("..")
shutil.rmtree("opal-tests-policy-repo")


@pytest.fixture(scope="session")
def docker_services():
"""Start OPAL containers."""
client = docker.from_env()
print("- Starting Docker containers")
client.containers.run("permitio/opal-server:latest", detach=True, ports={"7002": 7002})
client.containers.run("permitio/opal-client:latest", detach=True, ports={"7766": 7766})
time.sleep(10)

yield client

print("- Stopping Docker containers")
for container in client.containers.list():
container.stop()
container.remove()
1 change: 1 addition & 0 deletions app-tests/docker-compose-app-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ services:

opal_server:
image: permitio/opal-server:${OPAL_IMAGE_TAG:-latest}
env_file: .env
deploy:
mode: replicated
replicas: 2
Expand Down
Empty file added app-tests/pytest.ini
Empty file.
Empty file added app-tests/tests/__init__.py
Empty file.
56 changes: 56 additions & 0 deletions app-tests/tests/test_opal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import pytest
import time
import requests
import subprocess

def test_push_policy(prepare_policy_repo):
"""Test pushing a new policy to OPAL."""
repo_branch = prepare_policy_repo
policy_name = "test_policy"
rego_file = f"{policy_name}.rego"

subprocess.run(["touch", f"opal-tests-policy-repo/{rego_file}"], check=True)
subprocess.run(["git", "add", rego_file], cwd="opal-tests-policy-repo", check=True)
subprocess.run(["git", "commit", "-m", f"Add {rego_file}"], cwd="opal-tests-policy-repo", check=True)
subprocess.run(["git", "push"], cwd="opal-tests-policy-repo", check=True)

webhook_data = {
"gitEvent": "git.push",
"repository": {"git_url": "[email protected]:permitio/opal-tests-policy-repo.git"}
}

response = requests.post(
"http://localhost:7002/webhook",
json=webhook_data,
headers={"Content-Type": "application/json", "x-webhook-token": "xxxxx"}
)
time.sleep(5)

assert response.status_code == 200


def test_data_publish():
"""Test publishing data via OPAL client."""
user = "bob"
response = subprocess.run(
["opal-client", "publish-data-update", "--src-url", "https://api.country.is/23.54.6.78",
"-t", "policy_data", "--dst-path", f"/users/{user}/location"],
capture_output=True, text=True
)
time.sleep(5)

assert "Event Published Successfully" in response.stdout, f"Unexpected response: {response.stdout}"


def test_statistics():
"""Test statistics API."""
for port in range(7002, 7004):
response = requests.get(
f"http://localhost:{port}/stats",
headers={"Authorization": "Bearer xxxxx"}
)
print("📌 Debug: OPAL Server Response ->", response.text)
assert response.status_code == 200, f"Unexpected response: {response.text}"
assert '"client_count":' in response.text, "Statistics response does not contain expected client count"
assert '"server_count":' in response.text, "Statistics response does not contain expected server count"