From 1de97829a8911f11f1901a3f5029df435829be0e Mon Sep 17 00:00:00 2001 From: gichan2-jang Date: Fri, 30 Jun 2023 17:04:22 +0900 Subject: [PATCH] [Services] Remote model register - Impelent registering model relotely - Add unit test Signed-off-by: gichan2-jang --- c/src/meson.build | 1 + c/src/ml-api-remote-service.c | 183 ++++++++- c/src/ml-api-service-private.h | 4 +- meson.build | 1 + packaging/machine-learning-api.spec | 5 +- tests/capi/unittest_capi_remote_service.cc | 435 ++++++++++++++++++++- 6 files changed, 599 insertions(+), 30 deletions(-) diff --git a/c/src/meson.build b/c/src/meson.build index d53759d2..ef7e9cb5 100644 --- a/c/src/meson.build +++ b/c/src/meson.build @@ -105,6 +105,7 @@ if get_option('enable-ml-service') ml_service_deps = [nns_capi_dep, ml_agentd_deps] if nnstreamer_edge_dep.found() ml_service_deps += nnstreamer_edge_dep + ml_service_deps += curl_dep endif nns_capi_service_shared_lib = shared_library ('capi-ml-service', diff --git a/c/src/ml-api-remote-service.c b/c/src/ml-api-remote-service.c index 58152a2c..4585c6e9 100644 --- a/c/src/ml-api-remote-service.c +++ b/c/src/ml-api-remote-service.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "ml-api-internal.h" #include "ml-api-service.h" @@ -152,12 +153,12 @@ _mlrs_get_service_type (gchar * service_str) if (g_ascii_strcasecmp (service_str, "model_raw") == 0) { service_type = ML_REMOTE_SERVICE_TYPE_MODEL_RAW; - } else if (g_ascii_strcasecmp (service_str, "model_url") == 0) { - service_type = ML_REMOTE_SERVICE_TYPE_MODEL_URL; + } else if (g_ascii_strcasecmp (service_str, "model_uri") == 0) { + service_type = ML_REMOTE_SERVICE_TYPE_MODEL_URI; } else if (g_ascii_strcasecmp (service_str, "pipeline_raw") == 0) { service_type = ML_REMOTE_SERVICE_TYPE_PIPELINE_RAW; - } else if (g_ascii_strcasecmp (service_str, "pipeline_url") == 0) { - service_type = ML_REMOTE_SERVICE_TYPE_PIPELINE_URL; + } else if (g_ascii_strcasecmp (service_str, "pipeline_uri") == 0) { + service_type = ML_REMOTE_SERVICE_TYPE_PIPELINE_URI; } else { _ml_error_report ("Invalid service type: %s, Please check service type.", service_str); @@ -165,6 +166,123 @@ _mlrs_get_service_type (gchar * service_str) return service_type; } +/** + * @brief Get ml remote service activation type. + */ +static gboolean +_mlrs_parse_activate (gchar * activate) +{ + gboolean ret = TRUE; + + if (g_ascii_strcasecmp (activate, "false") == 0) { + ret = FALSE; + } + + return ret; +} + +/** + * @brief Callback function for receving data using curl. + */ +static size_t +curl_mem_write_cb (void *data, size_t size, size_t nmemb, void *clientp) +{ + size_t recv_size = size * nmemb; + GByteArray *array = (GByteArray *) clientp; + + if (!array || !data || recv_size == 0) + return 0; + + g_byte_array_append (array, data, recv_size); + + return recv_size; +} + +/** + * @brief Register model file given by the remote sender. + */ +static gboolean +_mlrs_model_register (gchar * service_key, nns_edge_data_h data_h, + void *data, nns_size_t data_len) +{ + guint version = -1; + gchar *description = NULL; + gchar *name = NULL; + gchar *current_dir = g_get_current_dir (); + gchar *dir_path = NULL; + gchar *model_path = NULL; + gchar *activate = NULL; + gboolean active_bool = TRUE; + GError *error = NULL; + gboolean ret = TRUE; + + nns_edge_data_get_info (data_h, "description", &description); + nns_edge_data_get_info (data_h, "name", &name); + nns_edge_data_get_info (data_h, "activate", &activate); + active_bool = _mlrs_parse_activate (activate); + + dir_path = g_build_path ("/", current_dir, service_key, NULL); + g_mkdir_with_parents (dir_path, 0755); + model_path = g_build_path ("/", dir_path, name, NULL); + + if (!g_file_set_contents (model_path, (char *) data, data_len, &error)) { + _ml_loge ("Failed to write data to file: %s", + error ? error->message : "unknown error"); + g_clear_error (&error); + ret = FALSE; + goto error; + } + + /** + * @todo Hashing the path. Where is the default path to save the model file? + */ + if (ML_ERROR_NONE != ml_service_model_register (service_key, model_path, + active_bool, description, &version)) { + _ml_loge ("Failed to register model, service ket:%s", service_key); + ret = FALSE; + } +error: + g_free (current_dir); + g_free (dir_path); + g_free (activate); + g_free (model_path); + g_free (description); + g_free (name); + + return ret; +} + +/** + * @brief Get data from gievn uri + */ +static gboolean +_mlrs_get_data_from_uri (gchar * uri, GByteArray * array) +{ + CURL *curl; + CURLcode res; + gboolean ret = FALSE; + + curl = curl_easy_init (); + if (curl) { + curl_easy_setopt (curl, CURLOPT_URL, (gchar *) uri); + curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, curl_mem_write_cb); + curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *) array); + + res = curl_easy_perform (curl); + + if (res != CURLE_OK) { + _ml_loge ("curl_easy_perform failed: %s\n", curl_easy_strerror (res)); + return FALSE; + } + + curl_easy_cleanup (curl); + ret = TRUE; + } + + return ret; +} + /** * @brief Process ml remote service */ @@ -197,20 +315,50 @@ _mlrs_process_remote_service (nns_edge_data_h data_h) } switch (service_type) { - case ML_REMOTE_SERVICE_TYPE_MODEL_URL: - /** @todo Download the model file from given URL */ + case ML_REMOTE_SERVICE_TYPE_MODEL_URI: + { + GByteArray *array = g_byte_array_new (); + + if (!_mlrs_get_data_from_uri ((gchar *) data, array)) { + _ml_error_report_return (NNS_EDGE_ERROR_IO, + "Failed to get data from uri: %s.", (gchar *) data); + } + if (!_mlrs_model_register (service_key, data_h, array->data, array->len)) { + _ml_error_report ("Failed to register model downloaded from: %s.", + (gchar *) data); + ret = NNS_EDGE_ERROR_UNKNOWN; + } + g_byte_array_free (array, TRUE); + break; + } case ML_REMOTE_SERVICE_TYPE_MODEL_RAW: - /** @todo Save model file to given path and register the model */ + { + if (!_mlrs_model_register (service_key, data_h, data, data_len)) { + _ml_error_report ("Failed to register model downloaded from: %s.", + (gchar *) data); + ret = NNS_EDGE_ERROR_UNKNOWN; + } break; - case ML_REMOTE_SERVICE_TYPE_PIPELINE_URL: - /** @todo Download the pipeline description from given URL */ + } + case ML_REMOTE_SERVICE_TYPE_PIPELINE_URI: + { + GByteArray *array = g_byte_array_new (); + + ret = _mlrs_get_data_from_uri ((gchar *) data, array); + if (!ret) { + _ml_error_report_return (ret, + "Failed to get data from uri: %s.", (gchar *) data); + } + ret = ml_service_set_pipeline (service_key, (gchar *) array->data); + g_byte_array_free (array, TRUE); + break; + } case ML_REMOTE_SERVICE_TYPE_PIPELINE_RAW: - ml_service_set_pipeline (service_key, (gchar *) data); + ret = ml_service_set_pipeline (service_key, (gchar *) data); break; default: - _ml_error_report - ("Unknown service type or not supported yet. Service num: %d", - service_type); + _ml_error_report ("Unknown service type or not supported yet. " + "Service num: %d", service_type); break; } return ret; @@ -364,6 +512,9 @@ ml_remote_service_register (ml_service_h handle, ml_option_h option, void *data, nns_edge_data_h data_h = NULL; int ret = NNS_EDGE_ERROR_NONE; gchar *service_str = NULL; + gchar *description = NULL; + gchar *name = NULL; + gchar *activate = NULL; check_feature_state (ML_FEATURE_SERVICE); check_feature_state (ML_FEATURE_INFERENCE); @@ -411,6 +562,12 @@ ml_remote_service_register (ml_service_h handle, ml_option_h option, void *data, nns_edge_data_set_info (data_h, "service-type", service_str); nns_edge_data_set_info (data_h, "service-key", service_key); + ml_option_get (option, "description", (void **) &description); + nns_edge_data_set_info (data_h, "description", description); + ml_option_get (option, "name", (void **) &name); + nns_edge_data_set_info (data_h, "name", name); + ml_option_get (option, "activate", (void **) &activate); + nns_edge_data_set_info (data_h, "activate", activate); ret = nns_edge_data_add (data_h, data, data_len, NULL); if (NNS_EDGE_ERROR_NONE != ret) { diff --git a/c/src/ml-api-service-private.h b/c/src/ml-api-service-private.h index c7395ce6..20b80410 100644 --- a/c/src/ml-api-service-private.h +++ b/c/src/ml-api-service-private.h @@ -38,9 +38,9 @@ typedef enum { typedef enum { ML_REMOTE_SERVICE_TYPE_UNKNOWN = 0, ML_REMOTE_SERVICE_TYPE_MODEL_RAW, - ML_REMOTE_SERVICE_TYPE_MODEL_URL, + ML_REMOTE_SERVICE_TYPE_MODEL_URI, ML_REMOTE_SERVICE_TYPE_PIPELINE_RAW, - ML_REMOTE_SERVICE_TYPE_PIPELINE_URL, + ML_REMOTE_SERVICE_TYPE_PIPELINE_URI, ML_REMOTE_SERVICE_TYPE_MAX } ml_remote_service_type_e; diff --git a/meson.build b/meson.build index 9474cde8..de8d80fb 100644 --- a/meson.build +++ b/meson.build @@ -32,6 +32,7 @@ nnstreamer_internal_dep = dependency('nnstreamer-internal') nnstreamer_single_dep = dependency('nnstreamer-single') nnstreamer_dep = dependency('nnstreamer') nnstreamer_edge_dep = dependency('nnstreamer-edge', required: false) +curl_dep = cc.find_library('curl', required: false) if get_option('enable-ml-service') libsystemd_dep = dependency('libsystemd') diff --git a/packaging/machine-learning-api.spec b/packaging/machine-learning-api.spec index 8c2723c3..23c2e7f7 100644 --- a/packaging/machine-learning-api.spec +++ b/packaging/machine-learning-api.spec @@ -161,6 +161,7 @@ BuildRequires: pkgconfig(json-glib-1.0) BuildRequires: dbus BuildRequires: pkgconfig(capi-appfw-package-manager) BuildRequires: pkgconfig(capi-appfw-app-common) +BuildRequires: libcurl-devel %endif %if 0%{?nnstreamer_edge_support} @@ -396,7 +397,6 @@ export MLAPI_BUILD_ROOT_PATH=$(pwd)/%{builddir} # Run test # If gcov package generation is enabled, pass the test from GBS. %if 0%{?unit_test} && !0%{?gcov} -bash %{test_script} ./tests/capi/unittest_capi_remote_service bash %{test_script} ./tests/capi/unittest_capi_inference_single bash %{test_script} ./tests/capi/unittest_capi_inference bash %{test_script} ./tests/capi/unittest_capi_datatype_consistency @@ -406,6 +406,9 @@ bash %{test_script} ./tests/daemon/unittest_ml_agent bash %{test_script} ./tests/daemon/unittest_service_db bash %{test_script} ./tests/daemon/unittest_gdbus_util bash %{test_script} ./tests/capi/unittest_capi_service_agent_client +%if 0%{?nnstreamer_edge_support} +bash %{test_script} ./tests/capi/unittest_capi_remote_service +%endif %endif %if 0%{?nnfw_support} diff --git a/tests/capi/unittest_capi_remote_service.cc b/tests/capi/unittest_capi_remote_service.cc index 8098a23e..7e04387d 100644 --- a/tests/capi/unittest_capi_remote_service.cc +++ b/tests/capi/unittest_capi_remote_service.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -108,7 +109,7 @@ TEST_F (MLRemoteService, registerPipeline) status = ml_option_set (client_option_h, "host", client_dest_host, g_free); EXPECT_EQ (ML_ERROR_NONE, status); - guint dest_port = 3000; + guint dest_port = _get_available_port (); status = ml_option_set (client_option_h, "port", &dest_port, NULL); EXPECT_EQ (ML_ERROR_NONE, status); @@ -186,6 +187,119 @@ TEST_F (MLRemoteService, registerPipeline) EXPECT_EQ (ML_ERROR_NONE, status); } + +/** + * @brief use case of pipeline registration using ml remote service. + */ +TEST_F (MLRemoteService, registerPipelineURI) +{ + int status; + + /**============= Prepare client ============= **/ + ml_service_h client_h; + ml_option_h client_option_h = NULL; + + status = ml_option_create (&client_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_node_type = g_strdup ("remote_sender"); + status = ml_option_set (client_option_h, "node-type", client_node_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_dest_host = g_strdup ("127.0.0.1"); + status = ml_option_set (client_option_h, "host", client_dest_host, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + guint dest_port = _get_available_port (); + status = ml_option_set (client_option_h, "port", &dest_port, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_connect_type = g_strdup ("TCP"); + status = ml_option_set (client_option_h, "connect-type", client_connect_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *topic = g_strdup ("remote_service_test_topic"); + status = ml_option_set (client_option_h, "topic", topic, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_remote_service_create (client_option_h, &client_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + /**============= Prepare server ============= **/ + ml_service_h server_h; + ml_option_h server_option_h = NULL; + status = ml_option_create (&server_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *server_node_type = g_strdup ("remote_receiver"); + status = ml_option_set (server_option_h, "node-type", server_node_type, g_free); + + gchar *dest_host = g_strdup ("127.0.0.1"); + status = ml_option_set (server_option_h, "dest-host", dest_host, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_option_set (server_option_h, "topic", topic, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_option_set (server_option_h, "dest-port", &dest_port, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *server_connect_type = g_strdup ("TCP"); + status = ml_option_set (server_option_h, "connect-type", server_connect_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_remote_service_create (server_option_h, &server_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + ml_option_h remote_service_option_h = NULL; + status = ml_option_create (&remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *service_type = g_strdup ("pipeline_uri"); + ml_option_set (remote_service_option_h, "service-type", service_type, g_free); + + gchar *service_key = g_strdup ("pipeline_test_key"); + ml_option_set (remote_service_option_h, "service-key", service_key, g_free); + + gchar *current_dir = g_get_current_dir (); + gchar *test_file_path = g_build_path ("/", current_dir, "test.pipeline", NULL); + const gchar *pipeline_desc = "fakesrc ! fakesink"; + + EXPECT_TRUE (g_file_set_contents ( + test_file_path, pipeline_desc, strlen (pipeline_desc) + 1, NULL)); + + gchar *pipeline_uri = g_strdup_printf ("file://%s", test_file_path); + g_free (test_file_path); + + status = ml_remote_service_register (client_h, remote_service_option_h, + pipeline_uri, strlen (pipeline_uri) + 1); + EXPECT_EQ (ML_ERROR_NONE, status); + + /** Wait for the server to register the pipeline. */ + g_usleep (1000000); + + gchar *ret_pipeline = NULL; + status = ml_service_get_pipeline (service_key, &ret_pipeline); + EXPECT_EQ (ML_ERROR_NONE, status); + EXPECT_STREQ (pipeline_desc, ret_pipeline); + + status = ml_service_delete_pipeline (service_key); + EXPECT_TRUE (status == ML_ERROR_NONE); + + g_free (ret_pipeline); + g_free (pipeline_uri); + status = ml_service_destroy (server_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_service_destroy (client_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (server_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (client_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); +} + /** * @brief Test ml_remote_service_create with invalid param. */ @@ -227,43 +341,336 @@ TEST_F (MLRemoteService, registerInvalidParam_n) EXPECT_EQ (ML_ERROR_NONE, status); gchar *client_dest_host = g_strdup ("127.0.0.1"); - status = ml_option_set (option_h, "dest-host", client_dest_host, g_free); + status = ml_option_set (option_h, "host", client_dest_host, g_free); EXPECT_EQ (ML_ERROR_NONE, status); - guint dest_port = 1883; - status = ml_option_set (option_h, "dest-port", &dest_port, NULL); + guint dest_port = _get_available_port (); + status = ml_option_set (option_h, "port", &dest_port, NULL); EXPECT_EQ (ML_ERROR_NONE, status); - gchar *client_connect_type = g_strdup ("HYBRID"); + gchar *client_connect_type = g_strdup ("TCP"); status = ml_option_set (option_h, "connect-type", client_connect_type, g_free); EXPECT_EQ (ML_ERROR_NONE, status); - - gchar *topic = g_strdup ("temp_test_topic"); - status = ml_option_set (option_h, "topic", topic, NULL); - EXPECT_EQ (ML_ERROR_NONE, status); - status = ml_remote_service_create (option_h, &service_h); EXPECT_EQ (ML_ERROR_NONE, status); + ml_option_h remote_service_option_h = NULL; + status = ml_option_create (&remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *service_type = g_strdup ("pipeline_raw"); + ml_option_set (remote_service_option_h, "service-type", service_type, g_free); + + gchar *service_key = g_strdup ("pipeline_test_key"); + ml_option_set (remote_service_option_h, "service-key", service_key, g_free); - status = ml_remote_service_register (NULL, option_h, str, len); + g_autofree gchar *pipeline_desc = g_strdup ("fakesrc ! fakesink"); + status = ml_remote_service_register (NULL, remote_service_option_h, str, len); EXPECT_EQ (ML_ERROR_INVALID_PARAMETER, status); status = ml_remote_service_register (service_h, NULL, str, len); EXPECT_EQ (ML_ERROR_INVALID_PARAMETER, status); - status = ml_remote_service_register (service_h, option_h, NULL, len); + status = ml_remote_service_register (service_h, remote_service_option_h, NULL, len); EXPECT_EQ (ML_ERROR_INVALID_PARAMETER, status); - status = ml_remote_service_register (service_h, option_h, str, 0); + status = ml_remote_service_register (service_h, remote_service_option_h, str, 0); EXPECT_EQ (ML_ERROR_INVALID_PARAMETER, status); - status = ml_option_destroy (option_h); EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); status = ml_service_destroy (service_h); EXPECT_EQ (ML_ERROR_NONE, status); } + +/** + * @brief use case of model registration using ml remote service. + */ +TEST_F (MLRemoteService, registerModel) +{ + int status; + + /**============= Prepare client ============= **/ + ml_service_h client_h; + ml_option_h client_option_h = NULL; + + status = ml_option_create (&client_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_node_type = g_strdup ("remote_sender"); + status = ml_option_set (client_option_h, "node-type", client_node_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_dest_host = g_strdup ("127.0.0.1"); + status = ml_option_set (client_option_h, "host", client_dest_host, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + guint dest_port = _get_available_port (); + status = ml_option_set (client_option_h, "port", &dest_port, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_connect_type = g_strdup ("TCP"); + status = ml_option_set (client_option_h, "connect-type", client_connect_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *topic = g_strdup ("remote_service_test_topic"); + status = ml_option_set (client_option_h, "topic", topic, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_remote_service_create (client_option_h, &client_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + /**============= Prepare server ============= **/ + ml_service_h server_h; + ml_option_h server_option_h = NULL; + status = ml_option_create (&server_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *server_node_type = g_strdup ("remote_receiver"); + status = ml_option_set (server_option_h, "node-type", server_node_type, g_free); + + gchar *dest_host = g_strdup ("127.0.0.1"); + status = ml_option_set (server_option_h, "dest-host", dest_host, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_option_set (server_option_h, "topic", topic, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_option_set (server_option_h, "dest-port", &dest_port, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *server_connect_type = g_strdup ("TCP"); + status = ml_option_set (server_option_h, "connect-type", server_connect_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_remote_service_create (server_option_h, &server_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + /** Set service option */ + const gchar *root_path = g_getenv ("MLAPI_SOURCE_ROOT_PATH"); + /* ml_remote_service_register () requires absolute path to model, ignore this case. */ + if (root_path == NULL) + return; + + gchar *test_model = g_build_filename (root_path, "tests", "test_models", + "models", "mobilenet_v1_1.0_224_quant.tflite", NULL); + EXPECT_TRUE (g_file_test (test_model, G_FILE_TEST_EXISTS)); + + gchar *contents = NULL; + gsize len = 0; + EXPECT_TRUE (g_file_get_contents (test_model, &contents, &len, NULL)); + + ml_option_h remote_service_option_h = NULL; + status = ml_option_create (&remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *service_key = g_strdup ("model_registration_test_key"); + ml_option_set (remote_service_option_h, "service-key", service_key, g_free); + + gchar *service_type = g_strdup ("model_raw"); + ml_option_set (remote_service_option_h, "service-type", service_type, g_free); + + gchar *activate = g_strdup ("true"); + ml_option_set (remote_service_option_h, "activate", activate, g_free); + + gchar *description = g_strdup ("temp description for remote model registeration test"); + ml_option_set (remote_service_option_h, "description", description, g_free); + + gchar *name = g_strdup ("mobilenet_v1_1.0_224_quant.tflite"); + ml_option_set (remote_service_option_h, "name", name, g_free); + + status = ml_remote_service_register (client_h, remote_service_option_h, contents, len); + EXPECT_EQ (ML_ERROR_NONE, status); + + /** Wait for the server to register the pipeline. */ + g_usleep (1000000); + + // Get model file + ml_information_h activated_model_info; + status = ml_service_model_get_activated (service_key, &activated_model_info); + EXPECT_EQ (ML_ERROR_NONE, status); + EXPECT_NE (activated_model_info, nullptr); + + gchar *activated_model_path; + status = ml_information_get (activated_model_info, "path", (void **) &activated_model_path); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *activated_model_contents = NULL; + gsize activated_model_len = 0; + EXPECT_TRUE (g_file_get_contents (activated_model_path, + &activated_model_contents, &activated_model_len, NULL)); + EXPECT_EQ (len, activated_model_len); + EXPECT_EQ (memcmp (contents, activated_model_contents, len), 0); + + status = ml_service_model_delete (service_key, 0U); + EXPECT_TRUE (status == ML_ERROR_NONE); + + g_remove (activated_model_path); + + g_free (contents); + g_free (test_model); + g_free (activated_model_contents); + status = ml_service_destroy (server_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_service_destroy (client_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (server_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (client_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_information_destroy (activated_model_info); + EXPECT_EQ (ML_ERROR_NONE, status); +} + +/** + * @brief use case of model registration from URI using ml remote service. + */ +TEST_F (MLRemoteService, registerModelURI) +{ + int status; + + /**============= Prepare client ============= **/ + ml_service_h client_h; + ml_option_h client_option_h = NULL; + + status = ml_option_create (&client_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_node_type = g_strdup ("remote_sender"); + status = ml_option_set (client_option_h, "node-type", client_node_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_dest_host = g_strdup ("127.0.0.1"); + status = ml_option_set (client_option_h, "host", client_dest_host, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + guint dest_port = _get_available_port (); + status = ml_option_set (client_option_h, "port", &dest_port, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *client_connect_type = g_strdup ("TCP"); + status = ml_option_set (client_option_h, "connect-type", client_connect_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *topic = g_strdup ("remote_service_test_topic"); + status = ml_option_set (client_option_h, "topic", topic, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_remote_service_create (client_option_h, &client_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + /**============= Prepare server ============= **/ + ml_service_h server_h; + ml_option_h server_option_h = NULL; + status = ml_option_create (&server_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *server_node_type = g_strdup ("remote_receiver"); + status = ml_option_set (server_option_h, "node-type", server_node_type, g_free); + + gchar *dest_host = g_strdup ("127.0.0.1"); + status = ml_option_set (server_option_h, "dest-host", dest_host, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_option_set (server_option_h, "topic", topic, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_option_set (server_option_h, "dest-port", &dest_port, NULL); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *server_connect_type = g_strdup ("TCP"); + status = ml_option_set (server_option_h, "connect-type", server_connect_type, g_free); + EXPECT_EQ (ML_ERROR_NONE, status); + + status = ml_remote_service_create (server_option_h, &server_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + /** Prepare model register service */ + const gchar *root_path = g_getenv ("MLAPI_SOURCE_ROOT_PATH"); + /* ml_remote_service_register () requires absolute path to model, ignore this case. */ + if (root_path == NULL) + return; + + gchar *test_model_path = g_build_filename (root_path, "tests", "test_models", + "models", "mobilenet_v1_1.0_224_quant.tflite", NULL); + EXPECT_TRUE (g_file_test (test_model_path, G_FILE_TEST_EXISTS)); + + ml_option_h remote_service_option_h = NULL; + status = ml_option_create (&remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *service_type = g_strdup ("model_uri"); + ml_option_set (remote_service_option_h, "service-type", service_type, g_free); + + gchar *service_key = g_strdup ("pipeline_test_key"); + ml_option_set (remote_service_option_h, "service-key", service_key, g_free); + + gchar *model_uri = g_strdup_printf ("file://%s", test_model_path); + + gchar *activate = g_strdup ("true"); + ml_option_set (remote_service_option_h, "activate", activate, g_free); + + gchar *description = g_strdup ("temp descriptio for remote model register test"); + ml_option_set (remote_service_option_h, "description", description, g_free); + + gchar *name = g_strdup ("mobilenet_v1_1.0_224_quant.tflite"); + ml_option_set (remote_service_option_h, "name", name, g_free); + + status = ml_remote_service_register ( + client_h, remote_service_option_h, model_uri, strlen (model_uri) + 1); + EXPECT_EQ (ML_ERROR_NONE, status); + g_free (model_uri); + + /** Wait for the server to register the pipeline. */ + g_usleep (1000000); + + gchar *contents = NULL; + gsize len = 0; + EXPECT_TRUE (g_file_get_contents (test_model_path, &contents, &len, NULL)); + + ml_information_h activated_model_info; + status = ml_service_model_get_activated (service_key, &activated_model_info); + EXPECT_EQ (ML_ERROR_NONE, status); + EXPECT_NE (activated_model_info, nullptr); + + gchar *activated_model_path; + status = ml_information_get (activated_model_info, "path", (void **) &activated_model_path); + EXPECT_EQ (ML_ERROR_NONE, status); + + gchar *activated_model_contents = NULL; + gsize activated_model_len = 0; + EXPECT_TRUE (g_file_get_contents (activated_model_path, + &activated_model_contents, &activated_model_len, NULL)); + EXPECT_EQ (len, activated_model_len); + EXPECT_EQ (memcmp (contents, activated_model_contents, len), 0); + + status = ml_service_model_delete (service_key, 0U); + EXPECT_TRUE (status == ML_ERROR_NONE); + + status = g_remove (activated_model_path); + EXPECT_TRUE (status == 0); + + g_free (contents); + g_free (activated_model_contents); + g_free (test_model_path); + status = ml_service_destroy (server_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_service_destroy (client_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (server_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (remote_service_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_option_destroy (client_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + status = ml_information_destroy (activated_model_info); + EXPECT_EQ (ML_ERROR_NONE, status); +} + /** * @brief Main gtest */