Skip to content

Commit 3bc520f

Browse files
committed
Add scripts, Dockerfile, etc.
1 parent 23882b9 commit 3bc520f

File tree

8 files changed

+411
-0
lines changed

8 files changed

+411
-0
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
output/
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
name: build
3+
env:
4+
image: pdok/ets-ogcapi-tiles10-docker
5+
on:
6+
push:
7+
tags:
8+
- '*'
9+
jobs:
10+
docker:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Docker meta
14+
id: docker_meta
15+
uses: docker/metadata-action@v3
16+
with:
17+
images: ${{ env.image }}
18+
tags: |
19+
type=semver,pattern={{major}}
20+
type=semver,pattern={{major}}.{{minor}}
21+
type=semver,pattern={{version}}
22+
- name: Login to PDOK Docker Hub
23+
if: startsWith(env.image, 'pdok/')
24+
uses: docker/login-action@v1
25+
with:
26+
username: koalapdok
27+
password: ${{ secrets.DOCKERHUB_PUSH }}
28+
- name: Set up Docker Buildx
29+
uses: docker/setup-buildx-action@v1
30+
- name: Cache Docker layers
31+
uses: actions/cache@v2
32+
with:
33+
path: /tmp/.buildx-cache
34+
key: ${{ runner.os }}-buildx-${{ github.sha }}
35+
restore-keys: |
36+
${{ runner.os }}-buildx-
37+
- name: Build and push
38+
id: docker_build
39+
uses: docker/build-push-action@v2
40+
with:
41+
push: true
42+
tags: ${{ steps.docker_meta.outputs.tags }}
43+
labels: ${{ steps.docker_meta.outputs.labels }}
44+
cache-from: type=local,src=/tmp/.buildx-cache
45+
cache-to: type=local,dest=/tmp/.buildx-cache-new
46+
- # Temp fix to cleanup cache
47+
# https://github.com/docker/build-push-action/issues/252
48+
# https://github.com/moby/buildkit/issues/1896
49+
name: Move cache
50+
run: |
51+
rm -rf /tmp/.buildx-cache
52+
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
53+
- name: Build result notification
54+
if: success() || failure()
55+
uses: 8398a7/action-slack@v3
56+
with:
57+
fields: all
58+
status: custom
59+
custom_payload: |
60+
{
61+
attachments: [{
62+
color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
63+
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}`,
64+
}]
65+
}
66+
env:
67+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
output/
2+
test-run-props.xml
3+
example/kubeconfig.yaml

Dockerfile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
FROM docker.io/maven:3-eclipse-temurin-8
2+
3+
# ARG REPO=https://github.com/opengeospatial/ets-ogcapi-tiles10.git
4+
# ARG REPO_REF="tags/1.1"
5+
# temporary, until PRs are approved/merged
6+
ARG REPO=https://github.com/kad-korpem/ets-ogcapi-tiles10.git
7+
ARG REPO_REF="allow-204-within-limits"
8+
9+
WORKDIR /src
10+
RUN git clone ${REPO} . && git checkout ${REPO_REF}
11+
12+
# temporary, until PRs are approved/merged
13+
RUN mvn spring-javaformat:apply
14+
15+
RUN mvn clean install
16+
RUN mv /src/target/ets-ogcapi-tiles10-*-aio.jar /src/target/ets-ogcapi-tiles10-aio.jar
17+
18+
FROM docker.io/eclipse-temurin:21-jre
19+
RUN apt update && apt install -y python3 \
20+
python3-pip
21+
22+
WORKDIR /src
23+
COPY scripts /src
24+
25+
RUN python3 -m pip config set global.break-system-packages true
26+
RUN python3 -m pip install -r requirements.txt
27+
LABEL AUTHOR="[email protected]"
28+
# set correct timezone
29+
ENV TZ=Europe/Amsterdam
30+
31+
COPY --from=0 /src/target/ets-ogcapi-tiles10-aio.jar /opt/ets-ogcapi-tiles10-aio.jar
32+
ENTRYPOINT ["bash", "/src/startup.sh"]

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,34 @@
11
# ets-ogcapi-tiles10-docker
2+
3+
[![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/)
4+
5+
PDOK Docker image for [OGC API - Tiles Compliance Test Suite](https://github.com/opengeospatial/ets-ogcapi-tiles10) for command-line use, with additional features:
6+
7+
- pass service url as command-line argument
8+
- when passing `-exitOnFail` flag, return code `0` if test suite passes all tests, otherwise `1` (instead of always returning `0`)
9+
10+
## Usage examples
11+
12+
```bash
13+
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
14+
```
15+
16+
```bash
17+
URL=https://api.pdok.nl/lv/bag/ogc/v1/
18+
cat > ./test-run-props.xml <<EOF
19+
<?xml version="1.0" encoding="UTF-8"?>
20+
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
21+
<properties version="1.0">
22+
<comment>Test run arguments</comment>
23+
<entry key="iut">${URL}</entry>
24+
<entry key="tilematrixsetdefinitionuri">http://www.opengis.net/def/tilematrixset/OGC/1.0/WebMercatorQuad</entry>
25+
<entry key="urltemplatefortiles">${URL}/tiles/WebMercatorQuad/{tileMatrix}/{tileRow}/{tileCol}?f=mvt</entry>
26+
<entry key="tilematrix">17</entry>
27+
<entry key="mintilerow">67500</entry>
28+
<entry key="maxtilerow">67510</entry>
29+
<entry key="mintilecol">43200</entry>
30+
<entry key="maxtilecol">43210</entry>
31+
</properties>
32+
EOF
33+
docker run -v "$(pwd):/mnt" pdok/ets-ogcapi-tiles10-docker:latest /mnt/test-run-props.xml --generateHtmlReport true --outputDir /mnt/output
34+
```

scripts/parse-results.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
#!/bin/env python3
2+
import argparse
3+
from pathlib import Path
4+
from rich.console import Console
5+
from rich.table import Table
6+
from junitparser import JUnitXml, Failure, Error, Skipped
7+
8+
err_console = Console(stderr=True)
9+
console = Console()
10+
11+
failed_table = Table(show_lines=True)
12+
errored_table = Table(show_lines=True)
13+
skipped_table = Table(show_lines=True)
14+
15+
16+
def get_api_docs_url(test_xml_name, name):
17+
return f'https://cite.opengeospatial.org/te2/about/ogcapi-tiles-1.0/1.0/site/apidocs/index.html?{test_xml_name.replace(".","/")}.html ({name})'
18+
19+
20+
def add_table(table, tuples, title):
21+
table.add_column(
22+
"Case Name", justify="right", style="cyan", no_wrap=False, overflow="fold"
23+
)
24+
table.add_column(
25+
"Error", justify="right", style="red", no_wrap=False, overflow="fold"
26+
)
27+
table.add_column(
28+
"File", justify="right", style="magenta", no_wrap=False, overflow="fold"
29+
)
30+
table.add_column(
31+
"Url", justify="right", style="orange1", no_wrap=False, overflow="fold"
32+
)
33+
for case in tuples:
34+
table.add_row(case[1], case[2], str(case[0]), case[3])
35+
36+
table.title = title
37+
console.print(table)
38+
39+
40+
def main(result_dir, service_url, pretty_print, exit_on_fail):
41+
"""
42+
Parse junit result.
43+
"""
44+
45+
failed_cases = []
46+
failed_tuples = []
47+
48+
skipped_cases = []
49+
skipped_tuples = []
50+
51+
errored_cases = []
52+
errored_tuples = []
53+
54+
dir_path = Path(args.result_dir)
55+
for junit_test in dir_path.glob("**/**/TEST-org.opengis.cite.*.xml"):
56+
test_xml = JUnitXml.fromfile(str(junit_test))
57+
58+
failed = [
59+
case
60+
for case in test_xml
61+
if any(isinstance(item, Failure) for item in case.result)
62+
]
63+
failed_message = [result.message for fail in failed for result in fail.result]
64+
failed_tuples += [
65+
(
66+
junit_test.name,
67+
test_xml.name,
68+
result.message,
69+
get_api_docs_url(test_xml.name, fail.name),
70+
)
71+
for fail in failed
72+
for result in fail.result
73+
]
74+
if failed:
75+
fail_name = next(iter([fail.name for fail in failed]), "")
76+
failed_cases += (
77+
[f"## {test_xml.name}"]
78+
+ [""]
79+
+ failed_message
80+
+ [""]
81+
+ [get_api_docs_url(test_xml.name, fail_name)]
82+
+ [""]
83+
)
84+
85+
skipped = [
86+
case
87+
for case in test_xml
88+
if any(isinstance(item, Skipped) for item in case.result)
89+
]
90+
errored_or_skipped = [
91+
case
92+
for case in test_xml
93+
if any(isinstance(item, Error) for item in case.result)
94+
]
95+
if errored_or_skipped:
96+
for case in errored_or_skipped:
97+
# TestNG SkipExceptions are wrongfully marked as errored when using the JUnit reporter.
98+
# Turn these errored tests into skipped tests.
99+
if case.result[0].type == 'org.testng.SkipException':
100+
skipped += [case]
101+
else:
102+
# Not a SkipException so treat as errored
103+
errored = [case]
104+
errored_message = [
105+
result.message for error in errored for result in error.result
106+
]
107+
errored_tuples += [
108+
(
109+
junit_test.name,
110+
test_xml.name,
111+
result.message,
112+
get_api_docs_url(test_xml.name, error.name),
113+
)
114+
for error in errored
115+
for result in error.result
116+
]
117+
if errored:
118+
error_name = next(iter([error.name for error in errored]), "")
119+
errored_cases += (
120+
[f"## {test_xml.name}"]
121+
+ errored_message
122+
+ [""]
123+
+ [get_api_docs_url(test_xml.name, error_name)]
124+
+ [""]
125+
)
126+
127+
# Handle skipped
128+
skipped_message = [result.message for skip in skipped for result in skip.result]
129+
skipped_tuples += [
130+
(
131+
junit_test.name,
132+
test_xml.name,
133+
result.message,
134+
get_api_docs_url(test_xml.name, skip.name),
135+
)
136+
for skip in skipped
137+
for result in skip.result
138+
]
139+
if skipped:
140+
skip_name = next(iter([skip.name for skip in skipped]), "")
141+
skipped_cases += (
142+
[f"## {test_xml.name}"]
143+
+ skipped_message
144+
+ [""]
145+
+ [get_api_docs_url(test_xml.name, skip_name)]
146+
+ [""]
147+
)
148+
149+
if pretty_print:
150+
console.print(
151+
"ogcapi-tiles-1.0-1.1 Test Suite Run",
152+
style="bold italic underline",
153+
justify="center",
154+
)
155+
console.print("\n")
156+
console.print(f"Output test run saved in: '{result_dir}'", justify="center")
157+
if service_url:
158+
console.print(f"Test instance: '{service_url}'", justify="center")
159+
console.print("\n")
160+
161+
if failed_tuples:
162+
add_table(
163+
failed_table, failed_tuples, f"FAILED TEST CASES ({len(failed_tuples)})"
164+
)
165+
166+
if errored_tuples:
167+
add_table(
168+
errored_table,
169+
errored_tuples,
170+
f"ERRORED TEST CASES ({len(errored_tuples)})",
171+
)
172+
173+
if skipped_tuples:
174+
add_table(
175+
skipped_table,
176+
skipped_tuples,
177+
f"SKIPPED TEST CASES ({len(skipped_tuples)})",
178+
)
179+
180+
else:
181+
console.print("# ogcapi-tiles-1.0-1.1 Test Suite Run\n")
182+
console.print(f"- Output test run saved in: '{result_dir}'")
183+
if service_url:
184+
console.print(f"- Test instance: '{service_url}'")
185+
console.print("\n")
186+
187+
if failed_cases:
188+
console.print("# FAILED TEST CASES\n", style="red")
189+
console.print("\n".join(failed_cases), style="red")
190+
191+
if errored_cases:
192+
console.print("# ERRORED TEST CASES\n", style="orange1")
193+
console.print("\n".join(errored_cases), style="orange1")
194+
195+
if skipped_cases:
196+
console.print("# SKIPPED TEST CASES\n", style="yellow")
197+
console.print("\n".join(skipped_cases), style="yellow")
198+
199+
if failed_cases and exit_on_fail:
200+
exit(1)
201+
202+
203+
if __name__ == "__main__":
204+
parser = argparse.ArgumentParser(description="Parse OAF ETS results")
205+
parser.add_argument(
206+
"result_dir", type=str, help="Directory with the result to parse"
207+
)
208+
parser.add_argument(
209+
"--service-url", help="Optional service url to print to console"
210+
)
211+
parser.add_argument(
212+
"--pretty-print", action="store_true", help="Print with a better formatting"
213+
)
214+
parser.add_argument(
215+
"--exit-on-fail",
216+
action="store_true",
217+
help="Force failing with exit code 1 when failed tests cases in result",
218+
)
219+
args = parser.parse_args()
220+
221+
dir_path = Path(args.result_dir)
222+
if not dir_path.exists():
223+
err_console.print(f"test dir '{args.result_dir}' should exist")
224+
exit(1)
225+
226+
main(args.result_dir, args.service_url, args.pretty_print, args.exit_on_fail)

scripts/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
junitparser==2.7.0
2+
rich==12

0 commit comments

Comments
 (0)