From f0f10f162e38c204666cb78b25b8a0f52ea8a46f Mon Sep 17 00:00:00 2001 From: Kostas Filippopolitis Date: Tue, 16 Jul 2024 19:38:37 +0300 Subject: [PATCH] Update Deployment Logic: - Kubernetes: Ensure GlobalWorker is deployed even in single worker deployments. - Flower: Configure the server to run on the GlobalWorker. --- .github/workflows/prod_env_tests.yml | 100 ++++++------------ .../controller/services/flower/controller.py | 16 +-- kubernetes/templates/exareme2-globalnode.yaml | 15 ++- mipdb/Dockerfile | 2 +- tasks.py | 24 +++-- .../flower/test_logistic_regression.py | 10 +- .../one_node_deployment_template.toml | 14 ++- .../master/monetdb_password.sh | 2 +- ...st_flower_logisticregression_validation.py | 1 + tests/prod_env_tests/test_get_datasets.py | 5 + .../test_get_datasets_locations.py | 84 +++++++-------- .../flower/test_processes_garbage_collect.py | 4 + tests/standalone_tests/conftest.py | 77 ++++++++++++-- .../test_pos_and_kw_args_in_algorithm_flow.py | 3 + .../worker_info/test_get_data_model_cdes.py | 4 + tests/test_data/globalworker.db | Bin 12288 -> 0 bytes tests/test_data/localworker1.db | Bin 282624 -> 0 bytes tests/test_data/localworker2.db | Bin 274432 -> 0 bytes 18 files changed, 207 insertions(+), 154 deletions(-) delete mode 100644 tests/test_data/globalworker.db delete mode 100644 tests/test_data/localworker1.db delete mode 100644 tests/test_data/localworker2.db diff --git a/.github/workflows/prod_env_tests.yml b/.github/workflows/prod_env_tests.yml index ba1eb6e41..9309839b8 100644 --- a/.github/workflows/prod_env_tests.yml +++ b/.github/workflows/prod_env_tests.yml @@ -203,82 +203,44 @@ jobs: - name: Wait for pods to get healthy run: timeout 300 bash -c 'while true; do if kubectl get pods --no-headers | awk '\''{if ($2 != "1/1" && $2 != "2/2" && $2 != "3/3" && $2 != "4/4") exit 1;}'\''; then echo "All pods are ready!"; break; else kubectl get pods -o wide; sleep 20; fi done' - - name: Initialize MONETDB from mipdb container + - name: Load data models into localworkers and globalworker run: | - for i in 0 1; do - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[$i].metadata.name") - kubectl exec $POD_NAME -c db-importer -- sh -c 'mipdb init' - done - GLOBAL_POD_NAME=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r '.items[0].metadata.name') - kubectl exec $GLOBAL_POD_NAME -c db-importer -- sh -c 'mipdb init' - - - name: Load dementia data model into localworkers and globalworker - run: | - for i in 0 1; do - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[$i].metadata.name") - kubectl exec $POD_NAME -c db-importer -- sh -c 'mipdb add-data-model /opt/data/dementia_v_0_1/CDEsMetadata.json' - done - GLOBAL_POD_NAME=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r '.items[0].metadata.name') - kubectl exec $GLOBAL_POD_NAME -c db-importer -- sh -c 'mipdb add-data-model /opt/data/dementia_v_0_1/CDEsMetadata.json' - - - name: Load dementia dataset csvs into localworkers and globalworker - run: | - for suffix in {0..9}; do - if [ $suffix -eq 0 ] || [ $suffix -eq 3 ] || [ $suffix -eq 6 ]; then - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[0].metadata.name") - elif [ $suffix -eq 1 ] || [ $suffix -eq 4 ] || [ $suffix -eq 7 ]; then - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[1].metadata.name") - else - POD_NAME=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r '.items[0].metadata.name') - fi - for dataset in edsd ppmi desd-synthdata; do - kubectl exec $POD_NAME -c db-importer -- sh -c "mipdb add-dataset /opt/data/dementia_v_0_1/${dataset}${suffix}.csv -d dementia -v 0.1" + LOCALWORKER1=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[0].metadata.name") + LOCALWORKER2=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[1].metadata.name") + GLOBALWORKER=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r ".items[0].metadata.name") + for POD in $LOCALWORKER1 $LOCALWORKER2 $GLOBALWORKER; do + kubectl exec $POD -c db-importer -- sh -c 'mipdb init' + for model in dementia_v_0_1 tbi_v_0_1 longitudinal_dementia_v_0_1; do + kubectl exec $POD -c db-importer -- sh -c "mipdb add-data-model /opt/data/${model}/CDEsMetadata.json" done done - - name: Load tbi data model into localworkers and globalworker + - name: Load dataset csvs into localworkers run: | - for i in 0 1; do - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[$i].metadata.name") - kubectl exec $POD_NAME -c db-importer -- sh -c 'mipdb add-data-model /opt/data/tbi_v_0_1/CDEsMetadata.json' - done - GLOBAL_POD_NAME=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r '.items[0].metadata.name') - kubectl exec $GLOBAL_POD_NAME -c db-importer -- sh -c 'mipdb add-data-model /opt/data/tbi_v_0_1/CDEsMetadata.json' - - - name: Load tbi dataset csvs into localworkers and globalworker - run: | - for suffix in {0..9}; do - if [ $suffix -eq 0 ] || [ $suffix -eq 3 ] || [ $suffix -eq 6 ]; then - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[0].metadata.name") - elif [ $suffix -eq 1 ] || [ $suffix -eq 4 ] || [ $suffix -eq 7 ]; then - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[1].metadata.name") - else - POD_NAME=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r '.items[0].metadata.name') - fi - kubectl exec $POD_NAME -c db-importer -- sh -c "mipdb add-dataset /opt/data/tbi_v_0_1/dummy_tbi${suffix}.csv -d tbi -v 0.1" - done - - - name: Load longitudinal dementia data model into localworkers and globalworker - run: | - for i in 0 1; do - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[$i].metadata.name") - kubectl exec $POD_NAME -c db-importer -- sh -c 'mipdb add-data-model /opt/data/longitudinal_dementia_v_0_1/CDEsMetadata.json' + LOCALWORKER1=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[0].metadata.name") + LOCALWORKER2=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[1].metadata.name") + GLOBALWORKER=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r ".items[0].metadata.name") + + for model in dementia_v_0_1 tbi_v_0_1 longitudinal_dementia_v_0_1; do + for filepath in $(kubectl exec $GLOBALWORKER -c db-importer -- ls /opt/data/${model}); do + filepath=/opt/data/${model}/${filepath} + if [[ $filepath == *test.csv ]]; then + echo "Loading file: $filepath at $GLOBALWORKER" + kubectl exec $GLOBALWORKER -c db-importer -- mipdb add-dataset $filepath -d ${model%_v_*} -v 0.1 + elif [[ $filepath == *.csv ]]; then + filename=$(basename $filepath) + suffix=$(echo $filename | grep -o '[0-9]*' | tail -1) + if (( suffix % 2 == 0 )); then + POD_NAME=$LOCALWORKER2 + else + POD_NAME=$LOCALWORKER1 + fi + echo "Loading file: $filepath at $POD_NAME" + kubectl exec $POD_NAME -c db-importer -- mipdb add-dataset $filepath -d ${model%_v_*} -v 0.1 + fi + done done - GLOBAL_POD_NAME=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r '.items[0].metadata.name') - kubectl exec $GLOBAL_POD_NAME -c db-importer -- sh -c 'mipdb add-data-model /opt/data/longitudinal_dementia_v_0_1/CDEsMetadata.json' - - name: Load longitudinal dementia datasets into localworkers and globalworker - run: | - for suffix in {0..2}; do - if [ $suffix -eq 0 ]; then - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[0].metadata.name") - elif [ $suffix -eq 1 ]; then - POD_NAME=$(kubectl get pods -l=nodeType=localworker -o json | jq -r ".items[1].metadata.name") - else - POD_NAME=$(kubectl get pods -l=nodeType=globalworker -o json | jq -r '.items[0].metadata.name') - fi - kubectl exec $POD_NAME -c db-importer -- sh -c "mipdb add-dataset /opt/data/longitudinal_dementia_v_0_1/longitudinal_dementia${suffix}.csv -d longitudinal_dementia -v 0.1" - done - name: Controller logs run: kubectl logs -l app=exareme2-controller --tail -1 diff --git a/exareme2/controller/services/flower/controller.py b/exareme2/controller/services/flower/controller.py index 57b2dc366..5cd51c282 100644 --- a/exareme2/controller/services/flower/controller.py +++ b/exareme2/controller/services/flower/controller.py @@ -70,18 +70,12 @@ async def exec_algorithm(self, algorithm_name, algorithm_request_dto): for worker in workers_info ] - server_task_handler, server_ip, server_id = ( - task_handlers[0], - workers_info[0].ip, - workers_info[0].id, + global_worker = self.worker_landscape_aggregator.get_global_worker() + server_task_handler = self._create_worker_tasks_handler( + request_id, global_worker ) - if len(task_handlers) > 1: - global_worker = self.worker_landscape_aggregator.get_global_worker() - server_task_handler = self._create_worker_tasks_handler( - request_id, global_worker - ) - server_ip = global_worker.ip - server_id = global_worker.id + server_ip = global_worker.ip + server_id = global_worker.id # Garbage Collect server_task_handler.garbage_collect() for handler in task_handlers: diff --git a/kubernetes/templates/exareme2-globalnode.yaml b/kubernetes/templates/exareme2-globalnode.yaml index 1fa26aec2..81758743a 100644 --- a/kubernetes/templates/exareme2-globalnode.yaml +++ b/kubernetes/templates/exareme2-globalnode.yaml @@ -1,4 +1,3 @@ -{{ if gt .Values.localnodes 1.0}} # Single node deployment apiVersion: apps/v1 kind: Deployment metadata: @@ -26,6 +25,9 @@ spec: - name: csv-data hostPath: path: {{ .Values.db.csvs_location }} + - name: credentials + hostPath: + path: {{ .Values.db.credentials_location }} containers: - name: monetdb image: {{ .Values.exareme2_images.repository }}/exareme2_db:{{ .Values.exareme2_images.version }} @@ -49,6 +51,10 @@ spec: volumeMounts: - mountPath: /home/monetdb name: db-data + - mountPath: /opt/data + name: csv-data + - mountPath: /opt/credentials + name: credentials startupProbe: exec: command: @@ -120,6 +126,8 @@ spec: - name: worker image: {{ .Values.exareme2_images.repository }}/exareme2_worker:{{ .Values.exareme2_images.version }} volumeMounts: + - mountPath: /opt/credentials + name: credentials - mountPath: /opt/data name: csv-data env: @@ -159,6 +167,10 @@ spec: value: "guest" - name: MONETDB_PUBLIC_PASSWORD value: "guest" + - name: SQLITE_DB_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName - name: SMPC_ENABLED value: {{ quote .Values.smpc.enabled }} {{ if .Values.smpc.enabled }} @@ -190,4 +202,3 @@ spec: - exareme2.worker.healthcheck periodSeconds: 30 timeoutSeconds: 10 -{{end}} diff --git a/mipdb/Dockerfile b/mipdb/Dockerfile index 8b5c66412..876099aad 100644 --- a/mipdb/Dockerfile +++ b/mipdb/Dockerfile @@ -30,7 +30,7 @@ WORKDIR $DATA_PATH ####################################################### # Installing dependencies ####################################################### -RUN pip install mipdb==3.0.0 # Must be updated together with pyproject.toml +RUN pip install mipdb==3.0.2 # Must be updated together with pyproject.toml RUN pip install click==8.1.2 RUN pip install pymonetdb==1.6.3 # Must be updated together with pyproject.toml diff --git a/tasks.py b/tasks.py index c5b92f542..bdf530845 100644 --- a/tasks.py +++ b/tasks.py @@ -503,6 +503,19 @@ def load_datasets( :param worker_id_and_ports: A list of tuples containing worker identifiers and ports. :param use_sockets: Flag to determine if data will be loaded via sockets. """ + if len(worker_id_and_ports) == 1: + worker_id, port = worker_id_and_ports[0] + for file in filenames: + if file.endswith(".csv") and not file.endswith("test.csv"): + csv = os.path.join(dirpath, file) + message( + f"Loading dataset {pathlib.PurePath(csv).name} in MonetDB at port {port}...", + Level.HEADER, + ) + cmd = f"poetry run mipdb add-dataset {csv} -d {data_model_code} -v {data_model_version} --copy_from_file {not use_sockets} {get_monetdb_configs_in_mipdb_format(port)} {get_sqlite_path(worker_id)}" + run(c, cmd) + return + # Load the first set of CSVs into the first worker first_worker_csvs = sorted( [ @@ -581,17 +594,6 @@ def load_test_datasets( if not local_worker_id_and_ports: raise Exception("Local worker config files cannot be loaded.") - # If only one local worker is specified, load the entire folder to that worker - if len(local_worker_id_and_ports) == 1: - worker_id, port = local_worker_id_and_ports[0] - cmd = f"poetry run mipdb load-folder {TEST_DATA_FOLDER} --copy_from_file {not use_sockets} {get_monetdb_configs_in_mipdb_format(port)} {get_sqlite_path(worker_id)}" - message( - f"Loading the folder '{TEST_DATA_FOLDER}' in MonetDB at port {port}...", - Level.HEADER, - ) - run(c, cmd) - return - # Process each dataset in the TEST_DATA_FOLDER for local workers for dirpath, dirnames, filenames in os.walk(TEST_DATA_FOLDER): if "CDEsMetadata.json" not in filenames: diff --git a/tests/algorithm_validation_tests/flower/test_logistic_regression.py b/tests/algorithm_validation_tests/flower/test_logistic_regression.py index 74de56b97..de166f7d5 100644 --- a/tests/algorithm_validation_tests/flower/test_logistic_regression.py +++ b/tests/algorithm_validation_tests/flower/test_logistic_regression.py @@ -24,10 +24,7 @@ def test_logistic_regression(get_algorithm_result): } input["type"] = "flower" algorithm_result = get_algorithm_result("logistic_regression", input) - print(algorithm_result) - assert algorithm_result == {"accuracy": 0.63} or algorithm_result == { - "accuracy": 0.3819241982507289 - } + assert algorithm_result == {"accuracy": 0.63} def test_logistic_regression_with_filters(get_algorithm_result): @@ -69,7 +66,4 @@ def test_logistic_regression_with_filters(get_algorithm_result): } input["type"] = "flower" algorithm_result = get_algorithm_result("logistic_regression", input) - print(algorithm_result) - assert algorithm_result == {"accuracy": 0.7884615384615384} or algorithm_result == { - "accuracy": 0.22443181818181818 - } + assert algorithm_result == {"accuracy": 0.7884615384615384} diff --git a/tests/algorithm_validation_tests/one_node_deployment_template.toml b/tests/algorithm_validation_tests/one_node_deployment_template.toml index 8ce14cbdf..b9bc263ef 100644 --- a/tests/algorithm_validation_tests/one_node_deployment_template.toml +++ b/tests/algorithm_validation_tests/one_node_deployment_template.toml @@ -33,11 +33,21 @@ optional=false enabled = false [[workers]] -id = "localworker1" -role="LOCALWORKER" +id = "globalworker" +role="GLOBALWORKER" rabbitmq_port=5670 monetdb_port=50000 local_monetdb_username="executor" local_monetdb_password="executor" public_monetdb_username="guest" public_monetdb_password="guest" + +[[workers]] +id = "localworker1" +role="LOCALWORKER" +rabbitmq_port=5671 +monetdb_port=50001 +local_monetdb_username="executor" +local_monetdb_password="executor" +public_monetdb_username="guest" +public_monetdb_password="guest" diff --git a/tests/prod_env_tests/deployment_configs/kind_configuration/master/monetdb_password.sh b/tests/prod_env_tests/deployment_configs/kind_configuration/master/monetdb_password.sh index 2d34996e9..15af13bf9 100755 --- a/tests/prod_env_tests/deployment_configs/kind_configuration/master/monetdb_password.sh +++ b/tests/prod_env_tests/deployment_configs/kind_configuration/master/monetdb_password.sh @@ -1,2 +1,2 @@ #!/bin/bash -export MONETDB_LOCAL_PASSWORD="global" +export MONETDB_LOCAL_PASSWORD="master" diff --git a/tests/prod_env_tests/test_flower_logisticregression_validation.py b/tests/prod_env_tests/test_flower_logisticregression_validation.py index 9bf454df2..10c7cfe7c 100644 --- a/tests/prod_env_tests/test_flower_logisticregression_validation.py +++ b/tests/prod_env_tests/test_flower_logisticregression_validation.py @@ -21,6 +21,7 @@ def test_logisticregression_algorithm(): "ppmi7", "ppmi8", "ppmi9", + "ppmi_test", ], "filters": None, }, diff --git a/tests/prod_env_tests/test_get_datasets.py b/tests/prod_env_tests/test_get_datasets.py index 40df10e9c..36c82f864 100644 --- a/tests/prod_env_tests/test_get_datasets.py +++ b/tests/prod_env_tests/test_get_datasets.py @@ -20,6 +20,7 @@ def expected_datasets_per_data_model(): "edsd7", "edsd8", "edsd9", + "edsd_test", "ppmi0", "ppmi1", "ppmi2", @@ -30,6 +31,7 @@ def expected_datasets_per_data_model(): "ppmi7", "ppmi8", "ppmi9", + "ppmi_test", "desd-synthdata0", "desd-synthdata1", "desd-synthdata2", @@ -40,6 +42,7 @@ def expected_datasets_per_data_model(): "desd-synthdata7", "desd-synthdata8", "desd-synthdata9", + "desd-synthdata_test", }, "tbi:0.1": { "dummy_tbi0", @@ -52,11 +55,13 @@ def expected_datasets_per_data_model(): "dummy_tbi7", "dummy_tbi8", "dummy_tbi9", + "dummy_tbi_test", }, "longitudinal_dementia:0.1": { "longitudinal_dementia0", "longitudinal_dementia1", "longitudinal_dementia2", + "longitudinal_dementia_test", }, } diff --git a/tests/prod_env_tests/test_get_datasets_locations.py b/tests/prod_env_tests/test_get_datasets_locations.py index 4c4cb76df..46a6a6129 100644 --- a/tests/prod_env_tests/test_get_datasets_locations.py +++ b/tests/prod_env_tests/test_get_datasets_locations.py @@ -9,54 +9,59 @@ @pytest.fixture def expected_datasets_locations(): return { - "longitudinal_dementia:0.1": { - "longitudinal_dementia0": "localworker1", - "longitudinal_dementia1": "localworker2", - "longitudinal_dementia2": "localworker3", - }, - "tbi:0.1": { - "dummy_tbi0": "localworker1", - "dummy_tbi1": "localworker2", - "dummy_tbi3": "localworker2", - "dummy_tbi5": "localworker2", - "dummy_tbi7": "localworker2", - "dummy_tbi9": "localworker2", - "dummy_tbi2": "localworker3", - "dummy_tbi4": "localworker3", - "dummy_tbi6": "localworker3", - "dummy_tbi8": "localworker3", - }, "dementia:0.1": { "desd-synthdata0": "localworker1", - "edsd0": "localworker1", - "ppmi0": "localworker1", "desd-synthdata1": "localworker2", + "desd-synthdata2": "localworker1", "desd-synthdata3": "localworker2", + "desd-synthdata4": "localworker1", "desd-synthdata5": "localworker2", + "desd-synthdata6": "localworker1", "desd-synthdata7": "localworker2", + "desd-synthdata8": "localworker1", "desd-synthdata9": "localworker2", - "edsd2": "localworker2", - "edsd4": "localworker2", - "edsd6": "localworker2", - "edsd8": "localworker2", + "desd-synthdata_test": "master", + "edsd0": "localworker1", + "edsd1": "localworker2", + "edsd2": "localworker1", + "edsd3": "localworker2", + "edsd4": "localworker1", + "edsd5": "localworker2", + "edsd6": "localworker1", + "edsd7": "localworker2", + "edsd8": "localworker1", + "edsd9": "localworker2", + "edsd_test": "master", + "ppmi0": "localworker1", "ppmi1": "localworker2", + "ppmi2": "localworker1", "ppmi3": "localworker2", + "ppmi4": "localworker1", "ppmi5": "localworker2", + "ppmi6": "localworker1", "ppmi7": "localworker2", + "ppmi8": "localworker1", "ppmi9": "localworker2", - "desd-synthdata2": "localworker3", - "desd-synthdata4": "localworker3", - "desd-synthdata6": "localworker3", - "desd-synthdata8": "localworker3", - "edsd1": "localworker3", - "edsd3": "localworker3", - "edsd5": "localworker3", - "edsd7": "localworker3", - "edsd9": "localworker3", - "ppmi2": "localworker3", - "ppmi4": "localworker3", - "ppmi6": "localworker3", - "ppmi8": "localworker3", + "ppmi_test": "master", + }, + "longitudinal_dementia:0.1": { + "longitudinal_dementia0": "localworker1", + "longitudinal_dementia1": "localworker2", + "longitudinal_dementia2": "localworker1", + "longitudinal_dementia_test": "master", + }, + "tbi:0.1": { + "dummy_tbi0": "localworker2", + "dummy_tbi1": "localworker1", + "dummy_tbi2": "localworker1", + "dummy_tbi3": "localworker1", + "dummy_tbi4": "localworker1", + "dummy_tbi5": "localworker1", + "dummy_tbi6": "localworker1", + "dummy_tbi7": "localworker1", + "dummy_tbi8": "localworker1", + "dummy_tbi9": "localworker1", + "dummy_tbi_test": "master", }, } @@ -64,9 +69,4 @@ def expected_datasets_locations(): def test_get_dataset_location(expected_datasets_locations): request = requests.get(datasets_locations_url) response = json.loads(request.text) - for worker_id in response: - assert worker_id in expected_datasets_locations - for data_model in response[worker_id]: - assert data_model in expected_datasets_locations[worker_id] - for dataset in response[worker_id][data_model]: - assert dataset in response[worker_id][data_model] + assert response == expected_datasets_locations diff --git a/tests/standalone_tests/algorithms/flower/test_processes_garbage_collect.py b/tests/standalone_tests/algorithms/flower/test_processes_garbage_collect.py index 641bb1f31..f9ab9c25a 100644 --- a/tests/standalone_tests/algorithms/flower/test_processes_garbage_collect.py +++ b/tests/standalone_tests/algorithms/flower/test_processes_garbage_collect.py @@ -14,8 +14,10 @@ @pytest.mark.slow def test_processes_garbage_collect( + globalworker_worker_service, localworker1_worker_service, load_data_localworker1, + load_test_data_globalworker, controller_service_with_localworker1, localworker1_celery_app, ): @@ -29,6 +31,7 @@ def test_processes_garbage_collect( algorithm_name="logistic_regression", number_of_clients=1, server_address=f"{COMMON_IP}:8080", + csv_paths="dataset1.csv,dataset2.csv", ) localworker1_celery_app.get_result( async_result=async_result, @@ -46,6 +49,7 @@ def test_processes_garbage_collect( "ppmi1", "ppmi2", "ppmi3", + "ppmi_test", ], "filters": None, }, diff --git a/tests/standalone_tests/conftest.py b/tests/standalone_tests/conftest.py index f1a74d289..9e2812773 100644 --- a/tests/standalone_tests/conftest.py +++ b/tests/standalone_tests/conftest.py @@ -35,7 +35,6 @@ PULL_DOCKER_IMAGES_STR = os.getenv("PULL_DOCKER_IMAGES", "true") PULL_DOCKER_IMAGES = PULL_DOCKER_IMAGES_STR.lower() == "true" - this_mod_path = os.path.dirname(os.path.abspath(__file__)) TEST_ENV_CONFIG_FOLDER = path.join(this_mod_path, "testing_env_configs") TEST_DATA_FOLDER = Path(this_mod_path).parent / "test_data" @@ -56,7 +55,6 @@ HEALTHCHECK_URL = f"http://{COMMON_IP}:4500/healthcheck" - RABBITMQ_GLOBALWORKER_NAME = "rabbitmq_test_globalworker" RABBITMQ_LOCALWORKER1_NAME = "rabbitmq_test_localworker1" RABBITMQ_LOCALWORKER2_NAME = "rabbitmq_test_localworker2" @@ -81,7 +79,6 @@ RABBITMQ_SMPC_LOCALWORKER2_PORT = 60006 RABBITMQ_SMPC_LOCALWORKER2_ADDR = f"{COMMON_IP}:{str(RABBITMQ_SMPC_LOCALWORKER2_PORT)}" - DATASET_SUFFIXES_LOCALWORKER1 = [0, 1, 2, 3] DATASET_SUFFIXES_LOCALWORKER2 = [4, 5, 6] DATASET_SUFFIXES_LOCALWORKERTMP = [7, 8, 9] @@ -176,6 +173,8 @@ SMPC_PLAYER3_PORT3 = 14002 SMPC_CLIENT1_PORT = 9005 SMPC_CLIENT2_PORT = 9006 + + ##################################### @@ -380,6 +379,62 @@ def _init_database_monetdb_container(db_port, worker_id): print(f"\nDatabase ({monetdb_configs.ip}:{monetdb_configs.port}) initialized.") +def _load_test_data_monetdb_container(db_port, worker_id): + monetdb_configs = MonetDBConfigurations(db_port) + # Check if the database is already loaded + cmd = f"mipdb list-datasets {monetdb_configs.convert_to_mipdb_format()} --sqlite_db_path {TEST_DATA_FOLDER}/{worker_id}.db" + res = subprocess.run( + cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + if "There are no datasets" not in str(res.stdout): + print( + f"\nDatabase ({monetdb_configs.ip}:{monetdb_configs.port}) already loaded, continuing." + ) + return + + datasets_per_data_model = {} + # Load the test data folder into the dbs + for dirpath, dirnames, filenames in os.walk(TEST_DATA_FOLDER): + if "CDEsMetadata.json" not in filenames: + continue + cdes_file = os.path.join(dirpath, "CDEsMetadata.json") + with open(cdes_file) as data_model_metadata_file: + data_model_metadata = json.load(data_model_metadata_file) + data_model_code = data_model_metadata["code"] + data_model_version = data_model_metadata["version"] + data_model = f"{data_model_code}:{data_model_version}" + + print( + f"\nLoading data model '{data_model_code}:{data_model_version}' metadata to database ({monetdb_configs.ip}:{monetdb_configs.port})" + ) + cmd = f"mipdb add-data-model {cdes_file} {monetdb_configs.convert_to_mipdb_format()} --sqlite_db_path {TEST_DATA_FOLDER}/{worker_id}.db" + subprocess.run( + cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + + csvs = sorted( + [f"{dirpath}/{file}" for file in filenames if file.endswith("test.csv")] + ) + + for csv in csvs: + cmd = f"mipdb add-dataset {csv} -d {data_model_code} -v {data_model_version} {monetdb_configs.convert_to_mipdb_format()} --sqlite_db_path {TEST_DATA_FOLDER}/{worker_id}.db" + subprocess.run( + cmd, + shell=True, + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + print( + f"\nLoading dataset {pathlib.PurePath(csv).name} to database ({monetdb_configs.ip}:{monetdb_configs.port})" + ) + datasets_per_data_model[data_model] = pathlib.PurePath(csv).name + + print(f"\nData loaded to database ({monetdb_configs.ip}:{monetdb_configs.port})") + time.sleep(2) # Needed to avoid db crash while loading + return datasets_per_data_model + + def _load_data_monetdb_container(db_port, dataset_suffixes, worker_id): monetdb_configs = MonetDBConfigurations(db_port) # Check if the database is already loaded @@ -424,15 +479,12 @@ def _load_data_monetdb_container(db_port, dataset_suffixes, worker_id): for csv in csvs: cmd = f"mipdb add-dataset {csv} -d {data_model_code} -v {data_model_version} {monetdb_configs.convert_to_mipdb_format()} --sqlite_db_path {TEST_DATA_FOLDER}/{worker_id}.db" - _env = os.environ.copy() - _env["DATA_PATH"] = str(TEST_DATA_FOLDER) subprocess.run( cmd, shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=_env, ) print( f"\nLoading dataset {pathlib.PurePath(csv).name} to database ({monetdb_configs.ip}:{monetdb_configs.port})" @@ -456,7 +508,7 @@ def init_data_globalworker(monetdb_globalworker): def load_data_localworker1(monetdb_localworker1): worker_config_file = LOCALWORKER1_CONFIG_FILE worker_id = get_worker_id(worker_config_file) - _init_database_monetdb_container(MONETDB_GLOBALWORKER_PORT, worker_id) + _init_database_monetdb_container(LOCALWORKER1_CONFIG_FILE, worker_id) loaded_datasets_per_data_model = _load_data_monetdb_container( MONETDB_LOCALWORKER1_PORT, DATASET_SUFFIXES_LOCALWORKER1, worker_id ) @@ -474,6 +526,17 @@ def load_data_localworker2(monetdb_localworker2): yield loaded_datasets_per_data_model +@pytest.fixture(scope="session") +def load_test_data_globalworker(monetdb_globalworker): + worker_config_file = GLOBALWORKER_CONFIG_FILE + worker_id = get_worker_id(worker_config_file) + _init_database_monetdb_container(MONETDB_GLOBALWORKER_PORT, worker_id) + loaded_datasets_per_data_model = _load_test_data_monetdb_container( + MONETDB_GLOBALWORKER_PORT, worker_id + ) + yield loaded_datasets_per_data_model + + @pytest.fixture(scope="function") def load_data_localworkertmp(monetdb_localworkertmp): worker_config_file = LOCALWORKERTMP_CONFIG_FILE diff --git a/tests/standalone_tests/controller/services/flower/test_pos_and_kw_args_in_algorithm_flow.py b/tests/standalone_tests/controller/services/flower/test_pos_and_kw_args_in_algorithm_flow.py index 96ea5d36e..0576fee42 100644 --- a/tests/standalone_tests/controller/services/flower/test_pos_and_kw_args_in_algorithm_flow.py +++ b/tests/standalone_tests/controller/services/flower/test_pos_and_kw_args_in_algorithm_flow.py @@ -8,8 +8,10 @@ @pytest.mark.slow def test_pos_and_kw_args_in_algorithm_flow( + globalworker_worker_service, localworker1_worker_service, load_data_localworker1, + load_test_data_globalworker, controller_service_with_localworker1, ): algorithm_name = "logistic_regression" @@ -23,6 +25,7 @@ def test_pos_and_kw_args_in_algorithm_flow( "ppmi1", "ppmi2", "ppmi3", + "ppmi_test", ], "filters": None, }, diff --git a/tests/standalone_tests/worker/worker_info/test_get_data_model_cdes.py b/tests/standalone_tests/worker/worker_info/test_get_data_model_cdes.py index a2baccecd..16d90c325 100644 --- a/tests/standalone_tests/worker/worker_info/test_get_data_model_cdes.py +++ b/tests/standalone_tests/worker/worker_info/test_get_data_model_cdes.py @@ -33,6 +33,7 @@ def get_test_cases_get_data_model_cdes(): "ppmi7": "PPMI_7", "ppmi8": "PPMI_8", "ppmi9": "PPMI_9", + "ppmi_test": "PPMI_TEST", "edsd0": "EDSD_0", "edsd1": "EDSD_1", "edsd2": "EDSD_2", @@ -43,6 +44,7 @@ def get_test_cases_get_data_model_cdes(): "edsd7": "EDSD_7", "edsd8": "EDSD_8", "edsd9": "EDSD_9", + "edsd_test": "EDSD_TEST", "desd-synthdata0": "DESD-synthdata_0", "desd-synthdata1": "DESD-synthdata_1", "desd-synthdata2": "DESD-synthdata_2", @@ -53,6 +55,7 @@ def get_test_cases_get_data_model_cdes(): "desd-synthdata7": "DESD-synthdata_7", "desd-synthdata8": "DESD-synthdata_8", "desd-synthdata9": "DESD-synthdata_9", + "desd-synthdata_test": "DESD-synthdata_TEST", }, ), "alzheimerbroadcategory": CommonDataElement( @@ -98,6 +101,7 @@ def get_test_cases_get_data_model_cdes(): "dummy_tbi7": "Dummy TBI_7", "dummy_tbi8": "Dummy TBI_8", "dummy_tbi9": "Dummy TBI_9", + "dummy_tbi_test": "Dummy TBI test", }, ), "gender_type": CommonDataElement( diff --git a/tests/test_data/globalworker.db b/tests/test_data/globalworker.db deleted file mode 100644 index 98651cbe4422b2a2a503bc7cb14f506dbf701cae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI#O>4q17zgmQ4rGFCH&4O?yC{rZb{?#g=+v%mvD@$@RWnwotF)Pyo%ZsP_5s&u z>kCtm?I!;~+b8{}ZSw0W-8?t~D$ILL;B@tuHOpaV~WKH)EvQBa}R_bk~ z$<7{I#UwS0-|R@A&>#Q-2tWV=5P$##AOHafKwxKqkG7dFmCMGLue?DZN1pOxsp9OK zs|jwooLuY5=9Jx~O5rfA`~HZUj>{WdkkfI=xwq|8n#cWdIFiA(5yK>;2TRnht@TF( zZyNvu5e8gGn-@w7kj)N>ZY6RA%XIO+f4NO% z6#L;zCb0H9{$#p~-|Fi1-aOg#qd@=y5P$##AOHafKmY;|fB*y_u*U+}|L^h7#nK=E W0SG_<0uX=z1Rwwb2tWV=slX3M*0@vv diff --git a/tests/test_data/localworker1.db b/tests/test_data/localworker1.db deleted file mode 100644 index e12f6409d1379715b2c00842aba6c26a56f3a27a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282624 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 diff --git a/tests/test_data/localworker2.db b/tests/test_data/localworker2.db deleted file mode 100644 index 7e5feb6c18a33542954d2f67be966657d39d56c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 274432 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