diff --git a/t/.env b/t/.env new file mode 100644 index 0000000..1474cc5 --- /dev/null +++ b/t/.env @@ -0,0 +1,19 @@ +# Password for the 'elastic' user (at least 6 characters) +ELASTIC_PASSWORD=tuscador1 + +# Version of Elastic products +STACK_VERSION=9.4.2 + +# Set the cluster name +CLUSTER_NAME=domdoc + +# Set to 'basic' or 'trial' to automatically start the 30-day trial +LICENSE=basic +#LICENSE=trial + +# Port to expose Elasticsearch HTTP API to the host +ES_PORT=9200 +#ES_PORT=127.0.0.1:9200 + +# Increase or decrease based on the available host memory (in bytes) +MEM_LIMIT=1073741824 diff --git a/t/Makefile b/t/Makefile new file mode 100644 index 0000000..dadf3a5 --- /dev/null +++ b/t/Makefile @@ -0,0 +1,43 @@ +.PHONY: test clean cluster docs search up down delete + +# docker stuff +up: + @echo "booting up docker containers" + docker compose up -d --remove-orphans + +waitup: + @echo "wait til es cluster is up and running" + mosscap msc-actions.yaml msc-docker.yaml -n -t 300 + +down: + @echo "shutting down docker containers" + docker compose down + +delete: + @echo "delete docker volumes" + docker volume rm t_certs t_esdata01 t_esdata02 t_esdata03 + +clean-docker: down delete + + +# mosscap esctl stuff +test: up waitup cluster docs search + +cluster: + @echo "setting up elastisearch cluster" + mosscap msc-actions.yaml msc-cluster.yaml -n + +docs: + @echo "put some docs" + mosscap msc-actions.yaml msc-docs.yaml -n -c 1000 -p 100 + +search: + @echo "make some searches" + mosscap msc-actions.yaml msc-search.yaml -n + +clean: + @echo "cleaning up cluster" + mosscap msc-actions.yaml msc-clean.yaml -n + rm -f *.state debug.log + + diff --git a/t/README.md b/t/README.md new file mode 100644 index 0000000..20d8d31 --- /dev/null +++ b/t/README.md @@ -0,0 +1,76 @@ +# Testing + +Building regular unit tests would require to create a mock +elasticsearch cluster, which is too much a chrore for a one man +show. Running a regular elasticsearch cluster on Codeberg CI is not +economically reasonable. + +Therefore I run tests manually. Here's how. + +# Dependencies + +The following is required: + +- linux, any distro will do +- docker in a decent version +- [mosscap](https://codeberg.org/scip/mosscap) + +# Docker + +There's a ready to use docker compose file, which fires up an +elasticsearch cluster with 3 nodes. To start it manually just execute +`make up`. + +When it's up and running it should look like this: + +```console +NAMES STATUS PORTS +t-es03-1 Up 16 minutes (healthy) 9200/tcp, 9300/tcp +t-es02-1 Up 16 minutes (healthy) 9200/tcp, 9300/tcp +t-es01-1 Up 16 minutes (healthy) 0.0.0.0:9200->9200/tcp, [::]:9200->9200/tcp, 9300/tcp +``` + +There's an esctl config file `cluster.yaml`, which you can use to +access that elasticsearch cluster, e.g.: + +```console +esctl -c cluster.yaml cluster status +DOCKER/DOMDOC STATUS +Cluster Name domdoc +ES Status green +ES Version 9.4.2 +Is Leader false +Active Shards 8 +Active Primary Shards 4 +Unassigned Shards 0 +Unassigned Primary Shards 0 +Pending Tasks 0 +Nodes 3 +Red Indices 0 +Long Running Tasks 0 +``` + +# Automated Tests + +To execute the automated tests, just execute `make test`. This boots +up the elasticsearch containers, waits until they are up and running, +creates data on it and queries it. + +# Cleanup + +To just clean up the elasticsearch cluster run `make clean`. + +To remove everything, run `make clean-docker`. + +# Reference + +## Mosscap configs + +| CONFIG | DESCRIPTION | +|------------------|----------------------------------------------------------------------| +| msc-actions.yaml | contains all actions, used by all item configs | +| msc-docker.yaml | single item: used to wait until elasticsearch containers are healthy | +| msc-cluster.yaml | single item: create indices etc | +| msc-docs.yaml | generator items: put docs into the index | +| msc-search.yaml | single item: do some searches | +| msc-clean.yaml | single item: clean up the elasticsearch cluster | diff --git a/t/cluster.yaml b/t/cluster.yaml new file mode 100644 index 0000000..9b7bcad --- /dev/null +++ b/t/cluster.yaml @@ -0,0 +1,8 @@ +# esctl config +clusters: + docker/domdoc: + uri: https://elastic:9200 + user: elastic + pass: tuscador1 + token: "" + default: false diff --git a/t/docker-compose.yaml b/t/docker-compose.yaml new file mode 100644 index 0000000..2ab497c --- /dev/null +++ b/t/docker-compose.yaml @@ -0,0 +1,207 @@ +services: + setup: + image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + volumes: + - certs:/usr/share/elasticsearch/config/certs + user: "0" + command: > + bash -c ' + if [ x${ELASTIC_PASSWORD} == x ]; then + echo "Set the ELASTIC_PASSWORD environment variable in the .env file"; + exit 1; + fi; + if [ ! -f config/certs/ca.zip ]; then + echo "Creating CA"; + bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip; + unzip config/certs/ca.zip -d config/certs; + fi; + if [ ! -f config/certs/certs.zip ]; then + echo "Creating certs"; + echo -ne \ + "instances:\n"\ + " - name: es01\n"\ + " dns:\n"\ + " - es01\n"\ + " - localhost\n"\ + " ip:\n"\ + " - 127.0.0.1\n"\ + " - name: es02\n"\ + " dns:\n"\ + " - es02\n"\ + " - localhost\n"\ + " ip:\n"\ + " - 127.0.0.1\n"\ + " - name: es03\n"\ + " dns:\n"\ + " - es03\n"\ + " - localhost\n"\ + " ip:\n"\ + " - 127.0.0.1\n"\ + > config/certs/instances.yml; + bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key; + unzip config/certs/certs.zip -d config/certs; + fi; + echo "Setting file permissions" + chown -R root:root config/certs; + find . -type d -exec chmod 750 \{\} \;; + find . -type f -exec chmod 640 \{\} \;; + echo "Waiting for Elasticsearch availability"; + until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done; + echo "All done!"; + ' + healthcheck: + test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"] + interval: 1s + timeout: 5s + retries: 120 + + es01: + depends_on: + setup: + condition: service_healthy + image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + volumes: + - certs:/usr/share/elasticsearch/config/certs + - esdata01:/usr/share/elasticsearch/data + ports: + - ${ES_PORT}:9200 + environment: + - node.name=es01 + - cluster.name=${CLUSTER_NAME} + - cluster.initial_master_nodes=es01 + - discovery.seed_hosts=es02 + - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} + - bootstrap.memory_lock=true + - xpack.security.enabled=true + - xpack.security.http.ssl.enabled=true + - xpack.security.http.ssl.key=certs/es01/es01.key + - xpack.security.http.ssl.certificate=certs/es01/es01.crt + - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.enabled=true + - xpack.security.transport.ssl.key=certs/es01/es01.key + - xpack.security.transport.ssl.certificate=certs/es01/es01.crt + - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.verification_mode=certificate + - xpack.license.self_generated.type=${LICENSE} + - xpack.ml.use_auto_machine_memory_percent=true + - node_roles=data_content + - xpack.searchable.snapshot.shared_cache.size="1gb" + - cluster.routing.allocation.disk.threshold_enabled=false + - cluster.routing.allocation.disk.watermark.low="2gb" + - cluster.routing.allocation.disk.watermark.high="1gb" + - cluster.routing.allocation.disk.watermark.flood_stage="500mb" + mem_limit: ${MEM_LIMIT} + ulimits: + memlock: + soft: -1 + hard: -1 + healthcheck: + test: + [ + "CMD-SHELL", + "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", + ] + interval: 10s + timeout: 10s + retries: 120 + + es02: + depends_on: + - es01 + image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + volumes: + - certs:/usr/share/elasticsearch/config/certs + - esdata02:/usr/share/elasticsearch/data + environment: + - node.name=es02 + - cluster.name=${CLUSTER_NAME} + - cluster.initial_master_nodes=es01,es02 + - discovery.seed_hosts=es01 + - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} + - bootstrap.memory_lock=true + - xpack.security.enabled=true + - xpack.security.http.ssl.enabled=true + - xpack.security.http.ssl.key=certs/es02/es02.key + - xpack.security.http.ssl.certificate=certs/es02/es02.crt + - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.enabled=true + - xpack.security.transport.ssl.key=certs/es02/es02.key + - xpack.security.transport.ssl.certificate=certs/es02/es02.crt + - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.verification_mode=certificate + - xpack.license.self_generated.type=${LICENSE} + - xpack.ml.use_auto_machine_memory_percent=true + - cluster.routing.allocation.disk.threshold_enabled=false + - cluster.routing.allocation.disk.watermark.low="2gb" + - cluster.routing.allocation.disk.watermark.high="1gb" + - cluster.routing.allocation.disk.watermark.flood_stage="500mb" + mem_limit: ${MEM_LIMIT} + ulimits: + memlock: + soft: -1 + hard: -1 + healthcheck: + test: + [ + "CMD-SHELL", + "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", + ] + interval: 10s + timeout: 10s + retries: 120 + + + es03: + depends_on: + - es01 + image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} + volumes: + - certs:/usr/share/elasticsearch/config/certs + - esdata03:/usr/share/elasticsearch/data + environment: + - node.name=es03 + - cluster.name=${CLUSTER_NAME} + - cluster.initial_master_nodes=es01,es03 + - discovery.seed_hosts=es01 + - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} + - bootstrap.memory_lock=true + - xpack.security.enabled=true + - xpack.security.http.ssl.enabled=true + - xpack.security.http.ssl.key=certs/es03/es03.key + - xpack.security.http.ssl.certificate=certs/es03/es03.crt + - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.enabled=true + - xpack.security.transport.ssl.key=certs/es03/es03.key + - xpack.security.transport.ssl.certificate=certs/es03/es03.crt + - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt + - xpack.security.transport.ssl.verification_mode=certificate + - xpack.license.self_generated.type=${LICENSE} + - xpack.ml.use_auto_machine_memory_percent=true + - cluster.routing.allocation.disk.threshold_enabled=false + - cluster.routing.allocation.disk.watermark.low="2gb" + - cluster.routing.allocation.disk.watermark.high="1gb" + - cluster.routing.allocation.disk.watermark.flood_stage="500mb" + mem_limit: ${MEM_LIMIT} + ulimits: + memlock: + soft: -1 + hard: -1 + healthcheck: + test: + [ + "CMD-SHELL", + "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", + ] + interval: 10s + timeout: 10s + retries: 120 + +volumes: + certs: + driver: local + esdata01: + driver: local + esdata02: + driver: local + esdata03: + driver: local diff --git a/t/msc-actions.yaml b/t/msc-actions.yaml new file mode 100644 index 0000000..6ffbdab --- /dev/null +++ b/t/msc-actions.yaml @@ -0,0 +1,68 @@ +# +# this is a mosscap action file, see: https://codeberg.org/scip/mosscap +vars: + esctl: ../esctl -c cluster.yaml + +actions: + wait: | + sleep [[.time]] + + docker_wait: | + for i in {1..20}; do + count=$(docker ps | grep healthy | wc -l) + if test $count -eq 3; then + echo "all containers are healthy" + exit + fi + sleep 5s + done + + echo "not all containers are healthy" + docker ps + + cluster_ls: | + [[.esctl]] cluster ls | grep -E domdoc.*reachable.*yes + + cluster_status: | + [[.esctl]] cluster status | grep green + + create_index_template: | + [[.esctl]] index template create [[.index]] -i [[.index]] \ + -s number_of_shards:3 \ + -s index.sort.field:@timestamp \ + -r 1m \ + user:keyword message:text @timestamp:date + + create_index: | + [[.esctl]] index create -s 2 -r 2 [[.index]] + + describe_index: | + [[.esctl]] index show [[.index]] | grep -E "fields.*@timestamp" + + index_ls: | + [[.esctl]] index ls | grep [[.index]] + + index_template_rm: | + [[.esctl]] index template rm [[.index]] + + index_rm: | + [[.esctl]] index rm [[.index]] + + timestamp: | + date --iso-8601=second + + date: | + date +%Y-%m-%d + + doc_add: | + [[.esctl]] doc add -i [[.index]] '{"user": "[[.user]]", "message":"[[.message]]", "@timestamp":"[[.ts]]"}' + + search: | + [[.esctl]] search -i [[.index]] -l 1 | jq .source.message + + search_date: | + [[.esctl]] search -i [[.index]] -l 1 | jq '.source."@timestamp"' | grep [[.today]] + + search_count: | + [[.esctl]] search -i [[.index]] -l 5000 | wc -l | grep 1000 + diff --git a/t/msc-clean.yaml b/t/msc-clean.yaml new file mode 100644 index 0000000..8a7c5ae --- /dev/null +++ b/t/msc-clean.yaml @@ -0,0 +1,14 @@ +# +# this is a mosscap item file, see: https://codeberg.org/scip/mosscap +items: + - name: docker/domdoc + +vars: + index: test + +tasks: + - name: delete_index + action: index_rm + + - name: delete_template + action: index_template_rm diff --git a/t/msc-cluster.yaml b/t/msc-cluster.yaml new file mode 100644 index 0000000..20e347d --- /dev/null +++ b/t/msc-cluster.yaml @@ -0,0 +1,28 @@ +# +# this is a mosscap item file, see: https://codeberg.org/scip/mosscap +statefile: cluster.state + +items: + - name: docker/domdoc + +vars: + index: test + +tasks: + - name: ls + action: cluster_ls + + - name: status + action: cluster_status + + - name: template + action: create_index_template + + - name: index + action: create_index + + - name: indexls + action: index_ls + + - name: describe + action: describe_index diff --git a/t/msc-docker.yaml b/t/msc-docker.yaml new file mode 100644 index 0000000..49f0bd7 --- /dev/null +++ b/t/msc-docker.yaml @@ -0,0 +1,12 @@ +# +# this is a mosscap item file, see: https://codeberg.org/scip/mosscap +items: + - name: docker/domdoc + +vars: + index: test + time: 5s + +tasks: + - name: wait + action: docker_wait diff --git a/t/msc-docs.yaml b/t/msc-docs.yaml new file mode 100644 index 0000000..8cf3c6f --- /dev/null +++ b/t/msc-docs.yaml @@ -0,0 +1,18 @@ +# +# this is a mosscap generator item file, see: https://codeberg.org/scip/mosscap +vars: + index: test + +tasks: + - name: ts + action: timestamp + + - name: add + action: doc_add + args: + ts: ts.result + +generate: + user: $name + message: "$rand $rand $rand" + diff --git a/t/msc-search.yaml b/t/msc-search.yaml new file mode 100644 index 0000000..c7835ea --- /dev/null +++ b/t/msc-search.yaml @@ -0,0 +1,26 @@ +# +# this is a mosscap item file, see: https://codeberg.org/scip/mosscap +items: + - name: docker/domdoc + +vars: + index: test + time: 5s + +tasks: + - name: today + action: date + + - name: search + action: search + + - name: date + action: search_date + args: + today: today.result + + - name: wait + action: wait + + - name: count + action: search_count