changeset 599:f3475c3e42e5

run integ tests after a PG downgrade
author Alain Mazy <am@osimis.io>
date Thu, 18 Jan 2024 17:46:54 +0100
parents b9ae7c59fee9
children 58384ae69f41
files NewTests/PostgresUpgrades/docker-compose.yml NewTests/PostgresUpgrades/docker-entrypoint-integ-tests.sh NewTests/PostgresUpgrades/downgrade.sh NewTests/PostgresUpgrades/downgrade.sql NewTests/PostgresUpgrades/orthanc-for-integ-tests.json NewTests/PostgresUpgrades/run-integ-tests-from-docker.sh NewTests/PostgresUpgrades/test_pg_upgrades.py NewTests/PostgresUpgrades/wait-for-it.sh
diffstat 8 files changed, 501 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/NewTests/PostgresUpgrades/docker-compose.yml	Wed Jan 10 15:19:46 2024 +0100
+++ b/NewTests/PostgresUpgrades/docker-compose.yml	Thu Jan 18 17:46:54 2024 +0100
@@ -15,7 +15,53 @@
       PG_LOCK: "false"
       PG_INDEX_ENABLED: "true"
       AC_AUTHENTICATION_ENABLED: "false"
-      
+
+  # Orthanc previous version
+  orthanc-pg-15-61:
+    image: osimis/orthanc:24.1.2
+    container_name: orthanc-pg-15-61
+    depends_on: [pg-15]
+    restart: unless-stopped
+    ports: ["8052:8042"]
+    volumes: ["storage-orthanc-pg-15:/var/lib/orthanc/db"]
+    environment:
+      VERBOSE_ENABLED: "true"
+      PG_HOST: "pg-15"
+      PG_LOCK: "false"
+      PG_INDEX_ENABLED: "true"
+      AC_AUTHENTICATION_ENABLED: "false"
+
+  # Orthanc previous version to run the integration tests
+  orthanc-pg-15-61-for-integ-tests:
+    image: osimis/orthanc:24.1.2
+    container_name: orthanc-pg-15-61-for-integ-tests
+    depends_on: [pg-15]
+    restart: unless-stopped
+    ports: ["8053:8042"]
+    volumes: 
+      - "storage-orthanc-pg-15:/var/lib/orthanc/db"
+      - "./orthanc-for-integ-tests.json:/etc/orthanc/orthanc.json"
+      - ./docker-entrypoint-integ-tests.sh:/docker-entrypoint-integ-tests.sh
+    entrypoint: /docker-entrypoint-integ-tests.sh
+
+    environment:
+      VERBOSE_ENABLED: "true"
+      PG_HOST: "pg-15"
+      PG_LOCK: "false"
+      PG_INDEX_ENABLED: "true"
+      AC_AUTHENTICATION_ENABLED: "false"
+
+  orthanc-tests:
+    image: jodogne/orthanc-tests
+    container_name: orthanc-tests
+    depends_on:
+      - orthanc-pg-15-61-for-integ-tests
+    volumes:
+      - ../../:/tests/orthanc-tests
+      - ./wait-for-it.sh:/scripts/wait-for-it.sh
+      - ./run-integ-tests-from-docker.sh:/scripts/run-integ-tests-from-docker.sh
+    entrypoint: /scripts/run-integ-tests-from-docker.sh
+
   # Orthanc latest version
   orthanc-pg-15-under-tests:
     image: ${ORTHANC_IMAGE_UNDER_TESTS:-osimis/orthanc:latest}
@@ -39,7 +85,10 @@
     container_name: pg-15
     restart: unless-stopped
     ports: ["5439:5432"]
