浏览代码

Merge branch 'cleanup-daemon-con_handler' of git.rwth-aachen.de:tobias.wach/ccats into cleanup-cli

Missingmew 5 年之前
父节点
当前提交
103af4e4b7

+ 0 - 35
README.md

@@ -2,38 +2,3 @@
 
 Covert Channels are Tricky Stuff
 
-## daemon installation
-
-Change to daemon/ and run cmake and compile with
-
-```
-mkdir build
-cmake ..
-```
-and
-```
-make
-```
-
-Copy executable
-
-```
-sudo cp ccats /usr/bin
-```
-
-
-Copy service file
-
-```
-sudo cp ccats.service /etc/systemd/system/
-```
-
-Enable and start service with
-
-```
-sudo systemctl enable ccats.service
-```
-and
-```
-sudo systemctl start ccats.service
-```

+ 1 - 1
autoformat.sh

@@ -1,2 +1,2 @@
 #!/bin/bash
-clang-format -i {daemon,cli,gui}/src/*.cpp {daemon,cli,gui}/include/*.h
+clang-format -i {daemon,cli,gui}/src/*.cpp {daemon,cli,gui}/include/*.h {daemon,cli,gui}/test/*.cpp

+ 4 - 13
daemon/CMakeLists.txt

@@ -5,17 +5,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
 
 project(ccats)
 
-add_executable(ccats src/main.cpp src/Sniffer.cpp src/Server.cpp src/base64.cpp src/JsonCommander.cpp src/FileManager.cpp)
+include(src/CMakeLists.txt)
 
-# use pkg-config to fix building on debian unstable
-find_package(PkgConfig REQUIRED)
-pkg_check_modules(TINS REQUIRED libtins>=4.2 libpcap)
-pkg_check_modules(JSONCPP REQUIRED jsoncpp)
-
-
-find_package(Threads REQUIRED)
-find_package(Boost 1.67 REQUIRED COMPONENTS system)
-# find_package(libtins 4.2 REQUIRED)
-
-include_directories(${Boost_INCLUDE_DIR} ${JSONCPP_INCLUDEDIR})
-target_link_libraries(ccats PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ${TINS_LIBRARIES} ${PCAP_LIBRARIES} ${JSONCPP_LIBRARIES})
+if(ENABLE_TESTS)
+  include(test/CMakeLists.txt)
+endif()

+ 49 - 0
daemon/README.md

@@ -0,0 +1,49 @@
+# Daemon
+
+## Build
+```
+mkdir build
+cd build
+cmake ..
+make
+```
+
+### Tests
+To build tests just set the `ENABLE_TESTS` variable to true and rebuild the program.
+```
+cmake .. -DENABLE_TESTS=true
+make
+```
+
+## Run
+Currently the first argument is the network interface for the sniffer.
+```
+bin/ccats lo
+```
+
+### Tests
+```
+make test
+```
+
+## Installation
+
+After building the program copy executable:
+```
+sudo cp bin/ccats /usr/bin
+```
+
+
+Copy service file:
+```
+sudo cp ccats.service /etc/systemd/system/
+```
+
+Enable and start service with:
+```
+sudo systemctl enable ccats.service
+```
+and start it
+```
+sudo systemctl start ccats.service
+```

+ 9 - 14
daemon/include/FileManager.h

@@ -56,25 +56,25 @@ public:
    * Checks if an upload is running
    * @return true - upload running | false - no upload
    */
-  bool isUploading();
+  virtual bool isUploading();
 
   /**
    * Check if a download is running
    * @return true - download running | false - no download
    */
-  bool isDownloading();
+  virtual bool isDownloading();
 
   /**
    * Opens put file if it doesn't exist
    * @return true - file is open | false - file is not open
    */
-  bool openPutFile(const std::string &filename);
+  virtual bool openPutFile(const std::string &filename);
 
   /**
    * Opens get file if it exists and reports the amount of chunks
    * @return true - file is open | false - file is not open
    */
-  bool openGetFile(const std::string &filename, int &chunks);
+  virtual bool openGetFile(const std::string &filename, int &chunks);
 
   /**
    * Closes file
@@ -89,7 +89,7 @@ public:
   /**
    * Closes put file and deletes it
    */
