[Services] Remote model register
authorgichan2-jang <gichan2.jang@samsung.com>
Fri, 30 Jun 2023 08:04:22 +0000 (17:04 +0900)
committerjaeyun-jung <39614140+jaeyun-jung@users.noreply.github.com>
Tue, 12 Sep 2023 02:53:57 +0000 (11:53 +0900)
 - Impelent registering model relotely
 - Add unit test

Signed-off-by: gichan2-jang <gichan2.jang@samsung.com>
c/src/meson.build
c/src/ml-api-remote-service.c
c/src/ml-api-service-common.c
c/src/ml-api-service-private.h
meson.build
packaging/machine-learning-api.spec
tests/capi/unittest_capi_remote_service.cc

index d53759d..ef7e9cb 100644 (file)
@@ -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',
index 0c4227e..7285c37 100644 (file)
@@ -15,6 +15,7 @@
 #include <gst/gstbuffer.h>
 #include <gst/app/app.h>
 #include <string.h>
+#include <curl/curl.h>
 
 #include "ml-api-internal.h"
 #include "ml-api-service.h"
@@ -154,12 +155,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);
@@ -168,6 +169,123 @@ _mlrs_get_service_type (gchar * service_str)
 }
 
 /**
+ * @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
  */
 static int
@@ -199,20 +317,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_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_URL:
-      /** @todo Download the pipeline description from given URL */
+    }
     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;
@@ -366,6 +514,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);
@@ -413,11 +564,18 @@ 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) {
     _ml_error_report ("Failed to add camera data to the edge data.\n");
     nns_edge_data_destroy (data_h);
+    return ret;
   }
 
   ret = nns_edge_send (remote_s->edge_h, data_h);
index f5f27c2..6fa8057 100644 (file)
@@ -69,6 +69,8 @@ ml_service_destroy (ml_service_h h)
   } else if (ML_SERVICE_TYPE_REMOTE == mls->type) {
     _ml_remote_service_s *mlrs = (_ml_remote_service_s *) mls->priv;
     nns_edge_release_handle (mlrs->edge_h);
+    /** Wait some time until release the edge handle. */
+    g_usleep (1000000);
     g_free (mlrs);
   } else {
     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
index c7395ce..20b8041 100644 (file)
@@ -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;
index 9474cde..de8d80f 100644 (file)
@@ -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')
index 8f8ffae..4a08887 100644 (file)
@@ -162,6 +162,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}
@@ -397,7 +398,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
@@ -407,6 +407,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}
index 8098a23..67cd232 100644 (file)
@@ -10,6 +10,7 @@
 #include <gtest/gtest.h>
 #include <gdbus-util.h>
 #include <gio/gio.h>
+#include <glib/gstdio.h>
 #include <ml-api-inference-pipeline-internal.h>
 #include <ml-api-internal.h>
 #include <ml-api-service-private.h>
@@ -104,12 +105,12 @@ TEST_F (MLRemoteService, registerPipeline)
   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);
+  gchar *client_host = g_strdup ("127.0.0.1");
+  status = ml_option_set (client_option_h, "host", client_host, g_free);
   EXPECT_EQ (ML_ERROR_NONE, status);
 
-  guint dest_port = 3000;
-  status = ml_option_set (client_option_h, "port", &dest_port, NULL);
+  guint port = _get_available_port ();
+  status = ml_option_set (client_option_h, "port", &port, NULL);
   EXPECT_EQ (ML_ERROR_NONE, status);
 
   gchar *client_connect_type = g_strdup ("TCP");
@@ -139,7 +140,7 @@ TEST_F (MLRemoteService, registerPipeline)
   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);
+  status = ml_option_set (server_option_h, "dest-port", &port, NULL);
   EXPECT_EQ (ML_ERROR_NONE, status);
 
   gchar *server_connect_type = g_strdup ("TCP");
@@ -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_host = g_strdup ("127.0.0.1");
+  status = ml_option_set (client_option_h, "host", client_host, g_free);
+  EXPECT_EQ (ML_ERROR_NONE, status);
+
+  guint port = _get_available_port ();
+  status = ml_option_set (client_option_h, "port", &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", &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.
  */
@@ -226,44 +340,340 @@ TEST_F (MLRemoteService, registerInvalidParam_n)
   status = ml_option_set (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 (option_h, "dest-host", client_dest_host, g_free);
+  gchar *client_host = g_strdup ("127.0.0.1");
+  status = ml_option_set (option_h, "host", client_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 port = _get_available_port ();
+  status = ml_option_set (option_h, "port", &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);
+  status = ml_remote_service_create (option_h, &service_h);
+  EXPECT_EQ (ML_ERROR_NONE, status);
+
+  status = ml_option_destroy (option_h);
   EXPECT_EQ (ML_ERROR_NONE, status);
 
-  status = ml_remote_service_create (option_h, &service_h);
+  ml_option_h remote_service_option_h = NULL;
+  status = ml_option_create (&remote_service_option_h);
   EXPECT_EQ (ML_ERROR_NONE, status);
 
-  status = ml_remote_service_register (NULL, option_h, str, len);
+  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);
+
+  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);
+  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_host = g_strdup ("127.0.0.1");
+  status = ml_option_set (client_option_h, "host", client_host, g_free);
+  EXPECT_EQ (ML_ERROR_NONE, status);
+
+  guint port = _get_available_port ();
+  status = ml_option_set (client_option_h, "port", &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", &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_host = g_strdup ("127.0.0.1");
+  status = ml_option_set (client_option_h, "host", client_host, g_free);
+  EXPECT_EQ (ML_ERROR_NONE, status);
+
+  guint port = _get_available_port ();
+  status = ml_option_set (client_option_h, "port", &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", &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
  */