Refactor app com API 79/280179/1
authorHwankyu Jhun <h.jhun@samsung.com>
Thu, 25 Aug 2022 04:01:49 +0000 (04:01 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Thu, 25 Aug 2022 04:01:49 +0000 (04:01 +0000)
To refactor app com API, unit tests are added.
The app com API is refactored using the AppRequest class.

Change-Id: Ieeafb5f9aeb461dfc38ca06decc943a2c01ce9dc
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/app_com.cc
test/unit_tests/test_app_com.cc [new file with mode: 0644]

index e1e2645..6b78bf7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 - 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ * Copyright (c) 2015 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "include/aul_app_com.h"
+
 #include <bundle_cpp.h>
 #include <bundle_internal.h>
 
 #include <mutex>
 #include <string>
 
+#include "app_request.h"
 #include "aul_api.h"
 #include "aul_util.h"
 #include "include/aul.h"
-#include "include/aul_app_com.h"
 #include "include/aul_cmd.h"
 #include "launch.h"
 
+using namespace aul::internal;
+
 namespace {
 
 class AppComConnection {
@@ -179,6 +183,45 @@ class Context {
 
 Context context;
 
+int AppComCreate(const char* endpoint,
+    aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
+    bool sync, aul_app_com_connection_h* connection) {
+  if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
+    _E("Invalid parameter");
+    return AUL_R_EINVAL;
+  }
+
+  if (!aul_is_initialized()) {
+    if (aul_launch_init(nullptr, nullptr) < 0)
+      return AUL_R_ENOINIT;
+  }
+
+  tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
+  if (permission) {
+    auto* handle = static_cast<AppComPermission*>(permission);
+    auto option = handle->GetPropagationOption();
+    if (option) {
+      auto* p = reinterpret_cast<unsigned char*>(&option);
+      std::vector<unsigned char> bytes;
+      std::copy(p, p + sizeof(option), std::back_inserter(bytes));
+      b.Add(AUL_K_COM_PROPAGATE, bytes);
+    }
+
+    if (!handle->GetPrivilege().empty())
+      b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
+  }
+
+  int ret = AppRequest(APP_COM_CREATE, getuid())
+      .With(std::move(b))
+      .SendSimply(sync ? AUL_SOCK_NONE : AUL_SOCK_NOREPLY);
+  if (ret == 0) {
+    *connection = static_cast<aul_app_com_connection_h>(
+        context.AddConnection(endpoint, callback, user_data));
+  }
+
+  return ret;
+}
+
 }  // namespace
 
 int app_com_recv(bundle* b) {
@@ -223,52 +266,6 @@ extern "C" API int aul_app_com_permission_set_privilege(
   return AUL_R_OK;
 }
 
-static int AppComCreate(const char* endpoint,
-    aul_app_com_permission_h permission, app_com_cb callback, void* user_data,
-    bool sync, aul_app_com_connection_h* connection) {
-  if (endpoint == nullptr || callback == nullptr || connection == nullptr) {
-    _E("Invalid parameter");
-    return AUL_R_EINVAL;
-  }
-
-  if (!aul_is_initialized()) {
-    if (aul_launch_init(nullptr, nullptr) < 0)
-      return AUL_R_ENOINIT;
-  }
-
-  tizen_base::Bundle b;
-  b.Add(AUL_K_COM_ENDPOINT, endpoint);
-
-  if (permission) {
-    auto* handle = static_cast<AppComPermission*>(permission);
-    auto option = handle->GetPropagationOption();
-    if (option) {
-      auto* p = reinterpret_cast<unsigned char*>(&option);
-      std::vector<unsigned char> bytes;
-      std::copy(p, p + sizeof(option), std::back_inserter(bytes));
-      b.Add(AUL_K_COM_PROPAGATE, bytes);
-    }
-
-    if (!handle->GetPrivilege().empty())
-      b.Add(AUL_K_COM_PRIVILEGE, handle->GetPrivilege());
-  }
-
-  int ret;
-  if (sync) {
-    ret = app_send_cmd(AUL_UTIL_PID, APP_COM_CREATE, b.GetHandle());
-  } else {
-    ret = app_send_cmd_with_noreply(AUL_UTIL_PID, APP_COM_CREATE,
-        b.GetHandle());
-  }
-
-  if (ret == 0) {
-    *connection = static_cast<aul_app_com_connection_h>(
-        context.AddConnection(endpoint, callback, user_data));
-  }
-
-  return ret;
-}
-
 extern "C" API int aul_app_com_create(const char* endpoint,
     aul_app_com_permission_h permission, app_com_cb callback,
     void* user_data, aul_app_com_connection_h* connection) {
@@ -296,12 +293,13 @@ extern "C" API int aul_app_com_join(const char* endpoint, const char* filter,
       return AUL_R_ENOINIT;
   }
 
-  tizen_base::Bundle b;
-  b.Add(AUL_K_COM_ENDPOINT, endpoint);
+  tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
   if (filter)
     b.Add(AUL_K_COM_FILTER, filter);
 
-  int ret = app_send_cmd(AUL_UTIL_PID, APP_COM_JOIN, b.GetHandle());
+  int ret = AppRequest(APP_COM_JOIN, getuid())
+      .With(std::move(b))
+      .SendSimply();
   if (ret == 0) {
     *connection = static_cast<aul_app_com_connection_h>(
         context.AddConnection(endpoint, callback, user_data));
@@ -314,9 +312,25 @@ extern "C" API int aul_app_com_send(const char* endpoint, bundle* envelope) {
   if (endpoint == nullptr || envelope == nullptr)
     return AUL_R_EINVAL;
 
-  bundle_del(envelope, AUL_K_COM_ENDPOINT);
-  bundle_add(envelope, AUL_K_COM_ENDPOINT, endpoint);
-  return app_send_cmd(AUL_UTIL_PID, APP_COM_SEND, envelope);
+  std::string com_endpoint;
+  tizen_base::Bundle b(envelope, false, false);
+  bundle_type type = b.GetType(AUL_K_COM_ENDPOINT);
+  if (type != BUNDLE_TYPE_NONE) {
+    com_endpoint = b.GetString(AUL_K_COM_ENDPOINT);
+    b.Delete(AUL_K_COM_ENDPOINT);
+  }
+
+  b.Add(AUL_K_COM_ENDPOINT, endpoint);
+
+  int ret = AppRequest(APP_COM_SEND, getuid())
+      .With(std::move(b))
+      .SendSimply();
+  if (type != BUNDLE_TYPE_NONE) {
+    b.Delete(AUL_K_COM_ENDPOINT);
+    b.Add(AUL_K_COM_ENDPOINT, com_endpoint);
+  }
+
+  return ret;
 }
 
 extern "C" API int aul_app_com_leave(aul_app_com_connection_h connection) {
@@ -331,17 +345,25 @@ extern "C" API int aul_app_com_leave(aul_app_com_connection_h connection) {
 
   std::lock_guard<std::recursive_mutex> lock(context.GetMutex());
   conn->Disable();
-  std::string endpoint = conn->GetEndpoint();
+
   g_idle_add_full(G_PRIORITY_HIGH, [](gpointer user_data) -> gboolean {
         auto* conn = static_cast<AppComConnection*>(user_data);
+        std::lock_guard<std::recursive_mutex> lock(context.GetMutex());
+        std::string endpoint = conn->GetEndpoint();
         context.RemoveConnection(conn);
+
+        if (context.ExistConnection(endpoint))
+          return G_SOURCE_REMOVE;
+
+        tizen_base::Bundle b { { AUL_K_COM_ENDPOINT, endpoint } };
+        int ret = AppRequest(APP_COM_LEAVE, getuid())
+            .With(std::move(b))
+            .SendSimply();
+        if (ret != 0)
+          _E("Failed to send leave request. error(%d)", ret);
+
         return G_SOURCE_REMOVE;
       }, connection, nullptr);
 
-  if (context.ExistConnection(endpoint))
-    return AUL_R_OK;
-
-  tizen_base::Bundle b;
-  b.Add(AUL_K_COM_ENDPOINT, endpoint);
-  return app_send_cmd(AUL_UTIL_PID, APP_COM_LEAVE, b.GetHandle());
+  return AUL_R_OK;
 }
diff --git a/test/unit_tests/test_app_com.cc b/test/unit_tests/test_app_com.cc
new file mode 100644 (file)
index 0000000..bcd55dc
--- /dev/null
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aul.h>
+#include <aul_app_com.h>
+#include <aul_cmd.h>
+#include <aul_sock.h>
+#include <gtest/gtest.h>
+
+#include <bundle_cpp.h>
+
+#include <memory>
+
+#include "mock/mock_hook.h"
+#include "mock/socket_mock.h"
+#include "mock/test_fixture.h"
+#include "src/launch.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::Invoke;
+
+namespace {
+
+constexpr const char kPrivilegeAppmanagerLaunch[] =
+    "http://tizen.org/privilege/appmanager.launch";
+
+class Mocks : virtual public ::testing::NiceMock<SocketMock> {};
+
+int AppComCb(const char* endpoint, aul_app_com_result_e result,
+    bundle* envelope, void* user_data) {
+  return 0;
+}
+
+}  // namespace
+
+class AppComTest : public TestFixture {
+ public:
+  AppComTest() : TestFixture(std::make_unique<::Mocks>()) {}
+
+  virtual void SetUp() {
+    loop_ = g_main_loop_new(nullptr, FALSE);
+    permission_ = aul_app_com_permission_create();
+  }
+
+  virtual void TearDown() {
+    if (permission_ != nullptr) {
+      aul_app_com_permission_destroy(permission_);
+      permission_ = nullptr;
+    }
+
+    if (loop_ != nullptr) {
+      g_main_loop_unref(loop_);
+      loop_ = nullptr;
+    }
+  }
+
+  void RunMainLoop() {
+    g_main_loop_run(loop_);
+  }
+
+  void QuitMainLoop() {
+    g_main_loop_quit(loop_);
+  }
+
+  std::shared_ptr<app_pkt_t> MakePacket(tizen_base::Bundle b) {
+    auto raw = b.ToRaw();
+    app_pkt_t* pkt =
+        static_cast<app_pkt_t*>(calloc(1, sizeof(app_pkt_t) + raw.second));
+    if (pkt == nullptr)
+      return nullptr;
+
+    pkt->opt = AUL_SOCK_BUNDLE;
+    pkt->cmd = AUL_R_OK;
+    pkt->len = raw.second;
+    memcpy(pkt->data, raw.first.get(), raw.second);
+
+    return std::shared_ptr<app_pkt_t>(pkt, free);
+  }
+
+  std::shared_ptr<app_pkt_t> MakePacket(std::string str) {
+    app_pkt_t* pkt = static_cast<app_pkt_t*>(
+        calloc(1, sizeof(app_pkt_t) + str.length() + 1));
+    if (pkt == nullptr)
+      return nullptr;
+
+    pkt->opt = AUL_SOCK_NONE;
+    pkt->cmd = APP_GET_INFO_OK;
+    pkt->len = str.length() + 1;
+    memcpy(pkt->data, str.c_str(), str.length());
+
+    return std::shared_ptr<app_pkt_t>(pkt, free);
+  }
+
+  bool touched_ = false;
+  aul_app_com_permission_h permission_ = nullptr;
+
+ private:
+  GMainLoop* loop_ = nullptr;
+};
+
+TEST_F(AppComTest, aul_app_com_permission_create_P) {
+  auto permission = aul_app_com_permission_create();
+  EXPECT_NE(permission, nullptr);
+
+  aul_app_com_permission_destroy(permission);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_destroy_P) {
+  aul_app_com_permission_destroy(permission_);
+  permission_ = nullptr;
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_propagation_P) {
+  int ret = aul_app_com_permission_set_propagation(permission_,
+      AUL_APP_COM_PUBLIC);
+  EXPECT_EQ(ret, AUL_R_OK);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_propagation_N) {
+  int ret = aul_app_com_permission_set_propagation(nullptr, AUL_APP_COM_PUBLIC);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_privilage_P) {
+  int ret = aul_app_com_permission_set_privilege(permission_,
+      kPrivilegeAppmanagerLaunch);
+  EXPECT_EQ(ret, AUL_R_OK);
+}
+
+TEST_F(AppComTest, aul_app_com_permission_set_privilege_N) {
+  int ret = aul_app_com_permission_set_privilege(nullptr,
+      kPrivilegeAppmanagerLaunch);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  ret = aul_app_com_permission_set_privilege(permission_, nullptr);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_create_P) {
+  int cmd = -1;
+  int opt = -1;
+  bundle* kb = nullptr;
+
+  ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+      .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = pkt->cmd;
+        opt = pkt->opt;
+
+        if (cmd == APP_COM_CREATE)
+          kb = bundle_decode(pkt->data, pkt->len);
+
+        if (cmd == APP_COM_LEAVE)
+          QuitMainLoop();
+
+        return n;
+      }));
+  ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+      .WillByDefault(
+          Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+        int ret = 0;
+        memcpy(buf, &ret, sizeof(int));
+        return sizeof(int);
+      }));
+
+  aul_app_com_connection_h connection = nullptr;
+  int ret = aul_app_com_create("app_com_create", nullptr, AppComCb, this,
+      &connection);
+  EXPECT_NE(kb, nullptr);
+  tizen_base::Bundle b(kb, false, true);
+
+  EXPECT_NE(connection, nullptr);
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_COM_CREATE);
+  EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+  EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_create");
+
+  aul_app_com_leave(connection);
+  RunMainLoop();
+}
+
+TEST_F(AppComTest, aul_app_com_create_N) {
+  int ret = aul_app_com_create("app_com_create_N", nullptr, AppComCb, this,
+      nullptr);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  aul_app_com_connection_h connection = nullptr;
+  ret = aul_app_com_create("app_com_create_N", nullptr, nullptr, this,
+      &connection);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  ret = aul_app_com_create(nullptr, nullptr, AppComCb, this, &connection);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_create_async_P) {
+  int cmd = -1;
+  int opt = -1;
+  bundle* kb = nullptr;
+
+  ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+      .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = pkt->cmd;
+        opt = pkt->opt;
+
+        if (cmd == APP_COM_CREATE)
+          kb = bundle_decode(pkt->data, pkt->len);
+
+        if (cmd == APP_COM_LEAVE)
+          QuitMainLoop();
+
+        return n;
+      }));
+  ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+      .WillByDefault(
+          Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+        int ret = 0;
+        memcpy(buf, &ret, sizeof(int));
+        return sizeof(int);
+      }));
+
+  aul_app_com_connection_h connection = nullptr;
+  int ret = aul_app_com_create_async("app_com_create_async", nullptr, AppComCb,
+      this, &connection);
+  EXPECT_NE(kb, nullptr);
+  tizen_base::Bundle b(kb, false, true);
+
+  EXPECT_NE(connection, nullptr);
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_COM_CREATE);
+  EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NOREPLY));
+  EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_create_async");
+
+  aul_app_com_leave(connection);
+  RunMainLoop();
+}
+
+TEST_F(AppComTest, aul_app_com_create_async_N) {
+  int ret = aul_app_com_create_async("app_com_create_async_N", nullptr,
+      AppComCb, this, nullptr);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  aul_app_com_connection_h connection = nullptr;
+  ret = aul_app_com_create_async("app_com_create_async_N", nullptr, nullptr,
+      this, &connection);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  ret = aul_app_com_create_async(nullptr, nullptr, AppComCb, this, &connection);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_join_P) {
+  int cmd = -1;
+  int opt = -1;
+  bundle* kb = nullptr;
+
+  ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+      .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = pkt->cmd;
+        opt = pkt->opt;
+
+        if (cmd == APP_COM_JOIN)
+          kb = bundle_decode(pkt->data, pkt->len);
+
+        if (cmd == APP_COM_LEAVE)
+          QuitMainLoop();
+
+        return n;
+      }));
+  ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+      .WillByDefault(
+          Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+        int ret = 0;
+        memcpy(buf, &ret, sizeof(int));
+        return sizeof(int);
+      }));
+
+  aul_app_com_connection_h connection = nullptr;
+  int ret = aul_app_com_join("app_com_join", nullptr, AppComCb,
+      this, &connection);
+  EXPECT_NE(kb, nullptr);
+  tizen_base::Bundle b(kb, false, true);
+
+  EXPECT_NE(connection, nullptr);
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_COM_JOIN);
+  EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+  EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_join");
+
+  aul_app_com_leave(connection);
+  RunMainLoop();
+}
+
+TEST_F(AppComTest, aul_app_com_join_N) {
+  int ret = aul_app_com_join("app_com_join_N", nullptr, AppComCb, this,
+      nullptr);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  aul_app_com_connection_h connection = nullptr;
+  ret = aul_app_com_join("app_com_join_N", nullptr, nullptr, this, &connection);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  ret = aul_app_com_join(nullptr, nullptr, AppComCb, this, &connection);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_send_P) {
+  int cmd = -1;
+  int opt = -1;
+  bundle* kb = nullptr;
+
+  ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+      .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = pkt->cmd;
+        opt = pkt->opt;
+        kb = bundle_decode(pkt->data, pkt->len);
+        return n;
+      }));
+  ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+      .WillByDefault(
+          Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+        int ret = 0;
+        memcpy(buf, &ret, sizeof(int));
+        return sizeof(int);
+      }));
+
+  tizen_base::Bundle envelope { { "Key", "Value" } };
+  int ret = aul_app_com_send("app_com_send", envelope.GetHandle());
+  EXPECT_NE(kb, nullptr);
+  tizen_base::Bundle b(kb, false, true);
+
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_COM_SEND);
+  EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+  EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_send");
+  EXPECT_EQ(b.GetString("Key"), "Value");
+}
+
+TEST_F(AppComTest, aul_app_com_send_N) {
+  int ret = aul_app_com_send("app_com_send_N", nullptr);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+
+  tizen_base::Bundle envelope;
+  ret = aul_app_com_send(nullptr, envelope.GetHandle());
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+}
+
+TEST_F(AppComTest, aul_app_com_leave_P) {
+  int cmd = -1;
+  int opt = -1;
+  bundle* kb = nullptr;
+
+  ON_CALL(GetMock<SocketMock>(), send(_, _, _, _))
+      .WillByDefault(Invoke([&](int fd, const void* buf, size_t n, int flags)
+          -> ssize_t {
+        const app_pkt_t* pkt = reinterpret_cast<const app_pkt_t*>(buf);
+        cmd = pkt->cmd;
+        opt = pkt->opt;
+
+        if (cmd == APP_COM_LEAVE) {
+          kb = bundle_decode(pkt->data, pkt->len);
+          QuitMainLoop();
+        }
+
+        return n;
+      }));
+  ON_CALL(GetMock<SocketMock>(), recv(_, _, _, _))
+      .WillByDefault(
+          Invoke([](int fd, void* buf, size_t n, int flags) -> ssize_t {
+        int ret = 0;
+        memcpy(buf, &ret, sizeof(int));
+        return sizeof(int);
+      }));
+
+  aul_app_com_connection_h connection = nullptr;
+  int ret = aul_app_com_join("app_com_leave", nullptr, AppComCb,
+      this, &connection);
+  EXPECT_EQ(ret, AUL_R_OK);
+
+  ret = aul_app_com_leave(connection);
+  RunMainLoop();
+
+  EXPECT_NE(kb, nullptr);
+  tizen_base::Bundle b(kb, false, true);
+
+  EXPECT_NE(connection, nullptr);
+  EXPECT_EQ(ret, AUL_R_OK);
+  EXPECT_EQ(cmd, APP_COM_LEAVE);
+  EXPECT_EQ(opt, (AUL_SOCK_BUNDLE | AUL_SOCK_NONE));
+  EXPECT_EQ(b.GetString(AUL_K_COM_ENDPOINT), "app_com_leave");
+}
+
+TEST_F(AppComTest, aul_app_com_leave_N) {
+  int ret = aul_app_com_leave(nullptr);
+  EXPECT_EQ(ret, AUL_R_EINVAL);
+}