Skip to content

Commit

Permalink
Merge pull request #1 from PDOK/setup_docker
Browse files Browse the repository at this point in the history
Add scripts, Dockerfile, etc.
  • Loading branch information
kad-korpem authored Dec 18, 2024
2 parents 23882b9 + 3bc520f commit 32599e3
Show file tree
Hide file tree
Showing 8 changed files with 411 additions and 0 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
output/
67 changes: 67 additions & 0 deletions .github/workflows/build-and-publish-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
name: build
env:
image: pdok/ets-ogcapi-tiles10-docker
on:
push:
tags:
- '*'
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v3
with:
images: ${{ env.image }}
tags: |
type=semver,pattern={{major}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{version}}
- name: Login to PDOK Docker Hub
if: startsWith(env.image, 'pdok/')
uses: docker/login-action@v1
with:
username: koalapdok
password: ${{ secrets.DOCKERHUB_PUSH }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
- # Temp fix to cleanup cache
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
- name: Build result notification
if: success() || failure()
uses: 8398a7/action-slack@v3
with:
fields: all
status: custom
custom_payload: |
{
attachments: [{
color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
text: `${process.env.AS_WORKFLOW} ${{ job.status }} for ${process.env.AS_REPO}!\n${process.env.AS_JOB} job on ${process.env.AS_REF} (commit: ${process.env.AS_COMMIT}, version: ${{ steps.docker_meta.outputs.version }}) by ${process.env.AS_AUTHOR} took ${process.env.AS_TOOK}`,
}]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output/
test-run-props.xml
example/kubeconfig.yaml
32 changes: 32 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM docker.io/maven:3-eclipse-temurin-8

# ARG REPO=https://github.com/opengeospatial/ets-ogcapi-tiles10.git
# ARG REPO_REF="tags/1.1"
# temporary, until PRs are approved/merged
ARG REPO=https://github.com/kad-korpem/ets-ogcapi-tiles10.git
ARG REPO_REF="allow-204-within-limits"

WORKDIR /src
RUN git clone ${REPO} . && git checkout ${REPO_REF}

# temporary, until PRs are approved/merged
RUN mvn spring-javaformat:apply

RUN mvn clean install
RUN mv /src/target/ets-ogcapi-tiles10-*-aio.jar /src/target/ets-ogcapi-tiles10-aio.jar

FROM docker.io/eclipse-temurin:21-jre
RUN apt update && apt install -y python3 \
python3-pip

WORKDIR /src
COPY scripts /src

RUN python3 -m pip config set global.break-system-packages true
RUN python3 -m pip install -r requirements.txt
LABEL AUTHOR="pdok@kadaster.nl"
# set correct timezone
ENV TZ=Europe/Amsterdam

COPY --from=0 /src/target/ets-ogcapi-tiles10-aio.jar /opt/ets-ogcapi-tiles10-aio.jar
ENTRYPOINT ["bash", "/src/startup.sh"]
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,34 @@
# ets-ogcapi-tiles10-docker

[![Docker Pulls](https://badgen.net/docker/pulls/pdok/ets-ogcapi-tiles10-docker?icon=docker&label=pulls)](https://hub.docker.com/r/pdok/ets-ogcapi-tiles10-docker/)

PDOK Docker image for [OGC API - Tiles Compliance Test Suite](https://github.com/opengeospatial/ets-ogcapi-tiles10) for command-line use, with additional features:

- pass service url as command-line argument
- when passing `-exitOnFail` flag, return code `0` if test suite passes all tests, otherwise `1` (instead of always returning `0`)

## Usage examples

```bash
docker run -t -v "$(pwd):/mnt" pdok/ets-ogcapi-tiles10-docker:latest https://api.pdok.nl/lv/bag/ogc/v1/ --generateHtmlReport true --outputDir /mnt/output --exitOnFail --prettyPrint
```

```bash
URL=https://api.pdok.nl/lv/bag/ogc/v1/
cat > ./test-run-props.xml <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties version="1.0">
<comment>Test run arguments</comment>
<entry key="iut">${URL}</entry>
<entry key="tilematrixsetdefinitionuri">http://www.opengis.net/def/tilematrixset/OGC/1.0/WebMercatorQuad</entry>
<entry key="urltemplatefortiles">${URL}/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}?f=mvt</entry>
<entry key="tilematrix">17</entry>
<entry key="mintilerow">67500</entry>
<entry key="maxtilerow">67510</entry>
<entry key="mintilecol">43200</entry>
<entry key="maxtilecol">43210</entry>
</properties>
EOF
docker run -v "$(pwd):/mnt" pdok/ets-ogcapi-tiles10-docker:latest /mnt/test-run-props.xml --generateHtmlReport true --outputDir /mnt/output
```
226 changes: 226 additions & 0 deletions scripts/parse-results.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
#!/bin/env python3
import argparse
from pathlib import Path
from rich.console import Console
from rich.table import Table
from junitparser import JUnitXml, Failure, Error, Skipped

err_console = Console(stderr=True)
console = Console()

failed_table = Table(show_lines=True)
errored_table = Table(show_lines=True)
skipped_table = Table(show_lines=True)


def get_api_docs_url(test_xml_name, name):
return f'https://cite.opengeospatial.org/te2/about/ogcapi-tiles-1.0/1.0/site/apidocs/index.html?{test_xml_name.replace(".","/")}.html ({name})'


def add_table(table, tuples, title):
table.add_column(
"Case Name", justify="right", style="cyan", no_wrap=False, overflow="fold"
)
table.add_column(
"Error", justify="right", style="red", no_wrap=False, overflow="fold"
)
table.add_column(
"File", justify="right", style="magenta", no_wrap=False, overflow="fold"
)
table.add_column(
"Url", justify="right", style="orange1", no_wrap=False, overflow="fold"
)
for case in tuples:
table.add_row(case[1], case[2], str(case[0]), case[3])

table.title = title
console.print(table)


def main(result_dir, service_url, pretty_print, exit_on_fail):
"""
Parse junit result.
"""

failed_cases = []
failed_tuples = []

skipped_cases = []
skipped_tuples = []

errored_cases = []
errored_tuples = []

dir_path = Path(args.result_dir)
for junit_test in dir_path.glob("**/**/TEST-org.opengis.cite.*.xml"):
test_xml = JUnitXml.fromfile(str(junit_test))

failed = [
case
for case in test_xml
if any(isinstance(item, Failure) for item in case.result)
]
failed_message = [result.message for fail in failed for result in fail.result]
failed_tuples += [
(
junit_test.name,
test_xml.name,
result.message,
get_api_docs_url(test_xml.name, fail.name),
)
for fail in failed
for result in fail.result
]
if failed:
fail_name = next(iter([fail.name for fail in failed]), "")
failed_cases += (
[f"## {test_xml.name}"]
+ [""]
+ failed_message
+ [""]
+ [get_api_docs_url(test_xml.name, fail_name)]
+ [""]
)

skipped = [
case
for case in test_xml
if any(isinstance(item, Skipped) for item in case.result)
]
errored_or_skipped = [
case
for case in test_xml
if any(isinstance(item, Error) for item in case.result)
]
if errored_or_skipped:
for case in errored_or_skipped:
# TestNG SkipExceptions are wrongfully marked as errored when using the JUnit reporter.
# Turn these errored tests into skipped tests.
if case.result[0].type == 'org.testng.SkipException':
skipped += [case]
else:
# Not a SkipException so treat as errored
errored = [case]
errored_message = [
result.message for error in errored for result in error.result
]
errored_tuples += [
(
junit_test.name,
test_xml.name,
result.message,
get_api_docs_url(test_xml.name, error.name),
)
for error in errored
for result in error.result
]
if errored:
error_name = next(iter([error.name for error in errored]), "")
errored_cases += (
[f"## {test_xml.name}"]
+ errored_message
+ [""]
+ [get_api_docs_url(test_xml.name, error_name)]
+ [""]
)

# Handle skipped
skipped_message = [result.message for skip in skipped for result in skip.result]
skipped_tuples += [
(
junit_test.name,
test_xml.name,
result.message,
get_api_docs_url(test_xml.name, skip.name),
)
for skip in skipped
for result in skip.result
]
if skipped:
skip_name = next(iter([skip.name for skip in skipped]), "")
skipped_cases += (
[f"## {test_xml.name}"]
+ skipped_message
+ [""]
+ [get_api_docs_url(test_xml.name, skip_name)]
+ [""]
)

if pretty_print:
console.print(
"ogcapi-tiles-1.0-1.1 Test Suite Run",
style="bold italic underline",
justify="center",
)
console.print("\n")
console.print(f"Output test run saved in: '{result_dir}'", justify="center")
if service_url:
console.print(f"Test instance: '{service_url}'", justify="center")
console.print("\n")

if failed_tuples:
add_table(
failed_table, failed_tuples, f"FAILED TEST CASES ({len(failed_tuples)})"
)

if errored_tuples:
add_table(
errored_table,
errored_tuples,
f"ERRORED TEST CASES ({len(errored_tuples)})",
)

if skipped_tuples:
add_table(
skipped_table,
skipped_tuples,
f"SKIPPED TEST CASES ({len(skipped_tuples)})",
)

else:
console.print("# ogcapi-tiles-1.0-1.1 Test Suite Run\n")
console.print(f"- Output test run saved in: '{result_dir}'")
if service_url:
console.print(f"- Test instance: '{service_url}'")
console.print("\n")

if failed_cases:
console.print("# FAILED TEST CASES\n", style="red")
console.print("\n".join(failed_cases), style="red")

if errored_cases:
console.print("# ERRORED TEST CASES\n", style="orange1")
console.print("\n".join(errored_cases), style="orange1")

if skipped_cases:
console.print("# SKIPPED TEST CASES\n", style="yellow")
console.print("\n".join(skipped_cases), style="yellow")

if failed_cases and exit_on_fail:
exit(1)


if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Parse OAF ETS results")
parser.add_argument(
"result_dir", type=str, help="Directory with the result to parse"
)
parser.add_argument(
"--service-url", help="Optional service url to print to console"
)
parser.add_argument(
"--pretty-print", action="store_true", help="Print with a better formatting"
)
parser.add_argument(
"--exit-on-fail",
action="store_true",
help="Force failing with exit code 1 when failed tests cases in result",
)
args = parser.parse_args()

dir_path = Path(args.result_dir)
if not dir_path.exists():
err_console.print(f"test dir '{args.result_dir}' should exist")
exit(1)

main(args.result_dir, args.service_url, args.pretty_print, args.exit_on_fail)
2 changes: 2 additions & 0 deletions scripts/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
junitparser==2.7.0
rich==12
Loading

0 comments on commit 32599e3

Please sign in to comment.