-    volumes: ["storage-pg-15:/var/lib/postgresql/data"]
+    volumes: 
+      - "storage-pg-15:/var/lib/postgresql/data"
+      - "./downgrade.sh:/scripts/downgrade.sh"
+      - "./downgrade.sql:/scripts/downgrade.sql"
     environment:
       POSTGRES_HOST_AUTH_METHOD: "trust"
     healthcheck:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NewTests/PostgresUpgrades/docker-entrypoint-integ-tests.sh	Thu Jan 18 17:46:54 2024 +0100
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -ex
+
+apt-get -y update 
+apt-get install -y libgdcm-tools 
+/docker-entrypoint.sh /tmp/orthanc.json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NewTests/PostgresUpgrades/downgrade.sh	Thu Jan 18 17:46:54 2024 +0100
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+pushd /scripts
+
+# TODO: change pg-transactions by the plugin version number !
+apt-get update && apt-get install -y wget && wget https://orthanc.uclouvain.be/hg/orthanc-databases/raw-file/pg-transactions/PostgreSQL/Plugins/SQL/Downgrades/V6.2ToV6.1.sql
+psql -U postgres -f V6.2ToV6.1.sql
+
+# if you want to test a downgrade procedure, you may use this code ...
+# psql -U postgres -f downgrade.sql
+popd
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NewTests/PostgresUpgrades/downgrade.sql	Thu Jan 18 17:46:54 2024 +0100
@@ -0,0 +1,1 @@
+-- you may paste here a test downgrade procedure to avoid rebuilding the docker image ...  check downgrade.sh
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NewTests/PostgresUpgrades/orthanc-for-integ-tests.json	Thu Jan 18 17:46:54 2024 +0100
@@ -0,0 +1,194 @@
+// how to obtain this file:
+// in orthanc-tests: generate the configuration file with python2 ./GenerateConfigurationForTests.py
+// then, paste it here and:
+// - remove the Plugins section
+// - remove the PostgreSQL/MySQL/Odbc sections
+// - update the IP of OrthancPeers and DicomModalities: replace localhost by orthanc-tests for the first item
+// - update the Worklists.Database to "/worklists"
+// - update the StorageDirectory to "/var/lib/orthand/db/"
+{
+    "AcceptedTransferSyntaxes": [
+      "1.2.840.10008.1.*"
+     ], 
+     "AllowFindSopClassesInStudy": false, 
+     "AuthenticationEnabled": true, 
+     "BuiltinDecoderTranscoderOrder": "After", 
+     "CaseSensitivePN": false, 
+     "CheckRevisions": true, 
+     "ConcurrentJobs": 2, 
+     "DefaultEncoding": "Utf8", 
+     "DefaultPrivateCreator": "Lunit", 
+     "DeidentifyLogs": true, 
+     "DicomAet": "ORTHANC", 
+     "DicomAlwaysAllowEcho": true, 
+     "DicomAlwaysAllowFind": false, 
+     "DicomAlwaysAllowFindWorklist": false, 
+     "DicomAlwaysAllowGet": false, 
+     "DicomAlwaysAllowMove": false, 
+     "DicomAlwaysAllowStore": true, 
+     "DicomAssociationCloseDelay": 0, 
+     "DicomCheckCalledAet": false, 
+     "DicomCheckModalityHost": false, 
+     "DicomEchoChecksFind": false, 
+     "DicomLossyTranscodingQuality": 90, 
+     "DicomModalities": {
+      "orthanctest": [
+       "ORTHANCTEST", 
+       "orthanc-tests", 
+       5001
+      ], 
+      "self": [
+       "ORTHANC", 
+       "127.0.0.1", 
+       4242
+      ]
+     }, 
+     "DicomModalitiesInDatabase": false, 
+     "DicomPort": 4242, 
+     "DicomScpTimeout": 30, 
+     "DicomScuPreferredTransferSyntax": "1.2.840.10008.1.2.1", 
+     "DicomScuTimeout": 10, 
+     "DicomServerEnabled": true, 
+     "DicomThreadsCount": 4, 
+     "DicomTlsEnabled": false, 
+     "DicomTlsRemoteCertificateRequired": true, 
+     "DicomWeb": {
+      "Servers": {
+       "sample": [
+        "http://localhost:8042/dicom-web/", 
+        "alice", 
+        "orthanctest"
+       ]
+      }
+     }, 
+     "Dictionary": {
+      "0009,0010": [
+       "LO", 
+       "Private data element", 
+       1, 
+       1, 
+       "Lunit"
+      ], 
+      "0009,1001": [
+       "DS", 
+       "Abnormality score", 
+       1, 
+       1, 
+       "Lunit"
+      ], 
+      "00e1,10c2": [
+       "UI", 
+       "PET-CT Multi Modality Name", 
+       1, 
+       1, 
+       "ELSCINT1"
+      ], 
+      "4321,1012": [
+       "LO", 
+       "RadioButton3", 
+       1, 
+       1, 
+       "RadioLogic"
+      ], 
+      "7053,1003": [
+       "ST", 
+       "Original Image Filename", 
+       1, 
+       1, 
+       "Philips PET Private Group"
+      ]
+     }, 
+     "ExecuteLuaEnabled": true, 
+     "HttpCompressionEnabled": false, 
+     "HttpDescribeErrors": true, 
+     "HttpPort": 8042, 
+     "HttpProxy": "", 
+     "HttpRequestTimeout": 30, 
+     "HttpServerEnabled": true, 
+     "HttpThreadsCount": 50, 
+     "HttpTimeout": 2, 
+     "HttpVerbose": false, 
+     "HttpsCACertificates": "/etc/ssl/certs/ca-certificates.crt", 
+     "HttpsVerifyPeers": true, 
+     "IndexDirectory": "/var/lib/orthanc/db/", 
+     "IngestTranscodingOfCompressed": true, 
+     "IngestTranscodingOfUncompressed": true, 
+     "JobsHistorySize": 1000, 
+     "LimitFindInstances": 0, 
+     "LimitFindResults": 0, 
+     "LoadPrivateDictionary": true, 
+     "LogExportedResources": true, 
+     "LuaScripts": [], 
+     "MallocArenaMax": 5, 
+     "MaximumPatientCount": 0, 
+     "MaximumPduLength": 16384, 
+     "MaximumStorageCacheSize": 128, 
+     "MaximumStorageSize": 0, 
+     "MediaArchiveSize": 1, 
+     "MetricsEnabled": true, 
+     "Name": "MyOrthanc", 
+   "OrthancExplorerEnabled": true, 
+   "OrthancPeers": {
+    "peer": [
+     "http://orthanc-tests:5000/", 
+     "alice", 
+     "orthanctest"
+    ], 
+    "self": {
+     "Password": "orthanctest", 
+     "Url": "http://127.0.0.1:8042/", 
+     "Username": "alice"
+    }, 
+    "transfers-bidirectional": {
+     "Password": "orthanctest", 
+     "RemoteSelf": "transfers-bidirectional", 
+     "Url": "http://localhost:8042/", 
+     "Username": "alice"
+    }, 
+    "transfers-simple": {
+     "Password": "orthanctest", 
+     "Url": "http://localhost:8042/", 
+     "Username": "alice"
+    }
+   }, 
+   "OrthancPeersInDatabase": false, 
+   "OverwriteInstances": true, 
+   "QueryRetrieveSize": 100, 
+   "RegisteredUsers": {
+    "alice": "orthanctest"
+   }, 
+   "RemoteAccessAllowed": true, 
+   "SaveJobs": false, 
+   "SslCertificate": "certificate.pem", 
+   "SslEnabled": false, 
+   "SslMinimumProtocolVersion": 4, 
+   "SslTrustedClientCertificates": "trustedClientCertificates.pem", 
+   "SslVerifyPeers": false, 
+   "StableAge": 1, 
+   "StorageAccessOnFind": "Always", 
+   "StorageCommitmentReportsSize": 100, 
+   "StorageCompression": false, 
+   "StorageDirectory": "/var/lib/orthanc/db/", 
+   "StoreDicom": true, 
+   "StoreMD5ForAttachments": true, 
+   "StrictAetComparison": false, 
+   "SyncStorageArea": false, 
+   "SynchronousCMove": false, 
+   "SynchronousZipStream": true, 
+   "TcpNoDelay": true, 
+   "TranscodeDicomProtocol": true, 
+   "UnknownSopClassAccepted": false, 
+   "UserContentType": {}, 
+   "UserMetadata": {
+     "my-metadata": 1098
+   },
+   "WebDavDeleteAllowed": true, 
+   "WebDavEnabled": true, 
+   "WebDavUploadAllowed": true, 
+   "Worklists": {
+     "Database": "/worklists", 
+     "Enable": true
+   }, 
+   "ZipLoaderThreads": 0
+  }
+  
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NewTests/PostgresUpgrades/run-integ-tests-from-docker.sh	Thu Jan 18 17:46:54 2024 +0100
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -ex
+
+/scripts/wait-for-it.sh orthanc-pg-15-61-for-integ-tests:8042 -t 60
+# python /tests/orthanc-tests/Tests/Run.py --server=orthanc-pg-15-61-for-integ-tests --force --docker -- -v  Orthanc.test_lua_deadlock
+python /tests/orthanc-tests/Tests/Run.py --server=orthanc-pg-15-61-for-integ-tests --force --docker -- -v
--- a/NewTests/PostgresUpgrades/test_pg_upgrades.py	Wed Jan 10 15:19:46 2024 +0100
+++ b/NewTests/PostgresUpgrades/test_pg_upgrades.py	Thu Jan 18 17:46:54 2024 +0100
@@ -36,11 +36,22 @@
 class TestPgUpgrades(unittest.TestCase):
 
     @classmethod
