Skip to content

Commit 52dc797

Browse files
whummerHarshCasper
authored andcommitted
add wiremock extension
* Add LocalStack WireMock extension that runs/proxies a WireMock container * Add sample app for integration testing * Add GitHub Actions workflow for extension tests
1 parent f4b4626 commit 52dc797

File tree

13 files changed

+659
-0
lines changed

13 files changed

+659
-0
lines changed

.github/workflows/wiremock.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: LocalStack WireMock Extension Tests
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
paths:
8+
- 'wiremock/**'
9+
push:
10+
branches:
11+
- main
12+
paths:
13+
- 'wiremock/**'
14+
workflow_dispatch:
15+
16+
env:
17+
LOCALSTACK_DISABLE_EVENTS: "1"
18+
LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
19+
20+
jobs:
21+
integration-tests:
22+
name: Run WireMock Extension Tests
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 10
25+
steps:
26+
- name: Checkout
27+
uses: actions/checkout@v4
28+
29+
- name: Set up Terraform
30+
uses: hashicorp/setup-terraform@v3
31+
32+
- name: Set up LocalStack and extension
33+
run: |
34+
cd wiremock
35+
36+
docker pull localstack/localstack-pro &
37+
docker pull wiremock/wiremock &
38+
docker pull public.ecr.aws/lambda/python:3.9 &
39+
pip install localstack terraform-local awscli-local[ver1]
40+
41+
make install
42+
make dist
43+
localstack extensions -v install file://$(ls ./dist/localstack_wiremock-*.tar.gz)
44+
45+
DEBUG=1 localstack start -d
46+
localstack wait
47+
48+
- name: Run sample app test
49+
run: |
50+
cd wiremock
51+
make sample
52+
53+
- name: Print logs
54+
if: always()
55+
run: |
56+
localstack logs
57+
localstack stop