-  void cancelPut();
+  virtual void cancelPut();
 
   /**
    * Checks if a file name is valid
@@ -101,28 +101,23 @@ public:
    * Return the name of the download file
    * @return name of the download file
    */
-  std::string getGetBaseFileName();
+  virtual std::string getGetBaseFileName();
 
   /**
    * Return the name of the upload file
    * @return name of the upload file
    */
-  std::string getPutBaseFileName();
+  virtual std::string getPutBaseFileName();
 
   /**
    * Writes data to put file
    */
-  void writePut(const std::vector<char> &data);
+  virtual void writePut(const std::vector<char> &data);
 
   /**
    * Reads data from get file
    */
-  std::vector<char> readGet();
-
-  /**
-   * Returns number of chunks for download
-   */
-  int getGetChunks();
+  virtual std::vector<char> readGet();
 };
 
 #endif

+ 8 - 0
daemon/include/JsonCommander.h

@@ -62,6 +62,14 @@ private:
    */
   const std::string protocolVersion = "0.2";
 
+  /**
+   * Map of all commands
+   *
+   * Used to find the command function fast
+   */
+  std::map<std::string, Response (JsonCommander::*)(const Json::Value &)>
+      commandsMap;
+
   /**
    * file manager for reading and writing files
    */

+ 21 - 0
daemon/src/CMakeLists.txt

@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+project(ccats)
+
+add_executable(ccats src/main.cpp src/Sniffer.cpp src/Server.cpp src/base64.cpp src/JsonCommander.cpp src/FileManager.cpp)
+
+# use pkg-config to fix building on debian unstable
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(TINS REQUIRED libtins>=4.2 libpcap)
+pkg_check_modules(JSONCPP REQUIRED jsoncpp)
+
+
+find_package(Threads REQUIRED)
+find_package(Boost 1.67 REQUIRED COMPONENTS system)
+# find_package(libtins 4.2 REQUIRED)
+
+include_directories(${Boost_INCLUDE_DIR} ${JSONCPP_INCLUDEDIR})
+target_link_libraries(ccats PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ${TINS_LIBRARIES} ${PCAP_LIBRARIES} ${JSONCPP_LIBRARIES})

+ 24 - 19
daemon/src/JsonCommander.cpp

@@ -2,27 +2,28 @@
 #include "../include/base64.h"
 
 JsonCommander::JsonCommander(FileManager &fileManager)