-    def setUpClass(cls):
+    def cleanup(cls):
         os.chdir(here)
         print("Cleaning old compose")
         subprocess.run(["docker", "compose", "down", "-v", "--remove-orphans"], check=True)
 
+
+    @classmethod
+    def setUpClass(cls):
+        cls.cleanup()
+
+    @classmethod
+    def tearDownClass(cls):
+        pass
+        # cls.cleanup()
+
+
     def test_upgrades_downgrades_with_pg_15(self):
 
         print("Launching PG-15 server")
@@ -60,7 +71,11 @@
         time.sleep(2)
 
         print("Launching newest Orthanc")
-        subprocess.run(["docker", "compose", "up", "orthanc-pg-15-under-tests", "-d"], check=True)
+        subprocess.run(["docker", "compose", "up", "orthanc-pg-15-under-tests", "-d"], 
+            env= {
+                "ORTHANC_IMAGE_UNDER_TESTS": Helpers.orthanc_under_tests_docker_image
+            },
+            check=True)
 
         o = OrthancApiClient("http://localhost:8050")
         o.wait_started()
@@ -68,14 +83,47 @@
         # make sure we can 'play' with Orthanc
         o.instances.get_tags(orthanc_id=instances[0])
         o.instances.delete_all()
+        self.assertEqual(0, int(o.get_json('/statistics')['TotalDiskSize']))
         instances = o.upload_folder(here / "../../Database/Knee")