wiremock/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.venv
2+
dist
3+
build
4+
**/*.egg-info
5+
.eggs
6+
.terraform*
7+
terraform.tfstate*
8+
*.zip

wiremock/Makefile

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
VENV_BIN = python3 -m venv
2+
VENV_DIR ?= .venv
3+
VENV_ACTIVATE = $(VENV_DIR)/bin/activate
4+
VENV_RUN = . $(VENV_ACTIVATE)
5+
6+
usage: ## Shows usage for this Makefile
7+
@cat Makefile | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
8+
9+
venv: $(VENV_ACTIVATE)
10+
11+
$(VENV_ACTIVATE): pyproject.toml
12+
test -d .venv || $(VENV_BIN) .venv
13+
$(VENV_RUN); pip install --upgrade pip setuptools plux
14+
$(VENV_RUN); pip install -e .[dev]
15+
touch $(VENV_DIR)/bin/activate
16+
17+
clean:
18+
rm -rf .venv/
19+
rm -rf build/
20+
rm -rf .eggs/
21+
rm -rf *.egg-info/
22+
23+
install: venv ## Install dependencies
24+
$(VENV_RUN); python -m plux entrypoints
25+
26+
dist: venv ## Create distribution
27+
$(VENV_RUN); python -m build
28+
29+
publish: clean-dist venv dist ## Publish extension to pypi
30+
$(VENV_RUN); pip install --upgrade twine; twine upload dist/*
31+
32+
entrypoints: venv # Generate plugin entrypoints for Python package
33+
$(VENV_RUN); python -m plux entrypoints
34+
35+
format: ## Run ruff to format the whole codebase
36+
$(VENV_RUN); python -m ruff format .; python -m ruff check --output-format=full --fix .
37+
38+
test: ## Run integration tests (requires LocalStack running with the Extension installed)
39+
$(VENV_RUN); pytest tests $(PYTEST_ARGS)
40+
41+
sample: ## Deploy sample app
42+
echo "Creating stubs in WireMock ..."
43+
bin/create-stubs.sh
44+
echo "Deploying sample app into LocalStack via Terraform ..."
45+
(cd sample-app; tflocal init; tflocal apply -auto-approve)
46+
apiId=$$(awslocal apigateway get-rest-apis | jq -r '.items[0].id'); \
47+
endpoint=https://$$apiId.execute-api.us-east-1.localhost.localstack.cloud/dev/time-off; \
48+
echo "Invoking local API Gateway endpoint: $$endpoint"; \
49+
curl -k -v $$endpoint | grep time_off_date
50+
51+
clean-dist: clean
52+
rm -rf dist/
53+
54+
.PHONY: clean clean-dist dist install publish usage venv format test

wiremock/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
WireMock on LocalStack
2+
========================
3+
4+
This repo contains a [LocalStack Extension](https://github.com/localstack/localstack-extensions) that facilitates developing [WireMock](https://wiremock.org)-based applications locally.
5+
6+
## Prerequisites
7+
8+
* Docker
9+
* LocalStack Pro (free trial available)
10+
* `localstack` CLI
11+
* `make`
12+
13+
## Install from GitHub repository
14+
15+
This extension can be installed directly from this Github repo via:
16+
17+
```bash
18+
localstack extensions install "git+https://github.com/whummer/localstack-utils.git#egg=localstack-wiremock&subdirectory=localstack-wiremock"
19+
```
20+
21+
## Install local development version
22+
23+
To install the extension into localstack in developer mode, you will need Python 3.11, and create a virtual environment in the extensions project.
24+
25+
In the newly generated project, simply run
26+
27+
```bash
28+
make install
29+
```
30+
31+
Then, to enable the extension for LocalStack, run
32+
33+
```bash
34+
localstack extensions dev enable .
35+
```
36+
37+
You can then start LocalStack with `EXTENSION_DEV_MODE=1` to load all enabled extensions:
38+
39+
```bash
40+
EXTENSION_DEV_MODE=1 localstack start
41+
```

wiremock/bin/create-stubs.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
echo "Downloading WireMock stub definitions..."
4+
5+
# Define the URL for the stub definitions and the temporary file path
6+
STUBS_URL="https://library.wiremock.org/catalog/api/p/personio.de/personio-de-personnel/personio.de-personnel-stubs.json"
7+
TMP_STUBS_FILE="/tmp/personio-stubs.json"
8+
9+
# Define the WireMock server URL
10+
WIREMOCK_URL="http://localhost:8080"
11+
12+
# Download the stub definitions
13+
curl -s -o "$TMP_STUBS_FILE" "$STUBS_URL"
14+
15+
echo "Download complete. Stubs saved to $TMP_STUBS_FILE"
16+
echo "Importing stubs into WireMock..."
17+
18+
# Send a POST request to WireMock's import endpoint with the downloaded file
19+
curl -v -X POST -H "Content-Type: application/json" --data-binary "@$TMP_STUBS_FILE" "$WIREMOCK_URL/__admin/mappings/import"
20+
21+
echo ""
22+
echo "WireMock stub import request sent."
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
name = "localstack_wiremock"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import os
2+
3+
from localstack.utils.container_utils.container_client import Util
4+
from localstack_wiremock.utils.docker import ProxiedDockerContainerExtension
5+
6+
7+
# Environment variable for WireMock Cloud API token - note: if this value is specified, then the
8+
# `wiremock/wiremock-runner` image is being used, otherwise the `wiremock/wiremock` OSS image.
9+
ENV_WIREMOCK_API_TOKEN = "WIREMOCK_API_TOKEN"
10+
# container port for WireMock endpoint - TODO make configurable over time
11+
PORT = 8080
12+
13+
14+
class WireMockExtension(ProxiedDockerContainerExtension):
15+
name = "localstack-wiremock"
16+
17+
HOST = "wiremock.<domain>"
18+
# name of the OSS Docker image
19+
DOCKER_IMAGE = "wiremock/wiremock"
20+
# name of the WireMock Cloud runner Docker image
21+
DOCKER_IMAGE_RUNNER = "wiremock/wiremock-runner"
22+
# name of the container
23+
CONTAINER_NAME = "ls-wiremock"
24+
25+
def __init__(self):
26+
env_vars = {}
27+
image_name = self.DOCKER_IMAGE
28+
kwargs = {}
29+
if api_token := os.getenv(ENV_WIREMOCK_API_TOKEN):
30+
env_vars["WMC_ADMIN_PORT"] = str(PORT)
31+
# TODO remove?
32+
# env_vars["WMC_DEFAULT_MODE"] = "record-many"
33+
env_vars["WMC_API_TOKEN"] = api_token
34+
env_vars["WMC_RUNNER_ENABLED"] = "true"
35+
image_name = self.DOCKER_IMAGE_RUNNER
36+
settings_file = Util.mountable_tmp_file()
37+
# TODO: set configs in YAML file
38+
kwargs["volumes"] = ([(settings_file, "/work/.wiremock/wiremock.yaml")],)
39+
super().__init__(
40+
image_name=image_name,
41+
container_ports=[PORT],
42+
container_name=self.CONTAINER_NAME,
43+
host=self.HOST,
44+
**kwargs,
45+
)

wiremock/localstack_wiremock/utils/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)