From 42f4aa96f8703332ee88f4a7f2c286ecf6242d64 Mon Sep 17 00:00:00 2001
From: Daniel Lyubomirov <daniel.lyubomirov@vereign.com>
Date: Mon, 29 Jun 2020 15:23:25 +0300
Subject: [PATCH] [17] update C flat api integration test

---
 cpp/include/vereign/vereign.h                 | 17 ++++---
 cpp/src/CMakeLists.txt                        | 12 ++---
 cpp/src/vereign/grpc/server.cc                | 16 +++----
 cpp/src/vereign/grpc/server.hh                |  3 +-
 cpp/src/vereign/restapi/client.cc             |  2 -
 cpp/src/vereign/restapi/client.hh             |  4 +-
 cpp/src/vereign/service/passport_service.cc   | 32 -------------
 cpp/src/vereign/service/passport_service.hh   | 45 -------------------
 cpp/src/vereign/vereign.cc                    |  7 +--
 cpp/tests/integration/CMakeLists.txt          | 16 ++++++-
 .../init_integration_test_storage.cc          | 34 ++++++++++++++
 cpp/tests/integration/integration_test.cc     | 42 ++++++++---------
 cpp/tests/util/env.hh                         | 13 ++----
 cpp/tests/vereign/grpc/server_test.cc         | 37 +++++++++++----
 cpp/tests/vereign/test/device.cc              | 36 +++++++++++++++
 cpp/tests/vereign/test/device.hh              | 14 +++---
 16 files changed, 173 insertions(+), 157 deletions(-)
 delete mode 100644 cpp/src/vereign/service/passport_service.cc
 delete mode 100644 cpp/src/vereign/service/passport_service.hh
 create mode 100644 cpp/tests/integration/init_integration_test_storage.cc

diff --git a/cpp/include/vereign/vereign.h b/cpp/include/vereign/vereign.h
index c450bd8..f77824c 100644
--- a/cpp/include/vereign/vereign.h
+++ b/cpp/include/vereign/vereign.h
@@ -1,5 +1,5 @@
-#ifndef VEREIGN_VEREIGN_H_
-#define VEREIGN_VEREIGN_H_
+#ifndef __VEREIGN_VEREIGN_H
+#define __VEREIGN_VEREIGN_H
 
 #ifdef _WIN32
   #ifdef WIN_EXPORT
@@ -84,8 +84,12 @@ typedef struct vereign_service vereign_service;
  * **NOTE: On failure the `err` object must be freed with vereign_error_free method.**
  *
  * @param listen_address gRPC listen address, for example "localhost:".
- * @param vereignHost Vereign restapi host.
- * @param vereignPort Vereign restapi port - https, 443...
+ * @param vereign_host Vereign restapi host.
+ * @param vereign_port Vereign restapi port - https, 443...
+ * @param storage_path Full path to directory where the storage files will stay.
+ *    If the `storage_path` is `nullptr`, a default will be used. Under linux this default is
+ *    `$HOME/vereign`, and under windows it is `C:\Users\<user>\AppData\Local\vereign`.
+ *
  * @param err On failure err is initialized with the reason of the failure,
  *    otherwise err is set to nullptr.
  * @returns vereign_service object if the gRPC is up and running, otherwise returns nullptr.
@@ -94,8 +98,7 @@ PUBLIC_API vereign_service* vereign_service_start(
   const char* listen_address,
   const char* vereign_host,
   const char* vereign_port,
-  // FIXME: public_key must come from a storage internally.
-  const char* public_key,
+  const char* storage_path,
   vereign_error** err
 );
 
@@ -122,4 +125,4 @@ PUBLIC_API void vereign_service_shutdown(vereign_service* service);
 };
 #endif
 
