From 25dd92f9a238f6c7bc2011b85d8508dc24f3d860 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 | 167 ++++++++- c/src/ml-api-service-private.h | 4 +- meson.build | 1 + packaging/machine-learning-api.spec | 1 + tests/capi/unittest_capi_remote_service.cc | 388 ++++++++++++++++++++- 6 files changed, 546 insertions(+), 16 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 c81c31d5..e1de39ae 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" @@ -151,12 +152,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,120 @@ _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 (activate && 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) + 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? + */ + ml_service_model_register (service_key, model_path, + active_bool, description, &version); +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 */ @@ -175,6 +290,7 @@ _mlrs_process_remote_service (nns_edge_data_h data_h) nns_size_t data_len; gchar *service_str = NULL; gchar *service_key = NULL; + gchar *description = NULL; ml_remote_service_type_e service_type; nns_edge_data_get (data_h, 0, &data, &data_len); @@ -182,22 +298,40 @@ _mlrs_process_remote_service (nns_edge_data_h data_h) nns_edge_data_get_info (data_h, "service-type", &service_str); service_type = _mlrs_get_service_type (service_str); nns_edge_data_get_info (data_h, "service-key", &service_key); + nns_edge_data_get_info (data_h, "description", &description); 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 (); + + _mlrs_get_data_from_uri ((gchar *) data, array); + g_message ("pipeline size: %u", array->len); + _mlrs_model_register (service_key, data_h, array->data, array->len); + 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 */ + { + _mlrs_model_register (service_key, data_h, data, data_len); 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 (); + + _mlrs_get_data_from_uri ((gchar *) data, array); + g_message ("pipeline size: %u", array->len); + 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); 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; } } @@ -346,6 +480,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); @@ -382,6 +519,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); ml_option_get (option, "service-key", (void **) &service_key); 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 db8a743e..c185331e 100644 --- a/c/src/ml-api-service-private.h +++ b/c/src/ml-api-service-private.h @@ -37,9 +37,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 c3f1d0c3..ac6d39f6 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 f663f687..e157467e 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} diff --git a/tests/capi/unittest_capi_remote_service.cc b/tests/capi/unittest_capi_remote_service.cc index 97554623..327d8cf1 100644 --- a/tests/capi/unittest_capi_remote_service.cc +++ b/tests/capi/unittest_capi_remote_service.cc @@ -189,6 +189,116 @@ 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 = 3000; + 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); + + 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. */ @@ -233,11 +343,11 @@ TEST_F (MLRemoteService, registerInvalidParam_n) status = ml_option_set (option_h, "dest-host", client_dest_host, g_free); EXPECT_EQ (ML_ERROR_NONE, status); - guint dest_port = 1883; + guint dest_port = 3000; status = ml_option_set (option_h, "dest-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); @@ -269,6 +379,280 @@ TEST_F (MLRemoteService, registerInvalidParam_n) 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 = 3000; + 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 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, contents, len); + EXPECT_EQ (ML_ERROR_NONE, status); + + /** Wait for the server to register the pipeline. */ + g_usleep (1000000); + + // Get model file + ml_option_h activated_model_option_h; + status = ml_service_model_get_activated (service_key, &activated_model_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + EXPECT_NE (activated_model_option_h, nullptr); + + gchar *activated_model_path; + status = ml_option_get (activated_model_option_h, "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); + + 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_option_destroy (activated_model_option_h); + 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 = 3000; + 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_option_h activated_model_option_h; + status = ml_service_model_get_activated (service_key, &activated_model_option_h); + EXPECT_EQ (ML_ERROR_NONE, status); + EXPECT_NE (activated_model_option_h, nullptr); + + gchar *activated_model_path; + status = ml_option_get (activated_model_option_h, "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); + + 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); +} + /** * @brief Main gtest */