+        size_before_downgrade = int(o.get_json('/statistics')['TotalDiskSize'])
 
-        print("Stopping new Orthanc ")
+        print("Stopping newest Orthanc ")
         subprocess.run(["docker", "compose", "stop", "orthanc-pg-15-under-tests"], check=True)
         time.sleep(2)
 
-        print("TODO Downgrading Orthanc DB and restart an Orthanc 23.12.1")
-        # ...
+        print("Downgrading Orthanc DB to v6.1")
+        subprocess.run(["docker", "exec", "pg-15", "./scripts/downgrade.sh"], check=True)
+        time.sleep(2)
+
+        print("Downgrading Orthanc DB to v6.1")
+        print("Launching previous Orthanc (DB v6.1)")
+        subprocess.run(["docker", "compose", "up", "orthanc-pg-15-61", "-d"], check=True)
+
+        o = OrthancApiClient("http://localhost:8052")
+        o.wait_started()
+
+        # make sure we can 'play' with Orthanc
+        o.instances.get_tags(orthanc_id=instances[0])
+        self.assertEqual(size_before_downgrade, int(o.get_json('/statistics')['TotalDiskSize']))
+        o.instances.delete_all()
+        self.assertEqual(0, int(o.get_json('/statistics')['TotalDiskSize']))
+        instances = o.upload_folder(here / "../../Database/Knee")
+        o.instances.delete_all()
+        self.assertEqual(0, int(o.get_json('/statistics')['TotalDiskSize']))
+
+        print("run the integration tests after a downgrade")
+        # first create the containers (orthanc-tests + orthanc-pg-15-61-for-integ-tests) so they know each other
+        # subprocess.run(["docker", "compose", "create", "orthanc-tests"], check=True)
+
+        # subprocess.run(["docker", "compose", "up", "orthanc-pg-15-61-for-integ-tests", "-d"], check=True)
+
+        # o = OrthancApiClient("http://localhost:8053", user="alice", pwd="orthanctest")
+        # o.wait_started()
+
+        # time.sleep(10000)
+        subprocess.run(["docker", "compose", "up", "orthanc-tests"], check=True)
+
+
 
     def test_latest_orthanc_with_pg_9(self):
         print("Launching PG-9 server")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NewTests/PostgresUpgrades/wait-for-it.sh	Thu Jan 18 17:46:54 2024 +0100
