From 4264eee5e3170314c96a3ee395ad22a512425ae7 Mon Sep 17 00:00:00 2001 From: Martin Weise <martin.weise@tuwien.ac.at> Date: Thu, 9 Mar 2023 07:55:12 +0100 Subject: [PATCH] Merge dev into feature branch --- .dbrepo2/deploy | 40 -- .dbrepo2/known_hosts | 6 - .fda-deployment/clean | 4 - .fda-deployment/clean-tmp | 6 - .fda-deployment/crontab | 2 - .../fda-authentication-service/install_cert | 52 --- .../fda-authentication-service/install_smtp | 2 - .fda-deployment/fda-ui/install_cert | 12 - .fda-deployment/hosts | 7 - .gitignore | 2 +- .gitlab-ci.yml | 133 +++--- .gitlab/jacoco2cobertura.py | 155 ------- .gitlab/tests/test_containers.py | 97 ----- .gitlab/tests/test_query.py | 284 ------------- .junit/hosts | 10 + {.dbrepo2 => .junit}/teardown | 0 Makefile | 112 ++--- docker-compose.dbrepo1.yml | 74 ++-- docker-compose.dbrepo2.yml | 76 ++-- docker-compose.prod.yml | 76 ++-- docker-compose.yml | 15 +- .../src/test/java/at/tuwien/BaseUnitTest.java | 2 +- .../java/at/tuwien/config/DockerConfig.java | 60 ++- .../service/QueueServiceIntegrationTest.java | 57 +-- .../service/UserServiceIntegrationTest.java | 59 +-- .../src/test/resources/application.properties | 2 +- .../tuwien/endpoints/ContainerEndpoint.java | 14 +- .../at/tuwien/endpoints/ImageEndpoint.java | 24 -- .../src/test/java/at/tuwien/BaseUnitTest.java | 35 +- .../endpoint/ContainerEndpointUnitTest.java | 37 +- .../endpoint/ImageEndpointUnitTest.java | 9 +- .../ContainerServiceIntegrationTest.java | 402 +----------------- .../java/at/tuwien/mapper/DatabaseMapper.java | 7 + .../repository/jpa/ContainerRepository.java | 2 - .../repository/jpa/DatabaseRepository.java | 10 + .../repository/jpa/IdentifierRepository.java | 10 + .../at/tuwien/service/ContainerService.java | 7 +- .../service/impl/ContainerServiceImpl.java | 16 +- .../at/tuwien/endpoints/DatabaseEndpoint.java | 23 - .../src/test/java/at/tuwien/BaseUnitTest.java | 36 +- .../java/at/tuwien/config/DockerConfig.java | 4 +- .../endpoint/DatabaseEndpointUnitTest.java | 108 ++++- .../src/test/resources/application.properties | 4 +- .../src/test/resources/nginx/nginx.conf | 2 +- .../java/at/tuwien/mapper/DatabaseMapper.java | 1 + .../api/container/ContainerBriefDto.java | 4 + .../tuwien/api/database/DatabaseBriefDto.java | 6 +- .../api/identifier/CreatorBriefDto.java | 28 ++ .../api/identifier/IdentifierBriefDto.java | 19 + .../at/tuwien/entities/database/Database.java | 18 +- .../entities/identifier/Identifier.java | 7 +- .../at/tuwien/endpoint/TableDataEndpoint.java | 9 +- .../src/main/resources/application-local.yml | 2 +- .../src/test/java/at/tuwien/BaseUnitTest.java | 56 ++- .../at/tuwien/auth/AuthTokenFilterTest.java | 4 - .../java/at/tuwien/config/DockerConfig.java | 13 +- .../java/at/tuwien/config/RabbitMqConfig.java | 4 +- .../endpoint/ExportEndpointUnitTest.java | 7 + .../endpoint/QueryEndpointUnitTest.java | 7 + .../endpoint/StoreEndpointUnitTest.java | 7 + .../endpoint/TableDataEndpointUnitTest.java | 7 + .../TableHistoryEndpointUnitTest.java | 7 + .../tuwien/endpoint/ViewEndpointUnitTest.java | 7 + .../RabbitMqListenerIntegrationTest.java | 54 ++- .../ViewIdxRepositoryIntegrationTest.java | 7 + .../ViewRepositoryIntegrationTest.java | 7 + .../ContainerServiceIntegrationTest.java | 7 + .../service/QueryServiceIntegrationTest.java | 11 +- .../service/QueueServiceIntegrationTest.java | 9 +- .../service/StoreServiceIntegrationTest.java | 7 + .../service/TableServiceIntegrationTest.java | 8 + .../tuwien/service/TableServiceUnitTest.java | 7 + .../service/ViewServiceIntegrationTest.java | 12 +- .../src/test/resources/application.properties | 8 +- .../test/resources/webserver/weather_aus.csv | 3 - .../tuwien/gateway/BrokerServiceGateway.java | 1 + .../impl/BrokerServiceGatewayImpl.java | 17 +- .../tuwien/listener/MessageQueueListener.java | 6 + .../listener/impl/RabbitMqListenerImpl.java | 2 +- .../at/tuwien/mapper/ContainerMapper.java | 15 + .../java/at/tuwien/mapper/ViewMapper.java | 2 +- .../java/at/tuwien/service/QueryService.java | 2 +- .../tuwien/service/impl/QueryServiceImpl.java | 49 +-- .../src/test/java/at/tuwien/BaseUnitTest.java | 20 +- .../java/at/tuwien/config/GatewayConfig.java | 2 +- .../MessageQueueServiceIntegrationTest.java | 4 +- .../service/TableServiceIntegrationTest.java | 4 +- .../test/java/at/tuwien/utils/AmqpUtils.java | 4 +- fda-ui/.gitignore | 4 +- fda-ui/.nycrc | 2 +- fda-ui/.prod/default.conf | 30 -- fda-ui/.prod/secure.conf | 38 -- fda-ui/Dockerfile | 11 +- fda-ui/components/DatabaseList.vue | 192 +++++++++ fda-ui/components/QueryList.vue | 77 ++-- fda-ui/components/TableList.vue | 30 +- fda-ui/components/TableToolbar.vue | 2 +- fda-ui/components/ViewList.vue | 8 +- fda-ui/components/dialogs/Persist.vue | 14 + fda-ui/components/query/Builder.vue | 4 - fda-ui/layouts/default.vue | 22 +- fda-ui/package.json | 8 +- .../database/_database_id/info.vue | 54 +-- .../_database_id/query/_query_id/index.vue | 3 + .../database/_database_id/settings.vue | 2 +- .../_database_id/table/_table_id/data.vue | 2 +- .../_database_id/table/_table_id/info.vue | 82 ++-- .../_database_id/table/_table_id/schema.vue | 4 +- fda-ui/pages/container/index.vue | 208 +-------- fda-ui/pages/forgot.vue | 3 + fda-ui/pages/login.vue | 3 + fda-ui/pages/search/index.vue | 19 +- fda-ui/pages/signup.vue | 7 + fda-ui/test/e2e/database.js | 69 +-- fda-ui/test/e2e/forgot.js | 18 + fda-ui/test/e2e/index.js | 47 +- fda-ui/test/e2e/login.js | 18 + fda-ui/test/e2e/search.js | 28 ++ fda-ui/test/e2e/signup.js | 21 + fda-ui/test/e2e/tables.js | 62 --- fda-ui/test/unit/query.js | 20 +- fda-ui/test/unit/utils.js | 279 ++++++++++++ fda-ui/utils/index.js | 24 +- fda-ui/yarn.lock | 28 ++ 124 files changed, 1773 insertions(+), 2246 deletions(-) delete mode 100755 .dbrepo2/deploy delete mode 100644 .dbrepo2/known_hosts delete mode 100755 .fda-deployment/clean delete mode 100755 .fda-deployment/clean-tmp delete mode 100644 .fda-deployment/crontab delete mode 100755 .fda-deployment/fda-authentication-service/install_cert delete mode 100755 .fda-deployment/fda-authentication-service/install_smtp delete mode 100755 .fda-deployment/fda-ui/install_cert delete mode 100644 .fda-deployment/hosts delete mode 100755 .gitlab/jacoco2cobertura.py delete mode 100644 .gitlab/tests/test_containers.py delete mode 100644 .gitlab/tests/test_query.py create mode 100644 .junit/hosts rename {.dbrepo2 => .junit}/teardown (100%) create mode 100644 fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java create mode 100644 fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java create mode 100644 fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java delete mode 100644 fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv create mode 100644 fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java delete mode 100644 fda-ui/.prod/default.conf delete mode 100644 fda-ui/.prod/secure.conf create mode 100644 fda-ui/components/DatabaseList.vue create mode 100644 fda-ui/test/e2e/forgot.js create mode 100644 fda-ui/test/e2e/login.js create mode 100644 fda-ui/test/e2e/search.js create mode 100644 fda-ui/test/e2e/signup.js delete mode 100644 fda-ui/test/e2e/tables.js create mode 100644 fda-ui/test/unit/utils.js diff --git a/.dbrepo2/deploy b/.dbrepo2/deploy deleted file mode 100755 index 2cda49aec7..0000000000 --- a/.dbrepo2/deploy +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# set version -TAG=latest - -# tear everything down -echo "Removing all data ..." -/bin/bash teardown -docker system prune -f --volumes || true - -echo "Pulling new images ..." -docker pull "dbrepo/analyse-service:${TAG}" -docker pull "dbrepo/authentication-service:${TAG}" -docker pull "dbrepo/metadata-db:${TAG}" -docker pull "dbrepo/ui:${TAG}" -docker pull "dbrepo/ui-proxy:${TAG}" -docker pull "dbrepo/identifier-service:${TAG}" -docker pull "dbrepo/container-service:${TAG}" -docker pull "dbrepo/database-service:${TAG}" -docker pull "dbrepo/discovery-service:${TAG}" -docker pull "dbrepo/gateway-service:${TAG}" -docker pull "dbrepo/query-service:${TAG}" -docker pull "dbrepo/table-service:${TAG}" -docker pull "dbrepo/units-service:${TAG}" -docker pull "dbrepo/broker-service:${TAG}" -docker pull "dbrepo/metadata-service:${TAG}" -echo "Pulled new images" - -# deploy dbrepo -echo "Deploy DBRepo ..." -docker compose -f ./docker-compose.dbrepo2.yml up -d - -# clone tuw specific deployment -git -C "/home/demo/dbrepo-tuw" pull || git clone ssh://git@gitlab.tuwien.ac.at:822/martin.weise/dbrepo-tuw.git "/home/demo/dbrepo-tuw" -cd /home/demo/dbrepo-tuw && git checkout dev - -# build tuw specific deployment -docker compose -f /home/demo/dbrepo-tuw/docker-compose.dbrepo2.yml build || exit 3 -docker compose -f /home/demo/dbrepo-tuw/docker-compose.dbrepo2.yml up -d || exit 4 -echo "Deployed TU Wien specific deployment" \ No newline at end of file diff --git a/.dbrepo2/known_hosts b/.dbrepo2/known_hosts deleted file mode 100644 index d17a72e2de..0000000000 --- a/.dbrepo2/known_hosts +++ /dev/null @@ -1,6 +0,0 @@ -gitlab.tuwien.ac.at ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKslN24njaMeH0xyVBO/lzeQ5/X/6UFkiz2qdcWihjT28slO/6pFBAxSzPUTBeVJWxKJgX9N+Hm65S9/Z2521E8Y9F56dcrOgeQBZ4GbLPSbEZIFN/71VL4cOh6tLahNZsAwd6y2Zi5XTAqho31VWfdCZkegZB3dNzLfOuC0t3KpxEAmWus5j8InNYDTBIy6U351/3h3oy32EdLvLpaHP+oy+QFAqXOlcXlKwHTfv9SSchQRLfWzrL4hVvohbCwMDBBvIP8J0WQ9mV95xfcwuipMWP3TksDGbst2MQ6HRXZ+yfie9Vgzg+++AjpHXQCMdalEmedNxCmxbHWYJxFHUV -gitlab.tuwien.ac.at ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC+2QClFaM3ZNQ6nl3nHkZdFSyNP26uHPzJEUBu9J4yC1ON9GPHb2P3rC//wS819e3LWP4PXb8ug/EyEjWN30MA= -gitlab.tuwien.ac.at ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILTzOKU3zEYNo1xy8rxZsa8D0/y4EN4oB0E7wgWCkOpZ -dbrepo2.ec.tuwien.ac.at ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC5GFfX4xmYeQdQQL81heBjKb4d1M8xjOjF4lpfNmc3/wyCPtP/dt4r3nkcOW3X14yPximy8BlArsPk4ul14BWNI9yrU5VA1FLlWq9Og6SfMJ1EAUNsePDd3qCpr/ljlydS3kWCVrXD1bNO0kQ3/36e9l64BDvZXyhI3n9DvkPO93n9xJ151IC9IwjnSzJQPghboUDRiYwT2B9wt+uC+k7tTV5tQH5kJk8fEa8nMyHOc8aD2miHubrcQJrYO/fv+vVxVWJKtSdz22wuvFnj8SfGClxbT8cfMo8X+LpIQOH8VYwIZVznuSlnNYOOYO6EGYyRnqud6oz0B5RUbwyeBhtAgZW1C1OXO9DVDLnazzFxJIzwhwyZCPurpLpP7bd6P+oFWy1A7bxIhfvdduEDE80vEOPrBl44TDe6RJR6QILtdUn9rrvcV/kgfj04zkQJjqMvX2pdCpdMIU1Pm+NQ53k3oOap7j9UHnpWX7C3mk76ueQddQxWZUhGsrFUAYSJfus= -dbrepo2.ec.tuwien.ac.at ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOGTeKw2aKnykIUmvLiBNaGbq3xlSEsnD1M1HiZsPJ9ZtfSV12y9F0yutV4j68Rb+eHbyOxoyVekfl19ODDvXLM= -dbrepo2.ec.tuwien.ac.at ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPpSoshRRtQBj4ebWeaWoeGr1XFIlx3L+BXV69fafBGr \ No newline at end of file diff --git a/.fda-deployment/clean b/.fda-deployment/clean deleted file mode 100755 index 03506fc6ef..0000000000 --- a/.fda-deployment/clean +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -docker container stop $(docker container ls -aq) || true -docker container rm $(docker container ls -aq) || true -docker volume rm $(docker volume ls -q) || true diff --git a/.fda-deployment/clean-tmp b/.fda-deployment/clean-tmp deleted file mode 100755 index ac34df7e9c..0000000000 --- a/.fda-deployment/clean-tmp +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -FILES=$(cd /tmp && find -exec basename '{}' ';' 2>/dev/null | egrep '^.{32}$' | egrep "^([a-z0-9]+)$") -for file in $FILES; do - rm -f /tmp/$file - echo "Removed /tmp/${file}" -done \ No newline at end of file diff --git a/.fda-deployment/crontab b/.fda-deployment/crontab deleted file mode 100644 index bbc97b1a42..0000000000 --- a/.fda-deployment/crontab +++ /dev/null @@ -1,2 +0,0 @@ -0 2 * * * /usr/bin/make -C /home/rocky/fda-services teardown -1 2 * * * /usr/bin/make -C /home/rocky/fda-services run \ No newline at end of file diff --git a/.fda-deployment/fda-authentication-service/install_cert b/.fda-deployment/fda-authentication-service/install_cert deleted file mode 100755 index f52db602f4..0000000000 --- a/.fda-deployment/fda-authentication-service/install_cert +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -TMP_CERT_LOCATION="/root/keys" -TMP_SAML_LOCATION="/root/keys" -KEY_STORE_LOCATION="/tmp/dbrepo.jks" -KEY_STORE_PASS="dbrepo" -CERT_LOCATION="/etc/letsencrypt/live/dbrepo.ossdip.at" -SAML_KEY="/root/keys/saml_sign.key" -SAML_PUB="/root/keys/saml_sign.cer" -TU_SAML_CERT="./fda-authentication-service/rest-service/src/main/resources/saml/tu.crt" - -# PLACE -sudo mkdir -p "${TMP_CERT_LOCATION}" -sudo mkdir -p "${TMP_SAML_LOCATION}" - -# REQUEST -sudo certbot certonly --standalone --preferred-challenges http -d dbrepo.ossdip.at \ - -m martin.weise@tuwien.ac.at --agree-tos --keep-until-expiring - -# CONVERT PKCS12 -sudo openssl pkcs12 -export -out "${TMP_SAML_LOCATION}/saml.p12" -in "${SAML_PUB}" \ - -inkey "${SAML_KEY}" -passout "pass:${KEY_STORE_PASS}" - -# CONVERT PKCS12 -sudo openssl pkcs12 -export -out "${TMP_CERT_LOCATION}/cert.p12" -in "${CERT_LOCATION}/cert.pem" \ - -inkey "${CERT_LOCATION}/privkey.pem" -passout "pass:${KEY_STORE_PASS}" - -# FIX PERMISSIONS -sudo chmod -R 644 "${TMP_CERT_LOCATION}" -sudo chmod -R 644 "${TMP_SAML_LOCATION}" - -# IMPORT SSL SIGN PRIVKEY -sudo keytool -noprompt -importkeystore -deststorepass "${KEY_STORE_PASS}" -destkeypass "${KEY_STORE_PASS}" \ - -destkeystore "${KEY_STORE_LOCATION}" -srckeystore "${TMP_CERT_LOCATION}/cert.p12" -srcstoretype PKCS12 \ - -srcstorepass "${KEY_STORE_PASS}" -alias 1 -destalias ssl - -# IMPORT SAML MESSAGE SIGN PRIVKEY -sudo keytool -noprompt -importkeystore -deststorepass "${KEY_STORE_PASS}" -destkeypass "${KEY_STORE_PASS}" \ - -destkeystore "${KEY_STORE_LOCATION}" -srckeystore "${TMP_SAML_LOCATION}" -srcstoretype PKCS12 \ - -srcstorepass "${KEY_STORE_PASS}" -alias 1 -destalias saml - -# IMPORT METADATA VERIFICATION PUBKEY -sudo keytool -noprompt -importcert -file "${TU_SAML_CERT}" -storepass "${KEY_STORE_PASS}" \ - -keystore "${KEY_STORE_LOCATION}" -alias tu - -# OWNERSHIP -sudo chown centos:docker "${TMP_CERT_LOCATION}" -sudo chown centos:docker "${TMP_SAML_LOCATION}" -sudo chown centos:docker "${KEY_STORE_LOCATION}" - -# TRUST LET'S ENCRYPT -sudo keytool -noprompt -import -alias letsencrypt -keystore "${KEY_STORE_LOCATION}" -storepass "${KEY_STORE_PASS}" \ - -file "${CERT_LOCATION}/chain.pem" diff --git a/.fda-deployment/fda-authentication-service/install_smtp b/.fda-deployment/fda-authentication-service/install_smtp deleted file mode 100755 index 22b0afaa76..0000000000 --- a/.fda-deployment/fda-authentication-service/install_smtp +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -sudo cat /root/smtp.secret >> ./.env diff --git a/.fda-deployment/fda-ui/install_cert b/.fda-deployment/fda-ui/install_cert deleted file mode 100755 index 9255312371..0000000000 --- a/.fda-deployment/fda-ui/install_cert +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -CA_PATH="/etc/letsencrypt/live/dbrepo.ossdip.at" - -sudo certbot certonly --standalone --preferred-challenges http -d dbrepo.ossdip.at --agree-tos --keep-until-expiring - -KEY=$(sudo sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' "${CA_PATH}/privkey.pem") -CERT=$(sudo sed -E ':a;N;$!ba;s/\r{0,1}\n/\\n/g' "${CA_PATH}/cert.pem") - -cat << EOF -UI_KEY="${KEY}" -UI_CERT="${CERT}" -EOF \ No newline at end of file diff --git a/.fda-deployment/hosts b/.fda-deployment/hosts deleted file mode 100644 index 40da214c6a..0000000000 --- a/.fda-deployment/hosts +++ /dev/null @@ -1,7 +0,0 @@ -# FDA USERDB -172.28.0.2 fda-userdb-weather-aus -172.28.0.3 fda-userdb-infection -172.28.0.4 fda-userdb-air -172.28.0.5 fda-userdb-u01 -172.28.0.6 fda-userdb-u02 -172.28.0.7 fda-userdb-u03 \ No newline at end of file diff --git a/.gitignore b/.gitignore index e372ff156b..ae9e683f84 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/ - +dbrepo-* # Notebooks .jupyter/ .pytest_cache/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c18ce65e3b..1967e4afea 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,6 @@ before_script: - "mvn --version" - "python3 --version" - "df / -h" - - "grep -rnw '@Test' | wc -l" variables: HOSTALIASES: ./hosts @@ -23,76 +22,77 @@ stages: - build-backend - build-frontend - test-backend + - test-frontend - build-docker - release -build-backend-metadata-db: +build-metadata-db: stage: build-backend script: - - "make build-backend-metadata-db" + - "make build-metadata-db" -build-backend-authentication: +build-authentication-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-authentication" + - "make build-authentication-service" -build-backend-identifier: +build-identifier-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-identifier" + - "make build-identifier-service" -build-backend-container: +build-container-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-container" + - "make build-container-service" -build-backend-database: +build-database-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-database" + - "make build-database-service" -build-backend-discovery: +build-discovery-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-discovery" + - "make build-discovery-service" -build-backend-gateway: +build-gateway-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-gateway" + - "make build-gateway-service" -build-backend-query: +build-query-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-query" + - "make build-query-service" -build-backend-table: +build-table-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-table" + - "make build-table-service" -build-backend-metadata: +build-metadata-service: stage: build-backend needs: - - build-backend-metadata-db + - build-metadata-db script: - - "make build-backend-metadata" + - "make build-metadata-service" build-semantics-service: stage: build-backend @@ -107,7 +107,7 @@ build-analyse-service: test-backend-authentication: stage: test-backend needs: - - build-backend-authentication + - build-authentication-service script: - "make test-authentication-service" - "cat ./fda-authentication-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -120,10 +120,11 @@ test-backend-authentication: reports: junit: ./fda-authentication-service/rest-service/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' -test-backend-identifier: + +test-identifier-service: stage: test-backend needs: - - build-backend-authentication + - build-authentication-service script: - "make test-identifier-service" - "cat ./fda-identifier-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -137,10 +138,10 @@ test-backend-identifier: junit: ./fda-identifier-service/rest-service/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' -test-backend-container: +test-container-service: stage: test-backend needs: - - build-backend-container + - build-container-service script: - "make test-container-service" - "cat ./fda-container-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -154,10 +155,10 @@ test-backend-container: junit: ./fda-container-service/rest-service/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' -test-backend-database: +test-database-service: stage: test-backend needs: - - build-backend-database + - build-database-service script: - "docker pull elasticsearch:7.13.4" - "make test-database-service" @@ -171,11 +172,12 @@ test-backend-database: reports: junit: ./fda-database-service/rest-service/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' + timeout: 2 hour -test-backend-discovery: +test-discovery-service: stage: test-backend needs: - - build-backend-discovery + - build-discovery-service script: - "make test-discovery-service" - "cat ./fda-discovery-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -189,10 +191,10 @@ test-backend-discovery: junit: ./fda-discovery-service/discovery/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' -test-backend-query: +test-query-service: stage: test-backend needs: - - build-backend-query + - build-query-service script: - "make test-query-service" - "cat ./fda-query-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -205,11 +207,12 @@ test-backend-query: reports: junit: ./fda-query-service/rest-service/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' + timeout: 2 hour -test-backend-table: +test-table-service: stage: test-backend needs: - - build-backend-table + - build-table-service script: - "make test-table-service" - "cat ./fda-table-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -223,10 +226,10 @@ test-backend-table: junit: ./fda-table-service/rest-service/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' -test-backend-metadata: +test-metadata-service: stage: test-backend needs: - - build-backend-metadata + - build-metadata-service script: - "make test-metadata-service" - "cat ./fda-metadata-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -240,10 +243,10 @@ test-backend-metadata: junit: ./fda-metadata-service/rest-service/target/surefire-reports/TEST-*.xml coverage: '/Total.*?([0-9]{1,3})%/' -test-backend-gateway: +test-gateway-service: stage: test-backend needs: - - build-backend-gateway + - build-gateway-service script: - "make test-gateway-service" - "cat ./fda-gateway-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" @@ -289,19 +292,35 @@ test-analyse-service: junit: ./fda-analyse-service/report.xml coverage: '/TOTAL.*?([0-9]{1,3})%/' +test-frontend: + stage: test-frontend + needs: + - build-frontend + script: + - "make test-frontend" + - "cat ./fda-ui/coverage.txt | grep -o 'Lines[^%]*%'" + artifacts: + when: always + paths: + - ./fda-analyse-service/report.xml + expire_in: 1 days + reports: + junit: ./fda-analyse-service/report.xml + coverage: '/TOTAL.*?([0-9]{1,3})%/' + build-docker: stage: build-docker needs: - - build-backend-metadata-db - - build-backend-authentication - - build-backend-identifier - - build-backend-container - - build-backend-database - - build-backend-discovery - - build-backend-gateway - - build-backend-query - - build-backend-table - - build-backend-metadata + - build-metadata-db + - build-authentication-service + - build-identifier-service + - build-container-service + - build-database-service + - build-discovery-service + - build-gateway-service + - build-query-service + - build-table-service + - build-metadata-service - build-semantics-service - build-analyse-service script: diff --git a/.gitlab/jacoco2cobertura.py b/.gitlab/jacoco2cobertura.py deleted file mode 100755 index 76ad75a705..0000000000 --- a/.gitlab/jacoco2cobertura.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python3 -import sys -import xml.etree.ElementTree as ET -import re -import os.path - -# branch-rate="0.0" complexity="0.0" line-rate="1.0" -# branch="true" hits="1" number="86" - -def find_lines(j_package, filename): - """Return all <line> elements for a given source file in a package.""" - lines = list() - sourcefiles = j_package.findall("sourcefile") - for sourcefile in sourcefiles: - if sourcefile.attrib.get("name") == os.path.basename(filename): - lines = lines + sourcefile.findall("line") - return lines - -def line_is_after(jm, start_line): - return int(jm.attrib.get('line', 0)) > start_line - -def method_lines(jmethod, jmethods, jlines): - """Filter the lines from the given set of jlines that apply to the given jmethod.""" - start_line = int(jmethod.attrib.get('line', 0)) - larger = list(int(jm.attrib.get('line', 0)) for jm in jmethods if line_is_after(jm, start_line)) - end_line = min(larger) if len(larger) else 99999999 - - for jline in jlines: - if start_line <= int(jline.attrib['nr']) < end_line: - yield jline - -def convert_lines(j_lines, into): - """Convert the JaCoCo <line> elements into Cobertura <line> elements, add them under the given element.""" - c_lines = ET.SubElement(into, 'lines') - for jline in j_lines: - mb = int(jline.attrib['mb']) - cb = int(jline.attrib['cb']) - ci = int(jline.attrib['ci']) - - cline = ET.SubElement(c_lines, 'line') - cline.set('number', jline.attrib['nr']) - cline.set('hits', '1' if ci > 0 else '0') # Probably not true but no way to know from JaCoCo XML file - - if mb + cb > 0: - percentage = str(int(100 * (float(cb) / (float(cb) + float(mb))))) + '%' - cline.set('branch', 'true') - cline.set('condition-coverage', percentage + ' (' + str(cb) + '/' + str(cb + mb) + ')') - - cond = ET.SubElement(ET.SubElement(cline, 'conditions'), 'condition') - cond.set('number', '0') - cond.set('type', 'jump') - cond.set('coverage', percentage) - else: - cline.set('branch', 'false') - -def guess_filename(path_to_class): - m = re.match('([^$]*)', path_to_class) - return (m.group(1) if m else path_to_class) + '.java' - -def add_counters(source, target): - target.set('line-rate', counter(source, 'LINE')) - target.set('branch-rate', counter(source, 'BRANCH')) - target.set('complexity', counter(source, 'COMPLEXITY', sum)) - -def fraction(covered, missed): - return covered / (covered + missed) - -def sum(covered, missed): - return covered + missed - -def counter(source, type, operation=fraction): - cs = source.findall('counter') - c = next((ct for ct in cs if ct.attrib.get('type') == type), None) - - if c is not None: - covered = float(c.attrib['covered']) - missed = float(c.attrib['missed']) - - return str(operation(covered, missed)) - else: - return '0.0' - -def convert_method(j_method, j_lines): - c_method = ET.Element('method') - c_method.set('name', j_method.attrib['name']) - c_method.set('signature', j_method.attrib['desc']) - - add_counters(j_method, c_method) - convert_lines(j_lines, c_method) - - return c_method - -def convert_class(j_class, j_package): - c_class = ET.Element('class') - c_class.set('name', j_class.attrib['name'].replace('/', '.')) - c_class.set('filename', guess_filename(j_class.attrib['name'])) - - all_j_lines = list(find_lines(j_package, c_class.attrib['filename'])) - - c_methods = ET.SubElement(c_class, 'methods') - all_j_methods = list(j_class.findall('method')) - for j_method in all_j_methods: - j_method_lines = method_lines(j_method, all_j_methods, all_j_lines) - c_methods.append(convert_method(j_method, j_method_lines)) - - add_counters(j_class, c_class) - convert_lines(all_j_lines, c_class) - - return c_class - -def convert_package(j_package): - c_package = ET.Element('package') - c_package.attrib['name'] = j_package.attrib['name'].replace('/', '.') - - c_classes = ET.SubElement(c_package, 'classes') - for j_class in j_package.findall('class'): - c_classes.append(convert_class(j_class, j_package)) - - add_counters(j_package, c_package) - - return c_package - -def convert_root(source, target, source_roots): - target.set('timestamp', str(int(source.find('sessioninfo').attrib['start']) / 1000)) - - sources = ET.SubElement(target, 'sources') - for s in source_roots: - ET.SubElement(sources, 'source').text = s - - packages = ET.SubElement(target, 'packages') - for package in source.findall('package'): - packages.append(convert_package(package)) - - add_counters(source, target) - -def jacoco2cobertura(filename, source_roots): - if filename == '-': - root = ET.fromstring(sys.stdin.read()) - else: - tree = ET.parse(filename) - root = tree.getroot() - - into = ET.Element('coverage') - convert_root(root, into, source_roots) - print(ET.tostring(into, encoding='utf8', method='xml').decode("utf-8")) - -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Usage: cover2cover.py FILENAME [SOURCE_ROOTS]") - sys.exit(1) - - filename = sys.argv[1] - source_roots = sys.argv[2:] if 2 < len(sys.argv) else '.' - - jacoco2cobertura(filename, source_roots) \ No newline at end of file diff --git a/.gitlab/tests/test_containers.py b/.gitlab/tests/test_containers.py deleted file mode 100644 index dd4e1a97cc..0000000000 --- a/.gitlab/tests/test_containers.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/env python3 -from api_container.api.container_endpoint_api import ContainerEndpointApi -from api_database.api.database_endpoint_api import DatabaseEndpointApi -import time - -container = ContainerEndpointApi() -database = DatabaseEndpointApi() - -def create_container(): - response = container.create1({ - "name": "Pilot Factory Data", - "repository": "mariadb", - "tag": "10.5" - }) - print("created container with id %d" % response.id) - return response - - -def start_container(container_id): - response = container.modify({ - "action": "start" - }, container_id) - print("... starting") - time.sleep(5) - print("started container with id %d" % response.id) - return response - - -def create_database(container_id, is_public=True): - response = database.create({ - "name": "Pilot Factory Data", - "is_public": is_public - }, container_id) - print("created database with id %d" % response.id) - return response - -token = "" # keep - -from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi -from api_authentication.api.user_endpoint_api import UserEndpointApi -import uuid - -authentication = AuthenticationEndpointApi() -user = UserEndpointApi() - -def create_user(username): - response = user.register({ - "username": username, - "password": username, - "email": username + "@gmail.com" - }) - print("created user with id %d" % response.id) - return response - - -def auth_user(username): - response = authentication.authenticate_user1({ - "username": username, - "password": username - }) - print("authenticated user with id %d" % response.id) - token = response.token - container.api_client.default_headers = {"Authorization": "Bearer " + token} - database.api_client.default_headers = {"Authorization": "Bearer " + token} - return response - - -def find_database(container_id, database_id): - response = database.find_by_id(container_id, database_id) - print("found database with id %d" % response.id) - return response - - -def update_database(container_id, database_id): - response = database.update({ - "description": "This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).", - "publisher": "Technical University of Vienna", - "license": { - "identifier": "CC0-1.0", - "uri": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" - }, - "language": "en", - "publication_year": 2022 - }, container_id, database_id) - print("updated database with id %d" % response.id) - return response - - -def test_containers(): - username = str(uuid.uuid1()).replace("-", "") - uid = create_user(username).id - auth_user(username) - # container 1 - cid = create_container().id - start_container(cid) - dbid = create_database(cid).id - update_database(cid, dbid) diff --git a/.gitlab/tests/test_query.py b/.gitlab/tests/test_query.py deleted file mode 100644 index 283f311b65..0000000000 --- a/.gitlab/tests/test_query.py +++ /dev/null @@ -1,284 +0,0 @@ -#!/bin/env python3 - -import time -import os -import shutil -import uuid - -from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi -from api_authentication.api.user_endpoint_api import UserEndpointApi -from api_container.api.container_endpoint_api import ContainerEndpointApi -from api_database.api.database_endpoint_api import DatabaseEndpointApi -from api_table.api.table_endpoint_api import TableEndpointApi -from api_query.api.table_data_endpoint_api import TableDataEndpointApi -from api_query.api.query_endpoint_api import QueryEndpointApi -from api_query.api.table_history_endpoint_api import TableHistoryEndpointApi -from api_identifier.api.identifier_endpoint_api import IdentifierEndpointApi -from api_identifier.api.persistence_endpoint_api import PersistenceEndpointApi -from api_query.api.view_endpoint_api import ViewEndpointApi -from api_query.rest import ApiException - -authentication = AuthenticationEndpointApi() -user = UserEndpointApi() -container = ContainerEndpointApi() -database = DatabaseEndpointApi() -table = TableEndpointApi() -query = QueryEndpointApi() -history = TableHistoryEndpointApi() -data = TableDataEndpointApi() -identifier = IdentifierEndpointApi() -persistence = PersistenceEndpointApi() -view = ViewEndpointApi() - -token = "" # keep - - -def create_user(username): - response = user.register({ - "username": username, - "password": username, - "email": username + "@gmail.com" - }) - print("created user with id %d" % response.id) - return response - - -def update_password(user_id, password): - response = user.update_password({ - "password": password - }, user_id) - print("updated password for user with id %d" % user_id) - return response - - -def auth_user(username): - response = authentication.authenticate_user1({ - "username": username, - "password": username - }) - print("authenticated user with id %d" % response.id) - token = response.token - container.api_client.default_headers = {"Authorization": "Bearer " + token} - database.api_client.default_headers = {"Authorization": "Bearer " + token} - table.api_client.default_headers = {"Authorization": "Bearer " + token} - data.api_client.default_headers = {"Authorization": "Bearer " + token} - query.api_client.default_headers = {"Authorization": "Bearer " + token} - identifier.api_client.default_headers = {"Authorization": "Bearer " + token} - user.api_client.default_headers = {"Authorization": "Bearer " + token} - persistence.api_client.default_headers = {"Authorization": "Bearer " + token} - history.api_client.default_headers = {"Authorization": "Bearer " + token} - view.api_client.default_headers = {"Authorization": "Bearer " + token} - return response - - -def create_container(): - response = container.create1({ - "name": "Pilot Factory Data", - "repository": "mariadb", - "tag": "10.5" - }) - print("created container with id %d" % response.id) - return response - - -def start_container(container_id): - response = container.modify({ - "action": "start" - }, container_id) - print("... starting") - time.sleep(5) - print("started container with id %d" % response.id) - return response - - -def create_database(container_id, is_public=True): - response = database.create({ - "name": "Pilot Factory Data", - "is_public": is_public - }, container_id) - print("created database with id %d" % response.id) - return response - - -def find_database(container_id, database_id): - response = database.find_by_id(container_id, database_id) - print("found database with id %d" % response.id) - return response - - -def update_database(container_id, database_id): - response = database.update({ - "description": "This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).", - "publisher": "Technical University of Vienna", - "license": { - "identifier": "CC0-1.0", - "uri": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" - }, - "language": "en", - "publication_year": 2022 - }, container_id, database_id) - print("updated database with id %d" % response.id) - return response - - -def create_table(container_id, database_id, columns=None): - if columns is None: - columns = [{ - "name": "Date", - "type": "date", - "dfid": 1, - "unique": False, - "primary_key": False, - "null_allowed": True, - }, { - "name": "Location", - "type": "string", - "unique": False, - "primary_key": False, - "null_allowed": True, - }, { - "name": "Parameter", - "type": "string", - "unique": False, - "primary_key": False, - "null_allowed": True, - }, { - "name": "Interval", - "type": "string", - "unique": False, - "primary_key": False, - "null_allowed": True, - }, { - "name": "Unit", - "type": "string", - "unique": False, - "primary_key": False, - "null_allowed": True, - }, { - "name": "Value", - "type": "decimal", - "unique": False, - "primary_key": False, - "null_allowed": True, - }, { - "name": "Status", - "type": "string", - "unique": False, - "primary_key": False, - "null_allowed": True, - }] - response = table.create({ - "name": "Airquality " + str(uuid.uuid1()), - "description": "Airquality in Zürich, Switzerland", - "columns": columns - }, "Bearer " + token, container_id, database_id) - print("created table with id %d" % response.id) - return response - - -def find_table(container_id, database_id, table_id): - response = table.find_by_id(container_id, database_id, table_id) - print("found table with id %d" % response.id) - return response - - -def fill_table(container_id, database_id, table_id): - response = data.import_csv({ - "location": "/path/to/data.csv", - "quote": "\"", - "null_element": "NA" - "separator": ",", - }, container_id, database_id, table_id) - print("filled table with id %d" % table_id) - return response - - -def create_query(container_id, database_id, statement, page=0, size=3): - response = query.execute({ - "statement": statement - }, container_id, database_id, page=page, size=size) - print("executed query with id %d" % response.id) - return response - - -def delete_tuple(container_id, database_id, table_id, keys): - response = data.delete(keys, container_id, database_id, table_id) - print("deleted tuples for table with id %d" % table_id) - return response - - -def download_query_data(container_id, database_id, query_id): - response = query.export1(container_id, database_id, query_id) - print("downloaded query data for query with id %d" % query_id) - return response - - -def list_views(container_id, database_id): - response = view.find_all(container_id, database_id) - print("list views for database with id %d" % database_id) - return response - - -def create_view(container_id, database_id, table_name): - response = view.create({ - "name": "Air Quality " + str(uuid.uuid1()), - "query": "SELECT `date`, `parameter`, `value` FROM `" + table_name + "` WHERE `date` = '2021-10-02T14:00'", - "is_public": True - }, container_id, database_id) - print("created view with id %d" % response.id) - return response - - -def data_view(container_id, database_id, view_id): - response = view.data(container_id, database_id, view_id) - print("retrieved data for view with id %d" % response.id) - return response - - -def test_identifiers(): - # - # create 1 user and 2 containers (public, private) - # - username = str(uuid.uuid1()).replace("-", "") - uid = create_user(username).id - auth_user(username) - # container 1 - cid = create_container().id - start_container(cid) - dbid = create_database(cid).id - update_database(cid, dbid) - tid = create_table(cid, dbid).id - tname = find_table(cid, dbid, tid).internal_name - fill_table(cid, dbid, tid) - create_query(cid, dbid, "select `id` from `" + tname + "`") - create_query(cid, dbid, "select `date` from `" + tname + "`") - qid = create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "`").id - create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "` order by `date` asc") - create_query(cid, dbid, "select t.`date`, t.location, t.status from `" + tname + "` t group by t.`date` order by t.`date` asc") - create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "` group by `date`, `location` asc") - download_query_data(cid, dbid, qid) - # container 2 (=private) - cid = create_container().id - start_container(cid) - dbid = create_database(cid, False).id - update_database(cid, dbid) - tid = create_table(cid, dbid).id - tname = find_table(cid, dbid, tid).internal_name - fill_table(cid, dbid, tid) - qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id - qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id - vid = create_view(cid, dbid, tname).id - data_view(cid, dbid, vid) - list_views(cid, dbid) - for i in range(5, 10): - delete_tuple(cid, dbid, tid, { - "keys": { - "id": i - } - }) - time.sleep(1) - delete_tuple(cid, dbid, tid, { - "keys": { - "location": "Schimmelstrasse" - } - }) diff --git a/.junit/hosts b/.junit/hosts new file mode 100644 index 0000000000..701ef56fa3 --- /dev/null +++ b/.junit/hosts @@ -0,0 +1,10 @@ +########################################################### +# PLACE IN /etc/hosts # +########################################################### + +172.30.0.5 dbrepo-userdb-u01 +172.30.0.6 dbrepo-userdb-u02 +172.30.0.7 dbrepo-userdb-u03 +172.30.0.8 dbrepo-userdb-u04 +172.31.0.2 dbrepo-broker-service +172.31.0.3 dbrepo-search-service \ No newline at end of file diff --git a/.dbrepo2/teardown b/.junit/teardown similarity index 100% rename from .dbrepo2/teardown rename to .junit/teardown diff --git a/Makefile b/Makefile index ec1921ff29..a5bce8de2e 100644 --- a/Makefile +++ b/Makefile @@ -4,39 +4,36 @@ TAG ?= latest all: -clean: - bash ./.dbrepo2/clean.sh - -build-backend: build-backend-metadata-db build-backend-database build-backend-query build-backend-table build-backend-identifier build-backend-authentication build-backend-container build-backend-discovery build-backend-gateway build-backend-metadata build-analyse-service +build-backend: build-metadata-db build-database-service build-query-service build-table-service build-identifier-service build-authentication-service build-container-service build-discovery-service build-gateway-service build-metadata-service build-analyse-service -build-backend-metadata-db: +build-metadata-db: mvn -f ./fda-metadata-db/pom.xml clean install -build-backend-authentication: build-backend-metadata-db +build-authentication-service: build-metadata-db mvn -f ./fda-authentication-service/pom.xml clean package -DskipTests -build-backend-identifier: build-backend-metadata-db +build-identifier-service: build-metadata-db mvn -f ./fda-identifier-service/pom.xml clean package -DskipTests -build-backend-table: build-backend-metadata-db +build-table-service: build-metadata-db mvn -f ./fda-table-service/pom.xml clean package -DskipTests -build-backend-container: build-backend-metadata-db +build-container-service: build-metadata-db mvn -f ./fda-container-service/pom.xml clean package -DskipTests -build-backend-database: build-backend-metadata-db +build-database-service: build-metadata-db mvn -f ./fda-database-service/pom.xml clean package -DskipTests -build-backend-discovery: build-backend-metadata-db +build-discovery-service: build-metadata-db mvn -f ./fda-discovery-service/pom.xml clean package -DskipTests -build-backend-gateway: build-backend-metadata-db +build-gateway-service: build-metadata-db mvn -f ./fda-gateway-service/pom.xml clean package -DskipTests -build-backend-query: build-backend-metadata-db +build-query-service: build-metadata-db mvn -f ./fda-query-service/pom.xml clean package -DskipTests -build-backend-metadata: build-backend-metadata-db +build-metadata-service: build-metadata-db mvn -f ./fda-metadata-service/pom.xml clean package -DskipTests build-semantics-service: @@ -150,93 +147,35 @@ release-search: release-metadata: docker push "dbrepo/metadata-service:${TAG}" -pull: pull-identifier pull-container pull-search pull-database pull-discovery pull-gateway pull-query pull-table pull-analyse pull-authentication pull-metadata-db pull-ui pull-units pull-broker pull-metadata - -pull-analyse: - docker pull "dbrepo/analyse-service:${TAG}" - -pull-authentication: - docker pull "dbrepo/authentication-service:${TAG}" - -pull-metadata-db: - docker pull "dbrepo/metadata-db:${TAG}" - -pull-ui: - docker pull "dbrepo/ui:${TAG}" - -pull-identifier: - docker pull "dbrepo/identifier-service:${TAG}" - -pull-container: - docker pull "dbrepo/container-service:${TAG}" - -pull-database: - docker pull "dbrepo/database-service:${TAG}" - -pull-discovery: - docker pull "dbrepo/discovery-service:${TAG}" - -pull-gateway: - docker pull "dbrepo/gateway-service:${TAG}" - -pull-query: - docker pull "dbrepo/query-service:${TAG}" - -pull-table: - docker pull "dbrepo/table-service:${TAG}" - -pull-units: - docker pull "dbrepo/semantics-service:${TAG}" - -pull-broker: - docker pull "dbrepo/broker-service:${TAG}" - -pull-metadata: - docker pull "dbrepo/metadata-service:${TAG}" - -pull-search: - docker pull "dbrepo/search-service:${TAG}" - test-backend: test-authentication-service test-container-service test-database-service test-discovery-service test-gateway-service test-query-service test-table-service test-identifier-service test-metadata-service test-semantics-service test-analyse-service -test-authentication-service: build-backend-metadata-db build-backend-authentication - docker system prune -f --volumes +test-authentication-service: clean build-metadata-db build-authentication-service docker pull rabbitmq:3-management-alpine mvn -f ./fda-authentication-service/pom.xml clean test verify -test-identifier-service: build-backend-metadata-db build-backend-identifier - docker system prune -f --volumes +test-identifier-service: clean build-metadata-db build-identifier-service mvn -f ./fda-identifier-service/pom.xml clean test verify -test-container-service: build-backend-metadata-db build-backend-container - docker system prune -f --volumes - docker pull mysql:8.0 +test-container-service: clean build-metadata-db build-container-service mvn -f ./fda-container-service/pom.xml clean test verify -test-database-service: build-backend-metadata-db build-backend-database - docker system prune -f --volumes +test-database-service: clean build-metadata-db build-database-service docker pull rabbitmq:3-management-alpine - docker pull nginx:alpine mvn -f ./fda-database-service/pom.xml clean test verify -test-discovery-service: build-backend-metadata-db build-backend-discovery - docker system prune -f --volumes +test-discovery-service: clean build-metadata-db build-discovery-service mvn -f ./fda-discovery-service/pom.xml clean test verify -test-gateway-service: build-backend-metadata-db build-backend-gateway - docker system prune -f --volumes +test-gateway-service: clean build-metadata-db build-gateway-service mvn -f ./fda-gateway-service/pom.xml clean test verify -test-query-service: build-backend-metadata-db build-backend-query - docker system prune -f --volumes +test-query-service: clean build-metadata-db build-query-service mvn -f ./fda-query-service/pom.xml clean test verify -test-table-service: build-backend-metadata-db build-backend-table - docker system prune -f --volumes +test-table-service: clean build-metadata-db build-table-service mvn -f ./fda-table-service/pom.xml clean test verify -test-metadata-service: build-backend-metadata-db build-backend-metadata - docker system prune -f --volumes +test-metadata-service: clean build-metadata-db build-metadata-service mvn -f ./fda-metadata-service/pom.xml clean test verify test-semantics-service: build-semantics-service @@ -245,13 +184,16 @@ test-semantics-service: build-semantics-service test-analyse-service: build-analyse-service bash ./fda-analyse-service/test.sh -coverage-frontend: clean build-frontend +coverage-frontend: build-frontend yarn --cwd ./fda-ui run coverage || true test-frontend: clean build-frontend yarn --cwd ./fda-ui install - docker compose up -d - yarn --cwd ./fda-ui run test + yarn --cwd ./fda-ui run test:unit || true + yarn --cwd ./fda-ui run coverage || true + +clean: + docker system prune -f --volumes test-clients: bash ./.gitlab/test.sh @@ -259,4 +201,4 @@ test-clients: test: test-backend test-frontend teardown: - ./.dbrepo2/teardown + ./.junit/teardown diff --git a/docker-compose.dbrepo1.yml b/docker-compose.dbrepo1.yml index dfd09f5097..01db36561d 100644 --- a/docker-compose.dbrepo1.yml +++ b/docker-compose.dbrepo1.yml @@ -31,7 +31,7 @@ networks: services: - metadata-db: + dbrepo-metadata-db: restart: on-failure container_name: dbrepo-metadata-db hostname: metadata-db @@ -60,7 +60,7 @@ services: logging: driver: json-file - gateway-service: + dbrepo-gateway-service: restart: on-failure container_name: dbrepo-gateway-service hostname: gateway-service @@ -72,12 +72,12 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy logging: driver: json-file - database-service: + dbrepo-database-service: restart: on-failure container_name: dbrepo-database-service hostname: database-service @@ -90,16 +90,16 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - container-service: + dbrepo-container-service: condition: service_healthy - broker-service: + dbrepo-broker-service: condition: service_started - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - container-service: + dbrepo-container-service: restart: on-failure container_name: dbrepo-container-service hostname: container-service @@ -111,12 +111,12 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - authentication-service: + dbrepo-authentication-service: restart: on-failure container_name: dbrepo-authentication-service hostname: authentication-service @@ -126,16 +126,16 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy - broker-service: + dbrepo-broker-service: condition: service_started - metadata-db: + dbrepo-metadata-db: condition: service_healthy logging: driver: json-file - query-service: + dbrepo-query-service: restart: on-failure container_name: dbrepo-query-service hostname: query-service @@ -148,14 +148,14 @@ services: volumes: - ${SHARED_FILESYSTEM}:/tmp depends_on: - table-service: + dbrepo-table-service: condition: service_healthy - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - table-service: + dbrepo-table-service: restart: on-failure container_name: dbrepo-table-service hostname: table-service @@ -169,16 +169,16 @@ services: - /var/run/docker.sock:/var/run/docker.sock - ${SHARED_FILESYSTEM}:/tmp depends_on: - authentication-service: + dbrepo-authentication-service: condition: service_healthy - search-service: + dbrepo-search-service: condition: service_started - broker-service: + dbrepo-broker-service: condition: service_started logging: driver: json-file - identifier-service: + dbrepo-identifier-service: restart: on-failure container_name: dbrepo-identifier-service hostname: identifier-service @@ -188,16 +188,16 @@ services: env_file: - .env depends_on: - query-service: + dbrepo-query-service: condition: service_healthy - authentication-service: + dbrepo-authentication-service: condition: service_healthy volumes: - ${SHARED_FILESYSTEM}:/tmp logging: driver: json-file - fda-metadata-service: + dbrepo-metadata-service: restart: on-failure container_name: dbrepo-metadata-service hostname: metadata-service @@ -207,12 +207,12 @@ services: env_file: - .env depends_on: - metadata-db: + dbrepo-metadata-db: condition: service_started logging: driver: json-file - analyse-service: + dbrepo-analyse-service: restart: on-failure container_name: dbrepo-analyse-service hostname: analyse-service @@ -226,12 +226,12 @@ services: - ${SHARED_FILESYSTEM}:/tmp - /var/run/docker.sock:/var/run/docker.sock depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy logging: driver: json-file - semantics-service: + dbrepo-semantics-service: restart: on-failure container_name: dbrepo-semantics-service hostname: semantics-service @@ -244,14 +244,14 @@ services: - ${SHARED_FILESYSTEM}:/tmp - /var/run/docker.sock:/var/run/docker.sock depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy - metadata-db: + dbrepo-metadata-db: condition: service_healthy logging: driver: json-file - broker-service: + dbrepo-broker-service: restart: on-failure container_name: dbrepo-broker-service hostname: broker-service @@ -264,14 +264,14 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy volumes: - broker-service-data:/var/lib/rabbitmq/ logging: driver: json-file - search-service: + dbrepo-search-service: restart: always container_name: dbrepo-search-service hostname: search-service @@ -279,7 +279,7 @@ services: networks: core: depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy ports: - 9200:9200 @@ -290,7 +290,7 @@ services: logging: driver: json-file - ui: + dbrepo-ui: restart: on-failure container_name: dbrepo-ui hostname: ui @@ -303,9 +303,9 @@ services: volumes: - ${SHARED_FILESYSTEM}:/tmp depends_on: - identifier-service: + dbrepo-identifier-service: condition: service_healthy - database-service: + dbrepo-database-service: condition: service_healthy logging: driver: json-file diff --git a/docker-compose.dbrepo2.yml b/docker-compose.dbrepo2.yml index dbd34f265e..7c169dd1ce 100644 --- a/docker-compose.dbrepo2.yml +++ b/docker-compose.dbrepo2.yml @@ -31,7 +31,7 @@ networks: services: - metadata-db: + dbrepo-metadata-db: restart: on-failure container_name: dbrepo-metadata-db hostname: metadata-db @@ -48,7 +48,7 @@ services: logging: driver: json-file - discovery-service: + dbrepo-discovery-service: restart: on-failure container_name: dbrepo-discovery-service hostname: discovery-service @@ -60,7 +60,7 @@ services: logging: driver: json-file - gateway-service: + dbrepo-gateway-service: restart: on-failure container_name: dbrepo-gateway-service hostname: gateway-service @@ -72,12 +72,12 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy logging: driver: json-file - database-service: + dbrepo-database-service: restart: on-failure container_name: dbrepo-database-service hostname: database-service @@ -90,16 +90,16 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - container-service: + dbrepo-container-service: condition: service_healthy - broker-service: + dbrepo-broker-service: condition: service_started - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - container-service: + dbrepo-container-service: restart: on-failure container_name: dbrepo-container-service hostname: container-service @@ -111,12 +111,12 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - authentication-service: + dbrepo-authentication-service: restart: on-failure container_name: dbrepo-authentication-service hostname: authentication-service @@ -126,16 +126,16 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy - broker-service: + dbrepo-broker-service: condition: service_started - metadata-db: + dbrepo-metadata-db: condition: service_healthy logging: driver: json-file - query-service: + dbrepo-query-service: restart: on-failure container_name: dbrepo-query-service hostname: query-service @@ -148,14 +148,14 @@ services: volumes: - ${SHARED_FILESYSTEM}:/tmp depends_on: - table-service: + dbrepo-table-service: condition: service_healthy - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - table-service: + dbrepo-table-service: restart: on-failure container_name: dbrepo-table-service hostname: table-service @@ -169,16 +169,16 @@ services: - /var/run/docker.sock:/var/run/docker.sock - ${SHARED_FILESYSTEM}:/tmp depends_on: - authentication-service: + dbrepo-authentication-service: condition: service_healthy - search-service: + dbrepo-search-service: condition: service_started - broker-service: + dbrepo-broker-service: condition: service_started logging: driver: json-file - identifier-service: + dbrepo-identifier-service: restart: on-failure container_name: dbrepo-identifier-service hostname: identifier-service @@ -188,16 +188,16 @@ services: env_file: - .env depends_on: - query-service: + dbrepo-query-service: condition: service_healthy - authentication-service: + dbrepo-authentication-service: condition: service_healthy volumes: - ${SHARED_FILESYSTEM}:/tmp logging: driver: json-file - metadata-service: + dbrepo-metadata-service: restart: on-failure container_name: dbrepo-metadata-service hostname: metadata-service @@ -207,12 +207,12 @@ services: env_file: - .env depends_on: - metadata-db: + dbrepo-metadata-db: condition: service_started logging: driver: json-file - analyse-service: + dbrepo-analyse-service: restart: on-failure container_name: dbrepo-analyse-service hostname: analyse-service @@ -226,12 +226,12 @@ services: - ${SHARED_FILESYSTEM}:/tmp - /var/run/docker.sock:/var/run/docker.sock depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy logging: driver: json-file - semantics-service: + dbrepo-semantics-service: restart: on-failure container_name: dbrepo-semantics-service hostname: semantics-service @@ -244,14 +244,14 @@ services: - ${SHARED_FILESYSTEM}:/tmp - /var/run/docker.sock:/var/run/docker.sock depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy - metadata-db: + dbrepo-metadata-db: condition: service_healthy logging: driver: json-file - broker-service: + dbrepo-broker-service: restart: on-failure container_name: dbrepo-broker-service hostname: broker-service @@ -264,14 +264,14 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy volumes: - broker-service-data:/var/lib/rabbitmq/ logging: driver: json-file - search-service: + dbrepo-search-service: restart: always container_name: dbrepo-search-service hostname: search-service @@ -279,7 +279,7 @@ services: networks: core: depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy env_file: - .env @@ -288,7 +288,7 @@ services: logging: driver: json-file - ui: + dbrepo-ui: restart: on-failure container_name: dbrepo-ui hostname: ui @@ -301,9 +301,9 @@ services: volumes: - ${SHARED_FILESYSTEM}:/tmp depends_on: - identifier-service: + dbrepo-identifier-service: condition: service_healthy - database-service: + dbrepo-database-service: condition: service_healthy logging: driver: json-file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 78fc30f911..8984baecab 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -31,7 +31,7 @@ networks: services: - metadata-db: + dbrepo-metadata-db: restart: on-failure container_name: dbrepo-metadata-db hostname: metadata-db @@ -48,7 +48,7 @@ services: logging: driver: json-file - discovery-service: + dbrepo-discovery-service: restart: on-failure container_name: dbrepo-discovery-service hostname: discovery-service @@ -60,7 +60,7 @@ services: logging: driver: json-file - gateway-service: + dbrepo-gateway-service: restart: on-failure container_name: dbrepo-gateway-service hostname: gateway-service @@ -72,12 +72,12 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy logging: driver: json-file - database-service: + dbrepo-database-service: restart: on-failure container_name: dbrepo-database-service hostname: database-service @@ -90,16 +90,16 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - container-service: + dbrepo-container-service: condition: service_healthy - broker-service: + dbrepo-broker-service: condition: service_started - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - container-service: + dbrepo-container-service: restart: on-failure container_name: dbrepo-container-service hostname: container-service @@ -111,12 +111,12 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - authentication-service: + dbrepo-authentication-service: restart: on-failure container_name: dbrepo-authentication-service hostname: authentication-service @@ -126,16 +126,16 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy - broker-service: + dbrepo-broker-service: condition: service_started - metadata-db: + dbrepo-metadata-db: condition: service_healthy logging: driver: json-file - query-service: + dbrepo-query-service: restart: on-failure container_name: dbrepo-query-service hostname: query-service @@ -148,14 +148,14 @@ services: volumes: - ${SHARED_FILESYSTEM}:/tmp depends_on: - table-service: + dbrepo-table-service: condition: service_healthy - authentication-service: + dbrepo-authentication-service: condition: service_healthy logging: driver: json-file - table-service: + dbrepo-table-service: restart: on-failure container_name: dbrepo-table-service hostname: table-service @@ -169,16 +169,16 @@ services: - /var/run/docker.sock:/var/run/docker.sock - ${SHARED_FILESYSTEM}:/tmp depends_on: - authentication-service: + dbrepo-authentication-service: condition: service_healthy - search-service: + dbrepo-search-service: condition: service_started - broker-service: + dbrepo-broker-service: condition: service_started logging: driver: json-file - identifier-service: + dbrepo-identifier-service: restart: on-failure container_name: dbrepo-identifier-service hostname: identifier-service @@ -188,16 +188,16 @@ services: env_file: - .env depends_on: - query-service: + dbrepo-query-service: condition: service_healthy - authentication-service: + dbrepo-authentication-service: condition: service_healthy volumes: - ${SHARED_FILESYSTEM}:/tmp logging: driver: json-file - metadata-service: + dbrepo-metadata-service: restart: on-failure container_name: dbrepo-metadata-service hostname: metadata-service @@ -207,12 +207,12 @@ services: env_file: - .env depends_on: - metadata-db: + dbrepo-metadata-db: condition: service_started logging: driver: json-file - analyse-service: + dbrepo-analyse-service: restart: on-failure container_name: dbrepo-analyse-service hostname: analyse-service @@ -226,12 +226,12 @@ services: - ${SHARED_FILESYSTEM}:/tmp - /var/run/docker.sock:/var/run/docker.sock depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy logging: driver: json-file - semantics-service: + dbrepo-semantics-service: restart: on-failure container_name: dbrepo-semantics-service hostname: semantics-service @@ -244,14 +244,14 @@ services: - ${SHARED_FILESYSTEM}:/tmp - /var/run/docker.sock:/var/run/docker.sock depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy - metadata-db: + dbrepo-metadata-db: condition: service_healthy logging: driver: json-file - broker-service: + dbrepo-broker-service: restart: on-failure container_name: dbrepo-broker-service hostname: broker-service @@ -263,14 +263,14 @@ services: env_file: - .env depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy volumes: - broker-service-data:/var/lib/rabbitmq/ logging: driver: json-file - search-service: + dbrepo-search-service: restart: always container_name: dbrepo-search-service hostname: search-service @@ -278,7 +278,7 @@ services: networks: core: depends_on: - discovery-service: + dbrepo-discovery-service: condition: service_healthy env_file: - .env @@ -287,7 +287,7 @@ services: logging: driver: json-file - ui: + dbrepo-ui: restart: on-failure container_name: dbrepo-ui hostname: ui @@ -302,9 +302,9 @@ services: volumes: - ${SHARED_FILESYSTEM}:/tmp depends_on: - identifier-service: + dbrepo-identifier-service: condition: service_healthy - database-service: + dbrepo-database-service: condition: service_healthy logging: driver: json-file diff --git a/docker-compose.yml b/docker-compose.yml index fd864bd166..955a59d41c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,27 +10,26 @@ volumes: broker-service-data: networks: - public: - name: public + userdb: + name: userdb driver: bridge ipam: config: - - subnet: 172.29.0.0/16 - userdb: - name: userdb + - subnet: 172.30.0.0/16 + public: + name: public driver: bridge ipam: config: - - subnet: 172.28.0.0/16 + - subnet: 172.31.0.0/16 core: name: core driver: bridge ipam: config: - - subnet: 172.27.0.0/16 + - subnet: 172.32.0.0/16 services: - fda-metadata-db: restart: on-failure container_name: dbrepo-metadata-db diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index be355787b9..c6c927f9b9 100644 --- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -294,7 +294,7 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_BROKER_ID = 1L; public final static String CONTAINER_BROKER_NAME = "broker-service"; public final static String CONTAINER_BROKER_INTERNAL_NAME = "broker-service"; - public final static String CONTAINER_BROKER_IP = "172.29.0.2"; + public final static String CONTAINER_BROKER_IP = "172.31.0.2"; public final static Container CONTAINER_BROKER = Container.builder() .id(CONTAINER_BROKER_ID) diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java index fc15443f9e..37b2ca7d1b 100644 --- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java +++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java @@ -4,7 +4,9 @@ import at.tuwien.entities.container.Container; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.model.HostConfig; +import com.github.dockerjava.api.model.Network; import com.github.dockerjava.api.model.RestartPolicy; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientBuilder; @@ -13,6 +15,7 @@ import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; import com.github.dockerjava.transport.DockerHttpClient; import lombok.extern.log4j.Log4j2; +import java.util.Arrays; import java.util.Objects; @Log4j2 @@ -56,7 +59,7 @@ public class DockerConfig { final CreateContainerResponse response = dockerClient.createContainerCmd(container.getImage().getRepository() + ":" + container.getImage().getTag()) .withHostConfig(hostConfig.withNetworkMode("fda-userdb")) .withName(container.getInternalName()) - .withIpv4Address("172.28.0.5") + .withIpv4Address("172.30.0.5") .withHostName(container.getInternalName()) .withEnv("MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=weather") .exec(); @@ -86,4 +89,59 @@ public class DockerConfig { log.debug("container {} was removed", container.getHash()); } + public static void removeAllContainers() { + dockerClient.listContainersCmd() + .withShowAll(true) + .exec() + .forEach(container -> { + log.info("Delete container {}", Arrays.asList(container.getNames())); + try { + dockerClient.stopContainerCmd(container.getId()).exec(); + } catch (NotModifiedException e) { + // ignore + } + dockerClient.removeContainerCmd(container.getId()).exec(); + }); + dockerClient.listVolumesCmd() + .withDanglingFilter(true) + .exec() + .getVolumes() + .forEach(volume -> { + log.info("Delete volume {}", volume.getName()); + try { + dockerClient.removeVolumeCmd(volume.getName()).exec(); + } catch (NotModifiedException e) { + // ignore + } + }); + } + + public static void removeAllNetworks() { + dockerClient.listNetworksCmd() + .exec() + .stream() + .filter(n -> n.getName().startsWith("fda")) + .forEach(network -> { + log.info("Delete network {}", network.getName()); + dockerClient.removeNetworkCmd(network.getId()).exec(); + }); + } + + public static void createAllNetworks() { + dockerClient.createNetworkCmd() + .withName("fda-userdb") + .withIpam(new Network.Ipam() + .withConfig(new Network.Ipam.Config() + .withSubnet("172.30.0.0/16"))) + .withEnableIpv6(false) + .exec(); + dockerClient.createNetworkCmd() + .withName("fda-public") + .withIpam(new Network.Ipam() + .withConfig(new Network.Ipam.Config() + .withSubnet("172.31.0.0/16"))) + .withEnableIpv6(false) + .exec(); + } + } diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java index f887b5a86c..ba84081446 100644 --- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java +++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java @@ -2,6 +2,7 @@ package at.tuwien.service; import at.tuwien.BaseUnitTest; import at.tuwien.api.amqp.CreateUserDto; +import at.tuwien.config.DockerConfig; import at.tuwien.config.RabbitMqConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.dto.AmqpUserBriefDto; @@ -13,9 +14,7 @@ import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.model.Network; import com.github.dockerjava.api.model.PortBinding; import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -56,24 +55,16 @@ public class QueueServiceIntegrationTest extends BaseUnitTest { @Autowired private RabbitMqConfig amqpConfig; + @BeforeAll + public static void beforeAll() { + afterAll(); + DockerConfig.createAllNetworks(); + } + @BeforeEach public void beforeEach() throws InterruptedException { afterEach(); - /* create networks */ - dockerClient.createNetworkCmd() - .withName("fda-userdb") - .withIpam(new Network.Ipam() - .withConfig(new Network.Ipam.Config() - .withSubnet("172.28.0.0/16"))) - .withEnableIpv6(false) - .exec(); - dockerClient.createNetworkCmd() - .withName("fda-public") - .withIpam(new Network.Ipam() - .withConfig(new Network.Ipam.Config() - .withSubnet("172.29.0.0/16"))) - .withEnableIpv6(false) - .exec(); + DockerConfig.createAllNetworks(); /* create container */ final PortBinding binding = PortBinding.parse("15672:15672"); final CreateContainerResponse response1 = dockerClient.createContainerCmd(IMAGE_BROKER_IMAGE + ":" + IMAGE_BROKER_TAG) @@ -92,28 +83,14 @@ public class QueueServiceIntegrationTest extends BaseUnitTest { @AfterEach public void afterEach() { - /* stop containers and remove them */ - dockerClient.listContainersCmd() - .withShowAll(true) - .exec() - .forEach(container -> { - log.info("Delete container {}", Arrays.asList(container.getNames())); - try { - dockerClient.stopContainerCmd(container.getId()).exec(); - } catch (NotModifiedException e) { - // ignore - } - dockerClient.removeContainerCmd(container.getId()).exec(); - }); - /* remove networks */ - dockerClient.listNetworksCmd() - .exec() - .stream() - .filter(n -> n.getName().startsWith("fda")) - .forEach(network -> { - log.info("Delete network {}", network.getName()); - dockerClient.removeNetworkCmd(network.getId()).exec(); - }); + DockerConfig.removeAllContainers(); + DockerConfig.removeAllNetworks(); + } + + @AfterAll + public static void afterAll() { + DockerConfig.removeAllContainers(); + DockerConfig.removeAllNetworks(); } @Test diff --git a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java index 371ed3450a..c72d988189 100644 --- a/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java +++ b/fda-authentication-service/rest-service/src/test/java/at/tuwien/service/UserServiceIntegrationTest.java @@ -6,6 +6,7 @@ import at.tuwien.api.user.RoleTypeDto; import at.tuwien.api.user.UserPasswordDto; import at.tuwien.api.user.UserRolesDto; import at.tuwien.config.AuthenticationConfig; +import at.tuwien.config.DockerConfig; import at.tuwien.config.RabbitMqConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.user.RoleType; @@ -14,8 +15,6 @@ import at.tuwien.exception.*; import at.tuwien.repositories.ImageRepository; import at.tuwien.repositories.UserRepository; import com.github.dockerjava.api.command.CreateContainerResponse; -import com.github.dockerjava.api.exception.NotModifiedException; -import com.github.dockerjava.api.model.Network; import com.github.dockerjava.api.model.PortBinding; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.*; @@ -25,13 +24,10 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.DuplicateKeyException; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.client.RestTemplate; -import javax.validation.ConstraintViolationException; -import java.util.Arrays; import java.util.List; import static at.tuwien.config.DockerConfig.*; @@ -71,57 +67,28 @@ public class UserServiceIntegrationTest extends BaseUnitTest { @BeforeAll public static void beforeAll() { afterAll(); - /* create networks */ - dockerClient.createNetworkCmd() - .withName("fda-userdb") - .withIpam(new Network.Ipam() - .withConfig(new Network.Ipam.Config() - .withSubnet("172.28.0.0/16"))) - .withEnableIpv6(false) - .exec(); - dockerClient.createNetworkCmd() - .withName("fda-public") - .withIpam(new Network.Ipam() - .withConfig(new Network.Ipam.Config() - .withSubnet("172.29.0.0/16"))) - .withEnableIpv6(false) - .exec(); - } - - @AfterAll - public static void afterAll() { - /* remove networks */ - dockerClient.listNetworksCmd() - .exec() - .stream() - .filter(n -> n.getName().startsWith("fda")) - .forEach(network -> { - log.info("Delete network {}", network.getName()); - dockerClient.removeNetworkCmd(network.getId()).exec(); - }); + DockerConfig.createAllNetworks(); } @BeforeEach public void beforeEach() { + afterEach(); + DockerConfig.createAllNetworks(); + /* metadata database */ imageRepository.save(IMAGE_1); userRepository.save(USER_1); } @AfterEach public void afterEach() { - /* stop containers and remove them */ - dockerClient.listContainersCmd() - .withShowAll(true) - .exec() - .forEach(container -> { - log.info("Delete container {}", Arrays.asList(container.getNames())); - try { - dockerClient.stopContainerCmd(container.getId()).exec(); - } catch (NotModifiedException e) { - // ignore - } - dockerClient.removeContainerCmd(container.getId()).exec(); - }); + DockerConfig.removeAllContainers(); + DockerConfig.removeAllNetworks(); + } + + @AfterAll + public static void afterAll() { + DockerConfig.removeAllContainers(); + DockerConfig.removeAllNetworks(); } @Test diff --git a/fda-authentication-service/rest-service/src/test/resources/application.properties b/fda-authentication-service/rest-service/src/test/resources/application.properties index b0ccd00eda..d57104b1ea 100644 --- a/fda-authentication-service/rest-service/src/test/resources/application.properties +++ b/fda-authentication-service/rest-service/src/test/resources/application.properties @@ -25,6 +25,6 @@ spring.rabbitmq.username=guest spring.rabbitmq.password=guest # user -fda.gateway.endpoint=http://172.29.0.2:15672/api/ +fda.gateway.endpoint=http://172.31.0.2:15672/api/ fda.mail.verify=true fda.token.max=1 \ No newline at end of file diff --git a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java index 9dfe9e4b53..5c3d11e564 100644 --- a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java +++ b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java @@ -5,6 +5,7 @@ import at.tuwien.entities.container.Container; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.mapper.ContainerMapper; +import at.tuwien.service.ContainerService; import at.tuwien.service.UserService; import at.tuwien.service.impl.ContainerServiceImpl; import io.micrometer.core.annotation.Timed; @@ -34,7 +35,7 @@ public class ContainerEndpoint { private final UserService userService; private final ContainerMapper containerMapper; - private final ContainerServiceImpl containerService; + private final ContainerService containerService; @Autowired public ContainerEndpoint(UserService userService, ContainerServiceImpl containerService, @@ -47,9 +48,10 @@ public class ContainerEndpoint { @GetMapping @Transactional(readOnly = true) @Operation(summary = "Find all containers") - public ResponseEntity<List<ContainerBriefDto>> findAll(Principal principal) { - log.debug("endpoint find all containers, principal={}", principal); - final List<Container> containers = containerService.getAll(); + public ResponseEntity<List<ContainerBriefDto>> findAll(Principal principal, + @RequestParam(required = false) Integer limit) { + log.debug("endpoint find all containers, principal={}, limit={}", principal, limit); + final List<Container> containers = containerService.getAll(limit); return ResponseEntity.ok() .body(containers.stream() .map(containerMapper::containerToDatabaseContainerBriefDto) @@ -95,7 +97,7 @@ public class ContainerEndpoint { @Valid @RequestBody ContainerChangeDto changeDto, @NotNull Principal principal) throws ContainerNotFoundException, ContainerAlreadyRunningException, ContainerAlreadyStoppedException, - UserNotFoundException, NotAllowedException { + UserNotFoundException, NotAllowedException, DockerClientException { log.debug("endpoint modify container, containerId={}, changeDto={}, principal={}", containerId, changeDto, principal); final User user = userService.findByUsername(principal.getName()); final Container container = containerService.find(containerId); @@ -124,7 +126,7 @@ public class ContainerEndpoint { @Operation(summary = "Delete some container", security = @SecurityRequirement(name = "bearerAuth")) public ResponseEntity<?> delete(@NotNull @PathVariable("id") Long containerId, @NotNull Principal principal) throws ContainerNotFoundException, - ContainerStillRunningException, ContainerAlreadyRemovedException { + ContainerStillRunningException, ContainerAlreadyRemovedException, DockerClientException { log.debug("endpoint delete container, containerId={}, principal={}", containerId, principal); containerService.remove(containerId); return ResponseEntity.status(HttpStatus.ACCEPTED) diff --git a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java index 7f02363385..bbb5d2ecba 100644 --- a/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java +++ b/fda-container-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java @@ -10,10 +10,6 @@ import at.tuwien.mapper.ImageMapper; import at.tuwien.service.impl.ImageServiceImpl; import io.micrometer.core.annotation.Timed; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; @@ -46,9 +42,6 @@ public class ImageEndpoint { } @GetMapping - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Found images") - }) @Transactional(readOnly = true) @Timed(value = "image.list", description = "Time needed to list the container images") @Operation(summary = "Find all images") @@ -62,10 +55,6 @@ public class ImageEndpoint { } @PostMapping - @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "Created image"), - @ApiResponse(responseCode = "404", description = "Image not found"), - }) @Transactional @Timed(value = "image.create", description = "Time needed to create a container image") @PreAuthorize("hasRole('ROLE_DEVELOPER')") @@ -86,10 +75,6 @@ public class ImageEndpoint { } @GetMapping("/{id}") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Found some image"), - @ApiResponse(responseCode = "404", description = "Image not found"), - }) @Transactional(readOnly = true) @Timed(value = "image.find", description = "Time needed to find a container image") @Operation(summary = "Find some image") @@ -104,10 +89,6 @@ public class ImageEndpoint { } @PutMapping("/{id}") - @ApiResponses(value = { - @ApiResponse(responseCode = "202", description = "Updated image"), - @ApiResponse(responseCode = "404", description = "Image not found"), - }) @Transactional @Timed(value = "image.update", description = "Time needed to update a container image") @PreAuthorize("hasRole('DEVELOPER')") @@ -125,11 +106,6 @@ public class ImageEndpoint { } @DeleteMapping("/{id}") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Deleted image"), - @ApiResponse(responseCode = "403", description = "Unable to delete image"), - @ApiResponse(responseCode = "404", description = "Image not found"), - }) @Transactional @Timed(value = "image.delete", description = "Time needed to delete a container image") @PreAuthorize("hasRole('DEVELOPER')") diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index c22a810fea..0a59ea1f45 100644 --- a/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-container-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -12,6 +12,7 @@ import at.tuwien.entities.container.image.ContainerImageEnvironmentItemType; import at.tuwien.entities.user.RoleType; import at.tuwien.entities.user.User; import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.HealthCheck; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -284,30 +285,36 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_1_ID = 1L; public final static String CONTAINER_1_HASH = "deadbeef"; - public final static String CONTAINER_1_NAME = "fda-userdb-u01"; - public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-fda-userdb-u01"; - public final static String CONTAINER_1_DATABASE = "univie"; - public final static String CONTAINER_1_IP = "172.28.0.5"; - public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS); + public final static String CONTAINER_1_IP = "172.30.0.5"; + public final static String CONTAINER_1_NAME = "u01"; + public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01"; + public final static Instant CONTAINER_1_CREATED = Instant.now().minus(2, HOURS); + public final static Instant CONTAINER_1_UPDATED = Instant.now(); + public final static HealthCheck CONTAINER_1_HEALTHCHECK = new HealthCheck() + .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb")); + + public final static String[] CONTAINER_1_ENV = new String[]{"MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_USER=mariadb", + "MARIADB_PASSWORD=mariadb", "MARIADB_DATABASE=weather"}; public final static Container CONTAINER_1 = Container.builder() .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) + .hash(CONTAINER_1_HASH) .internalName(CONTAINER_1_INTERNALNAME) + .created(CONTAINER_1_CREATED) + .lastModified(CONTAINER_1_UPDATED) + .ipAddress(CONTAINER_1_IP) .imageId(IMAGE_1_ID) .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) .creator(USER_1) + .owner(USER_1) .build(); public final static Long CONTAINER_2_ID = 2L; public final static String CONTAINER_2_HASH = "deadbeef"; - public final static String CONTAINER_2_NAME = "fda-userdb-u02"; - public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-fda-userdb-u02"; - public final static String CONTAINER_2_DATABASE = "univie"; - public final static String CONTAINER_2_IP = "172.28.0.6"; + public final static String CONTAINER_2_NAME = "u02"; + public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02"; + public final static String CONTAINER_2_IP = "172.30.0.6"; public final static Instant CONTAINER_2_CREATED = Instant.now().minus(2, HOURS); public final static Container CONTAINER_2 = Container.builder() @@ -324,8 +331,8 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_3_ID = 3L; public final static String CONTAINER_3_HASH = "deadbeef"; - public final static String CONTAINER_3_NAME = "fda-userdb-u03"; - public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-fda-userdb-u03"; + public final static String CONTAINER_3_NAME = "u03"; + public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03"; public final static String CONTAINER_3_DATABASE = "u03"; public final static String CONTAINER_3_IP = "173.38.0.7"; public final static Instant CONTAINER_3_CREATED = Instant.now().minus(2, HOURS); diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java index 7407254558..cd82d0b81d 100644 --- a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java +++ b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ContainerEndpointUnitTest.java @@ -2,7 +2,7 @@ package at.tuwien.endpoint; import at.tuwien.BaseUnitTest; import at.tuwien.api.container.*; -import at.tuwien.config.DockerUtil; +import at.tuwien.config.DockerConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.endpoints.ContainerEndpoint; import at.tuwien.entities.container.Container; @@ -48,7 +48,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { private ContainerEndpoint containerEndpoint; @Autowired - private DockerUtil dockerUtil; + private DockerConfig dockerUtil; @Test public void findById_anonymous_succeeds() throws DockerClientException, ContainerNotFoundException, @@ -142,7 +142,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void delete_developer_succeeds() throws ContainerStillRunningException, ContainerAlreadyRemovedException, - ContainerNotFoundException { + ContainerNotFoundException, DockerClientException { /* mock */ when(userRepository.findByUsername(USER_2_USERNAME)) @@ -170,7 +170,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { public void findAll_anonymous_succeeds() { /* test */ - findAll_generic(null); + findAll_generic(null, null); } @Test @@ -178,7 +178,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { public void findAll_anonymous2_succeeds() { /* test */ - findAll_generic(null); + findAll_generic(null, null); } @Test @@ -190,7 +190,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { .thenReturn(Optional.of(USER_1)); /* test */ - findAll_generic(USER_1_PRINCIPAL); + findAll_generic(USER_1_PRINCIPAL, null); } @Test @@ -202,7 +202,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { .thenReturn(Optional.of(USER_2)); /* test */ - findAll_generic(USER_2_PRINCIPAL); + findAll_generic(USER_2_PRINCIPAL, null); } @Test @@ -214,7 +214,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { .thenReturn(Optional.of(USER_3)); /* test */ - findAll_generic(USER_3_PRINCIPAL); + findAll_generic(USER_3_PRINCIPAL, null); } @Test @@ -337,7 +337,8 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void modify_researcherStart_succeeds() throws ContainerAlreadyRunningException, - ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException { + ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException, + DockerClientException { /* mock */ when(userRepository.findByUsername(USER_1_USERNAME)) @@ -367,7 +368,8 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void modify_researcherStop_succeeds() throws ContainerAlreadyRunningException, - ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException { + ContainerAlreadyStoppedException, ContainerNotFoundException, UserNotFoundException, NotAllowedException, + DockerClientException { /* mock */ when(userRepository.findByUsername(USER_1_USERNAME)) @@ -398,7 +400,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void modify_developerForeignStart_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException, - NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException { + NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException { /* mock */ when(userRepository.findByUsername(USER_2_USERNAME)) @@ -411,7 +413,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void modify_developerForeignStop_succeeds() throws UserNotFoundException, ContainerAlreadyRunningException, - NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException { + NotAllowedException, ContainerAlreadyStoppedException, ContainerNotFoundException, DockerClientException { /* mock */ when(userRepository.findByUsername(USER_2_USERNAME)) @@ -471,7 +473,7 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { } public void delete_generic(Long containerId, Container container, Principal principal) throws ContainerNotFoundException, - ContainerStillRunningException, ContainerAlreadyRemovedException { + ContainerStillRunningException, ContainerAlreadyRemovedException, DockerClientException { /* mock */ when(containerService.find(containerId)) @@ -486,14 +488,14 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { assertNull(response.getBody()); } - public void findAll_generic(Principal principal) { + public void findAll_generic(Principal principal, Integer limit) { /* mock */ - when(containerService.getAll()) + when(containerService.getAll(limit)) .thenReturn(List.of(CONTAINER_1, CONTAINER_2)); /* test */ - final ResponseEntity<List<ContainerBriefDto>> response = containerEndpoint.findAll(principal); + final ResponseEntity<List<ContainerBriefDto>> response = containerEndpoint.findAll(principal, limit); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); final List<ContainerBriefDto> body = response.getBody(); @@ -522,7 +524,8 @@ public class ContainerEndpointUnitTest extends BaseUnitTest { } public void modify_generic(ContainerActionTypeDto data, Long containerId, Container container, Principal principal) - throws ContainerAlreadyRunningException, ContainerNotFoundException, ContainerAlreadyStoppedException, UserNotFoundException, NotAllowedException { + throws ContainerAlreadyRunningException, ContainerNotFoundException, ContainerAlreadyStoppedException, + UserNotFoundException, NotAllowedException, DockerClientException { final ContainerChangeDto request = ContainerChangeDto.builder() .action(data) .build(); diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java index f84ae04db5..9ef775d53d 100644 --- a/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java +++ b/fda-container-service/rest-service/src/test/java/at/tuwien/endpoint/ImageEndpointUnitTest.java @@ -1,21 +1,17 @@ package at.tuwien.endpoint; import at.tuwien.BaseUnitTest; -import at.tuwien.api.container.*; import at.tuwien.api.container.image.ImageBriefDto; import at.tuwien.api.container.image.ImageChangeDto; import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.api.container.image.ImageDto; -import at.tuwien.config.DockerUtil; +import at.tuwien.config.DockerConfig; import at.tuwien.config.ReadyConfig; -import at.tuwien.endpoints.ContainerEndpoint; import at.tuwien.endpoints.ImageEndpoint; -import at.tuwien.entities.container.Container; import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.*; import at.tuwien.repository.jpa.ImageRepository; import at.tuwien.repository.jpa.UserRepository; -import at.tuwien.service.impl.ContainerServiceImpl; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -31,7 +27,6 @@ import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; -import javax.ws.rs.NotAllowedException; import java.security.Principal; import java.util.List; import java.util.Optional; @@ -57,7 +52,7 @@ public class ImageEndpointUnitTest extends BaseUnitTest { private ImageEndpoint imageEndpoint; @Autowired - private DockerUtil dockerUtil; + private DockerConfig dockerUtil; @Test public void findAll_anonymous_succeeds() { diff --git a/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java index 8aef59c9fc..fd1c316006 100644 --- a/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java +++ b/fda-container-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java @@ -5,7 +5,6 @@ import at.tuwien.api.container.ContainerCreateRequestDto; import at.tuwien.config.DockerUtil; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.container.Container; -import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.*; import at.tuwien.repository.jpa.ContainerRepository; import at.tuwien.repository.jpa.ImageRepository; @@ -66,32 +65,19 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { .withName("fda-userdb") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.28.0.0/16"))) + .withSubnet("172.30.0.0/16"))) .withEnableIpv6(false) .exec(); dockerClient.createNetworkCmd() .withName("fda-public") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.29.0.0/16"))) + .withSubnet("172.31.0.0/16"))) .withEnableIpv6(false) .exec(); /* mock data */ userRepository.save(USER_1); - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); imageRepository.save(IMAGE_1); } @@ -151,30 +137,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); containerRepository.save(CONTAINER_1); /* test */ @@ -221,30 +183,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { ContainerAlreadyRunningException { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); @@ -257,30 +195,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { ContainerAlreadyStoppedException { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); dockerUtil.startContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); @@ -293,30 +207,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void change_startSavedButNotFound_fails() { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); containerRepository.save(CONTAINER_1); /* test */ @@ -329,30 +219,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void change_removeSavedButNotFound_fails() { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); containerRepository.save(CONTAINER_1); /* test */ @@ -365,77 +231,31 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void getAll_succeeds() { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - final Container CONTAINER_2 = Container.builder() - .id(CONTAINER_2_ID) - .name(CONTAINER_2_NAME) - .internalName(CONTAINER_2_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_2_HASH) - .ipAddress(CONTAINER_2_IP) - .created(CONTAINER_2_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); containerRepository.save(CONTAINER_1); containerRepository.save(CONTAINER_2); /* test */ - final List<Container> response = containerService.getAll(); + final List<Container> response = containerService.getAll(null); assertEquals(2, response.size()); } + @Test + public void getAll_limit_succeeds() { + + /* mock */ + containerRepository.save(CONTAINER_1); + containerRepository.save(CONTAINER_2); + + /* test */ + final List<Container> response = containerService.getAll(1); + assertEquals(1, response.size()); + } + @Test public void remove_succeeds() throws DockerClientException, ContainerStillRunningException, ContainerNotFoundException, ContainerAlreadyRemovedException { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); dockerUtil.stopContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); @@ -457,30 +277,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void remove_stillRunning_fails() throws InterruptedException { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); dockerUtil.startContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); @@ -495,30 +291,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void change_alreadyRunning_fails() throws InterruptedException { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); dockerUtil.startContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); @@ -533,30 +305,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void change_startNotFound_fails() { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); /* test */ @@ -569,30 +317,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void change_alreadyStopped_fails() throws InterruptedException { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); dockerUtil.startContainer(CONTAINER_1); dockerUtil.stopContainer(CONTAINER_1); @@ -608,30 +332,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void change_stopNeverStarted_fails() { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); @@ -645,30 +345,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void change_stopSavedButNotFound_fails() { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); containerRepository.save(CONTAINER_1); /* test */ @@ -682,30 +358,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { ContainerNotRunningException { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); dockerUtil.startContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); @@ -731,30 +383,6 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { public void inspect_notRunning_fails() { /* mock */ - final ContainerImage IMAGE_1 = ContainerImage.builder() - .id(IMAGE_1_ID) - .repository(IMAGE_1_REPOSITORY) - .tag(IMAGE_1_TAG) - .hash(IMAGE_1_HASH) - .jdbcMethod(IMAGE_1_JDBC) - .dialect(IMAGE_1_DIALECT) - .driverClass(IMAGE_1_DRIVER) - .compiled(IMAGE_1_BUILT) - .size(IMAGE_1_SIZE) - .environment(IMAGE_1_ENV) - .defaultPort(IMAGE_1_PORT) - .build(); - final Container CONTAINER_1 = Container.builder() - .id(CONTAINER_1_ID) - .name(CONTAINER_1_NAME) - .internalName(CONTAINER_1_INTERNALNAME) - .imageId(IMAGE_1_ID) - .image(IMAGE_1) - .hash(CONTAINER_1_HASH) - .ipAddress(CONTAINER_1_IP) - .created(CONTAINER_1_CREATED) - .build(); - log.info("Container id {}", CONTAINER_1.getId()); dockerUtil.createContainer(CONTAINER_1); containerRepository.save(CONTAINER_1); diff --git a/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java index 6a7b557780..1879065a2d 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java +++ b/fda-container-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java @@ -1,5 +1,6 @@ package at.tuwien.mapper; +import at.tuwien.api.database.DatabaseBriefDto; import at.tuwien.api.database.DatabaseDto; import at.tuwien.entities.database.Database; import org.mapstruct.Mapper; @@ -14,4 +15,10 @@ public interface DatabaseMapper { }) DatabaseDto databaseToDatabaseDto(Database data); + /* keep */ + @Mappings({ + @Mapping(target = "container", ignore = true) + }) + DatabaseBriefDto databaseToDatabaseBriefDto(Database data); + } diff --git a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java index 37b8abb773..df2a6eba16 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java +++ b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/ContainerRepository.java @@ -9,8 +9,6 @@ import java.util.Optional; @Repository public interface ContainerRepository extends JpaRepository<Container, Long> { - Optional<Container> findByHash(String hash); - Optional<Container> findByInternalName(String internalName); } diff --git a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java new file mode 100644 index 0000000000..688993ab3c --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/DatabaseRepository.java @@ -0,0 +1,10 @@ +package at.tuwien.repository.jpa; + +import at.tuwien.entities.database.Database; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface DatabaseRepository extends JpaRepository<Database, Long> { + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java new file mode 100644 index 0000000000..f76f9976d6 --- /dev/null +++ b/fda-container-service/services/src/main/java/at/tuwien/repository/jpa/IdentifierRepository.java @@ -0,0 +1,10 @@ +package at.tuwien.repository.jpa; + +import at.tuwien.entities.identifier.Identifier; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface IdentifierRepository extends JpaRepository<Identifier, Long> { + +} diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java b/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java index 2528621ed4..26654fc34f 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java +++ b/fda-container-service/services/src/main/java/at/tuwien/service/ContainerService.java @@ -56,9 +56,12 @@ public interface ContainerService { Container inspect(Long id) throws ContainerNotFoundException, DockerClientException, ContainerNotRunningException; /** - * @return + * Retrieve a list of all containers from the metadata database + * + * @param limit Return at most this amount of results, optional. + * @return The list of containers. */ - List<Container> getAll(); + List<Container> getAll(Integer limit); /** * @param containerId diff --git a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java index 4dc6996229..9753d9687e 100644 --- a/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java +++ b/fda-container-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java @@ -22,6 +22,7 @@ import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.model.*; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.util.SocketUtils; @@ -31,6 +32,7 @@ import org.springframework.transaction.annotation.Transactional; import java.security.Principal; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @Log4j2 @Service @@ -79,7 +81,7 @@ public class ContainerServiceImpl implements ContainerService { /* check duplicate */ final Optional<Container> optional = containerRepository.findByInternalName(container.getInternalName()); if (optional.isPresent()) { - log.error("Failed to create container with internal name {}", container.getInternalName()); + log.error("Failed to create container with internal name {}, it already exists", container.getInternalName()); throw new ContainerAlreadyExistsException("Container name already exists"); } /* create the volume */ @@ -212,9 +214,15 @@ public class ContainerServiceImpl implements ContainerService { } @Override - @Transactional - public List<Container> getAll() { - final List<Container> containers = containerRepository.findAll(Sort.by(Sort.Direction.DESC, "created")); + @Transactional(readOnly = true) + public List<Container> getAll(Integer limit) { + final List<Container> containers; + if (limit == null) { + containers = containerRepository.findAll(Sort.by(Sort.Direction.DESC, "created")); + } else { + containers = containerRepository.findAll(PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "created"))) + .toList(); + } log.info("Found {} containers", containers.size()); return containers; } diff --git a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java index 57820c3a21..bfeb98549b 100644 --- a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java +++ b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java @@ -3,12 +3,9 @@ package at.tuwien.endpoints; import at.tuwien.api.database.*; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.identifier.IdentifierType; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.mapper.DatabaseMapper; -import at.tuwien.mapper.IdentifierMapper; import at.tuwien.repository.jpa.DatabaseAccessRepository; import at.tuwien.service.*; import at.tuwien.service.impl.MariaDbServiceImpl; @@ -27,7 +24,6 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; import java.security.Principal; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; @Log4j2 @@ -39,27 +35,22 @@ public class DatabaseEndpoint extends AbstractEndpoint { private final UserService userService; private final AccessService accessService; private final DatabaseMapper databaseMapper; - private final IdentifierMapper identifierMapper; private final MariaDbServiceImpl databaseService; private final QueryStoreService queryStoreService; - private final IdentifierService identifierService; private final MessageQueueService messageQueueService; private final DatabaseAccessRepository databaseAccessRepository; @Autowired public DatabaseEndpoint(DatabaseMapper databaseMapper, ContainerService containerService, UserService userService, MariaDbServiceImpl databaseService, QueryStoreService queryStoreService, - IdentifierService identifierService, IdentifierMapper identifierMapper, MessageQueueService messageQueueService, AccessService accessService, DatabaseAccessRepository databaseAccessRepository) { super(databaseService, containerService, databaseAccessRepository); this.userService = userService; this.accessService = accessService; this.databaseMapper = databaseMapper; - this.identifierMapper = identifierMapper; this.databaseService = databaseService; this.queryStoreService = queryStoreService; - this.identifierService = identifierService; this.messageQueueService = messageQueueService; this.databaseAccessRepository = databaseAccessRepository; } @@ -71,18 +62,10 @@ public class DatabaseEndpoint extends AbstractEndpoint { public ResponseEntity<List<DatabaseBriefDto>> list(@NotNull @PathVariable("id") Long containerId, @NotNull Principal principal) { log.debug("endpoint list databases, containerId={}, principal={}", containerId, principal); - final List<Identifier> identifiers = identifierService.findAll(containerId); final List<DatabaseBriefDto> databases = databaseService.findAll(containerId) .stream() .map(databaseMapper::databaseToDatabaseBriefDto) .collect(Collectors.toList()); - databases.forEach(db -> { - final Optional<Identifier> id = identifiers.stream() - .filter(i -> i.getContainerId().equals(containerId) && i.getDatabaseId().equals(containerId) && - i.getType().equals(IdentifierType.DATABASE)) - .findFirst(); - id.ifPresent(identifier -> db.setIdentifier(identifierMapper.identifierToIdentifierDto(identifier))); - }); log.trace("list databases resulted in databases {}", databases); return ResponseEntity.ok(databases); } @@ -175,12 +158,6 @@ public class DatabaseEndpoint extends AbstractEndpoint { log.debug("endpoint find database, containerId={}, databaseId={}", containerId, databaseId); final Database database = databaseService.findById(containerId, databaseId); final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database); - try { - final Identifier identifier = identifierService.find(containerId, databaseId, IdentifierType.DATABASE); - dto.setIdentifier(identifierMapper.identifierToIdentifierDto(identifier)); - } catch (IdentifierNotFoundException e) { - // ignore - } if (principal != null && database.getOwner().getUsername().equals(principal.getName())) { /* only owner sees the access rights */ final List<DatabaseAccess> accesses = accessService.list(databaseId); diff --git a/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index 7a1890e25d..e32140f007 100644 --- a/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-database-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -50,7 +50,7 @@ public abstract class BaseUnitTest { .build(); public final static String GATEWAY_NAME = "fda-gateway-service"; - public final static String GATEWAY_IP = "172.29.0.3"; + public final static String GATEWAY_IP = "172.31.0.3"; public final static String GATEWAY_HOSTNAME = "gateway-service"; public final static Integer GATEWAY_PORT = 9095; public final static String GATEWAY_IMAGE = "nginx"; @@ -58,7 +58,7 @@ public abstract class BaseUnitTest { public final static String CONTAINER_SEARCH_NAME = "search-mock-service"; public final static String CONTAINER_SEARCH_INTERNAL_NAME = "search-mock-service"; - public final static String CONTAINER_SEARCH_IP = "172.29.0.3"; + public final static String CONTAINER_SEARCH_IP = "172.31.0.3"; public final static String CONTAINER_SEARCH_REPOSITORY = "elasticsearch"; public final static String CONTAINER_SEARCH_TAG = "7.13.4"; @@ -330,9 +330,9 @@ public abstract class BaseUnitTest { .build(); public final static Long CONTAINER_BROKER_ID = 5L; - public final static String CONTAINER_BROKER_NAME = "broker-service"; - public final static String CONTAINER_BROKER_INTERNAL_NAME = "broker-service"; - public final static String CONTAINER_BROKER_IP = "172.29.0.2"; + public final static String CONTAINER_BROKER_NAME = "dbrepo-broker-service"; + public final static String CONTAINER_BROKER_INTERNAL_NAME = "dbrepo-broker-service"; + public final static String CONTAINER_BROKER_IP = "172.31.0.2"; public final static String CONTAINER_BROKER_HASH = "deadbeef"; public final static Instant CONTAINER_BROKER_CREATED = Instant.now().minus(1, HOURS); public final static HealthCheck CONTAINER_BROKER_HEALTHCHECK = new HealthCheck() @@ -366,9 +366,9 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_1_ID = 1L; public final static String CONTAINER_1_HASH = "deadbeef"; - public final static String CONTAINER_1_IP = "172.28.0.5"; - public final static String CONTAINER_1_NAME = "fda-userdb-u01"; - public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01"; + public final static String CONTAINER_1_IP = "172.30.0.5"; + public final static String CONTAINER_1_NAME = "u01"; + public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01"; public final static Instant CONTAINER_1_CREATED = Instant.now().minus(2, HOURS); public final static Instant CONTAINER_1_UPDATED = Instant.now(); public final static HealthCheck CONTAINER_1_HEALTHCHECK = new HealthCheck() @@ -393,9 +393,9 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_2_ID = 2L; public final static String CONTAINER_2_HASH = "deadbeef"; - public final static String CONTAINER_2_IP = "172.28.0.6"; - public final static String CONTAINER_2_NAME = "fda-userdb-u02"; - public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02"; + public final static String CONTAINER_2_IP = "172.30.0.6"; + public final static String CONTAINER_2_NAME = "u02"; + public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02"; public final static Instant CONTAINER_2_CREATED = Instant.now().minus(2, HOURS); public final static Instant CONTAINER_2_UPDATED = Instant.now(); public final static HealthCheck CONTAINER_2_HEALTHCHECK = new HealthCheck() @@ -420,9 +420,9 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_3_ID = 3L; public final static String CONTAINER_3_HASH = "deadbeef"; - public final static String CONTAINER_3_IP = "172.28.0.7"; - public final static String CONTAINER_3_NAME = "fda-userdb-u03"; - public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03"; + public final static String CONTAINER_3_IP = "172.30.0.7"; + public final static String CONTAINER_3_NAME = "u03"; + public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03"; public final static Instant CONTAINER_3_CREATED = Instant.now().minus(2, HOURS); public final static Instant CONTAINER_3_UPDATED = Instant.now(); public final static HealthCheck CONTAINER_3_HEALTHCHECK = new HealthCheck() @@ -447,9 +447,9 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_4_ID = 4L; public final static String CONTAINER_4_HASH = "deadbeef"; - public final static String CONTAINER_4_IP = "172.28.0.8"; - public final static String CONTAINER_4_NAME = "fda-userdb-u04"; - public final static String CONTAINER_4_INTERNALNAME = "fda-userdb-u04"; + public final static String CONTAINER_4_IP = "172.30.0.8"; + public final static String CONTAINER_4_NAME = "u04"; + public final static String CONTAINER_4_INTERNALNAME = "dbrepo-userdb-u04"; public final static Instant CONTAINER_4_CREATED = Instant.now().minus(2, HOURS); public final static Instant CONTAINER_4_UPDATED = Instant.now(); public final static HealthCheck CONTAINER_4_HEALTHCHECK = new HealthCheck() @@ -473,7 +473,7 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_ELASTIC_ID = 5L; public final static String CONTAINER_ELASTIC_NAME = "fda-elastic-service"; public final static String CONTAINER_ELASTIC_INTERNAL_NAME = "search-mock-service"; - public final static String CONTAINER_ELASTIC_IP = "172.29.0.3"; + public final static String CONTAINER_ELASTIC_IP = "172.31.0.3"; public final static String CONTAINER_ELASTIC_HASH = "deadbeef"; public final static Instant CONTAINER_ELASTIC_CREATED = Instant.now().minus(1, HOURS); diff --git a/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java b/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java index 5340810c86..7c55429c92 100644 --- a/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java +++ b/fda-database-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java @@ -157,14 +157,14 @@ public class DockerConfig extends BaseUnitTest { .withName("fda-userdb") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.28.0.0/16"))) + .withSubnet("172.30.0.0/16"))) .withEnableIpv6(false) .exec(); dockerClient.createNetworkCmd() .withName("fda-public") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.29.0.0/16"))) + .withSubnet("172.31.0.0/16"))) .withEnableIpv6(false) .exec(); } diff --git a/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java b/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java index 4808082aff..61cbf30d02 100644 --- a/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java +++ b/fda-database-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java @@ -143,49 +143,67 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @Test public void list_anonymousPublic_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), null); } @Test @WithAnonymousUser public void list_anonymous2Public_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), null); } @Test public void list_anonymousPrivate_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_1_PUBLIC); + /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_2), null); + list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null); } @Test @WithAnonymousUser public void list_anonymous2Private_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_1_PUBLIC); + /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_2), null); + list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), null); } @Test @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void list_researcherPublic_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_1_USERNAME)) .thenReturn(Optional.of(USER_1)); /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_1_PRINCIPAL); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL); } @Test @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void list_researcherPublicWithIdentifiers_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_1_USERNAME)) .thenReturn(Optional.of(USER_1)); @@ -193,13 +211,16 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { .thenReturn(List.of(IDENTIFIER_1)); /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_1_PRINCIPAL); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL); } @Test @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void list_researcherPrivate_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_1_USERNAME)) .thenReturn(Optional.of(USER_1)); @@ -212,18 +233,24 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void list_researcherPublicForeignContainer_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_1_USERNAME)) .thenReturn(Optional.of(USER_1)); /* test */ - list_generic(CONTAINER_2_ID, CONTAINER_2, List.of(DATABASE_1), USER_1_PRINCIPAL); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_1_PRINCIPAL); } @Test @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void list_researcherPrivateForeignContainer_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_1_USERNAME)) .thenReturn(Optional.of(USER_1)); @@ -236,18 +263,24 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void list_developerPublic_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_2_USERNAME)) .thenReturn(Optional.of(USER_2)); /* test */ - list_generic(CONTAINER_2_ID, CONTAINER_2, List.of(DATABASE_1), USER_2_PRINCIPAL); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_2_PRINCIPAL); } @Test @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void list_developerPrivate_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_2_USERNAME)) .thenReturn(Optional.of(USER_2)); @@ -260,66 +293,84 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void list_developerPublicForeignContainer_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_2_USERNAME)) .thenReturn(Optional.of(USER_2)); /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_2_PRINCIPAL); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_2_PRINCIPAL); } @Test @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void list_developerPrivateForeignContainer_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_1_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_2_USERNAME)) .thenReturn(Optional.of(USER_2)); /* test */ - list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_2), USER_2_PRINCIPAL); + list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_2_PRINCIPAL); } @Test @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"}) public void list_dataStewardPublic_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_3_USERNAME)) .thenReturn(Optional.of(USER_3)); /* test */ - list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_1), USER_3_PRINCIPAL); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_3_PRINCIPAL); } @Test @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"}) public void list_dataStewardPrivate_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_1_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_3_USERNAME)) .thenReturn(Optional.of(USER_3)); /* test */ - list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_2), USER_3_PRINCIPAL); + list_generic(CONTAINER_1_ID, CONTAINER_1, List.of(DATABASE_1), USER_3_PRINCIPAL); } @Test @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"}) public void list_dataStewardPublicForeignContainer_succeeds() { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_3_USERNAME)) .thenReturn(Optional.of(USER_3)); /* test */ - list_generic(CONTAINER_2_ID, CONTAINER_2, List.of(DATABASE_1), USER_3_PRINCIPAL); + list_generic(CONTAINER_3_ID, CONTAINER_3, List.of(DATABASE_3), USER_3_PRINCIPAL); } @Test @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"}) public void list_dataStewardPrivateForeignContainer_succeeds() { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* mock */ when(userRepository.findByUsername(USER_3_USERNAME)) .thenReturn(Optional.of(USER_3)); @@ -497,8 +548,11 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void findById_researcherPublic_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* test */ - findById_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL); + findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL); } @Test @@ -506,6 +560,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { public void findById_researcherPublicForeignDatabase_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* test */ findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL); } @@ -514,6 +571,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @WithMockUser(username = USER_1_USERNAME, roles = {"RESEARCHER"}) public void findById_researcherPrivate_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* test */ findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_1_PRINCIPAL); } @@ -523,6 +583,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { public void findById_researcherPrivateForeignDatabase_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* test */ findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_1_PRINCIPAL); } @@ -532,6 +595,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { public void findById_developerPublicForeignDatabase_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* test */ findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL); } @@ -540,6 +606,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @WithMockUser(username = USER_2_USERNAME, roles = {"DEVELOPER"}) public void findById_developerPrivate_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* test */ findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_2_PRINCIPAL); } @@ -548,6 +617,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { @WithMockUser(username = USER_3_USERNAME, roles = {"DATA_STEWARD"}) public void findById_dataStewardPublic_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* test */ findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_3_PRINCIPAL); } @@ -557,8 +629,11 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { public void findById_dataStewardPublicForeignDatabase_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertTrue(DATABASE_3_PUBLIC); + /* test */ - findById_generic(CONTAINER_1_ID, CONTAINER_1, DATABASE_1_ID, DATABASE_1, USER_3_PRINCIPAL); + findById_generic(CONTAINER_3_ID, CONTAINER_3, DATABASE_3_ID, DATABASE_3, USER_3_PRINCIPAL); } @Test @@ -566,6 +641,9 @@ public class DatabaseEndpointUnitTest extends BaseUnitTest { public void findById_dataStewardPrivateForeignDatabase_succeeds() throws AccessDeniedException, DatabaseNotFoundException { + /* pre-condition */ + assertFalse(DATABASE_2_PUBLIC); + /* test */ findById_generic(CONTAINER_2_ID, CONTAINER_2, DATABASE_2_ID, DATABASE_2, USER_3_PRINCIPAL); } diff --git a/fda-database-service/rest-service/src/test/resources/application.properties b/fda-database-service/rest-service/src/test/resources/application.properties index 33b8c25e25..ddfddd8b33 100644 --- a/fda-database-service/rest-service/src/test/resources/application.properties +++ b/fda-database-service/rest-service/src/test/resources/application.properties @@ -22,8 +22,8 @@ logging.level.root=error logging.level.at.tuwien.=info # rabbitmq -fda.gateway.endpoint=http://broker-service:15672 -spring.rabbitmq.host=broker-service +fda.gateway.endpoint=http://dbrepo-broker-service:15672 +spring.rabbitmq.host=dbrepo-broker-service # elastic fda.elastic.endpoint=search-mock-service:9200 \ No newline at end of file diff --git a/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf b/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf index f4ada65dc8..6604865024 100644 --- a/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf +++ b/fda-database-service/rest-service/src/test/resources/nginx/nginx.conf @@ -39,7 +39,7 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; - proxy_pass http://broker-service:15672; + proxy_pass http://dbrepo-broker-service:15672; proxy_read_timeout 90; } } diff --git a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java index 26aca837e2..f986f75772 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java +++ b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java @@ -85,6 +85,7 @@ public interface DatabaseMapper { @Mapping(target = "id", source = "id"), @Mapping(target = "engine", source = "container.image", qualifiedByName = "engineMapping"), @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"), + @Mapping(target = "container", ignore = true), }) DatabaseBriefDto databaseToDatabaseBriefDto(Database data); diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java index c8a6ff55aa..e48292d753 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.container; +import at.tuwien.api.database.DatabaseBriefDto; import at.tuwien.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; @@ -36,6 +37,9 @@ public class ContainerBriefDto { @Schema(example = "air-quality") private String internalName; + @org.springframework.data.annotation.Transient + private DatabaseBriefDto database; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") private Instant created; } diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java index 699889b1c1..d91f7ce74d 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java @@ -1,6 +1,7 @@ package at.tuwien.api.database; import at.tuwien.api.container.ContainerBriefDto; +import at.tuwien.api.identifier.IdentifierBriefDto; import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonFormat; @@ -30,7 +31,7 @@ public class DatabaseBriefDto { @Schema(example = "Air Quality in Austria") private String description; - private IdentifierDto identifier; + private IdentifierBriefDto identifier; @JsonProperty("is_public") @Schema(example = "true") @@ -39,11 +40,10 @@ public class DatabaseBriefDto { @Schema(example = "mariadb:10.5") private String engine; + @ToString.Exclude @org.springframework.data.annotation.Transient private ContainerBriefDto container; - private UserBriefDto creator; - @Schema(example = "2020-08-04 11:12:00") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") private Instant created; diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java new file mode 100644 index 0000000000..ad0910407b --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java @@ -0,0 +1,28 @@ + +package at.tuwien.api.identifier; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +@Data +@Getter +@Setter +@Builder +public class CreatorBriefDto { + + @NotBlank + @Schema(example = "Josiah") + private String firstname; + + @NotBlank + @Schema(example = "Carberry") + private String lastname; + + @Schema(example = "Wesleyan University") + private String affiliation; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java index a3e816be75..c17feec05c 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java @@ -12,6 +12,7 @@ import lombok.Setter; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.time.Instant; +import java.util.List; @Data @Getter @@ -43,6 +44,24 @@ public class IdentifierBriefDto { @NotNull private IdentifierTypeDto type; + @NotNull + @Schema(example = "everyone") + private VisibilityTypeDto visibility; + + @Schema(example = "10.1038/nphys1170") + private String doi; + + @Schema(example = "TU Wien") + private String publisher; + + @NotNull + @JsonProperty("publication_year") + @Schema(example = "2022") + private Integer publicationYear; + + @NotNull + private List<CreatorBriefDto> creators; + @JsonIgnore @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") private Instant created; diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java index 90a49b81b8..a3233d7135 100644 --- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/database/Database.java @@ -5,16 +5,15 @@ import at.tuwien.entities.database.table.Table; import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.user.User; import lombok.*; -import net.sf.jsqlparser.statement.select.FromItem; -import org.hibernate.annotations.GenericGenerator; -import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.Where; +import org.hibernate.annotations.*; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.*; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import java.io.Serializable; import java.time.Instant; import java.util.List; @@ -28,7 +27,7 @@ import java.util.List; @javax.persistence.Table(name = "mdb_databases", uniqueConstraints = { @UniqueConstraint(columnNames = {"id", "internalName"}) }) -public class Database { +public class Database implements Serializable { @Id @EqualsAndHashCode.Include @@ -73,6 +72,13 @@ public class Database { }) private User contact; + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) + @JoinColumnsOrFormulas({ + @JoinColumnOrFormula(formula = @JoinFormula(value = "'DATABASE'", referencedColumnName = "identifier_type")), + @JoinColumnOrFormula(column = @JoinColumn(name = "id", referencedColumnName = "dbid", insertable = false, updatable = false)), + }) + private Identifier identifier; + @ToString.Exclude @org.springframework.data.annotation.Transient @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE) diff --git a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java index a6385bb908..95ffd29e59 100644 --- a/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java +++ b/fda-metadata-db/entities/src/main/java/at/tuwien/entities/identifier/Identifier.java @@ -3,19 +3,16 @@ package at.tuwien.entities.identifier; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.LanguageType; import at.tuwien.entities.database.License; -import at.tuwien.entities.user.Token; import at.tuwien.entities.user.User; import lombok.*; import org.hibernate.annotations.GenericGenerator; -import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.Where; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import javax.persistence.*; import javax.validation.constraints.NotBlank; +import java.io.Serializable; import java.time.Instant; import java.util.List; @@ -29,7 +26,7 @@ import java.util.List; @javax.persistence.Table(name = "mdb_identifiers", uniqueConstraints = { @UniqueConstraint(columnNames = {"qid", "cid", "dbid"}) }) -public class Identifier { +public class Identifier implements Serializable { @Id @EqualsAndHashCode.Include diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java index 117a60a338..277e622b62 100644 --- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java +++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/TableDataEndpoint.java @@ -147,7 +147,7 @@ public class TableDataEndpoint extends AbstractEndpoint { @RequestParam(required = false) String sortColumn) throws TableNotFoundException, DatabaseNotFoundException, DatabaseConnectionException, ImageNotSupportedException, TableMalformedException, PaginationException, ContainerNotFoundException, - QueryStoreException, NotAllowedException, QueryMalformedException, SortException, UserNotFoundException { + NotAllowedException, QueryMalformedException, SortException, UserNotFoundException { log.debug("endpoint find table data, containerId={}, databaseId={}, tableId={}, principal={}, timestamp={}, page={}, size={}, sortDirection={}, sortColumn={}", containerId, databaseId, tableId, principal, timestamp, page, size, sortDirection, sortColumn); /* check */ @@ -156,16 +156,9 @@ public class TableDataEndpoint extends AbstractEndpoint { throw new NotAllowedException("Missing data view permission"); } validateDataParams(page, size, sortDirection, sortColumn); - /* find */ - // TODO: Remove these comments - //final Long count = queryService.count(containerId, databaseId, tableId, timestamp, principal); - //log.debug("find table data has produced {} tuples", count); - //final HttpHeaders headers = new HttpHeaders(); - //headers.set("FDA-COUNT", count.toString()); final QueryResultDto response = queryService.tableFindAll(containerId, databaseId, tableId, timestamp, page, size, principal); log.trace("find table data resulted in result {}", response); return ResponseEntity.ok() - // .headers(headers) .body(response); } diff --git a/fda-query-service/rest-service/src/main/resources/application-local.yml b/fda-query-service/rest-service/src/main/resources/application-local.yml index 8e36da9b7b..9451262fbd 100644 --- a/fda-query-service/rest-service/src/main/resources/application-local.yml +++ b/fda-query-service/rest-service/src/main/resources/application-local.yml @@ -32,7 +32,7 @@ logging: pattern.console: "%d %highlight(%-5level) %msg%n" level: root: warn - at.tuwien.: info + at.tuwien.: trace org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug eureka: instance.hostname: query-service diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index dd59dcd081..556aa3937d 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -300,12 +300,22 @@ public abstract class BaseUnitTest { .tag(IMAGE_ELASTIC_TAG) .build(); + public final static Long IMAGE_PROXY_ID = 4L; + public final static String IMAGE_PROXY_REPOSITORY = "nginx"; + public final static String IMAGE_PROXY_TAG = "latest"; + + public final static ContainerImage IMAGE_PROXY = ContainerImage.builder() + .id(IMAGE_PROXY_ID) + .repository(IMAGE_PROXY_REPOSITORY) + .tag(IMAGE_PROXY_TAG) + .build(); + public final static Long CONTAINER_1_ID = 1L; public final static String CONTAINER_1_HASH = "deadbeef"; public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1; public final static String CONTAINER_1_NAME = "u01"; - public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01"; - public final static String CONTAINER_1_IP = "172.28.0.5"; + public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01"; + public final static String CONTAINER_1_IP = "172.30.0.5"; public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS); public final static String[] CONTAINER_1_ENV = new String[]{"MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=weather"}; @@ -328,8 +338,8 @@ public abstract class BaseUnitTest { public final static String CONTAINER_2_HASH = "deadbeef"; public final static ContainerImage CONTAINER_2_IMAGE = IMAGE_1; public final static String CONTAINER_2_NAME = "u02"; - public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02"; - public final static String CONTAINER_2_IP = "172.28.0.6"; + public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02"; + public final static String CONTAINER_2_IP = "172.30.0.6"; public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS); public final static String[] CONTAINER_2_ENV = new String[]{"MARIADB_USER=mariadb", "MARIADB_PASSWORD=mariadb", "MARIADB_ROOT_PASSWORD=mariadb", "MARIADB_DATABASE=zoo"}; @@ -352,8 +362,8 @@ public abstract class BaseUnitTest { public final static String CONTAINER_3_HASH = "deadbeef"; public final static ContainerImage CONTAINER_3_IMAGE = IMAGE_1; public final static String CONTAINER_3_NAME = "u03"; - public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03"; - public final static String CONTAINER_3_IP = "172.28.0.7"; + public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03"; + public final static String CONTAINER_3_IP = "172.30.0.7"; public final static Instant CONTAINER_3_CREATED = Instant.now().minus(1, HOURS); public final static HealthCheck CONTAINER_3_HEALTHCHECK = new HealthCheck() .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb")); @@ -373,8 +383,8 @@ public abstract class BaseUnitTest { public final static String CONTAINER_4_HASH = "deadbeef"; public final static ContainerImage CONTAINER_4_IMAGE = IMAGE_1; public final static String CONTAINER_4_NAME = "u04"; - public final static String CONTAINER_4_INTERNALNAME = "fda-userdb-u04"; - public final static String CONTAINER_4_IP = "172.28.0.8"; + public final static String CONTAINER_4_INTERNALNAME = "dbrepo-userdb-u04"; + public final static String CONTAINER_4_IP = "172.30.0.8"; public final static Instant CONTAINER_4_CREATED = Instant.now().minus(1, HOURS); public final static HealthCheck CONTAINER_4_HEALTHCHECK = new HealthCheck() .withTest(List.of("CMD", "mysqladmin", "ping", "--host=127.0.0.1", "--password=mariadb")); @@ -394,9 +404,9 @@ public abstract class BaseUnitTest { .build(); public final static Long CONTAINER_BROKER_ID = 5L; - public final static String CONTAINER_BROKER_NAME = "broker-service"; - public final static String CONTAINER_BROKER_INTERNAL_NAME = "broker-service"; - public final static String CONTAINER_BROKER_IP = "172.29.0.2"; + public final static String CONTAINER_BROKER_NAME = "dbrepo-broker-service"; + public final static String CONTAINER_BROKER_INTERNAL_NAME = "dbrepo-broker-service"; + public final static String CONTAINER_BROKER_IP = "172.31.0.2"; public final static String CONTAINER_BROKER_HASH = "deadbeef"; public final static Instant CONTAINER_BROKER_CREATED = Instant.now().minus(1, HOURS); public final static HealthCheck CONTAINER_BROKER_HEALTHCHECK = new HealthCheck() @@ -418,7 +428,7 @@ public abstract class BaseUnitTest { public final static Long CONTAINER_ELASTIC_ID = 6L; public final static String CONTAINER_ELASTIC_NAME = "fda-elastic-service"; public final static String CONTAINER_ELASTIC_INTERNAL_NAME = "search-mock-service"; - public final static String CONTAINER_ELASTIC_IP = "172.29.0.3"; + public final static String CONTAINER_ELASTIC_IP = "172.31.0.3"; public final static String CONTAINER_ELASTIC_HASH = "deadbeef"; public final static Instant CONTAINER_ELASTIC_CREATED = Instant.now().minus(1, HOURS); @@ -434,6 +444,28 @@ public abstract class BaseUnitTest { .creator(USER_1) .build(); + public final static Long CONTAINER_PROXY_ID = 7L; + public final static String CONTAINER_PROXY_NAME = "dbrepo-proxy"; + public final static String CONTAINER_PROXY_INTERNAL_NAME = "dbrepo-proxy"; + public final static String CONTAINER_PROXY_IP = "172.31.0.4"; + public final static String CONTAINER_PROXY_HASH = "deadbeef"; + public final static Instant CONTAINER_PROXY_CREATED = Instant.now().minus(1, HOURS); + public final static String[] CONTAINER_PROXY_ENV = new String[]{}; + public final static HealthCheck CONTAINER_PROXY_HEALTHCHECK = new HealthCheck() + .withTest(List.of("CMD", "service", "nginx", "status")); + + public final static Container CONTAINER_PROXY = Container.builder() + .id(CONTAINER_PROXY_ID) + .name(CONTAINER_PROXY_NAME) + .internalName(CONTAINER_PROXY_INTERNAL_NAME) + .imageId(IMAGE_PROXY_ID) + .image(IMAGE_PROXY) + .hash(CONTAINER_PROXY_HASH) + .ipAddress(CONTAINER_PROXY_IP) + .created(CONTAINER_PROXY_CREATED) + .creator(USER_1) + .build(); + public final static Long DATABASE_1_ID = 1L; public final static String DATABASE_1_NAME = "Weather"; public final static String DATABASE_1_INTERNALNAME = "weather"; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java index eac1924398..bf3df721ba 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/auth/AuthTokenFilterTest.java @@ -5,7 +5,6 @@ import at.tuwien.config.H2Utils; import at.tuwien.config.IndexConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.gateway.AuthenticationServiceGateway; -import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.UserRepository; import com.rabbitmq.client.Channel; import lombok.extern.log4j.Log4j2; @@ -46,9 +45,6 @@ public class AuthTokenFilterTest extends BaseUnitTest { @MockBean private UserRepository userRepository; - @MockBean - private RabbitMqListenerImpl rabbitMqListener; - @MockBean private AuthenticationServiceGateway authenticationServiceGateway; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java b/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java index 2f03e666f1..f91219b29e 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/config/DockerConfig.java @@ -90,12 +90,16 @@ public class DockerConfig extends BaseUnitTest { final HostConfig hostConfig1; final String network = (container.getInternalName().contains("userdb") ? "fda-userdb" : "fda-public"); if (bind == null) { + log.trace("map standard binding /tmp:/tmp"); hostConfig1 = hostConfig.withNetworkMode(network) .withBinds(Bind.parse("/tmp:/tmp")); } else { - hostConfig1 = hostConfig.withNetworkMode(network).withBinds(Bind.parse(bind), Bind.parse("/tmp:/tmp")); + log.trace("map non-standard binding {}, /tmp:/tmp", bind); + hostConfig1 = hostConfig.withNetworkMode(network) + .withBinds(Bind.parse(bind), Bind.parse("/tmp:/tmp")); } if (port != null) { + log.trace("map port binding {}:{}", port, port); hostConfig1.withPortBindings(PortBinding.parse(port + ":" + port)); } final CreateContainerCmd cmd = dockerClient.createContainerCmd(container.getImage().getRepository() + ":" + container.getImage().getTag()) @@ -158,14 +162,14 @@ public class DockerConfig extends BaseUnitTest { .withName("fda-userdb") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.28.0.0/16"))) + .withSubnet("172.30.0.0/16"))) .withEnableIpv6(false) .exec(); dockerClient.createNetworkCmd() .withName("fda-public") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.29.0.0/16"))) + .withSubnet("172.31.0.0/16"))) .withEnableIpv6(false) .exec(); } @@ -191,6 +195,9 @@ public class DockerConfig extends BaseUnitTest { case 5: log.debug("container with id {} has a health check config", containerId); return CONTAINER_BROKER_HEALTHCHECK; + case 7: + log.debug("container with id {} has a health check config", containerId); + return CONTAINER_PROXY_HEALTHCHECK; } log.trace("container with id {} does not have a healthcheck config", containerId); return null; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java b/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java index 0ee03e69ad..72ef54c966 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/config/RabbitMqConfig.java @@ -33,7 +33,7 @@ public class RabbitMqConfig { public List<ConsumerDto> findAllConsumers() throws IOException { log.trace("gateway broker find all consumers"); - final URI findUri = URI.create("http://broker-service:15672/api/consumers/%2F"); + final URI findUri = URI.create("http://dbrepo-broker-service:15672/api/consumers/%2F"); final ResponseEntity<List<ConsumerDto>> response = restTemplate.exchange(findUri, HttpMethod.GET, new HttpEntity<>(null, getHeaders()), new ParameterizedTypeReference<>() { }); @@ -52,7 +52,7 @@ public class RabbitMqConfig { } } for (Map.Entry<String, Integer> consumer : consumers.entrySet()) { - log.debug("queue {} has {} consumers", consumer.getKey(), consumer.getValue()); + log.trace("queue {} has {} consumers", consumer.getKey(), consumer.getValue()); } return response.getBody(); } diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java index 4b3898d83a..f5126e08b4 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ExportEndpointUnitTest.java @@ -7,6 +7,8 @@ import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.DatabaseAccessRepository; import at.tuwien.repository.jpa.TableRepository; @@ -49,9 +51,14 @@ public class ExportEndpointUnitTest extends BaseUnitTest { @MockBean private IndexConfig indexInitializer; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private QueryService queryService; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java index 7b1e9ade2c..8f315d2b40 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/QueryEndpointUnitTest.java @@ -10,6 +10,8 @@ import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.ContainerRepository; import at.tuwien.repository.jpa.DatabaseAccessRepository; @@ -52,9 +54,14 @@ public class QueryEndpointUnitTest extends BaseUnitTest { @MockBean private IndexConfig indexInitializer; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private DatabaseAccessRepository databaseAccessRepository; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java index f323836cf2..42782640bd 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/StoreEndpointUnitTest.java @@ -9,6 +9,8 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.querystore.Query; import at.tuwien.repository.jpa.IdentifierRepository; @@ -51,9 +53,14 @@ public class StoreEndpointUnitTest extends BaseUnitTest { @MockBean private IndexConfig indexInitializer; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @Autowired private StoreEndpoint storeEndpoint; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java index 38de6122bf..4cf2392ed0 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableDataEndpointUnitTest.java @@ -11,6 +11,8 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.database.table.Table; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.service.AccessService; import at.tuwien.service.DatabaseService; @@ -47,9 +49,14 @@ public class TableDataEndpointUnitTest extends BaseUnitTest { @MockBean private Channel channel; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private QueryServiceImpl queryService; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java index a06089955e..9a649b2e39 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/TableHistoryEndpointUnitTest.java @@ -9,6 +9,8 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.database.table.Table; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.DatabaseAccessRepository; import at.tuwien.service.DatabaseService; @@ -48,9 +50,14 @@ public class TableHistoryEndpointUnitTest extends BaseUnitTest { @MockBean private Channel channel; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private QueryService queryService; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java index 36430b419c..5cf4aadd98 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java @@ -11,6 +11,8 @@ import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.service.AccessService; import at.tuwien.service.DatabaseService; @@ -50,9 +52,14 @@ public class ViewEndpointUnitTest extends BaseUnitTest { @MockBean private IndexConfig indexInitializer; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private QueryService queryService; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/listener/RabbitMqListenerIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/listener/RabbitMqListenerIntegrationTest.java index 1ddaac142a..79b0f37ba1 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/listener/RabbitMqListenerIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/listener/RabbitMqListenerIntegrationTest.java @@ -3,9 +3,6 @@ package at.tuwien.listener; import at.tuwien.BaseUnitTest; import at.tuwien.api.amqp.ConsumerDto; import at.tuwien.config.*; -import at.tuwien.exception.*; -import at.tuwien.gateway.BrokerServiceGateway; -import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.*; import com.rabbitmq.client.BuiltinExchangeType; import com.rabbitmq.client.Channel; @@ -18,16 +15,18 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.io.IOException; import java.util.*; +import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.when; @Log4j2 +@ActiveProfiles(profiles = "junit") @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @SpringBootTest @ExtendWith(SpringExtension.class) @@ -39,9 +38,6 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest { @MockBean private IndexConfig indexConfig; - @MockBean - private BrokerServiceGateway brokerServiceGateway; - @Autowired private Channel channel; @@ -57,12 +53,6 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest { @Autowired private TableRepository tableRepository; - @Autowired - private RabbitMqListenerImpl rabbitMqListener; - - @Autowired - private TableColumnRepository tableColumnRepository; - @Autowired private H2Utils h2Utils; @@ -73,12 +63,14 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest { private AmqpConfig amqpConfig; @Rule - public Timeout globalTimeout = Timeout.seconds(60); + public Timeout globalTimeout = Timeout.seconds(300); @BeforeAll public static void beforeAll() throws InterruptedException { afterAll(); + /* create networks */ DockerConfig.createAllNetworks(); + /* create containers */ DockerConfig.createContainer(null, CONTAINER_BROKER, 15672, CONTAINER_BROKER_ENV); DockerConfig.startContainer(CONTAINER_BROKER); } @@ -104,7 +96,11 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest { } @Test - public void updateConsumers_succeeds() throws AmqpException, IOException, InterruptedException { + public void updateConsumers_succeeds() throws IOException, InterruptedException { + + /* pre-condition */ + assertEquals(0, getConsumers().size()); + assertEquals(2, amqpConfig.getAmqpConsumers()); /* mock */ channel.exchangeDeclare(DATABASE_1_EXCHANGE, BuiltinExchangeType.FANOUT); @@ -114,21 +110,23 @@ public class RabbitMqListenerIntegrationTest extends BaseUnitTest { channel.queueBind(TABLE_2_QUEUE_NAME, DATABASE_1_EXCHANGE, TABLE_2_ROUTING_KEY); channel.queueDeclare(TABLE_3_QUEUE_NAME, true, false, false, null); channel.queueBind(TABLE_3_QUEUE_NAME, DATABASE_1_EXCHANGE, TABLE_3_ROUTING_KEY); - when(brokerServiceGateway.findAllConsumers()) - .thenReturn(List.of()); - - /* pre-condition */ - assertEquals(0, rabbitMqConfig.findAllConsumers().size()); - assertEquals(2, amqpConfig.getAmqpConsumers()); /* test */ - rabbitMqListener.updateConsumers(); - Thread.sleep(10 * 1000); - final List<ConsumerDto> response = rabbitMqConfig.findAllConsumers(); - assertEquals(6, response.size()); - assertEquals(2, (int) response.stream().filter(c -> c.getQueue().getName().equals(TABLE_1_QUEUE_NAME)).count()); - assertEquals(2, (int) response.stream().filter(c -> c.getQueue().getName().equals(TABLE_2_QUEUE_NAME)).count()); - assertEquals(2, (int) response.stream().filter(c -> c.getQueue().getName().equals(TABLE_3_QUEUE_NAME)).count()); + Thread.sleep(30 * 1000) /* wait for scheduled insert */; + final List<ConsumerDto> response = getConsumers(); + final List<ConsumerDto> consumers1 = response.stream().filter(c -> c.getQueue().getName().equals(TABLE_1_QUEUE_NAME)).collect(Collectors.toList()); + assertEquals(2, consumers1.size()); + final List<ConsumerDto> consumers2 = response.stream().filter(c -> c.getQueue().getName().equals(TABLE_2_QUEUE_NAME)).collect(Collectors.toList()); + assertEquals(2, consumers2.size()); + final List<ConsumerDto> consumers3 = response.stream().filter(c -> c.getQueue().getName().equals(TABLE_3_QUEUE_NAME)).collect(Collectors.toList()); + assertEquals(2, consumers3.size()); + } + + private List<ConsumerDto> getConsumers() throws IOException { + return rabbitMqConfig.findAllConsumers() + .stream() + .filter(c -> List.of(TABLE_1_QUEUE_NAME, TABLE_2_QUEUE_NAME, TABLE_3_QUEUE_NAME).contains(c.getQueue().getName())) + .collect(Collectors.toList()); } } diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java index d8d59487f6..834eb21836 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewIdxRepositoryIntegrationTest.java @@ -7,6 +7,8 @@ import at.tuwien.config.DockerConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.View; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.elastic.ViewIdxRepository; import at.tuwien.repository.jpa.*; @@ -45,9 +47,14 @@ public class ViewIdxRepositoryIntegrationTest extends BaseUnitTest { @MockBean private Channel channel; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private UserRepository userRepository; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java index 4000a15599..eddcffdc8e 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/repository/ViewRepositoryIntegrationTest.java @@ -5,6 +5,8 @@ import at.tuwien.config.H2Utils; import at.tuwien.config.IndexConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.View; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.*; import com.rabbitmq.client.Channel; @@ -36,9 +38,14 @@ public class ViewRepositoryIntegrationTest extends BaseUnitTest { @MockBean private Channel channel; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private IndexConfig indexConfig; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java index 29d3e0f2d8..ba53952bab 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java @@ -5,6 +5,8 @@ import at.tuwien.config.IndexConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.container.Container; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.*; import com.rabbitmq.client.Channel; @@ -35,9 +37,14 @@ public class ContainerServiceIntegrationTest extends BaseUnitTest { @MockBean private Channel channel; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @Autowired private ImageRepository imageRepository; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java index ba2db43d65..421304d117 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueryServiceIntegrationTest.java @@ -10,6 +10,8 @@ import at.tuwien.config.IndexConfig; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.querystore.Query; import at.tuwien.repository.jpa.*; @@ -56,9 +58,14 @@ public class QueryServiceIntegrationTest extends BaseUnitTest { @MockBean private IndexConfig indexInitializer; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private DatabaseRepository databaseRepository; @@ -79,12 +86,10 @@ public class QueryServiceIntegrationTest extends BaseUnitTest { private final static String BIND_ZOO = new File("./src/test/resources/zoo").toPath().toAbsolutePath() + ":/docker-entrypoint-initdb.d"; @BeforeAll - public static void beforeAll() throws InterruptedException { + public static void beforeAll() { afterAll(); /* create network */ DockerConfig.createAllNetworks(); - DockerConfig.createContainer(null, CONTAINER_BROKER, 15672, CONTAINER_BROKER_ENV); - DockerConfig.startContainer(CONTAINER_BROKER); } @AfterAll diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java index 0fe3b659ef..49a47646b2 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java @@ -8,6 +8,8 @@ import at.tuwien.config.DockerConfig; import at.tuwien.config.IndexConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.exception.AmqpException; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.DatabaseRepository; import at.tuwien.repository.jpa.TableRepository; @@ -53,11 +55,16 @@ public class QueueServiceIntegrationTest extends BaseUnitTest { @MockBean private IndexConfig indexInitializer; + @MockBean + private RabbitMqConsumer rabbitMqConsumer; + + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ @MockBean - private RabbitMqConsumer rabbitMqConsumer; + private BrokerServiceGateway brokerServiceGateway; @Autowired private AmqpConfig amqpConfig; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java index 17e9cb979b..3307d1bf81 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/StoreServiceIntegrationTest.java @@ -9,6 +9,8 @@ import at.tuwien.config.MariaDbConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.exception.*; import at.tuwien.entities.database.Database; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.querystore.Query; import at.tuwien.repository.jpa.*; @@ -51,9 +53,14 @@ public class StoreServiceIntegrationTest extends BaseUnitTest { @MockBean private Channel channel; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private TableRepository tableRepository; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java index 14b294520f..87c8fa13f7 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -8,6 +8,8 @@ import at.tuwien.config.IndexConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.ContainerRepository; import at.tuwien.repository.jpa.DatabaseRepository; @@ -50,9 +52,14 @@ public class TableServiceIntegrationTest extends BaseUnitTest { @MockBean private Channel channel; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private TableRepository tableRepository; @@ -94,6 +101,7 @@ public class TableServiceIntegrationTest extends BaseUnitTest { /* metadata db */ imageRepository.save(IMAGE_1); containerRepository.save(CONTAINER_1); + DATABASE_1.setTables(List.of()); databaseRepository.save(DATABASE_1); } diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java index 69ce154d9f..4a523c0a23 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -5,6 +5,8 @@ import at.tuwien.config.IndexConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; +import at.tuwien.listener.MessageQueueListener; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.jpa.*; import com.rabbitmq.client.Channel; @@ -39,9 +41,14 @@ public class TableServiceUnitTest extends BaseUnitTest { @MockBean private IndexConfig indexInitializer; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @Autowired private TableService tableService; diff --git a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java index d827ec5bfa..c2cf5c3008 100644 --- a/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java +++ b/fda-query-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java @@ -9,13 +9,10 @@ import at.tuwien.config.MariaDbConfig; import at.tuwien.config.ReadyConfig; import at.tuwien.entities.database.View; import at.tuwien.exception.*; +import at.tuwien.gateway.BrokerServiceGateway; import at.tuwien.listener.impl.RabbitMqListenerImpl; import at.tuwien.repository.elastic.ViewIdxRepository; import at.tuwien.repository.jpa.*; -import com.github.dockerjava.api.command.CreateContainerResponse; -import com.github.dockerjava.api.exception.NotModifiedException; -import com.github.dockerjava.api.model.Bind; -import com.github.dockerjava.api.model.Network; import com.rabbitmq.client.Channel; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.AfterAll; @@ -30,12 +27,10 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.io.File; import java.sql.SQLException; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; -import static at.tuwien.config.DockerConfig.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; @@ -60,9 +55,14 @@ public class ViewServiceIntegrationTest extends BaseUnitTest { @MockBean private ViewIdxRepository viewIdxRepository; + /* keep */ @MockBean private RabbitMqListenerImpl rabbitMqListener; + /* keep */ + @MockBean + private BrokerServiceGateway brokerServiceGateway; + @MockBean private DatabaseRepository databaseRepository; diff --git a/fda-query-service/rest-service/src/test/resources/application.properties b/fda-query-service/rest-service/src/test/resources/application.properties index aac636db15..4eea490a91 100644 --- a/fda-query-service/rest-service/src/test/resources/application.properties +++ b/fda-query-service/rest-service/src/test/resources/application.properties @@ -19,12 +19,14 @@ spring.jpa.show-sql=false # additional logging logging.level.root=error -logging.level.at.tuwien.=info +logging.level.at.tuwien.=trace # broker service -spring.rabbitmq.host=broker-service +spring.rabbitmq.host=dbrepo-broker-service spring.rabbitmq.username=guest spring.rabbitmq.password=guest # search service -fda.elastic.endpoint=search-mock-service:9200 \ No newline at end of file +fda.consumers=2 +fda.gateway.endpoint: http://localhost:15672 +fda.elastic.endpoint=dbrepo-search-service:9200 \ No newline at end of file diff --git a/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv b/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv deleted file mode 100644 index 9bfb33891d..0000000000 --- a/fda-query-service/rest-service/src/test/resources/webserver/weather_aus.csv +++ /dev/null @@ -1,3 +0,0 @@ -1,2008-12-01,Albury,13.4,0.6 -2,2008-12-02,Albury,7.4,0 -3,2008-12-03,Albury,12.9,0 \ No newline at end of file diff --git a/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java b/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java index 8a5bc1c3f1..e8f0b9c364 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java +++ b/fda-query-service/services/src/main/java/at/tuwien/gateway/BrokerServiceGateway.java @@ -5,5 +5,6 @@ import at.tuwien.api.amqp.ConsumerDto; import java.util.List; public interface BrokerServiceGateway { + List<ConsumerDto> findAllConsumers(); } diff --git a/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java b/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java index 16afe426ad..4629fbe4cc 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java +++ b/fda-query-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java @@ -7,7 +7,9 @@ import at.tuwien.gateway.BrokerServiceGateway; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.env.Environment; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -17,6 +19,7 @@ import org.springframework.web.client.RestTemplate; import java.net.URI; import java.nio.charset.Charset; +import java.util.Arrays; import java.util.List; @Slf4j @@ -26,20 +29,30 @@ public class BrokerServiceGatewayImpl implements BrokerServiceGateway { private final AmqpConfig amqpConfig; private final RestTemplate restTemplate; private final GatewayConfig gatewayConfig; + private final Environment environment; private final static String VIRTUAL_SERVER = "%2F"; @Autowired - public BrokerServiceGatewayImpl(AmqpConfig amqpConfig, RestTemplate restTemplate, GatewayConfig gatewayConfig) { + public BrokerServiceGatewayImpl(AmqpConfig amqpConfig, RestTemplate restTemplate, GatewayConfig gatewayConfig, + Environment environment) { this.amqpConfig = amqpConfig; this.restTemplate = restTemplate; this.gatewayConfig = gatewayConfig; + this.environment = environment; } @Override public List<ConsumerDto> findAllConsumers() { + final StringBuilder urlBuilder = new StringBuilder(gatewayConfig.getGatewayEndpoint()) + .append("/api"); + if (Arrays.stream(environment.getActiveProfiles()).noneMatch(p -> p.equals("junit"))) { + urlBuilder.append("/broker"); + } + urlBuilder.append("/consumers/") + .append(VIRTUAL_SERVER); log.trace("gateway broker find all consumers, virtual server={}", VIRTUAL_SERVER); - final URI findUri = URI.create(gatewayConfig.getGatewayEndpoint() + "/api/broker/consumers/" + VIRTUAL_SERVER); + final URI findUri = URI.create(urlBuilder.toString()); final ResponseEntity<List<ConsumerDto>> response = restTemplate.exchange(findUri, HttpMethod.GET, new HttpEntity<>(null, getHeaders()), new ParameterizedTypeReference<>() { }); diff --git a/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java b/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java index ebdc5a4739..afac64a7a0 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java +++ b/fda-query-service/services/src/main/java/at/tuwien/listener/MessageQueueListener.java @@ -1,4 +1,10 @@ package at.tuwien.listener; +import at.tuwien.exception.AmqpException; +import org.springframework.scheduling.annotation.Scheduled; + public interface MessageQueueListener { + + @Scheduled(fixedDelay = 5000) + void updateConsumers() throws AmqpException; } diff --git a/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java b/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java index 1423461dd1..bc45a78888 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java +++ b/fda-query-service/services/src/main/java/at/tuwien/listener/impl/RabbitMqListenerImpl.java @@ -14,7 +14,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.IOException; import java.util.List; @Log4j2 @@ -35,6 +34,7 @@ public class RabbitMqListenerImpl implements MessageQueueListener { this.brokerServiceGateway = brokerServiceGateway; } + @Override @Scheduled(fixedDelay = 5000) @Transactional(readOnly = true) public void updateConsumers() throws AmqpException { diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java new file mode 100644 index 0000000000..7c49211efb --- /dev/null +++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/ContainerMapper.java @@ -0,0 +1,15 @@ +package at.tuwien.mapper; + +import at.tuwien.api.container.ContainerDto; +import at.tuwien.entities.container.Container; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface ContainerMapper { + + org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ContainerMapper.class); + + /* keep */ + ContainerDto containerToContainerDto(Container data); + +} diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java index 35bcfffb45..04234f583f 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java +++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/ViewMapper.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.Locale; import java.util.regex.Pattern; -@Mapper(componentModel = "spring") +@Mapper(componentModel = "spring", uses = {ContainerMapper.class}) public interface ViewMapper { org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ViewMapper.class); diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java index 686e0c78ec..01924d9fb2 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/QueryService.java @@ -165,7 +165,7 @@ public interface QueryService { QueryResultDto viewFindAll(Long containerId, Long databaseId, View view, Long page, Long size, Principal principal) throws ViewNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, DatabaseConnectionException, ViewMalformedException, PaginationException, - ContainerNotFoundException, QueryMalformedException, UserNotFoundException; + ContainerNotFoundException, QueryMalformedException, UserNotFoundException, TableMalformedException; /** * Finds one query by container-database-query triple. diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java index 0bd5f0c992..0c84ec5bb7 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java @@ -101,7 +101,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService columns = parseColumns(query.getQuery(), database); } catch (JSQLParserException e) { log.error("Failed to map/parse columns: {}", e.getMessage()); - throw new ColumnParseException(e.getMessage(), e); + throw new ColumnParseException("Failed to map/parse columns: " + e.getMessage(), e); } final String statement = queryMapper.queryToRawTimestampedQuery(query.getQuery(), database, query.getCreated(), true, page, size); final QueryResultDto dto = executeNonPersistent(containerId, databaseId, statement, columns); @@ -143,7 +143,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService } } - private QueryResultDto executeNonPersistent(Long containerId, Long databaseId, String statement, List<TableColumn> columns) throws QueryMalformedException, DatabaseNotFoundException { + private QueryResultDto executeNonPersistent(Long containerId, Long databaseId, String statement, List<TableColumn> columns) + throws QueryMalformedException, DatabaseNotFoundException, TableMalformedException { /* find */ final Database database = databaseService.find(containerId, databaseId); final User root = databaseMapper.containerToPrivilegedUser(database.getContainer()); @@ -156,14 +157,15 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService final ResultSet resultSet = preparedStatement.executeQuery(); return queryMapper.resultListToQueryResultDto(columns, resultSet); } catch (SQLException e) { - log.error("Failed to map object: {}", e.getMessage()); - throw new QueryMalformedException("Failed to map object", e); + log.error("Failed to execute and map time-versioned query: {}", e.getMessage()); + throw new TableMalformedException("Failed to execute and map time-versioned query: " + e.getMessage(), e); } finally { dataSource.close(); } } - private Long executeCountNonPersistent(Long containerId, Long databaseId, String statement) throws QueryMalformedException, TableMalformedException, DatabaseNotFoundException, QueryStoreException { + private Long executeCountNonPersistent(Long containerId, Long databaseId, String statement) + throws QueryMalformedException, TableMalformedException, DatabaseNotFoundException, QueryStoreException { /* find */ final Database database = databaseService.find(containerId, databaseId); final User root = databaseMapper.containerToPrivilegedUser(database.getContainer()); @@ -177,7 +179,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService return queryMapper.resultSetToNumber(resultSet); } catch (SQLException e) { log.error("Failed to map object: {}", e.getMessage()); - throw new TableMalformedException("Failed to map object", e); + throw new TableMalformedException("Failed to map object: " + e.getMessage(), e); } finally { dataSource.close(); } @@ -187,8 +189,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService @Transactional(readOnly = true) public QueryResultDto tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Long page, Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException, - ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException, - ContainerNotFoundException, QueryMalformedException, UserNotFoundException { + ImageNotSupportedException, TableMalformedException, QueryMalformedException { /* find */ final Table table = tableService.find(containerId, databaseId, tableId); /* run query */ @@ -199,9 +200,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService @Override @Transactional(readOnly = true) public QueryResultDto viewFindAll(Long containerId, Long databaseId, View view, - Long page, Long size, Principal principal) throws ViewNotFoundException, DatabaseNotFoundException, - ImageNotSupportedException, DatabaseConnectionException, ViewMalformedException, PaginationException, - ContainerNotFoundException, QueryMalformedException, UserNotFoundException { + Long page, Long size, Principal principal) throws DatabaseNotFoundException, + ImageNotSupportedException, QueryMalformedException, TableMalformedException { /* find */ /* run query */ String statement = queryMapper.viewToRawFindAllQuery(view, size, page); @@ -231,9 +231,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService @Transactional(readOnly = true) public QueryResultDto findAllView(Long containerId, Long databaseId, Long viewId, Instant timestamp, Long page, - Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException, - ImageNotSupportedException, DatabaseConnectionException, TableMalformedException, PaginationException, - ContainerNotFoundException, QueryMalformedException, UserNotFoundException { + Long size, Principal principal) throws TableNotFoundException, DatabaseNotFoundException, + ImageNotSupportedException, TableMalformedException, QueryMalformedException { /* find */ final Table table = tableService.find(containerId, databaseId, viewId); /* run query */ @@ -244,9 +243,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService @Override @Transactional(readOnly = true) public ExportResource tableFindAll(Long containerId, Long databaseId, Long tableId, Instant timestamp, Principal principal) - throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, - DatabaseConnectionException, TableMalformedException, PaginationException, ContainerNotFoundException, - FileStorageException, QueryMalformedException, UserNotFoundException { + throws TableNotFoundException, DatabaseNotFoundException, FileStorageException, QueryMalformedException { final String filename = RandomStringUtils.randomAlphabetic(40) + ".csv"; /* find */ final Database database = databaseService.find(containerId, databaseId); @@ -266,7 +263,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService FileUtils.forceDelete(file); } catch (IOException | SQLException e) { log.error("Failed to execute query and/or export file: {}", e.getMessage()); - throw new FileStorageException("Failed to execute query and/or export file", e); + throw new FileStorageException("Failed to execute query and/or export file: " + e.getMessage(), e); } finally { dataSource.close(); } @@ -319,7 +316,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService @Transactional public void update(Long containerId, Long databaseId, Long tableId, TableCsvUpdateDto data, Principal principal) throws ImageNotSupportedException, TableMalformedException, DatabaseNotFoundException, - TableNotFoundException, QueryMalformedException, UserNotFoundException { + TableNotFoundException, QueryMalformedException { /* find */ final Database database = databaseService.find(containerId, databaseId); final Table table = tableService.find(containerId, databaseId, tableId); @@ -334,7 +331,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService preparedStatement.executeUpdate(); } catch (SQLException e) { log.error("Failed to update tuples: {}", e.getMessage()); - throw new TableMalformedException("Failed to update tuples", e); + throw new TableMalformedException("Failed to update tuples: " + e.getMessage(), e); } finally { dataSource.close(); } @@ -351,10 +348,6 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService final User root = databaseMapper.containerToPrivilegedUser(database.getContainer()); log.trace("parsed insert data {}", data); /* run query */ - if (data.getData().size() == 0) { - log.error("Failed to parse data, the provided map {} is empty", data.getData()); - throw new TableMalformedException("Failed to parse data"); - } final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(), database.getContainer(), database, root); /* prepare the statement */ @@ -364,14 +357,14 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService preparedStatement.executeUpdate(); } catch (DateTimeParseException e) { log.error("Failed to parse date: {}", e.getMessage()); - throw new TableMalformedException("Failed to parse date", e); + throw new TableMalformedException("Failed to parse date: " + e.getMessage(), e); } catch (NumberFormatException e) { log.error("Failed to parse number: {}", e.getMessage()); - throw new TableMalformedException("Failed to parse number", e); + throw new TableMalformedException("Failed to parse number: " + e.getMessage(), e); } catch (Exception e) { log.error("Database failed to accept tuple: {}", e.getMessage()); log.throwing(e); - throw new TableMalformedException("Database failed to accept tuple " + e.getMessage(), e); + throw new TableMalformedException("Database failed to accept tuple: " + e.getMessage(), e); } finally { dataSource.close(); } @@ -397,7 +390,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService preparedStatement.executeUpdate(); } catch (SQLException e) { log.error("Failed to delete tuples: {}", e.getMessage()); - throw new TableMalformedException("Failed to delete tuples", e); + throw new TableMalformedException("Failed to delete tuples: " + e.getMessage(), e); } finally { dataSource.close(); } diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index ff9d2c1e77..d971603dd8 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -83,9 +83,9 @@ public abstract class BaseUnitTest { public final static String DATABASE_NET = "fda-userdb"; - public final static String BROKER_NAME = "fda-broker-service"; - public final static String BROKER_IP = "172.29.0.2"; - public final static String BROKER_HOSTNAME = "broker-service"; + public final static String BROKER_NAME = "dbrepo-broker-service"; + public final static String BROKER_IP = "172.31.0.2"; + public final static String BROKER_HOSTNAME = "dbrepo-broker-service"; public final static Integer BROKER_MANAGEMENT_PORT = 15672; public final static String BROKER_IMAGE = "rabbitmq"; public final static String BROKER_TAG = "3-management-alpine"; @@ -146,24 +146,24 @@ public abstract class BaseUnitTest { public final static String CONTAINER_1_HASH = "deadbeef"; public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1; public final static String CONTAINER_1_NAME = "u01"; - public final static String CONTAINER_1_INTERNALNAME = "fda-userdb-u01"; - public final static String CONTAINER_1_IP = "172.28.0.5"; + public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01"; + public final static String CONTAINER_1_IP = "172.30.0.5"; public final static Instant CONTAINER_1_CREATED = Instant.now().minus(1, HOURS); public final static Long CONTAINER_2_ID = 2L; public final static String CONTAINER_2_HASH = "deadbeef"; public final static ContainerImage CONTAINER_2_IMAGE = IMAGE_1; public final static String CONTAINER_2_NAME = "u02"; - public final static String CONTAINER_2_INTERNALNAME = "fda-userdb-u02"; - public final static String CONTAINER_2_IP = "172.28.0.6"; + public final static String CONTAINER_2_INTERNALNAME = "dbrepo-userdb-u02"; + public final static String CONTAINER_2_IP = "172.30.0.6"; public final static Instant CONTAINER_2_CREATED = Instant.now().minus(1, HOURS); public final static Long CONTAINER_3_ID = 3L; public final static String CONTAINER_3_HASH = "deadbeef"; public final static ContainerImage CONTAINER_3_IMAGE = IMAGE_1; public final static String CONTAINER_3_NAME = "u03"; - public final static String CONTAINER_3_INTERNALNAME = "fda-userdb-u03"; - public final static String CONTAINER_3_IP = "172.28.0.7"; + public final static String CONTAINER_3_INTERNALNAME = "dbrepo-userdb-u03"; + public final static String CONTAINER_3_IP = "172.30.0.7"; public final static Instant CONTAINER_3_CREATED = Instant.now().minus(1, HOURS); public final static Long DATABASE_1_ID = 1L; @@ -739,7 +739,7 @@ public abstract class BaseUnitTest { public final static String CONTAINER_NGINX_NET = "fda-public"; public final static String CONTAINER_NGINX_NAME = "file-service"; public final static String CONTAINER_NGINX_INTERNALNAME = "fda-test-file-service"; - public final static String CONTAINER_NGINX_IP = "172.29.0.3"; + public final static String CONTAINER_NGINX_IP = "172.31.0.3"; public final static Instant CONTAINER_NGINX_CREATED = Instant.now().minus(3, HOURS); public final static Long CONCEPT_1_ID = 1L; diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java b/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java index 6cf55041ba..26d1b50051 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/config/GatewayConfig.java @@ -21,7 +21,7 @@ public class GatewayConfig { @Bean("brokerRestTemplate") public RestTemplate brokerRestTemplate() { final RestTemplate restTemplate = new RestTemplate(); - restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("http://broker-service:15672")); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("http://dbrepo-broker-service:15672")); restTemplate.getInterceptors() .add(new BasicAuthenticationInterceptor(brokerUsername, brokerPassword)); return restTemplate; diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java index 300e882c68..1b5a0ecb18 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/MessageQueueServiceIntegrationTest.java @@ -67,14 +67,14 @@ public class MessageQueueServiceIntegrationTest extends BaseUnitTest { .withName("fda-userdb") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.28.0.0/16"))) + .withSubnet("172.30.0.0/16"))) .withEnableIpv6(false) .exec(); dockerClient.createNetworkCmd() .withName("fda-public") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.29.0.0/16"))) + .withSubnet("172.31.0.0/16"))) .withEnableIpv6(false) .exec(); /* create amqp */ diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java index 0592842109..49fc8fef9e 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -98,14 +98,14 @@ public class TableServiceIntegrationTest extends BaseUnitTest { .withName("fda-userdb") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.28.0.0/16"))) + .withSubnet("172.30.0.0/16"))) .withEnableIpv6(false) .exec(); dockerClient.createNetworkCmd() .withName("fda-public") .withIpam(new Network.Ipam() .withConfig(new Network.Ipam.Config() - .withSubnet("172.29.0.0/16"))) + .withSubnet("172.31.0.0/16"))) .withEnableIpv6(false) .exec(); /* create container */ diff --git a/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java b/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java index 6caf0d930e..dfc90d2ea2 100644 --- a/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java +++ b/fda-table-service/rest-service/src/test/java/at/tuwien/utils/AmqpUtils.java @@ -34,7 +34,7 @@ public class AmqpUtils { public void createExchange(String exchange) { exchange = exchange.replace("/", "%2F"); - final URI uri = URI.create("http://broker-service:15672/api/exchanges/%2F/" + exchange); + final URI uri = URI.create("http://dbrepo-broker-service:15672/api/exchanges/%2F/" + exchange); final CreateExchangeDto payload = CreateExchangeDto.builder() .type("fanout") .autoDelete(false) @@ -67,7 +67,7 @@ public class AmqpUtils { } public boolean queueExists(String queue) { - final URI uri = URI.create("http://broker-service:15672/api/queues/%2F/"); + final URI uri = URI.create("http://dbrepo-broker-service:15672/api/queues/%2F/"); final ResponseEntity<QueueDto[]> response = restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(null), QueueDto[].class); if (!response.getStatusCode().equals(HttpStatus.OK)) { log.error("Failed to find queue, code is {}", response.getStatusCode()); diff --git a/fda-ui/.gitignore b/fda-ui/.gitignore index 0c83f47701..a6a8dd571f 100644 --- a/fda-ui/.gitignore +++ b/fda-ui/.gitignore @@ -21,6 +21,7 @@ lib-cov # Coverage directory used by tools like istanbul coverage/ +coverage.txt # nyc test coverage .nyc_output @@ -93,4 +94,5 @@ sw.* *.swp # CI records some videos for the e2e tests -videos +videos/ +screenshots/ diff --git a/fda-ui/.nycrc b/fda-ui/.nycrc index ccda5111b9..a4841b7947 100644 --- a/fda-ui/.nycrc +++ b/fda-ui/.nycrc @@ -6,7 +6,7 @@ "branches": 35, "check-coverage": true, "include": [ "components/**/*.vue", "layouts/**/*.vue", "pages/**/*.vue", "server-middleware/**/*.js", "store/**/*.js"], - "exclude": ["node_modules"], + "exclude": ["node_modules", "server-middleware", "store"], "extension": [".js", ".vue"], "reporter": [ "lcov", diff --git a/fda-ui/.prod/default.conf b/fda-ui/.prod/default.conf deleted file mode 100644 index 43a88f37d8..0000000000 --- a/fda-ui/.prod/default.conf +++ /dev/null @@ -1,30 +0,0 @@ -server { - listen 3000 default_server; - server_name dbrepo.local; - proxy_set_header Host dbrepo.local; - - root /usr/share/nginx/html; - index index.html index.htm; - - location /api { - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://fda-gateway-service:9095; - } - - location / { - root /usr/share/nginx/html; - try_files $uri $uri/ /index.html; - index index.html index.htm; - } - - # allow post on static pages - error_page 405 =200 $uri; - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } - -} diff --git a/fda-ui/.prod/secure.conf b/fda-ui/.prod/secure.conf deleted file mode 100644 index 402ce356e6..0000000000 --- a/fda-ui/.prod/secure.conf +++ /dev/null @@ -1,38 +0,0 @@ -server { - listen 443 default_server; - server_name dbrepo.ossdip.at; - proxy_set_header Host dbrepo.ossdip.at; - - root /usr/share/nginx/html; - - index index.html; - location / { - root /usr/share/nginx/html; - try_files $uri $uri/ /index.html; - index index.html index.htm; - } - - location /api { - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://fda-gateway-service:9095; - } - - location /server-middleware { - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass https://fda-ui:443; - } - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } - - ssl on; - ssl_certificate /etc/nginx/conf.d/cert.pem; - ssl_certificate_key /etc/nginx/conf.d/privkey.pem; - -} diff --git a/fda-ui/Dockerfile b/fda-ui/Dockerfile index b7d21fc55b..0df37b3162 100644 --- a/fda-ui/Dockerfile +++ b/fda-ui/Dockerfile @@ -1,4 +1,3 @@ -# FROM node:lts as build FROM node:14-alpine as build MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> @@ -35,6 +34,9 @@ COPY ./utils ./utils RUN yarn build > /dev/null +FROM node:14-alpine as runtime +MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> + EXPOSE 3000 EXPOSE 9100 @@ -51,6 +53,13 @@ ENV VERSION="${TAG}" ENV TITLE="Database Repository" ENV ICON="/favicon.ico" +WORKDIR /app + +COPY --from=build /usr/local/bin/node_exporter/ /usr/local/bin/node_exporter/ +COPY --from=build /app /app + +RUN ls -la + COPY ./docker-entrypoint.sh /app/docker-entrypoint.sh RUN chmod +x /app/docker-entrypoint.sh diff --git a/fda-ui/components/DatabaseList.vue b/fda-ui/components/DatabaseList.vue new file mode 100644 index 0000000000..ab94f978c1 --- /dev/null +++ b/fda-ui/components/DatabaseList.vue @@ -0,0 +1,192 @@ +<template> + <div> + <v-progress-linear v-if="loadingContainers || loadingDatabases" :color="loadingColor" :indeterminate="!error" /> + <v-card + v-for="(container, idx) in containers" + :key="idx" + :to="link(container)" + :disabled="!container.database" + flat + tile> + <v-divider class="mx-4" /> + <v-card-title v-if="!hasDatabase(container)" v-text="container.name" /> + <v-card-title v-if="hasDatabase(container)"> + <a :href="`/container/${container.id}/database/${container.database.id}`">{{ container.name }}</a> + </v-card-title> + <v-card-subtitle v-if="!hasIdentifier(container)" class="db-subtitle" v-text="formatCreator(container.creator)" /> + <v-card-subtitle v-if="hasIdentifier(container)" class="db-subtitle" v-text="formatCreatorz(container)" /> + <v-card-text class="db-description"> + <div class="db-tags"> + <v-chip v-if="hasDatabase(container) && container.database.is_public" small color="green" outlined>Public</v-chip> + <v-chip v-if="hasDatabase(container) && !container.database.is_public" small color="red" outlined>Private</v-chip> + <v-chip v-if="hasIdentifier(container)" small outlined>PID</v-chip> + <v-chip + v-if="identifierCreated(container)" + small + outlined + v-text="container.database.identifier.publisher" /> + </div> + <div v-text="identifierDescription(container)" /> + </v-card-text> + <v-card-text v-if="canInit(container)" class="db-buttons"> + <v-btn + small + secondary + :loading="container.database.loading" + @click.stop="initDatabase(container)"> + Start + </v-btn> + </v-card-text> + <v-divider v-if="idx - 1 === databases.length" class="mx-4" /> + </v-card> + <v-toolbar flat> + <v-toolbar-title> + <v-btn + small + color="secondary"> + More + </v-btn> + </v-toolbar-title> + </v-toolbar> + </div> +</template> + +<script> +import { formatCreators, formatUser, formatYearUTC, isResearcher } from '@/utils' + +export default { + data () { + return { + loadingContainers: false, + loadingCreate: false, + createDbDialog: false, + databases: [], + containers: [], + searchQuery: null, + createDatabaseDto: { + name: null, + is_public: true + }, + items: [ + { text: 'Databases', to: '/container', activeClass: '' } + ], + loadingDatabases: false, + error: false + } + }, + computed: { + loadingColor () { + return this.error ? 'red lighten-2' : 'primary' + }, + token () { + return this.$store.state.token + }, + user () { + return this.$store.state.user + }, + isResearcher () { + return isResearcher(this.user) + }, + config () { + if (this.token === null) { + return {} + } + return { + headers: { Authorization: `Bearer ${this.token}` } + } + } + }, + mounted () { + this.loadContainers() + }, + methods: { + formatCreator (creator) { + return formatUser(creator) + }, + formatCreatorz (container) { + const creators = formatCreators(container) + return creators || this.formatCreator(container.creator) + }, + canInit (container) { + if (!this.token) { + return false + } + if (container.creator.username !== this.user.username) { + return false + } + return !container.database.id && !this.loadingDatabases + }, + hasDatabase (container) { + return container.database + }, + hasIdentifier (container) { + return container.database && container.database.identifier + }, + async initDatabase (container) { + await this.startContainer(container) + .then(() => this.createDatabase(container)) + }, + identifierCreated (container) { + if (!container.database.identifier) { + return null + } + return formatYearUTC(container.database.identifier.created) + }, + identifierDescription (container) { + if (!container.database.identifier) { + return null + } + return container.database.identifier.description + }, + async loadContainers () { + this.createDbDialog = false + try { + this.loadingContainers = true + const res = await this.$axios.get('/api/container?limit=100') + this.containers = res.data + console.debug('containers', this.containers) + this.error = false + } catch (error) { + this.error = true + console.error('Failed to retrieve containers', error) + const { message } = error.response.data + this.$toast.error(`Failed to retrieve containers: ${message}`) + } + this.loadingContainers = false + }, + async startContainer (container) { + try { + container.database.loading = true + const res = await this.$axios.put(`/api/container/${container.id}`, { action: 'start' }, this.config) + console.debug('started container', res.data) + this.error = false + } catch (error) { + const { status } = error.response + if (status !== 409) { + this.error = true + this.$toast.error('Failed to start container') + } + } + container.database.loading = false + }, + link (container) { + if (!container.database || !container.database.id) { + return null + } + return `/container/${container.id}/database/${container.database.id}` + } + } +} +</script> + +<style> +.v-chip:not(:first-child) { + margin-left: 8px; +} +.db-subtitle { + padding-bottom: 8px; +} +.db-tags { + margin-bottom: 8px; +} +</style> diff --git a/fda-ui/components/QueryList.vue b/fda-ui/components/QueryList.vue index 96227d2816..5e5f6772b1 100644 --- a/fda-ui/components/QueryList.vue +++ b/fda-ui/components/QueryList.vue @@ -2,9 +2,6 @@ <div> <v-progress-linear v-if="loadingIdentifiers || loadingQueries || error" :color="loadingColor" :value="loadProgress" /> <v-tabs-items> - <v-card v-if="!loadingQueries && queries.length === 0 && !error" flat> - <v-card-text v-text="emptyMessage" /> - </v-card> <div v-if="!loadingQueries && !error"> <div v-for="(item,i) in queries" :key="i"> <v-divider v-if="i !== 0" class="mx-4" /> @@ -16,12 +13,15 @@ <pre>{{ item.query }}</pre> </v-list-item-subtitle> </v-list-item-content> + <v-list-item-action v-if="item.identifier"> + <v-icon color="primary">mdi-identifier</v-icon> + </v-list-item-action> </v-list-item> </v-list-item-group> </div> </div> <div v-if="!loadingIdentifiers && loadingQueries"> - <!-- show identifiers when error --> + <!-- show identifiers when loading subsets --> <div v-for="(item,i) in identifiers" :key="i"> <v-divider v-if="i !== 0" class="mx-4" /> <v-list-item-group> @@ -32,6 +32,28 @@ <pre>{{ item.query }}</pre> </v-list-item-subtitle> </v-list-item-content> + <v-list-item-action> + <v-icon color="primary">mdi-identifier</v-icon> + </v-list-item-action> + </v-list-item> + </v-list-item-group> + </div> + </div> + <div v-if="!loadingIdentifiers && !isPublicOrOwner"> + <!-- show identifiers when private --> + <div v-for="(item,i) in identifiers" :key="i"> + <v-divider v-if="i !== 0" class="mx-4" /> + <v-list-item-group> + <v-list-item two-line :class="clazz(item)" :to="link(item)" :href="navigate(item)"> + <v-list-item-content> + <v-list-item-title v-text="item.title" /> + <v-list-item-subtitle class="mt-2"> + <pre>{{ item.query }}</pre> + </v-list-item-subtitle> + </v-list-item-content> + <v-list-item-action> + <v-icon color="primary">mdi-identifier</v-icon> + </v-list-item-action> </v-list-item> </v-list-item-group> </div> @@ -81,11 +103,20 @@ export default { creator () { return this.queryDetails.creator }, - emptyMessage () { - if (this.isPublicOrOwner()) { - return '(no subsets)' + isPublicOrOwner () { + if (!this.database) { + return false + } + if (this.database.is_public) { + return true + } + if (this.token === null) { + return false } - return '(private database)' + if (!this.user) { + return false + } + return this.database.creator.username === this.user.username } }, mounted () { @@ -117,10 +148,14 @@ export default { const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/query?persisted=true`, this.config) this.queries = res.data console.debug('queries', this.queries) - } catch (err) { - this.error = true - console.error('Connection to query store failed', err.response.index) - this.$toast.error(err.response.index.message) + } catch (error) { + const { status, data } = error.response + const { message } = data + if (status !== 405) { + this.error = true + console.error('Connection to query store failed', error) + this.$toast.error(`Failed to connect to query store: ${message}`) + } } this.loadingQueries = false }, @@ -149,29 +184,11 @@ export default { return `/pid/${queryOrIdentifier.identifier.id}` }, clazz (queryOrIdentifier) { - if (!('identifier' in queryOrIdentifier) || queryOrIdentifier.identifier === null) { - return null - } if ('query_id' in queryOrIdentifier || queryOrIdentifier.identifier) { return 'primary--text' } return null }, - isPublicOrOwner () { - if (!this.database) { - return false - } - if (this.database.is_public) { - return true - } - if (this.token === null) { - return false - } - if (!this.user) { - return false - } - return this.database.creator.username === this.user.username - }, simulateProgress () { if (this.loadProgress !== 0) { return diff --git a/fda-ui/components/TableList.vue b/fda-ui/components/TableList.vue index c326f81505..456a8f6b08 100644 --- a/fda-ui/components/TableList.vue +++ b/fda-ui/components/TableList.vue @@ -9,7 +9,9 @@ <div v-for="(item,i) in tables" :key="i"> <v-divider v-if="i !== 0" class="mx-4" /> <v-list-item-group> - <v-list-item two-line :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${item.id}`"> + <v-list-item + two-line + :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${item.id}`"> <v-list-item-content> <v-list-item-title v-text="item.name" /> <v-list-item-subtitle class="mt-2" v-text="item.description" /> @@ -113,29 +115,11 @@ export default { } return formatTimestampUTCLabel(this.tableDetails.created) }, - hasReadAccess () { - if (!this.database) { - return false - } - if (this.database.is_public) { - /* database is public */ - return true - } - if (!this.user) { + canRead () { + if (!this.user || !this.access) { return false } - if (this.database.creator.username === this.user.username) { - /* user is creator of database */ - return true - } - if (!this.access) { - return false - } - if (this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all') { - /* user has some level of access */ - return true - } - return false + return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all' }, canModify () { if (!this.token || !this.user.username) { @@ -171,7 +155,7 @@ export default { /* use cache */ this.tableDetails = table /* load remaining info */ - if (this.hasReadAccess) { + if (this.canRead) { try { this.loadingDetails = true const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${table.id}`, this.config) diff --git a/fda-ui/components/TableToolbar.vue b/fda-ui/components/TableToolbar.vue index 350f5a1e50..c138b2e7dc 100644 --- a/fda-ui/components/TableToolbar.vue +++ b/fda-ui/components/TableToolbar.vue @@ -35,7 +35,7 @@ <v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/info`"> Info </v-tab> - <v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/data`"> + <v-tab v-if="canRead" :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/data`"> Data </v-tab> <v-tab :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/table/${$route.params.table_id}/schema`"> diff --git a/fda-ui/components/ViewList.vue b/fda-ui/components/ViewList.vue index ef511dbd6e..b2aff93d4e 100644 --- a/fda-ui/components/ViewList.vue +++ b/fda-ui/components/ViewList.vue @@ -9,7 +9,7 @@ <div v-for="(item,i) in views" :key="i"> <v-divider v-if="i !== 0" class="mx-4" /> <v-list-item-group> - <v-list-item two-line :class="clazz(item)" :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/view/${item.id}`"> + <v-list-item two-line :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/view/${item.id}`"> <v-list-item-content> <v-list-item-title v-text="item.name" /> <v-list-item-subtitle class="mt-2"> @@ -127,12 +127,6 @@ export default { this.$toast.error('Failed to delete view') console.error('Failed to delete view') } - }, - clazz (view) { - if (view.is_public === false) { - return null - } - return 'primary--text' } } } diff --git a/fda-ui/components/dialogs/Persist.vue b/fda-ui/components/dialogs/Persist.vue index f57c31ec22..a8595e18fd 100644 --- a/fda-ui/components/dialogs/Persist.vue +++ b/fda-ui/components/dialogs/Persist.vue @@ -64,6 +64,19 @@ required /> </v-col> </v-row> + <v-row dense> + <v-col> + <v-select + id="visibility" + v-model="visibility" + name="visibility" + label="Visibility *" + :items="['Public']" + disabled + :rules="[v => !!v || $t('Required')]" + required /> + </v-col> + </v-row> <v-row v-for="(creator,i) in identifier.creators" :key="`c-${i}`" dense> <v-col cols="3"> <v-text-field @@ -200,6 +213,7 @@ export default { loading: false, error: false, // XXX: `error` is never changed licenses: [], + visibility: 'Public', identifier: { cid: parseInt(this.$route.params.container_id), dbid: parseInt(this.$route.params.database_id), diff --git a/fda-ui/components/query/Builder.vue b/fda-ui/components/query/Builder.vue index 218ec97969..311aac14f2 100644 --- a/fda-ui/components/query/Builder.vue +++ b/fda-ui/components/query/Builder.vue @@ -209,10 +209,6 @@ export default { } }, computed: { - selectItems () { - const columns = this.tableDetails && this.tableDetails.columns - return columns || [] - }, columnNames () { return this.columns && this.columns.map(s => s.internal_name) }, diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue index 03887d4bed..c49740af9e 100644 --- a/fda-ui/layouts/default.vue +++ b/fda-ui/layouts/default.vue @@ -50,7 +50,7 @@ single-line hide-details placeholder="Search ..." /> - <v-btn icon class="ml-2" type="submit" @click="retrieve"> + <v-btn icon class="ml-2" type="submit" name="search-submit" @click="retrieve"> <v-icon>mdi-magnify</v-icon> </v-btn> <v-spacer /> @@ -227,8 +227,10 @@ export default { this.loadUser() this.setTheme() this.loadDatabase() - .then(() => this.loadIdentifier()) - this.loadTable() + .then(() => { + this.loadIdentifier() + this.loadTable() + }) this.loadAccess() if (this.$route.query && this.$route.query.q) { this.search = this.$route.query.q @@ -298,9 +300,17 @@ export default { const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}`, this.config) this.$store.commit('SET_TABLE', res.data) console.debug('table', this.table) - } catch (err) { - console.error('Could not load table', err) - this.$toast.error('Could not load table') + } catch (error) { + const { status, data } = error.response + if (status === 405) { + const table = this.database.tables.filter(t => t.id === Number(this.$route.params.table_id))[0] + console.debug('====>', table, this.$route.params.table_id) + this.$store.commit('SET_TABLE', table) + } else { + const { message } = data + console.error('Failed to load table', error) + this.$toast.error(`Failed to load table: ${message}`) + } } this.loading = false }, diff --git a/fda-ui/package.json b/fda-ui/package.json index de4d543b89..1649177b07 100644 --- a/fda-ui/package.json +++ b/fda-ui/package.json @@ -8,15 +8,16 @@ "build": "nuxt build", "start": "nuxt start", "generate": "nuxt generate", + "clean": "rm -f ./videos/*", "ver": "nuxt --version", "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .", "lint": "yarn lint:js", - "coverage": "nyc ava test/unit/**/* test/specs/**/*", + "coverage": "nyc ava test/unit/**/* test/specs/**/* > ./coverage.txt", "test:unit": "ava test/unit/**/* test/specs/**/*", "test:watch": "ava --watch test/unit/**/* test/specs/**/*", - "test:e2e": "cross-env PORT=3001 ava --timeout=2h --fail-fast test/e2e/**", + "test:e2e": "yarn clean && cross-env PORT=3001 ava --timeout=2h --fail-fast test/e2e/**", "test:e2e:docker": "cross-env PORT=3000 SLOWMO=500 ava --timeout=2h --fail-fast test/e2e/**", - "test": "yarn test:unit && yarn test:e2e:docker" + "test": "yarn clean && yarn test:unit && yarn test:e2e:docker && yarn coverage" }, "dependencies": { "@babel/plugin-transform-runtime": "^7.13.9", @@ -25,6 +26,7 @@ "@nuxtjs/eslint-module": "^2.0.0", "@nuxtjs/proxy": "^2.1.0", "@nuxtjs/vuetify": "^1.11.2", + "axios": "^1.3.0", "chart.js": "^3.8.0", "core-js": "^3.6.5", "date-fns": "^2.16.1", diff --git a/fda-ui/pages/container/_container_id/database/_database_id/info.vue b/fda-ui/pages/container/_container_id/database/_database_id/info.vue index 6b48493049..b9224362e6 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/info.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/info.vue @@ -114,33 +114,7 @@ </v-card-actions> </v-card-text> </v-card> - <v-divider v-if="hasIdentifier || (isCreator && isResearcher) || isDataSteward" /> - <v-card flat tile> - <v-card-title>Container</v-card-title> - <v-card-text> - <v-list dense> - <v-list-item> - <v-list-item-content> - <v-list-item-title class="mt-2"> - Container Name - </v-list-item-title> - <v-list-item-content> - <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" /> - <span v-if="!loading" v-text="container_name" /> - </v-list-item-content> - <v-list-item-title class="mt-2"> - Container Internal Name - </v-list-item-title> - <v-list-item-content> - <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" /> - <span v-if="!loading" v-text="container_internal_name" /> - </v-list-item-content> - </v-list-item-content> - </v-list-item> - </v-list> - </v-card-text> - </v-card> - <v-divider /> + <v-divider v-if="isDataSteward || hasIdentifier || (!hasIdentifier && isCreator && isResearcher)" /> <v-card flat tile> <v-card-title>Database</v-card-title> <v-card-text> @@ -205,6 +179,32 @@ </v-list> </v-card-text> </v-card> + <v-divider /> + <v-card flat tile> + <v-card-title>Container</v-card-title> + <v-card-text> + <v-list dense> + <v-list-item> + <v-list-item-content> + <v-list-item-title class="mt-2"> + Container Name + </v-list-item-title> + <v-list-item-content> + <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" /> + <span v-if="!loading" v-text="container_name" /> + </v-list-item-content> + <v-list-item-title class="mt-2"> + Container Internal Name + </v-list-item-title> + <v-list-item-content> + <v-skeleton-loader v-if="loading" type="text" class="skeleton-small" /> + <span v-if="!loading" v-text="container_internal_name" /> + </v-list-item-content> + </v-list-item-content> + </v-list-item> + </v-list> + </v-card-text> + </v-card> </v-tab-item> </v-tabs-items> <v-dialog diff --git a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue index 47c5a02fe7..4ca589d152 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/query/_query_id/index.vue @@ -336,6 +336,9 @@ export default { if (this.query.creator.username === this.username) { return true } + if (!this.query.identifier) { + return false + } return this.query.identifier.visibility === 'everyone' }, canWrite () { diff --git a/fda-ui/pages/container/_container_id/database/_database_id/settings.vue b/fda-ui/pages/container/_container_id/database/_database_id/settings.vue index 63f3d69a7d..a22d9092ed 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/settings.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/settings.vue @@ -174,7 +174,7 @@ export default { async updateDatabaseVisibility () { try { this.loading = true - await this.$axios.put(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/transfer`, this.modifyVisibility, this.config) + await this.$axios.put(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/visibility`, this.modifyVisibility, this.config) this.$toast.success('Successfully updated the database') location.reload() } catch (err) { diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue index c532c2814e..b401b043bf 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/data.vue @@ -1,5 +1,5 @@ <template> - <div> + <div v-if="canRead"> <TableToolbar :selection="selection" @modified="modified" /> <v-toolbar :color="versionColor" flat> <v-toolbar-title> diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue index 50e51aaafa..9a27f6db5c 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/info.vue @@ -31,16 +31,18 @@ <span v-if="table && table.creator">{{ formatCreator(table.creator) }} <span v-if="is_owner(table)" style="flex:none;"> (you)</span></span> <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" /> </v-list-item-content> - <v-list-item-title class="mt-2"> + <v-list-item-title v-if="table && table.created" class="mt-2"> Table Creation </v-list-item-title> - <v-list-item-content> - <span v-if="table && table.created">{{ createdUTC }}</span> - <v-skeleton-loader v-if="!table" type="text" class="skeleton-small" /> + <v-list-item-content v-if="table && table.created"> + <span>{{ createdUTC }}</span> + </v-list-item-content> + <v-list-item-content v-if="!table"> + <v-skeleton-loader type="text" class="skeleton-medium" /> </v-list-item-content> </v-list-item-content> </v-list-item> - <v-list-item> + <v-list-item v-if="canModify"> <v-list-item-icon> <v-icon>mdi-rabbit</v-icon> </v-list-item-icon> @@ -58,29 +60,35 @@ <pre v-if="database && database.exchange_name">{{ database.exchange_name }}</pre> <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" /> </v-list-item-content> - <v-list-item-title class="mt-2"> + <v-list-item-title v-if="table && table.queue_name" class="mt-2"> Queue Name </v-list-item-title> - <v-list-item-content> - <pre v-if="table && table.queue_name">{{ table.queue_name }}</pre> - <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" /> + <v-list-item-content v-if="table && table.queue_name"> + <pre>{{ table.queue_name }}</pre> </v-list-item-content> - <v-list-item-title class="mt-2"> + <v-list-item-content v-if="!table"> + <v-skeleton-loader type="text" class="skeleton-medium" /> + </v-list-item-content> + <v-list-item-title v-if="table && table.routing_key" class="mt-2"> Routing Key </v-list-item-title> - <v-list-item-content> - <pre v-if="table && table.routing_key">{{ table.routing_key }}</pre> - <v-skeleton-loader v-if="!table" type="text" class="skeleton-medium" /> + <v-list-item-content v-if="table && table.routing_key"> + <pre>{{ table.routing_key }}</pre> </v-list-item-content> - <v-list-item-title v-if="hasReadAccess" class="mt-2"> + <v-list-item-content v-if="!table"> + <v-skeleton-loader type="text" class="skeleton-medium" /> + </v-list-item-content> + <v-list-item-title v-if="canRead" class="mt-2"> Consumer Count </v-list-item-title> - <v-list-item-content v-if="hasReadAccess" class="amqp-consumer"> - <span v-text="`${consumersUp}/${consumersTotal}`" /> + <v-list-item-content v-if="canRead" class="amqp-consumer"> + <span v-if="attemptedLoadingConsumers" v-text="`${consumersUp}/${consumersTotal}`" /> <v-badge + v-if="attemptedLoadingConsumers" class="ml-1" :color="consumersState.color" :content="consumersState.text" /> + <v-skeleton-loader v-else type="text" class="skeleton-xsmall" /> </v-list-item-content> </v-list-item-content> </v-list-item> @@ -101,6 +109,7 @@ export default { data () { return { loadingConsumers: false, + attemptedLoadingConsumers: false, selection: [], consumers: [], items: [ @@ -137,29 +146,11 @@ export default { table () { return this.$store.state.table }, - hasReadAccess () { - if (!this.database) { - return false - } - if (this.database.is_public) { - /* database is public */ - return true - } - if (!this.user) { + canRead () { + if (!this.user || !this.access) { return false } - if (this.database.creator.username === this.user.username) { - /* user is creator of database */ - return true - } - if (!this.access) { - return false - } - if (this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all') { - /* user has some level of access */ - return true - } - return false + return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all' }, createdUTC () { if (this.table.created === undefined || this.table.created === null) { @@ -192,7 +183,7 @@ export default { return this.consumers.filter(c => c.active).length }, canModify () { - if (!this.token || !this.user.username) { + if (!this.token || !this.user.username || !this.table || !('creator' in this.table) || !this.table.creator || !('username' in this.table.creator) || !this.table.creator.username) { /* not yet loaded */ return false } @@ -223,9 +214,11 @@ export default { } } }, - mounted () { - this.pollConsumerStatus(true) - setInterval(() => this.pollConsumerStatus(false), 5 * 1000) + watch: { + table (val) { + this.pollConsumerStatus(true) + setInterval(() => this.pollConsumerStatus(false), 5 * 1000) + } }, methods: { formatCreator (creator) { @@ -247,10 +240,13 @@ export default { const consumers = res.data.filter(c => c.queue.name === this.table.queue_name) console.debug('filtered', consumers) this.consumers = consumers - } catch (err) { - console.error('Could not find consumers', err) + } catch (error) { + const { message } = error + console.error('Failed to find consumers', error) + this.$toast.error(`Failed to find consumers: ${message}`) } this.loadingConsumers = false + this.attemptedLoadingConsumers = true } } } diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue index 712dafbd36..72022b57c9 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/schema.vue @@ -183,10 +183,10 @@ export default { return null }, hasUnit (item) { - return item.unit !== null + return item.unit && 'uri' in item.unit }, hasConcept (item) { - return item.concept !== null + return item.concept && 'uri' in item.concept }, pick (item) { this.column = item diff --git a/fda-ui/pages/container/index.vue b/fda-ui/pages/container/index.vue index f2036ed2d7..b442a2e51a 100644 --- a/fda-ui/pages/container/index.vue +++ b/fda-ui/pages/container/index.vue @@ -2,67 +2,16 @@ <div> <v-toolbar flat> <v-toolbar-title> - <span>Databases</span> + Recent Databases </v-toolbar-title> <v-spacer /> <v-toolbar-title> - <v-btn v-if="isResearcher" color="primary" @click.stop="createDbDialog = true"> + <v-btn v-if="isResearcher" color="primary" name="create-database" @click.stop="createDbDialog = true"> <v-icon left>mdi-plus</v-icon> Database </v-btn> </v-toolbar-title> </v-toolbar> - <v-toolbar dense flat> - <v-toolbar-items> - <span class="mr-4">Filter:</span> - <v-checkbox - v-model="filterPrivate" - label="Private" /> - <v-checkbox - v-if="user" - v-model="filterMine" - class="ml-2" - label="Mine" /> - </v-toolbar-items> - </v-toolbar> - <v-progress-linear v-if="loadingContainers || loadingDatabases" :color="loadingColor" :indeterminate="!error" /> - <v-card - v-for="(container, idx) in filter(containers)" - :key="idx" - :to="link(container)" - :disabled="!container.database" - flat - tile> - <v-divider class="mx-4" /> - <v-card-title v-if="notInit(container)" v-text="container.name" /> - <v-card-title v-if="!notInit(container)"> - <a :href="`/container/${container.id}/database/${container.database.id}`">{{ container.name }}</a> - </v-card-title> - <v-card-subtitle v-if="!container.database.identifier" class="db-subtitle" v-text="formatCreator(container.creator)" /> - <v-card-subtitle v-if="container.database.identifier" class="db-subtitle" v-text="formatCreatorz(container)" /> - <v-card-text class="db-description"> - <div class="db-tags"> - <v-chip v-if="!notInit(container) && container.database.is_public" small color="green" outlined>Public</v-chip> - <v-chip v-if="!notInit(container) && !container.database.is_public" small color="red" outlined>Private</v-chip> - <v-chip v-if="identifierCreated(container)" small outlined>Database</v-chip> - <v-chip - v-if="identifierCreated(container)" - small - outlined - v-text="container.database.identifier.publisher" /> - <v-chip v-if="identifierCreated(container)" small outlined v-text="identifierCreated(container)" /> - </div> - <div v-text="identifierDescription(container)" /> - </v-card-text> - <v-card-text v-if="canInit(container)" class="db-buttons"> - <v-btn - small - secondary - :loading="container.database.loading" - @click.stop="initDatabase(container)"> - Start - </v-btn> - </v-card-text> - </v-card> + <DatabaseList /> <v-dialog v-model="createDbDialog" persistent @@ -75,22 +24,19 @@ <script> import { mdiDatabaseArrowRightOutline } from '@mdi/js' import CreateDB from '@/components/dialogs/CreateDB' -import { formatTimestampUTCLabel, formatCreators, formatYearUTC, formatUser, isResearcher } from '@/utils' +import DatabaseList from '@/components/DatabaseList' +import { isResearcher } from '@/utils' export default { components: { - CreateDB + CreateDB, + DatabaseList }, data () { return { loadingContainers: false, loadingCreate: false, createDbDialog: false, - databases: [], - containers: [], - filterPrivate: false, - filterMine: false, - searchQuery: null, createDatabaseDto: { name: null, is_public: true @@ -104,18 +50,12 @@ export default { } }, computed: { - loadingColor () { - return this.error ? 'red lighten-2' : 'primary' - }, token () { return this.$store.state.token }, user () { return this.$store.state.user }, - isResearcher () { - return isResearcher(this.user) - }, config () { if (this.token === null) { return {} @@ -123,119 +63,12 @@ export default { return { headers: { Authorization: `Bearer ${this.token}` } } + }, + isResearcher () { + return isResearcher(this.user) } }, - mounted () { - this.loadContainers() - .then(() => this.loadDatabases()) - }, methods: { - formatCreator (creator) { - return formatUser(creator) - }, - formatCreatorz (container) { - return formatCreators(container) - }, - canInit (container) { - if (!this.token) { - return false - } - if (container.creator.username !== this.user.username) { - return false - } - return !container.database.id && !this.loadingDatabases - }, - notInit (container) { - return !container.database.id - }, - async initDatabase (container) { - await this.startContainer(container) - .then(() => this.createDatabase(container)) - }, - filter (containers) { - if (this.loadingDatabases) { - return [] - } - let filtered = containers - if (this.filterPrivate) { - filtered = filtered.filter(c => !c.database.is_public) - } - if (this.user && this.filterMine) { - filtered = filtered.filter(c => c.creator.username === this.user.username) - } - return filtered - }, - identifierCreated (container) { - if (!container.database.identifier) { - return null - } - return formatYearUTC(container.database.identifier.created) - }, - identifierDescription (container) { - if (!container.database.identifier) { - return null - } - return container.database.identifier.description - }, - async loadContainers () { - this.createDbDialog = false - try { - this.loadingContainers = true - const res = await this.$axios.get('/api/container/') - this.containers = res.data.map((container) => { - container.database = { - id: null, - loading: false - } - return container - }) - console.debug('containers', this.containers) - this.error = false - } catch (err) { - console.error('containers', err) - this.error = true - } - this.loadingContainers = false - }, - async loadDatabases () { - if (this.containers.length === 0) { - return - } - this.loadingDatabases = true - for (const container of this.containers) { - try { - const res = await this.$axios.get(`/api/container/${container.id}/database`, this.config) - for (const info of res.data) { - info.container_id = container.id - info.visibility = info.is_public - info.created = formatTimestampUTCLabel(info.created) - const filtered = this.containers.filter(c => c.id === container.id)[0] - filtered.database = info - } - } catch (err) { - if (err.response === undefined || err.response.status === undefined || err.response.status !== 401) { - console.error('Failed to load databases for container', err) - } - } - } - this.loadingDatabases = false - console.debug('containers with databases', this.containers) - }, - async startContainer (container) { - try { - container.database.loading = true - const res = await this.$axios.put(`/api/container/${container.id}`, { action: 'start' }, this.config) - console.debug('started container', res.data) - this.error = false - } catch (error) { - const { status } = error.response - if (status !== 409) { - this.error = true - this.$toast.error('Failed to start container') - } - } - container.database.loading = false - }, async createDatabase (container) { try { container.database.loading = true @@ -256,29 +89,8 @@ export default { this.createDbDialog = false if (event.success) { this.loadContainers() - .then(() => this.loadDatabases()) } - }, - link (container) { - if (!container.database || !container.database.id) { - return null - } - return `/container/${container.id}/database/${container.database.id}` } } } </script> -<style scoped> - tbody tr { - cursor: pointer; - } - .v-chip:not(:first-child) { - margin-left: 8px; - } - .db-subtitle { - padding-bottom: 8px; - } - .db-tags { - margin-bottom: 8px; - } -</style> diff --git a/fda-ui/pages/forgot.vue b/fda-ui/pages/forgot.vue index af20390b04..809139658b 100644 --- a/fda-ui/pages/forgot.vue +++ b/fda-ui/pages/forgot.vue @@ -18,6 +18,7 @@ v-model="data.username" autocomplete="off" autofocus + name="username" label="Username" /> </v-col> </v-row> @@ -27,6 +28,7 @@ v-model="data.email" autocomplete="off" type="email" + name="email" label="E-Mail Address" /> </v-col> </v-row> @@ -38,6 +40,7 @@ :disabled="!valid || !formValid" color="primary" type="submit" + name="submit" @click="forgot"> Reset password </v-btn> diff --git a/fda-ui/pages/login.vue b/fda-ui/pages/login.vue index c063503b90..44ee3235cf 100644 --- a/fda-ui/pages/login.vue +++ b/fda-ui/pages/login.vue @@ -18,6 +18,7 @@ autocomplete="off" autofocus required + name="username" :rules="[v => !!v || $t('Required')]" label="Username *" /> </v-col> @@ -29,6 +30,7 @@ autocomplete="off" type="password" required + name="password" :rules="[v => !!v || $t('Required')]" label="Password *" /> </v-col> @@ -41,6 +43,7 @@ :disabled="!valid" color="primary" type="submit" + name="submit" :loading="loading" @click="login"> Login diff --git a/fda-ui/pages/search/index.vue b/fda-ui/pages/search/index.vue index a6d5489897..a466a0f922 100644 --- a/fda-ui/pages/search/index.vue +++ b/fda-ui/pages/search/index.vue @@ -46,6 +46,12 @@ export default { } return this.$route.query.q }, + type () { + if (!this.$route.query || !this.$route.query.t) { + return null + } + return this.$route.query.t + }, header () { if (this.results.length !== 1) { return `${this.results.length} results` @@ -64,7 +70,14 @@ export default { watch: { '$route.query.q': { handler (query) { - this.retrieve(query) + this.retrieve() + }, + deep: true, + immediate: true + }, + '$route.query.t': { + handler (type) { + this.retrieve() }, deep: true, immediate: true @@ -76,13 +89,13 @@ export default { } }, methods: { - async retrieve (v) { + async retrieve () { if (this.loading) { return } this.loading = true try { - const res = await this.$axios.get(`/retrieve/databaseindex,tableindex,columnindex,identifierindex,viewindex/_search?q=${v}*&terminate_after=50`, this.elasticConfig) + const res = await this.$axios.get(`/retrieve/_all/_search?q=${this.query}*&terminate_after=50`, this.elasticConfig) console.info('search results', res.data.hits.total.value) console.debug('search results for', this.$route.query.q, 'are', res.data.hits.hits) this.results = res.data.hits.hits.map(h => h._source) diff --git a/fda-ui/pages/signup.vue b/fda-ui/pages/signup.vue index d777c2b568..2b88602a4e 100644 --- a/fda-ui/pages/signup.vue +++ b/fda-ui/pages/signup.vue @@ -20,6 +20,7 @@ autocomplete="off" autofocus required + name="email" :rules="[v => !!v || $t('Required')]" hint="e.g. max.mustermann@work.com" label="Work E-Mail Address *" /> @@ -31,6 +32,7 @@ v-model="createAccount.username" autocomplete="off" required + name="username" :rules="[v => !!v || $t('Required'), v => /^[a-z0-9]{3,}$/.test(v) || $t('Only lowercase letters, min. 3 length')]" hint="e.g. mmustermann" @@ -43,6 +45,7 @@ v-model="createAccount.password" autocomplete="off" required + name="password" :rules="[v => !!v || $t('Required')]" type="password" label="Password *" /> @@ -54,6 +57,7 @@ v-model="password2" autocomplete="off" required + name="password-confirm" :rules="[v => !!v || $t('Required'), v => (!!v && v) === createAccount.password || $t('Not matching!')]" type="password" label="Repeat Password *" /> @@ -64,6 +68,7 @@ <v-checkbox v-model="consent" required + name="consent" :rules="[v => !!v || $t('Required')]" label="I understand the warning and do not use production data" /> </v-col> @@ -73,6 +78,7 @@ <v-checkbox v-model="privacy" required + name="privacy" :rules="[v => !!v || $t('Required')]" label="I have read and accept the privacy statement" /> </v-col> @@ -84,6 +90,7 @@ :disabled="!valid" color="primary" type="submit" + name="submit" :loading="loading" @click="register"> Submit diff --git a/fda-ui/test/e2e/database.js b/fda-ui/test/e2e/database.js index 1820f89fbf..15a86e980b 100644 --- a/fda-ui/test/e2e/database.js +++ b/fda-ui/test/e2e/database.js @@ -1,63 +1,24 @@ const test = require('ava') -const axios = require('axios') +const { mutations } = require('store') const { pageMacro, before, after } = require('./_utils') test.before(before) test.after(after) -test('create database and see the tabs', pageMacro, async (t, page) => { - const database = 'Test Database ' + Math.random().toString(36).substring(7) - const description = 'Test Description' - - await page.go('/databases') - - // Click create new button - await page.click('button:has-text("Database")') - - // Fill database name - await page.fill('input[name="database"]', database) - - // Fill database description - await page.fill('textarea[name="description"]', description) - - // Press Tab - await page.press('textarea[name="description"]', 'Tab') - - // Select mariadb:10.5 - await page.press('#engine', 'ArrowDown') - - // Click submit button - await page.click('button:has-text("Create")') - - // See page load - let success = await page.waitForSelector('text=' + database) - t.true(!!success, `Database ${database} seems not to be created, notification not found`) - - const id = await axios.get('http://localhost:9092/api/database/').then(function (response) { - return response.filter(function (item) { - return item.name === database - }).id - }) - - // ------------------------------------------------------------------------------------------------------------------- - - await page.go('/databases/' + id + '/info') - - // find 'mariadb' anywhere on the page: - success = await page.waitForSelector('text=mariadb:10.5') - t.true(!!success, 'Could not find the mariadb image on the site') - - await page.go('/databases/' + id + '/tables') - - // find 'mariadb' anywhere on the page: - success = await page.waitForSelector('text=(no tables)') - t.true(!!success, 'Could not find the tables on the site') - - // ------------------------------------------------------------------------------------------------------------------- +test('databases_seeDatabases_succeeds', pageMacro, async (t, page) => { + await page.go('/container') + /* test */ + const success = await page.waitForSelector('main >> header >> text=Databases') + t.true(!!success, 'Failed to find \'Databases\' in page') +}) - await page.go('/databases/' + id + '/queries') +test('databases_createDatabase_succeeds', pageMacro, async (t, page) => { + const state = { token: null, user: null, database: null, table: null, access: null } - // find 'mariadb' anywhere on the page: - success = await page.waitForSelector('text=(no queries)') - t.true(!!success, 'Could not find the queries on the site') + await page.go('/container') + mutations.SET_TOKEN(state, 'ABC') + mutations.SET_USER(state, { username: 'ava' }) + await page.screenshot({ path: './screenshots/databases_createDatabase_succeeds.png' }) + /* test */ + t.true(true) }) diff --git a/fda-ui/test/e2e/forgot.js b/fda-ui/test/e2e/forgot.js new file mode 100644 index 0000000000..03c3415564 --- /dev/null +++ b/fda-ui/test/e2e/forgot.js @@ -0,0 +1,18 @@ +const test = require('ava') +const { pageMacro, before, after } = require('./_utils') + +test.before(before) +test.after(after) + +test('login_succeeds', pageMacro, async (t, page) => { + const email = 'ava@example.com' + const username = 'ava' + + await page.go('/forgot') + await page.fill('input[name="username"]', username) + await page.fill('input[name="email"]', email) + + /* test */ + const success = await page.waitForSelector('button[name="submit"]:not([disabled])') + t.true(!!success, 'Failed to reset user information') +}) diff --git a/fda-ui/test/e2e/index.js b/fda-ui/test/e2e/index.js index ee391d1d6d..399bd9485e 100644 --- a/fda-ui/test/e2e/index.js +++ b/fda-ui/test/e2e/index.js @@ -4,7 +4,50 @@ const { pageMacro, before, after } = require('./_utils') test.before(before) test.after(after) -test('visit homepage', pageMacro, async (t, page) => { +test('home_seeDatabaseRepository_succeeds', pageMacro, async (t, page) => { await page.go('/') - t.is(await page.title(), 'FAIR Data Austria - Database Repository (Sandbox)') + + // find 'Database Repository' anywhere on the page: + const success = await page.waitForSelector('text=Database Repository') + t.true(!!success, 'Failed to find \'Database Repository\' in page') +}) + +test('home_seeInformation_succeeds', pageMacro, async (t, page) => { + await page.go('/') + + // find 'Information' anywhere on the page: + const success = await page.waitForSelector('text=Information') + t.true(!!success, 'Failed to find \'Information\' in page') +}) + +test('home_seeDatabases_succeeds', pageMacro, async (t, page) => { + await page.go('/') + + // find 'Databases' anywhere on the page: + const success = await page.waitForSelector('text=Databases') + t.true(!!success, 'Failed to find \'Databases\' in page') +}) + +test('home_seeLogin_succeeds', pageMacro, async (t, page) => { + await page.go('/') + + // find 'Login' anywhere on the page: + const success = await page.waitForSelector('text=Login') + t.true(!!success, 'Failed to find \'Login\' in page') +}) + +test('home_seeSignup_succeeds', pageMacro, async (t, page) => { + await page.go('/') + + // find 'Signup' anywhere on the page: + const success = await page.waitForSelector('text=Signup') + t.true(!!success, 'Failed to find \'Signup\' in page') +}) + +test('home_seeSearch_succeeds', pageMacro, async (t, page) => { + await page.go('/') + + // find 'Search' anywhere on the page: + const success = await page.waitForSelector('[placeholder="Search ..."]') + t.true(!!success, 'Failed to find \'Search\' in page') }) diff --git a/fda-ui/test/e2e/login.js b/fda-ui/test/e2e/login.js new file mode 100644 index 0000000000..1ddae6a394 --- /dev/null +++ b/fda-ui/test/e2e/login.js @@ -0,0 +1,18 @@ +const test = require('ava') +const { pageMacro, before, after } = require('./_utils') + +test.before(before) +test.after(after) + +test('login_succeeds', pageMacro, async (t, page) => { + const username = 'ava' + const password = Math.random().toString(36).substring(7) + + await page.go('/login') + await page.fill('input[name="username"]', username) + await page.fill('input[name="password"]', password) + + /* test */ + const success = await page.waitForSelector('button[name="submit"]:not([disabled])') + t.true(!!success, 'Failed to login') +}) diff --git a/fda-ui/test/e2e/search.js b/fda-ui/test/e2e/search.js new file mode 100644 index 0000000000..b2fbc9868e --- /dev/null +++ b/fda-ui/test/e2e/search.js @@ -0,0 +1,28 @@ +const test = require('ava') +const { pageMacro, before, after } = require('./_utils') + +test.before(before) +test.after(after) + +test('search_succeeds', pageMacro, async (t, page) => { + const query = 'dummy' + + await page.go('/') + await page.fill('input[placeholder="Search ..."]', query) + + /* test */ + const success = await page.waitForSelector('button[name="search-submit"]') + t.true(!!success, 'Failed to search') +}) + +test('search_execute_succeeds', pageMacro, async (t, page) => { + const query = 'dummy' + + await page.go('/') + await page.fill('input[placeholder="Search ..."]', query) + await page.click('button[name="search-submit"]') + + /* test */ + const success = await page.waitForSelector('button[name="search-submit"]') + t.true(!!success, 'Failed to search') +}) diff --git a/fda-ui/test/e2e/signup.js b/fda-ui/test/e2e/signup.js new file mode 100644 index 0000000000..d25e27a274 --- /dev/null +++ b/fda-ui/test/e2e/signup.js @@ -0,0 +1,21 @@ +const test = require('ava') +const { pageMacro, before, after } = require('./_utils') + +test.before(before) +test.after(after) + +test('signup_succeeds', pageMacro, async (t, page) => { + const email = 'ava@example.com' + const username = 'ava' + const password = Math.random().toString(36).substring(7) + + await page.go('/signup') + await page.fill('input[name="email"]', email) + await page.fill('input[name="username"]', username) + await page.fill('input[name="password"]', password) + await page.fill('input[name="password-confirm"]', password) + + /* test */ + const success = await page.waitForSelector('button[name="submit"]:not([disabled])') + t.true(!!success, 'Failed to sign-up') +}) diff --git a/fda-ui/test/e2e/tables.js b/fda-ui/test/e2e/tables.js deleted file mode 100644 index 208280da77..0000000000 --- a/fda-ui/test/e2e/tables.js +++ /dev/null @@ -1,62 +0,0 @@ -const test = require('ava') -const axios = require('axios') -const { pageMacro, before, after } = require('./_utils') - -test.before(before) -test.after(after) - -test('create table using form', pageMacro, async (t, page) => { - const database = 'Test Database ' + Math.random().toString(36).substring(7) - const table = 'Test Table ' + Math.random().toString(36).substring(7) - const description = 'Test Description' - - await page.go('/databases') - - // Click create new button - await page.click('button:has-text("Database")') - - // Fill database name - await page.fill('input[name="database"]', database) - - // Fill database description - await page.fill('textarea[name="description"]', description) - - // Press Tab - await page.press('textarea[name="description"]', 'Tab') - - // Select mariadb:10.5 - await page.press('#engine', 'ArrowDown') - - // Click submit button - await page.click('button:has-text("Create")') - - // See page load - let success = await page.waitForSelector('text=' + database) - t.true(!!success, `Database ${database} seems not to be created, notification not found`) - - const id = await axios.get('http://localhost:9092/api/database/').then(function (response) { - return response.filter(function (item) { - return item.name === database - }).id - }) - - // ------------------------------------------------------------------------------------------------------------------- - - await page.go('/databases/' + id + '/tables') - - // Click create new button - await page.click('button:has-text("Create Table")') - - // Fill table name - await page.fill('input[name="name"]', table) - - // Fill table description - await page.fill('input[name="description"]', description) - - // Click submit button - await page.click('button:has-text("Create Table")') - - // See page load - success = await page.waitForSelector('text=aaaaaaaa') - t.true(!!success, `Table ${database} seems not to be created, notification not found`) -}) diff --git a/fda-ui/test/unit/query.js b/fda-ui/test/unit/query.js index af97f55145..1721491863 100644 --- a/fda-ui/test/unit/query.js +++ b/fda-ui/test/unit/query.js @@ -1,14 +1,14 @@ const test = require('ava') const { buildQuery, castNum } = require('@/server-middleware/query') -test('simple select', (t) => { +test('buildQuery_succeeds', (t) => { const r = buildQuery({ table: 'Table' }) t.is(r.sql, 'select * from `Table`') }) -test('select some columns', (t) => { +test('buildQuery_columns_succeeds', (t) => { const r = buildQuery({ table: 'Table', select: ['database', 'bbb'] @@ -16,7 +16,7 @@ test('select some columns', (t) => { t.is(r.sql, 'select `database`, `bbb` from `Table`') }) -test('simple where clause', (t) => { +test('buildQuery_where_succeeds', (t) => { const r = buildQuery({ table: 'Table', clauses: [ @@ -26,7 +26,7 @@ test('simple where clause', (t) => { t.is(r.sql, 'select * from `Table` where `foo` = 42') }) -test('simple where clause with numeric string', (t) => { +test('buildQuery_whereNumeric_succeeds', (t) => { const r = buildQuery({ table: 'Table', clauses: [ @@ -36,7 +36,7 @@ test('simple where clause with numeric string', (t) => { t.is(r.sql, 'select * from `Table` where `foo` = 42') }) -test('simple where clause with non-numeric string', (t) => { +test('buildQuery_whereString_succeeds', (t) => { const r = buildQuery({ table: 'Table', clauses: [ @@ -46,7 +46,7 @@ test('simple where clause with non-numeric string', (t) => { t.is(r.sql, 'select * from `Table` where `foo` = \'bla\'') }) -test('using unallowed operator', (t) => { +test('buildQuery_illegalOperator_fails', (t) => { const r = buildQuery({ table: 'Table', clauses: [ @@ -57,7 +57,7 @@ test('using unallowed operator', (t) => { t.is(r.error, 'The operator "UNKNOWN" is not permitted') }) -test('where clause with explicit `and`', (t) => { +test('buildQuery_whereAndExplicit_succeeds', (t) => { const r = buildQuery({ table: 'Table', clauses: [ @@ -69,7 +69,7 @@ test('where clause with explicit `and`', (t) => { t.is(r.sql, 'select * from `Table` where `foo` = 42 and `bar` = 42') }) -test('where clause with implicit `and`', (t) => { +test('buildQuery_whereAndImplicit_succeeds', (t) => { const r = buildQuery({ table: 'Table', clauses: [ @@ -81,7 +81,7 @@ test('where clause with implicit `and`', (t) => { t.is(r.sql, 'select * from `Table` where `foo` = 42 and `bar` = 42') }) -test('where clause with `or`', (t) => { +test('buildQuery_whereOr', (t) => { const r = buildQuery({ table: 'Table', clauses: [ @@ -93,7 +93,7 @@ test('where clause with `or`', (t) => { t.is(r.sql, 'select * from `Table` where `foo` = 42 or `bar` = 42') }) -test('cast numeric strings to numbers', (t) => { +test('castNum_succeeds', (t) => { t.is(castNum(''), '') t.is(castNum(' '), ' ') t.is(castNum('0'), 0) diff --git a/fda-ui/test/unit/utils.js b/fda-ui/test/unit/utils.js new file mode 100644 index 0000000000..4b6a0f0be0 --- /dev/null +++ b/fda-ui/test/unit/utils.js @@ -0,0 +1,279 @@ +const test = require('ava') +const { + isNonNegativeInteger, + isDeveloper, + isResearcher, + isDataSteward, + formatUser, + formatDateUTC, + formatYearUTC, + formatMonthUTC, + formatDayUTC, + formatTimestamp, + formatCreators, + formatTimestampUTCLabel, + formatTimestampUTC +} = require('@/utils') + +test('isNonNegativeInteger_succeeds', (t) => { + /* test */ + const response = isNonNegativeInteger('1') + t.is(response, true) +}) + +test('isNonNegativeInteger_zero_succeeds', (t) => { + /* test */ + const response = isNonNegativeInteger('0') + t.is(response, true) +}) + +test('isNonNegativeInteger_fails', (t) => { + /* test */ + const response = isNonNegativeInteger('-1') + t.is(response, false) +}) + +test('isDeveloper_succeeds', (t) => { + const user = { roles: ['ROLE_DEVELOPER'] } + /* test */ + const response = isDeveloper(user) + t.is(response, true) +}) + +test('isDeveloper_fails', (t) => { + const user = { roles: [] } + /* test */ + const response = isDeveloper(user) + t.is(response, false) +}) + +test('isDeveloper_otherRole_fails', (t) => { + const user = { roles: ['ROLE_RESEARCHER'] } + /* test */ + const response = isDeveloper(user) + t.is(response, false) +}) + +test('isResearcher_succeeds', (t) => { + const user = { roles: ['ROLE_RESEARCHER'] } + /* test */ + const response = isResearcher(user) + t.is(response, true) +}) + +test('isResearcher_fails', (t) => { + const user = { roles: [] } + /* test */ + const response = isResearcher(user) + t.is(response, false) +}) + +test('isResearcher_otherRole_fails', (t) => { + const user = { roles: ['ROLE_DEVELOPER'] } + /* test */ + const response = isResearcher(user) + t.is(response, false) +}) + +test('isDataSteward_succeeds', (t) => { + const user = { roles: ['ROLE_DATA_STEWARD'] } + /* test */ + const response = isDataSteward(user) + t.is(response, true) +}) + +test('isDataSteward_fails', (t) => { + const user = { roles: [] } + /* test */ + const response = isDataSteward(user) + t.is(response, false) +}) + +test('isDataSteward_otherRole_fails', (t) => { + const user = { roles: ['ROLE_DEVELOPER'] } + /* test */ + const response = isDataSteward(user) + t.is(response, false) +}) + +test('formatUser_fails', (t) => { + const user = null + /* test */ + const response = formatUser(user) + t.is(response, null) +}) + +test('formatUser_usernameMissing_fails', (t) => { + const user = { lastname: null, firstname: null } + /* test */ + const response = formatUser(user) + t.is(response, null) +}) + +test('formatUser_succeeds', (t) => { + const user = { lastname: null, firstname: null, username: 'mweise' } + /* test */ + const response = formatUser(user) + t.is(response, 'mweise') +}) + +test('formatUser_firstnameLastname_succeeds', (t) => { + const user = { lastname: 'Martin', firstname: 'Weise', username: 'mweise' } + /* test */ + const response = formatUser(user) + t.is(response, 'Weise Martin') +}) + +test('formatUser_titles_succeeds', (t) => { + const user = { lastname: 'Martin', firstname: 'Weise', username: 'mweise', titles_before: 'Dipl.-Ing.', titles_after: 'BSc' } + /* test */ + const response = formatUser(user) + t.is(response, 'Dipl.-Ing. Weise Martin BSc') +}) + +test('formatDateUTC_succeeds', (t) => { + /* test */ + const response = formatDateUTC('2023-02-15 10:32:21') + t.is(response, '2023-02-15') +}) + +test('formatDateUTC_fails', (t) => { + /* test */ + const response = formatDateUTC(null) + t.is(response, null) +}) + +test('formatYearUTC_fails', (t) => { + /* test */ + const response = formatYearUTC(null) + t.is(response, null) +}) + +test('formatYearUTC_succeeds', (t) => { + /* test */ + const response = formatYearUTC('2023-02-15 10:32:21') + t.is(response, '2023') +}) + +test('formatMonthUTC_fails', (t) => { + /* test */ + const response = formatMonthUTC(null) + t.is(response, null) +}) + +test('formatMonthUTC_succeeds', (t) => { + /* test */ + const response = formatMonthUTC('2023-02-15 10:32:21') + t.is(response, '02') +}) + +test('formatDayUTC_fails', (t) => { + /* test */ + const response = formatDayUTC(null) + t.is(response, null) +}) + +test('formatDayUTC_succeeds', (t) => { + /* test */ + const response = formatDayUTC('2023-02-15 10:32:21') + t.is(response, '15') +}) + +test('formatTimestamp_fails', (t) => { + /* test */ + const response = formatTimestamp(null) + t.is(response, null) +}) + +test('formatTimestamp_succeeds', (t) => { + /* test */ + const response = formatTimestamp('2023-02-15 10:32:21') + t.is(response, '2023-02-15 10:32:21') +}) + +test('formatCreators_containerMissing_fails', (t) => { + const container = null + /* test */ + const response = formatCreators(container) + t.is(response, null) +}) + +test('formatCreators_databaseMissing_fails', (t) => { + const container = { } + /* test */ + const response = formatCreators(container) + t.is(response, null) +}) + +test('formatCreators_identifierMissing_fails', (t) => { + const container = { database: { } } + /* test */ + const response = formatCreators(container) + t.is(response, null) +}) + +test('formatCreators_creatorsMissing_fails', (t) => { + const container = { database: { identifier: { } } } + /* test */ + const response = formatCreators(container) + t.is(response, null) +}) + +test('formatCreators_identifierNull_fails', (t) => { + const container = { database: { identifier: null } } + /* test */ + const response = formatCreators(container) + t.is(response, null) +}) + +test('formatCreators_creatorsEmpty_fails', (t) => { + const container = { database: { identifier: { creators: [] } } } + /* test */ + const response = formatCreators(container) + t.is(response, null) +}) + +test('formatCreators_single_succeeds', (t) => { + const container = { database: { identifier: { creators: [{ firstname: 'Martin', lastname: 'Weise' }] } } } + /* test */ + const response = formatCreators(container) + t.is(response, 'M., Weise') +}) + +test('formatCreators_double_succeeds', (t) => { + const container = { database: { identifier: { creators: [{ firstname: 'Martin', lastname: 'Weise' }, { firstname: 'Tobias', lastname: 'Grantner' }] } } } + /* test */ + const response = formatCreators(container) + t.is(response, 'M., Weise, & T., Grantner') +}) + +test('formatCreators_multiple_succeeds', (t) => { + const container = { database: { identifier: { creators: [{ firstname: 'Martin', lastname: 'Weise' }, { firstname: 'Tobias', lastname: 'Grantner' }, { firstname: 'Josef', lastname: 'Taha' }] } } } + /* test */ + const response = formatCreators(container) + t.is(response, 'M., Weise, T., Grantner, & J., Taha') +}) + +test('formatTimestampUTCLabel_succeeds', (t) => { + /* test */ + const response = formatTimestampUTCLabel('2023-02-15 10:32:21') + t.is(response, '2023-02-15 09:32:21 (UTC)') +}) + +test('formatTimestampUTCLabel_fails', (t) => { + /* test */ + const response = formatTimestampUTCLabel(null) + t.is(response, null) +}) + +test('formatTimestampUTC_fails', (t) => { + /* test */ + const response = formatTimestampUTC(null) + t.is(response, null) +}) + +test('formatTimestampUTC_succeeds', (t) => { + /* test */ + const response = formatTimestampUTC('2023-02-15 10:32:21') + t.is(response, '2023-02-15 09:32:21') +}) diff --git a/fda-ui/utils/index.js b/fda-ui/utils/index.js index 5e8dde7871..2cb3310639 100644 --- a/fda-ui/utils/index.js +++ b/fda-ui/utils/index.js @@ -53,10 +53,10 @@ function formatUser (user) { if (!user) { return null } - if (!('firstname' in user) || !('lastname' in user)) { - return user.username - } - if (user.firstname === null || user.lastname === null) { + if (!('firstname' in user) || !('lastname' in user) || user.firstname === null || user.lastname === null) { + if (!('username' in user)) { + return null + } return user.username } let name = '' @@ -70,13 +70,6 @@ function formatUser (user) { return name } -function padLeft (str, padString, length) { - while (str.length < length) { - str = padString + str - } - return str -} - function formatDateUTC (str) { if (str === null) { return null @@ -117,8 +110,8 @@ function formatTimestamp (str) { } function formatCreators (container) { - if (!container.database.identifier || !container.database.identifier.creators) { - return '' + if (!container || !('database' in container) || !('identifier' in container.database) || !container.database.identifier || !('creators' in container.database.identifier) || !container.database.identifier.creators) { + return null } const creators = container.database.identifier.creators if (creators.length === 0) { @@ -127,8 +120,8 @@ function formatCreators (container) { let str = '' for (let i = 0; i < creators.length; i++) { /* separator */ - if (i > 0 && creators.length === 2) { - str += ' & ' + if (creators.length > 1 && i === creators.length - 1) { + str += ', & ' } else if (i > 0 && creators.length !== 2) { str += ', ' } @@ -170,7 +163,6 @@ module.exports = { formatYearUTC, formatMonthUTC, formatDayUTC, - padLeft, formatCreators, isDeveloper, isResearcher, diff --git a/fda-ui/yarn.lock b/fda-ui/yarn.lock index e302f9ae08..421217b621 100644 --- a/fda-ui/yarn.lock +++ b/fda-ui/yarn.lock @@ -2767,6 +2767,15 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" +axios@^1.3.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.3.tgz#e7011384ba839b885007c9c9fae1ff23dceb295b" + integrity sha512-eYq77dYIFS77AQlhzEL937yUBSepBfPIe8FcgEDN35vMNZKMrs81pgnyrQpwfy4NF4b4XWX1Zgx7yX+25w8QJA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-eslint@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" @@ -5639,6 +5648,11 @@ follow-redirects@^1.0.0, follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -5661,6 +5675,15 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -10091,6 +10114,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" -- GitLab