-#endif // VEREIGN_VEREIGN_H_
+#endif // __VEREIGN_VEREIGN_H
diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt
index 31f883c..1ad9784 100644
--- a/cpp/src/CMakeLists.txt
+++ b/cpp/src/CMakeLists.txt
@@ -56,7 +56,7 @@ set(VEREIGNLIB_SRC
   vereign/restapi/detail/http_reader.cc
   vereign/restapi/client.cc
 
-  # vereign/grpc/gen/gen.cc
+  vereign/grpc/gen/gen.cc
   vereign/grpc/json/encoder.cc
   vereign/grpc/service_registry.cc
   vereign/grpc/server.cc
@@ -83,13 +83,7 @@ set(VEREIGNLIB_SRC
 
   vereign/identity/provider.cc
 
-  vereign/service/gen/passport_service.cc
-  vereign/service/passport_service.cc
   vereign/service/identity_service.cc
-
-  # FIXME: remove this
-  vereign/service/gen/identity_service.cc
-  vereign/service/gen/passport_service.cc
 )
 
 
@@ -106,8 +100,8 @@ elseif (WIN32)
   )
 endif()
 
-# file(GLOB GENERATED_SERVICES_SRC vereign/service/gen/*.cc)
-# list(APPEND VEREIGNLIB_SRC ${GENERATED_SERVICES_SRC})
+file(GLOB GENERATED_SERVICES_SRC vereign/service/gen/*.cc)
+list(APPEND VEREIGNLIB_SRC ${GENERATED_SERVICES_SRC})
 
 add_library(vereignlib STATIC ${VEREIGNLIB_SRC})
 set_property(TARGET vereignlib PROPERTY POSITION_INDEPENDENT_CODE ON)
diff --git a/cpp/src/vereign/grpc/server.cc b/cpp/src/vereign/grpc/server.cc
index ac7566b..8a4b21a 100644
--- a/cpp/src/vereign/grpc/server.cc
+++ b/cpp/src/vereign/grpc/server.cc
@@ -10,8 +10,8 @@
 
 #include <vereign/restapi/client.hh>
 #include <vereign/restapi/client_session.hh>
-// #include <vereign/service/gen/gen.hh>
-// #include <vereign/grpc/gen/gen.hh>
+#include <vereign/service/gen/gen.hh>
+#include <vereign/grpc/gen/gen.hh>
 #include <vereign/grpc/service_registry.hh>
 
 // manually written api
@@ -35,15 +35,15 @@ namespace asio = boost::asio;
 class Server::Impl {
 public:
   Impl(
-    const std::string& listenAddress,
-    const std::string& vereignHost,
-    const std::string& vereignPort,
+    const std::string& listen_address,
+    const std::string& vereign_host,
+    const std::string& vereign_port,
     std::string storage_path
   ) : selected_port_{0},
     work_guard_{asio::make_work_guard(ioc_)},
     ssl_context_{asio::ssl::context::tlsv12_client},
     client_{std::make_unique<restapi::Client>(
-      ioc_, ssl_context_, vereignHost, vereignPort
+      ioc_, ssl_context_, vereign_host, vereign_port
     )},
     client_session_{std::make_unique<restapi::ClientSession>(*client_)},
     kvstorage_{nullptr},
@@ -66,7 +66,7 @@ public:
     // ssl_context.set_verify_mode(ssl::verify_peer);
     ::grpc::ServerBuilder builder;
     builder.AddListeningPort(
-      listenAddress,
+      listen_address,
       ::grpc::InsecureServerCredentials(),
       &selected_port_
     );
@@ -78,7 +78,7 @@ public:
     );
 
     // register all generated services
-    // grpc::gen::RegisterAll(*client_session_, services_registry_);
+    grpc::gen::RegisterAll(*client_session_, services_registry_);
 
     services_registry_.RegisterIntoBuilder(builder);
 
diff --git a/cpp/src/vereign/grpc/server.hh b/cpp/src/vereign/grpc/server.hh
index 16b65dc..ef3e890 100644
--- a/cpp/src/vereign/grpc/server.hh
+++ b/cpp/src/vereign/grpc/server.hh
@@ -34,7 +34,8 @@ public:
    * @param vereignHost Vereign restapi host.
    * @param vereignPort Vereign restapi port - https, 443...
    * @param storage_path Path to directory that will be used for the crypto storage.
-   *    If storage_path is empty string, a default is used - $HOME/vereign.
+   *    If storage_path is empty string, a default is used. Under linux this default is
+   *    `$HOME/vereign`, and under windows it is `C:\Users\<user>\AppData\Local\vereign`.
    *
    * @throws BindError when the gRPC server could not start listening.
    */
diff --git a/cpp/src/vereign/restapi/client.cc b/cpp/src/vereign/restapi/client.cc
index fe22698..e42834b 100644
--- a/cpp/src/vereign/restapi/client.cc
+++ b/cpp/src/vereign/restapi/client.cc
@@ -8,8 +8,6 @@
 #include <boost/beast/version.hpp>
 #include <boost/asio/dispatch.hpp>
 
-#include <chrono>
-
 namespace {
   constexpr std::string_view httpUserAgent = "Vereign Client Library";
 }
diff --git a/cpp/src/vereign/restapi/client.hh b/cpp/src/vereign/restapi/client.hh
index cc8fe0d..6fddf60 100644
--- a/cpp/src/vereign/restapi/client.hh
+++ b/cpp/src/vereign/restapi/client.hh
@@ -1,8 +1,6 @@
 #ifndef __VEREIGN_RESTAPI_CLIENT_HH
 #define __VEREIGN_RESTAPI_CLIENT_HH
 
-#include <chrono>
-#include <type_traits>
 #include <vereign/restapi/detail/post_task.hh>
 #include <vereign/restapi/http_header.hh>
 
@@ -16,6 +14,8 @@
 #include <string>
 #include <future>
 #include <deque>
+#include <chrono>
+#include <type_traits>
 
 namespace vereign {
 namespace restapi {
diff --git a/cpp/src/vereign/service/passport_service.cc b/cpp/src/vereign/service/passport_service.cc
deleted file mode 100644
index e6cf883..0000000
--- a/cpp/src/vereign/service/passport_service.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "vereign/service/gen/passport_service.hh"
-#include <vereign/service/passport_service.hh>
-#include <vereign/restapi/client_session.hh>
-
-namespace {
-  const std::string listPassportsPath = "listPassports";
-}
-
-namespace vereign {
-namespace service {
-
-PassportService::PassportService(restapi::ClientSession& client_session)
-  : gen::PassportService{client_session},
-    client_session_{client_session}
-{}
-
-
-std::future<PassportService::ListPassportsResult>
-PassportService::ListPassportsManually(
-    const client_library::ListPassportsForm* req,
-    client_library::ListPassportsFormResponse* resp
-) {
-  return client_session_.Post(
-    gen::PassportService::ServicePath + listPassportsPath,
-    req,
-    resp
-  );
-}
-
-
-} // namespace service
-} // namespace vereign
diff --git a/cpp/src/vereign/service/passport_service.hh b/cpp/src/vereign/service/passport_service.hh
deleted file mode 100644
index f59b4b2..0000000
--- a/cpp/src/vereign/service/passport_service.hh
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef __VEREIGN_SERVICE_PASSPORT_SERVICE_HH
-#define __VEREIGN_SERVICE_PASSPORT_SERVICE_HH
-
-#include <vereign/restapi/client_session.hh>
-#include <vereign/restapi/post_result.hh>
-#include <vereign/client_library/types.gen.pb.h>
-#include <vereign/service/gen/passport_service.hh>
-
-#include <future>
-
-namespace vereign {
-
-namespace restapi {
-  class ClientSession;
-}
-
-namespace service {
-
-template <class Request, class Response>
-using Result = restapi::PostResult<Request, Response>;
-
-class PassportService : public gen::PassportService {
-public:
-  explicit PassportService(restapi::ClientSession& client_session);
-
-  PassportService(const PassportService&) = delete;
-  PassportService& operator=(const PassportService&) = delete;
-
-  using ListPassportsResult = Result<
-    const client_library::ListPassportsForm*,
-    client_library::ListPassportsFormResponse*>;
-
-  std::future<ListPassportsResult> ListPassportsManually(
-    const client_library::ListPassportsForm* req,
-    client_library::ListPassportsFormResponse* resp
-  );
-
-private:
-  restapi::ClientSession& client_session_;
-};
-
-} // namespace service
-} // namespace vereign
-
-#endif // __VEREIGN_SERVICE_PASSPORT_SERVICE_HH
diff --git a/cpp/src/vereign/vereign.cc b/cpp/src/vereign/vereign.cc
index 5bbc7e9..6095a55 100644
--- a/cpp/src/vereign/vereign.cc
+++ b/cpp/src/vereign/vereign.cc
@@ -27,8 +27,7 @@ auto vereign_service_start(
   const char* listen_address,
   const char* vereign_host,
   const char* vereign_port,
-  // FIXME: public_key must come from a storage internally.
-  const char* public_key,
+  const char* storage_path,
   vereign_error** err
 ) -> vereign_service* {
   if (err != nullptr) {
@@ -42,7 +41,7 @@ auto vereign_service_start(
       listen_address,
       vereign_host,
       vereign_port,
-      public_key
+      storage_path != nullptr ? storage_path : ""
     );
 
     return new vereign_service{std::move(serviceImpl)};
@@ -59,7 +58,6 @@ auto vereign_service_start(
   return nullptr;
 }
 
-
 auto vereign_service_selected_port(vereign_service* service) -> int {
   return service->impl->SelectedPort();
 }
@@ -72,4 +70,3 @@ void vereign_service_shutdown(vereign_service* service) {
   service->impl->Shutdown();
   delete service;
 }
-
diff --git a/cpp/tests/integration/CMakeLists.txt b/cpp/tests/integration/CMakeLists.txt
index 9efb102..885f356 100644
--- a/cpp/tests/integration/CMakeLists.txt
+++ b/cpp/tests/integration/CMakeLists.txt
@@ -1,7 +1,6 @@
 include_directories(
   ${CMAKE_SOURCE_DIR}/src
   ${CMAKE_SOURCE_DIR}/include
-  # ${VENDOR_INSTALL_DIR}/include
   ${CMAKE_SOURCE_DIR}/proto/cpp
 )
 
@@ -24,3 +23,18 @@ add_test(
   NAME integration_test
   COMMAND integration_test
 )
+
+list(APPEND INIT_INTEGRATION_TEST_STORAGE_SRC
+  ../vereign/test/device.cc
+  ../vereign/test/service_context.cc
+
+  init_integration_test_storage.cc
+)
+
+add_executable(init_integration_test_storage ${INIT_INTEGRATION_TEST_STORAGE_SRC})
+
+target_link_libraries(init_integration_test_storage
+  vereignlib
+  Threads::Threads
+)
+
diff --git a/cpp/tests/integration/init_integration_test_storage.cc b/cpp/tests/integration/init_integration_test_storage.cc
new file mode 100644
index 0000000..32a3fe0
--- /dev/null
+++ b/cpp/tests/integration/init_integration_test_storage.cc
@@ -0,0 +1,34 @@
+#include <vereign/fs/util.hh>
+#include <vereign/fs/path.hh>
+#include <vereign/fs/operations.hh>
+#include <vereign/test/device.hh>
+#include <vereign/test/service_context.hh>
+#include <util/env.hh>
+
+using namespace vereign;
+
+/**
+ * The init_integration_test_storage tool is used for creating a new device with
+ * initialized storage at ${HOME}/vereign_integration_test dir.
+ *
+ * FIXME: create a command line utility for this and other commands like starting a gRPC
+ *        server for integration tests.
+ */
+auto main(int argc, char** argv) -> int {
+  boost::ignore_unused(argc);
+  boost::ignore_unused(argv);
+
+  auto public_key = test::RequireEnv("TEST_VEREIGN_PUB_KEY");
+  auto host = test::RequireEnv("TEST_VEREIGN_API_HOST");
+  auto port = test::GetEnv("TEST_VEREIGN_API_PORT", "https");
+  auto storage_path = test::GetEnv("TEST_VEREIGN_INTEGRATION_STORAGE", "");
+  auto pin = test::GetEnv("TEST_VEREIGN_PIN", "foo");
+
+  if (storage_path == "") {
+    storage_path = fs::path::Join(fs::HomePath(), "vereign_integration_test");
+  }
+
+  fs::CreateDirectory(storage_path);
+
+  test::PrepareNewDevice(host, port, public_key, pin, storage_path);
+}
diff --git a/cpp/tests/integration/integration_test.cc b/cpp/tests/integration/integration_test.cc
index ef42c72..e3db449 100644
--- a/cpp/tests/integration/integration_test.cc
+++ b/cpp/tests/integration/integration_test.cc
@@ -1,16 +1,20 @@
 #include <vereign/vereign.h>
-#include <util/env.hh>
+
 #include <vereign/client_library/types.gen.pb.h>
 #include <vereign/client_library/passport_api.gen.grpc.pb.h>
+#include <vereign/client_library/identity_api.gen.grpc.pb.h>
 #include <vereign/core/scope_guard.hh>
-#include <grpcpp/create_channel.h>
+#include <util/env.hh>
 
+#include <grpcpp/create_channel.h>
 #include <catch2/catch.hpp>
 
 TEST_CASE("C API integration", "[.integration]") {
-  auto publicKey = vereign::test::RequireEnv("TEST_VEREIGN_PUB_KEY");
+  // NOTE: use the init_integration_storage tool to create a new test storage
+  auto storage_path = vereign::test::RequireEnv("TEST_VEREIGN_INTEGRATION_STORAGE");
   auto host = vereign::test::RequireEnv("TEST_VEREIGN_API_HOST");
   auto port = vereign::test::GetEnv("TEST_VEREIGN_API_PORT", "https");
+  auto pin = vereign::test::GetEnv("TEST_VEREIGN_PIN", "foo");
 
   // start the service
   vereign_error* err = nullptr;
@@ -18,7 +22,7 @@ TEST_CASE("C API integration", "[.integration]") {
     "localhost:",
     host.data(),
     port.data(),
-    publicKey.data(),
+    storage_path.data(),
     &err
   );
   CHECK(service != nullptr);
@@ -35,28 +39,24 @@ TEST_CASE("C API integration", "[.integration]") {
     ::grpc::InsecureChannelCredentials()
   );
 
+  auto identity_client = vereign::client_library::IdentityAPI::NewStub(channel);
+  auto login_req = vereign::client_library::LoginFormPreviousAddedDevice{};
+  login_req.set_pin(pin);
+  auto login_resp = vereign::client_library::EmptyResponse{};
+  ::grpc::ClientContext login_ctx;
+  auto status = identity_client->LoginWithPreviouslyAddedDevice(&login_ctx, login_req, &login_resp);
+  REQUIRE(status.error_message() == "");
+  REQUIRE(status.ok() == true);
+  REQUIRE(login_resp.error() == "");
+  CHECK(login_resp.status() == "OK");
+  CHECK(login_resp.code() == "200");
+
   auto client = vereign::client_library::PassportAPI::NewStub(channel);
 
   vereign::client_library::ListPassportsForm req;
   vereign::client_library::ListPassportsFormResponse resp;
   ::grpc::ClientContext ctx;
-  auto status = client->ListPassports(&ctx, req, &resp);
-
-  // std::cout << vereign::test::ProtobufToJson(resp) << std::endl;
-
-  REQUIRE(status.error_message() == "");
-  REQUIRE(resp.error() == "");
-  CHECK(resp.status() == "OK");
-  CHECK(resp.code() == "200");
-  CHECK(resp.data().size() > 0);
-  for (auto& passport : resp.data()) {
-    CHECK(passport.uuid().size() == 36);
-  }
-
-  req.Clear();
-  resp.Clear();
-  ::grpc::ClientContext manually_ctx;
-  status = client->ListPassportsManually(&manually_ctx, req, &resp);
+  status = client->ListPassports(&ctx, req, &resp);
 
   // std::cout << vereign::test::ProtobufToJson(resp) << std::endl;
 
diff --git a/cpp/tests/util/env.hh b/cpp/tests/util/env.hh
index cb01a8c..d32fd97 100644
--- a/cpp/tests/util/env.hh
+++ b/cpp/tests/util/env.hh
@@ -2,24 +2,20 @@
 #define __VEREIGN_TEST_UTIL_ENV_HH
 
 #include <string>
-
-#include <catch2/catch.hpp>
 #include <fmt/core.h>
 
-namespace vereign {
-namespace test {
+namespace vereign::test {
 
-inline std::string RequireEnv(const std::string& name) {
+inline auto RequireEnv(const std::string& name) -> std::string {
   auto var = std::getenv(name.c_str());
   if (var == nullptr) {
-    FAIL(fmt::format("{} env variable is required", name));
-    return "";
+    throw std::runtime_error{fmt::format("{} env variable is required", name)};
   }
 
   return var;
 }
 
-inline std::string GetEnv(const std::string& name, const std::string& default_) {
+inline auto GetEnv(const std::string& name, const std::string& default_) -> std::string {
   auto var = std::getenv(name.c_str());
   if (var == nullptr) {
     return default_;
@@ -28,7 +24,6 @@ inline std::string GetEnv(const std::string& name, const std::string& default_)
   return var;
 }
 
-} // namespace vereign
 } // namespace test
 
 #endif // __VEREIGN_TEST_UTIL_ENV_HH
diff --git a/cpp/tests/vereign/grpc/server_test.cc b/cpp/tests/vereign/grpc/server_test.cc
index 29f7f07..f6b5c38 100644
--- a/cpp/tests/vereign/grpc/server_test.cc
+++ b/cpp/tests/vereign/grpc/server_test.cc
@@ -3,7 +3,12 @@
 #include <vereign/core/scope_guard.hh>
 #include <vereign/client_library/passport_api.gen.grpc.pb.h>
 #include <vereign/client_library/types.gen.pb.h>
+#include <vereign/client_library/identity_api.gen.grpc.pb.h>
+#include <vereign/service/identity_service.hh>
 #include <vereign/fs/util.hh>
+#include <vereign/fs/path.hh>
+#include <vereign/test/device.hh>
+#include <vereign/test/service_context.hh>
 
 #include <util/env.hh>
 #include <util/protobuf.hh>
@@ -11,13 +16,14 @@
 
 #include <catch2/catch.hpp>
 
-TEST_CASE("grpc::Server", "[vereign/grpc/server][.integration]") {
-  auto publicKey = vereign::test::RequireEnv("TEST_VEREIGN_PUB_KEY");
-  auto host = vereign::test::RequireEnv("TEST_VEREIGN_API_HOST");
-  auto port = vereign::test::GetEnv("TEST_VEREIGN_API_PORT", "https");
+using namespace vereign;
 
-  auto storage_path = vereign::fs::TempDir("server_test_");
-  auto storage_rm = vereign::fs::RemoveAllGuard(storage_path);
+TEST_CASE("grpc::Server", "[vereign/grpc/server][.integration]") {
+  // NOTE: use the init_integration_storage tool to create a new test storage
+  auto storage_path = vereign::test::RequireEnv("TEST_VEREIGN_INTEGRATION_STORAGE");
+  auto host = test::RequireEnv("TEST_VEREIGN_API_HOST");
+  auto port = test::GetEnv("TEST_VEREIGN_API_PORT", "https");
+  auto pin = vereign::test::GetEnv("TEST_VEREIGN_PIN", "foo");
 
   vereign::grpc::Server server{"localhost:", host, port, storage_path};
   auto on_exit = vereign::core::MakeScopeGuard([&server] {
@@ -29,12 +35,25 @@ TEST_CASE("grpc::Server", "[vereign/grpc/server][.integration]") {
     ::grpc::InsecureChannelCredentials()
   );
 
-  auto client = vereign::client_library::PassportAPI::NewStub(channel);
+  // register new device
+  auto identity_client = vereign::client_library::IdentityAPI::NewStub(channel);
+  auto login_req = vereign::client_library::LoginFormPreviousAddedDevice{};
+  auto login_resp = vereign::client_library::EmptyResponse{};
+  login_req.set_pin(pin);
+
+  ::grpc::ClientContext login_ctx;
+  identity_client->LoginWithPreviouslyAddedDevice(&login_ctx, login_req, &login_resp);
+
+  CHECK(login_resp.error() == "");
+  CHECK(login_resp.status() == "OK");
+  REQUIRE(login_resp.code() == "200");
+
+  auto passport_client = vereign::client_library::PassportAPI::NewStub(channel);
 
   vereign::client_library::ListPassportsForm req;
   vereign::client_library::ListPassportsFormResponse resp;
   ::grpc::ClientContext ctx;
-  auto status = client->ListPassports(&ctx, req, &resp);
+  auto status = passport_client->ListPassports(&ctx, req, &resp);
 
   // std::cout << vereign::test::ProtobufToJson(resp) << std::endl;
 
@@ -52,7 +71,7 @@ TEST_CASE("grpc::Server", "[vereign/grpc/server][.integration]") {
   getInterReq.set_uuid(resp.data().at(0).uuid());
   vereign::client_library::GetInteractionsFormResponse getInterResp;
   ::grpc::ClientContext getInterCtx;
-  status = client->GetInteractions(&getInterCtx, getInterReq, &getInterResp);
+  status = passport_client->GetInteractions(&getInterCtx, getInterReq, &getInterResp);
   CHECK(status.error_message() == "");
   CHECK(getInterResp.error() == "");
   CHECK(getInterResp.status() == "OK");
diff --git a/cpp/tests/vereign/test/device.cc b/cpp/tests/vereign/test/device.cc
index 15329a5..bc47ef4 100644
--- a/cpp/tests/vereign/test/device.cc
+++ b/cpp/tests/vereign/test/device.cc
@@ -3,6 +3,7 @@
 #include <vereign/client_library/common_types.pb.h>
 #include <vereign/client_library/types.gen.pb.h>
 #include <vereign/fs/util.hh>
+#include <vereign/fs/path.hh>
 #include <vereign/test/service_context.hh>
 #include <vereign/restapi/client_session.hh>
 #include <vereign/service/identity_service.hh>
@@ -104,4 +105,39 @@ void Device::CreateNewDevice(ServiceContext& service_context, const std::string&
   AuthorizeDevice(service_context.IdentityProvider().GetDeviceHash());
 }
 
+void PrepareNewDevice(
+  const std::string& host,
+  const std::string& port,
+  const std::string& public_key,
+  const std::string& pin,
+  const std::string& storage_path
+) {
+  // the old device is used later for new device confirmation and authorization
+  auto old_storage_path = fs::TempFilePath("test_db_");
+  auto rm_old_storage_path = fs::RemoveFileGuard{old_storage_path};
+  auto old_device_ctx = test::ServiceContext{host, port, old_storage_path};
+  auto old_device = test::Device{old_device_ctx};
+  old_device.Login(public_key);
+
+  auto service_context = test::ServiceContext{host, port, fs::path::Join(storage_path, "db")};
+  auto identity_service = service::IdentityService{
+    service_context.ClientSession(),
+    service_context.IdentityProvider()
+  };
+
+  // register new device
+  auto register_req = std::make_unique<vereign::client_library::LoginFormNewDevice>();
+  auto register_resp = std::make_unique<vereign::client_library::LoginFormNewDeviceResponse>();
+  register_req->set_pin(pin);
+
+  identity_service.LoginWithNewDevice(register_req.get(), register_resp.get());
+  if (register_resp->code() != "200") {
+    throw std::runtime_error("register new device failed with: " + register_resp->error());
+  }
+
+  // confirm and authorize the new device using an old device
+  old_device.ConfirmNewDevice(register_resp->data().qrcode(), register_resp->data().actionid());
+  old_device.AuthorizeDevice(service_context.IdentityProvider().GetDeviceHash());
+}
+
 } // namespace vereign::test
diff --git a/cpp/tests/vereign/test/device.hh b/cpp/tests/vereign/test/device.hh
index 34440c9..be09ce1 100644
--- a/cpp/tests/vereign/test/device.hh
+++ b/cpp/tests/vereign/test/device.hh
@@ -1,13 +1,7 @@
 #ifndef __TESTS_VEREIGN_TEST_DEVICE_HH
 #define __TESTS_VEREIGN_TEST_DEVICE_HH
 
-#include <boost/asio/io_context.hpp>
-#include <boost/asio/ssl/context.hpp>
-#include <boost/asio/executor_work_guard.hpp>
-#include <boost/filesystem/path.hpp>
-
 #include <memory>
-#include <thread>
 
 namespace vereign::service {
 class IdentityService;
@@ -35,6 +29,14 @@ private:
   std::unique_ptr<service::IdentityService> identity_service_;
 };
 
+void PrepareNewDevice(
+  const std::string& host,
+  const std::string& port,
+  const std::string& public_key,
+  const std::string& pin,
+  const std::string& storage_path
+);
+
 } // namespace vereign::test
 
 #endif // __TESTS_VEREIGN_TEST_DEVICE_HH
-- 
GitLab