-    : fileManager(fileManager) {}
+    : fileManager(fileManager) {
+  commandsMap["status"] = &JsonCommander::executeStatus;
+  commandsMap["close"] = &JsonCommander::executeClose;
+  commandsMap["list"] = &JsonCommander::executeList;
+  commandsMap["put"] = &JsonCommander::executePut;
+  commandsMap["putdata"] = &JsonCommander::executePutdata;
+  commandsMap["get"] = &JsonCommander::executeGet;
+  commandsMap["getdata"] = &JsonCommander::executeGetdata;
+}
 
 JsonCommander::~JsonCommander() {}
 
 JsonCommander::Response JsonCommander::execute(const Json::Value &message) {
   JsonCommander::Response response;
-  if (message["command"].asString().compare("status") == 0) {
-    response = executeStatus(message);
-  } else if (message["command"].asString().compare("close") == 0) {
-    response = executeClose(message);
-  } else if (message["command"].asString().compare("list") == 0) {
-    response = executeList(message);
-  } else if (message["command"].asString().compare("put") == 0) {
-    response = executePut(message);
-  } else if (message["command"].asString().compare("putdata") == 0) {
-    response = executePutdata(message);
-  } else if (message["command"].asString().compare("get") == 0) {
-    response = executeGet(message);
-  } else if (message["command"].asString().compare("getdata") == 0) {
-    response = executeGetdata(message);
+
+  Response (JsonCommander::*commandExecutor)(const Json::Value &) =
+      commandsMap[message["command"].asString()];
+
+  if (commandExecutor != nullptr) {
+    response = (this->*commandExecutor)(message);
   } else {
+    // command does not exist
     response.action = close;
   }
 
@@ -84,7 +85,8 @@ JsonCommander::Response JsonCommander::executePut(const Json::Value &message) {
   response.json["command"] = "put";
   response.json["file"] = message["file"].asString();
 
-  if (!message["file"].isString() || !message["size"].isInt()) {
+  if (!message["file"].isString() || !message["size"].isInt() ||
+      !message["chunks"].isInt()) {
     // if request is incomplete close connection
     response.action = closeAndSend;
     response.json["accept"] = false;
@@ -94,6 +96,10 @@ JsonCommander::Response JsonCommander::executePut(const Json::Value &message) {
     response.action = send;
     response.json["accept"] = false;
     response.json["error"] = "upload already running";
+  } else if (message["chunks"].asInt() <= 0) {
+    response.action = send;
+    response.json["accept"] = false;
+    response.json["error"] = "there must be at least one chunk";
   } else if (fileManager.checkFilename(message["file"].asString())) {
     // accept request
     response.action = send;
@@ -102,7 +108,7 @@ JsonCommander::Response JsonCommander::executePut(const Json::Value &message) {
     if (opened) {
       response.json["accept"] = true;
       response.json["error"] = "";
-      this->putFileReceived = -1;
+      this->putFileReceived = message["chunks"].asInt();
     } else {
       response.json["accept"] = false;
       response.json["error"] = "file already exists";
@@ -149,8 +155,7 @@ JsonCommander::executePutdata(const Json::Value &message) {
   } else if (message["file"].asString().compare(
                  fileManager.getPutBaseFileName()) == 0) {
 
-    if (this->putFileReceived == -1 ||
-        --this->putFileReceived == message["remaining"].asInt()) {
+    if (--this->putFileReceived == message["remaining"].asInt()) {
       // accept request
       response.action = send;
       response.json["cancel"] = false;

+ 32 - 0
daemon/test/CMakeLists.txt

@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+project(ccats)
+
+# use pkg-config to fix building on debian unstable
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(JSONCPP REQUIRED jsoncpp)
+
+
+find_package(Threads REQUIRED)
+find_package(Boost 1.67 REQUIRED COMPONENTS system)
+
+# Setup testing
+enable_testing()
+
+pkg_check_modules(GMOCK REQUIRED gmock)
+
+find_package(GTest REQUIRED)
+
+include_directories(${Boost_INCLUDE_DIR} ${JSONCPP_INCLUDEDIR} ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR})
+
+# Add test cpp file
+add_executable(jsonCommanderTest test/JsonCommanderTest.cpp src/JsonCommander.cpp src/FileManager.cpp src/base64.cpp)
+target_link_libraries(jsonCommanderTest ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} ${JSONCPP_LIBRARIES} ${GMOCK_LIBRARIES} ${GTEST_LIBRARY} ${GTEST_MAIN_LIBRARY})
+
+add_test(
+  NAME jsonCommanderTest
+  COMMAND jsonCommanderTest
+)

+ 29 - 0
daemon/test/FileManagerMock.h

@@ -0,0 +1,29 @@
+#ifndef FILEMANAGERMOCK_H
+#define FILEMANAGERMOCK_H
+
+#include <gmock/gmock.h>
+#include "../include/FileManager.h"
+
+/**
+ * @class FileManagerMock
+ *
+ * Gmock stub class for FileManager so you can test without writing and reading actual files.
+ */
+class FileManagerMock : public FileManager {
+public:
+  MOCK_METHOD(bool, openGetFile, (const std::string &filename, int &chunks), (override));
+  MOCK_METHOD(bool, openPutFile, (const std::string &filename), (override));
+
+  MOCK_METHOD(bool, isDownloading, (), (override));
+  MOCK_METHOD(bool, isUploading, (), (override));
+
+  MOCK_METHOD(void, cancelPut, (), (override));
+
+  MOCK_METHOD(std::string, getGetBaseFileName, (), (override));
+  MOCK_METHOD(std::string, getPutBaseFileName, (), (override));
+
+  MOCK_METHOD(void, writePut, (const std::vector<char> &data), (override));
+  MOCK_METHOD(std::vector<char>, readGet, (), (override));
+};
+
+#endif

+ 631 - 0
daemon/test/JsonCommanderTest.cpp

@@ -0,0 +1,631 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "../include/JsonCommander.h"
+#include "FileManagerMock.h"
+
+namespace {
+/* Version tests */
+TEST(testVersion, Positive) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string versionString = "0.2";
+  Json::Value version;
+  version["version"] = versionString;
+
+  JsonCommander::Response response = jsonCommander.testVersion(version);
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["version"].asString(), versionString);
+}
+
+TEST(testVersion, Negative) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string versionString = "0.1";
+  Json::Value version;
+  version["version"] = versionString;
+
+  JsonCommander::Response response = jsonCommander.testVersion(version);
+  EXPECT_TRUE(response.action == JsonCommander::Action::closeAndSend);
+  EXPECT_FALSE(response.json["accept"].asBool());
+  EXPECT_FALSE(response.json["version"].asString().compare(versionString) == 0);
+}
+
+/* Status tests */
+TEST(Status, Ok) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "status";
+  Json::Value message;
+  message["command"] = command;
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_EQ(response.json["response"].asString(), "ok");
+}
+
+TEST(Status, Downloading) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "status";
+  Json::Value message;
+  message["command"] = command;
+
+  ON_CALL(fileManager, isDownloading()).WillByDefault(testing::Return(true));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_EQ(response.json["response"].asString(), "download running");
+}
+
+TEST(Status, Uploading) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "status";
+  Json::Value message;
+  message["command"] = command;
+
+  ON_CALL(fileManager, isUploading()).WillByDefault(testing::Return(true));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_EQ(response.json["response"].asString(), "upload running");
+}
+
+TEST(Status, UploadingAndDownloading) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "status";
+  Json::Value message;
+  message["command"] = command;
+
+  ON_CALL(fileManager, isDownloading()).WillByDefault(testing::Return(true));
+  ON_CALL(fileManager, isUploading()).WillByDefault(testing::Return(true));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_EQ(response.json["response"].asString(),
+            "download and upload running");
+}
+
+/* Close tests */
+TEST(Close, Close) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "close";
+  Json::Value message;
+  message["command"] = command;
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::closeAndSend);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_EQ(response.json["response"].asString(), "bye");
+}
+
+/* Put tests */
+TEST(Put, Positive) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "put";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+  message["size"] = 1337;
+  message["chunks"] = 1;
+
+  ON_CALL(fileManager, openPutFile(testing::_))
+      .WillByDefault(testing::Return(true));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["error"].asString(), "");
+}
+
+TEST(Put, Negative) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "put";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+  message["size"] = 1337;
+  message["chunks"] = 1;
+
+  ON_CALL(fileManager, openPutFile(testing::_))
+      .WillByDefault(testing::Return(false));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_FALSE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_TRUE(response.json["error"].asString().length() > 0);
+}
+
+/* Putdata tests */
+TEST(Putdata, Positive) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  /* start with put */
+  std::string command = "put";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+  message["size"] = 1337;
+  const int chunks = 3;
+  message["chunks"] = chunks;
+
+  ON_CALL(fileManager, openPutFile(testing::_))
+      .WillByDefault(testing::Return(true));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  /* putdata */
+  command = "putdata";
+
+  ON_CALL(fileManager, isUploading()).WillByDefault(testing::Return(true));
+  ON_CALL(fileManager, getPutBaseFileName())
+      .WillByDefault(testing::Return(filename));
+
+  for (int remaining = chunks - 1; remaining >= 0; remaining--) {
+    message = Json::Value();
+    message["command"] = command;
+    message["file"] = filename;
+    message["data"] = "MTMzNw==";
+    message["remaining"] = remaining;
+    message["cancel"] = false;
+
+    response = jsonCommander.execute(message);
+
+    EXPECT_TRUE(response.action == JsonCommander::Action::send);
+    EXPECT_EQ(response.json["command"].asString(), command);
+    EXPECT_FALSE(response.json["cancel"].asBool());
+    EXPECT_EQ(response.json["received"].asInt(), remaining);
+    EXPECT_EQ(response.json["file"].asString(), filename);
+    EXPECT_EQ(response.json["error"].asString(), "");
+  }
+}
+
+TEST(Putdata, Cancel) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  /* start with put */
+  std::string command = "put";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+  message["size"] = 1337;
+  const int chunks = 3;
+  message["chunks"] = chunks;
+
+  ON_CALL(fileManager, openPutFile(testing::_))
+      .WillByDefault(testing::Return(true));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  /* putdata */
+  command = "putdata";
+
+  ON_CALL(fileManager, isUploading()).WillByDefault(testing::Return(true));
+  ON_CALL(fileManager, getPutBaseFileName())
+      .WillByDefault(testing::Return(filename));
+
+  int remaining = chunks - 1;
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["data"] = "MTMzNw==";
+  message["remaining"] = remaining;
+  message["cancel"] = false;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_FALSE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["received"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  // cancel transfer
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["data"] = "MTMzNw==";
+  message["remaining"] = --remaining;
+  message["cancel"] = true;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["received"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["error"].asString(), "");
+}
+
+TEST(Putdata, WrongRemaining) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  /* start with put */
+  std::string command = "put";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+  message["size"] = 1337;
+  const int chunks = 3;
+  message["chunks"] = chunks;
+
+  ON_CALL(fileManager, openPutFile(testing::_))
+      .WillByDefault(testing::Return(true));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  /* putdata */
+  command = "putdata";
+
+  ON_CALL(fileManager, isUploading()).WillByDefault(testing::Return(true));
+  ON_CALL(fileManager, getPutBaseFileName())
+      .WillByDefault(testing::Return(filename));
+
+  int remaining = chunks - 1;
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["data"] = "MTMzNw==";
+  message["remaining"] = remaining;
+  message["cancel"] = false;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_FALSE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["received"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["error"].asString(), "");
+  message = Json::Value();
+
+  // skip remaining=1 and provoke an error
+  remaining = 0;
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["data"] = "MTMzNw==";
+  message["remaining"] = remaining;
+  message["cancel"] = false;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["received"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_TRUE(response.json["error"].asString().length() > 0);
+}
+
+/* Get tests */
+TEST(Get, Positive) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "get";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+
+  EXPECT_CALL(fileManager, openGetFile(testing::_, testing::_))
+      .WillOnce(testing::DoAll(testing::SetArgReferee<1, int>(3),
+                               testing::Return(true)));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_TRUE(response.json["chunks"].asInt() > 0);
+  EXPECT_EQ(response.json["error"].asString(), "");
+}
+
+TEST(Get, Negative) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  const std::string command = "get";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+
+  EXPECT_CALL(fileManager, openGetFile(testing::_, testing::_))
+      .WillOnce(testing::Return(false));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_FALSE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["chunks"].asInt(), -1);
+  EXPECT_TRUE(response.json["error"].asString().length() > 0);
+}
+
+/* Getdata tests */
+TEST(Getdata, Positive) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  std::string command = "get";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+
+  const int chunks = 3;
+  EXPECT_CALL(fileManager, openGetFile(testing::_, testing::_))
+      .WillOnce(testing::DoAll(testing::SetArgReferee<1, int>(chunks),
+                               testing::Return(true)));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["chunks"].asInt(), chunks);
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  /* getdata */
+  command = "getdata";
+
+  ON_CALL(fileManager, isDownloading()).WillByDefault(testing::Return(true));
+  ON_CALL(fileManager, getGetBaseFileName())
+      .WillByDefault(testing::Return(filename));
+
+  std::vector<char> data;
+  data.push_back('1');
+  data.push_back('3');
+  data.push_back('3');
+  data.push_back('7');
+
+  ON_CALL(fileManager, readGet()).WillByDefault(testing::Return(data));
+
+  for (int remaining = chunks - 1; remaining >= 0; remaining--) {
+    message = Json::Value();
+    message["command"] = command;
+    message["file"] = filename;
+    message["chunk"] = remaining;
+    message["cancel"] = false;
+
+    response = jsonCommander.execute(message);
+
+    EXPECT_TRUE(response.action == JsonCommander::Action::send);
+    EXPECT_EQ(response.json["command"].asString(), command);
+    EXPECT_FALSE(response.json["cancel"].asBool());
+    EXPECT_EQ(response.json["remaining"].asInt(), remaining);
+    EXPECT_EQ(response.json["file"].asString(), filename);
+    EXPECT_EQ(response.json["data"].asString(), "MTMzNw==");
+    EXPECT_EQ(response.json["error"].asString(), "");
+  }
+}
+
+TEST(Getdata, Cancle) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  std::string command = "get";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+
+  const int chunks = 3;
+  EXPECT_CALL(fileManager, openGetFile(testing::_, testing::_))
+      .WillOnce(testing::DoAll(testing::SetArgReferee<1, int>(chunks),
+                               testing::Return(true)));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["chunks"].asInt(), chunks);
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  /* getdata */
+  command = "getdata";
+
+  ON_CALL(fileManager, isDownloading()).WillByDefault(testing::Return(true));
+  ON_CALL(fileManager, getGetBaseFileName())
+      .WillByDefault(testing::Return(filename));
+
+  std::vector<char> data;
+  data.push_back('1');
+  data.push_back('3');
+  data.push_back('3');
+  data.push_back('7');
+
+  ON_CALL(fileManager, readGet()).WillByDefault(testing::Return(data));
+
+  int remaining = chunks - 1;
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["chunk"] = remaining;
+  message["cancel"] = false;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_FALSE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["remaining"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["data"].asString(), "MTMzNw==");
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  // set cancel to true
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["chunk"] = --remaining;
+  message["cancel"] = true;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["remaining"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["data"].asString(), "");
+  EXPECT_EQ(response.json["error"].asString(), "");
+}
+
+TEST(Getdata, WrongChunk) {
+  FileManagerMock fileManager;
+
+  JsonCommander jsonCommander(fileManager);
+
+  std::string command = "get";
+  const std::string filename = "cool.txt";
+  Json::Value message;
+  message["command"] = command;
+  message["file"] = filename;
+
+  const int chunks = 3;
+  EXPECT_CALL(fileManager, openGetFile(testing::_, testing::_))
+      .WillOnce(testing::DoAll(testing::SetArgReferee<1, int>(chunks),
+                               testing::Return(true)));
+
+  JsonCommander::Response response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["accept"].asBool());
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["chunks"].asInt(), chunks);
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  /* getdata */
+  command = "getdata";
+
+  ON_CALL(fileManager, isDownloading()).WillByDefault(testing::Return(true));
+  ON_CALL(fileManager, getGetBaseFileName())
+      .WillByDefault(testing::Return(filename));
+
+  std::vector<char> data;
+  data.push_back('1');
+  data.push_back('3');
+  data.push_back('3');
+  data.push_back('7');
+
+  ON_CALL(fileManager, readGet()).WillByDefault(testing::Return(data));
+
+  int remaining = chunks - 1;
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["chunk"] = remaining;
+  message["cancel"] = false;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_FALSE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["remaining"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["data"].asString(), "MTMzNw==");
+  EXPECT_EQ(response.json["error"].asString(), "");
+
+  // skip chunk=0
+  remaining = 0;
+  message = Json::Value();
+  message["command"] = command;
+  message["file"] = filename;
+  message["chunk"] = remaining;
+  message["cancel"] = false;
+
+  response = jsonCommander.execute(message);
+
+  EXPECT_TRUE(response.action == JsonCommander::Action::send);
+  EXPECT_EQ(response.json["command"].asString(), command);
+  EXPECT_TRUE(response.json["cancel"].asBool());
+  EXPECT_EQ(response.json["remaining"].asInt(), remaining);
+  EXPECT_EQ(response.json["file"].asString(), filename);
+  EXPECT_EQ(response.json["data"].asString(), "");
+  EXPECT_TRUE(response.json["error"].asString().length() > 0);
+}
+} // namespace