@@ -0,0 +1,177 @@
+#!/usr/bin/env bash
+#   Use this script to test if a given TCP host/port are available
+
+cmdname=$(basename $0)
+
+echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
+
+usage()
+{
+    cat << USAGE >&2
+Usage:
+    $cmdname host:port [-s] [-t timeout] [-- command args]
+    -h HOST | --host=HOST       Host or IP under test
+    -p PORT | --port=PORT       TCP port under test
+                                Alternatively, you specify the host and port as host:port
+    -s | --strict               Only execute subcommand if the test succeeds
+    -q | --quiet                Don't output any status messages
+    -t TIMEOUT | --timeout=TIMEOUT
+                                Timeout in seconds, zero for no timeout
+    -- COMMAND ARGS             Execute command with args after the test finishes
+USAGE
+    exit 1
+}
+
+wait_for()
+{
+    if [[ $TIMEOUT -gt 0 ]]; then
+        echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
+    else
+        echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
+    fi
+    start_ts=$(date +%s)
+    while :
+    do
+        if [[ $ISBUSY -eq 1 ]]; then
+            nc -z $HOST $PORT
+            result=$?
+        else
+            (echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1
+            result=$?
+        fi
+        if [[ $result -eq 0 ]]; then
+            end_ts=$(date +%s)
+            echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
+            break
+        fi
+        sleep 1
+    done
+    return $result
+}
+
+wait_for_wrapper()
+{
+    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
+    if [[ $QUIET -eq 1 ]]; then
+        timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
+    else
+        timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
+    fi
+    PID=$!
+    trap "kill -INT -$PID" INT
+    wait $PID
+    RESULT=$?
+    if [[ $RESULT -ne 0 ]]; then
+        echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
+    fi
+    return $RESULT
+}
+
+# process arguments
+while [[ $# -gt 0 ]]
+do
+    case "$1" in
+        *:* )
+        hostport=(${1//:/ })
+        HOST=${hostport[0]}
+        PORT=${hostport[1]}
+        shift 1
+        ;;
+        --child)
+        CHILD=1
+        shift 1
+        ;;
+        -q | --quiet)
+        QUIET=1
+        shift 1
+        ;;
+        -s | --strict)
+        STRICT=1
+        shift 1
+        ;;
+        -h)
+        HOST="$2"
+        if [[ $HOST == "" ]]; then break; fi
+        shift 2
+        ;;
+        --host=*)
+        HOST="${1#*=}"
+        shift 1
+        ;;
+        -p)
+        PORT="$2"
+        if [[ $PORT == "" ]]; then break; fi
+        shift 2
+        ;;
+        --port=*)
+        PORT="${1#*=}"
+        shift 1
+        ;;
+        -t)
+        TIMEOUT="$2"
+        if [[ $TIMEOUT == "" ]]; then break; fi
+        shift 2
+        ;;
+        --timeout=*)
+        TIMEOUT="${1#*=}"
+        shift 1
+        ;;
+        --)
+        shift
+        CLI=("$@")
+        break
+        ;;
+        --help)
+        usage
+        ;;
+        *)
+        echoerr "Unknown argument: $1"
+        usage
+        ;;
+    esac
+done
+
+if [[ "$HOST" == "" || "$PORT" == "" ]]; then
+    echoerr "Error: you need to provide a host and port to test."
+    usage
+fi
+
+TIMEOUT=${TIMEOUT:-15}
+STRICT=${STRICT:-0}
+CHILD=${CHILD:-0}
+QUIET=${QUIET:-0}
+
+# check to see if timeout is from busybox?
+# check to see if timeout is from busybox?
+TIMEOUT_PATH=$(realpath $(which timeout))
+if [[ $TIMEOUT_PATH =~ "busybox" ]]; then
+        ISBUSY=1
+        BUSYTIMEFLAG="-t"
+else
+        ISBUSY=0
+        BUSYTIMEFLAG=""
+fi
+
+if [[ $CHILD -gt 0 ]]; then
+    wait_for
+    RESULT=$?
+    exit $RESULT
+else
+    if [[ $TIMEOUT -gt 0 ]]; then
+        wait_for_wrapper
+        RESULT=$?
+    else
+        wait_for
+        RESULT=$?
+    fi
+fi
+
+if [[ $CLI != "" ]]; then
+    if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
+        echoerr "$cmdname: strict mode, refusing to execute subprocess"
+        exit $RESULT
+    fi
+    exec "${CLI[@]}"
+else
+    exit $RESULT
+fi
\ No newline at end of file