diff --git a/packages/filesystem/include/filesystem/File.h b/packages/filesystem/include/filesystem/File.h
index 07d52bb1..bbc45dc8 100644
--- a/packages/filesystem/include/filesystem/File.h
+++ b/packages/filesystem/include/filesystem/File.h
@@ -14,6 +14,18 @@
 namespace l {
 namespace filesystem {
 
+	template<class T, const size_t SIZE>
+	void convert(std::stringstream& dst, std::array<T, SIZE>& src, size_t count = 0) {
+		static_assert(sizeof(T) == sizeof(char));
+		dst.write(reinterpret_cast<char*>(src.data()), count > 0 ? count : src.size());
+	}
+
+	bool read(const std::filesystem::path& mLocation, char* dst, size_t count, size_t position = 0);
+	bool write(const std::filesystem::path& mLocation, const char* src, size_t count, size_t position = 0);
+
+	bool read(const std::filesystem::path& mLocation, std::stringstream& data);
+	bool write(const std::filesystem::path& mLocation, std::stringstream& data);
+
 	std::time_t getTime(std::filesystem::file_time_type tp);
 	std::string toString(std::time_t t, std::string format = "%Y-%m-%d %X");
 
diff --git a/packages/filesystem/source/common/filesystem/File.cpp b/packages/filesystem/source/common/filesystem/File.cpp
index 59ee9c5b..57d51a7e 100644
--- a/packages/filesystem/source/common/filesystem/File.cpp
+++ b/packages/filesystem/source/common/filesystem/File.cpp
@@ -15,6 +15,91 @@
 namespace l {
 namespace filesystem {
 
+	std::atomic_int32_t count_reads_ops = 0;
+	std::atomic_int32_t count_write_ops = 0;
+	std::atomic_bool abort_all_reads = false;
+	std::atomic_bool abort_all_writes = false;
+
+	bool read(const std::filesystem::path& mLocation, char* dst, size_t count, size_t position) {
+		if (!std::filesystem::exists(mLocation)) {
+			return false;
+		}
+
+		std::ifstream ifs(mLocation);
+		if (!ifs.good()) {
+			return false;
+		}
+		if (position > 0) {
+			ifs.seekg(position);
+		}
+		ifs.read(dst, static_cast<std::streamsize>(count));
+		return true;
+	}
+
+	bool write(const std::filesystem::path& mLocation, const char* src, size_t count, size_t position) {
+		if (!std::filesystem::exists(mLocation)) {
+			if (!std::filesystem::create_directories(mLocation.parent_path())) {
+				return false;
+			}
+		}
+
+		std::ofstream ofs(mLocation);
+		if (!ofs.good()) {
+			return false;
+		}
+		if (position > 0) {
+			ofs.seekp(position);
+		}
+		ofs.write(src, static_cast<std::streamsize>(count));
+		return true;
+	}
+
+
+	bool read(const std::filesystem::path& mLocation, std::stringstream& data) {
+		if (!std::filesystem::exists(mLocation)) {
+			return false;
+		}
+
+		std::ifstream ifs(mLocation);
+		count_reads_ops++;
+		std::array<char, 2048> buf;
+		for (;;) {
+			ifs.read(buf.data(), buf.size());
+			size_t count = static_cast<size_t>(ifs.gcount());
+			if (count <= 0 || abort_all_reads) {
+				break;
+			}
+
+			convert(data, buf, count);
+		}
+		ifs.close();
+		count_reads_ops--;
+
+		return true;
+	}
+
+	bool write(const std::filesystem::path& mLocation, std::stringstream& data) {
+		if (std::filesystem::create_directories(mLocation.parent_path())) {
+			return false;
+		}
+
+		std::ofstream ofs(mLocation, std::ofstream::out);
+		count_write_ops++;
+		std::array<char, 2048> buf;
+		for (;;) {
+			data.read(buf.data(), buf.size());
+			size_t count = static_cast<size_t>(data.gcount());
+			if (count <= 0 || abort_all_writes) {
+				break;
+			}
+			ofs.write(buf.data(), count);
+		}
+		ofs.close();
+		count_write_ops--;
+
+		return true;
+	}
+
 	std::time_t getTime(std::filesystem::file_time_type tp) {
 		auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(tp - std::filesystem::file_time_type::clock::now()
 			+ std::chrono::system_clock::now());
diff --git a/packages/network/tests/common/NetworkInterfaceTest.cpp b/packages/network/tests/common/NetworkInterfaceTest.cpp
new file mode 100644
index 00000000..469672a3
--- /dev/null
+++ b/packages/network/tests/common/NetworkInterfaceTest.cpp
@@ -0,0 +1,54 @@
+#include "testing/Test.h"
+#include "logging/Log.h"
+#include "logging/String.h"
+
+#include "network/NetworkInterface.h"
+#include "filesystem/File.h"
+
+#include <array>
+
+using namespace l;
+
+TEST(NetworkInterface, Setup) {
+
+	std::stringstream telegramToken;
+	if (!l::filesystem::read("tests/telegrambottoken.txt", telegramToken)) {
+		return 0;
+	}
+
+	auto networkManager = l::network::CreateNetworkManager(2, false);
+	auto networkInterface = l::network::CreateNetworkInterface(networkManager);
+
+	std::string query = "bot";
+	query += telegramToken.str();
+	query += "/sendMessage?";
+
+	auto telegramHandler = [&](
+		bool success,
+		std::string_view queryArguments,
+		l::network::RequestStringStream& request) {
+			TEST_TRUE_NO_RET(success, "");
+
+			LOG(LogInfo) << "Query arguments: '" << queryArguments << "'";
+			LOG(LogInfo) << request.GetResponse().str();
+			return l::concurrency::RunnableResult::SUCCESS;
+		};
+
+	networkInterface->CreateInterface("Telegram", "https", "api.telegram.org");
+	networkInterface->CreateRequestTemplate<std::stringstream>("Telegram", "TradeFlowBot1", query, 1, 2000, 5, telegramHandler);
+
+	std::string chatId = "6640331275"; // TradeFlowGroup
+	std::string args;
+	std::string message = "NetworkInterface";
+	args += "chat_id=" + chatId;
+	args += "&text=" + message;
+
+	networkInterface->SendRequest("Telegram", "TradeFlowBot1", args, 1, 2000, 5, nullptr);
+
+	std::this_thread::sleep_for(std::chrono::milliseconds(20));
+
+	networkManager->ClearJobs();
+	networkManager->Shutdown();
+
+	return 0;
+}
diff --git a/packages/network/tests/common/NetworkManagerTest.cpp b/packages/network/tests/common/NetworkManagerTest.cpp
index 10caa320..70cb80d2 100644
--- a/packages/network/tests/common/NetworkManagerTest.cpp
+++ b/packages/network/tests/common/NetworkManagerTest.cpp
@@ -28,6 +28,7 @@ TEST(NetworkManager, Setup) {
 			return l::concurrency::RunnableResult::SUCCESS;
 		}
 	);
+
 	auto request2 = std::make_unique<l::network::RequestStringStream>("requestName", "https://httpbin.org/anything", 25000,
 		[&](bool success, std::string_view queryArguments, l::network::RequestStringStream& request) {
 			TEST_TRUE_NO_RET(success, "");
@@ -38,13 +39,42 @@ TEST(NetworkManager, Setup) {
 		}
 	);
 
-
 	networkManager->CreateRequestTemplate(std::move(request1));
 	networkManager->CreateRequestTemplate(std::move(request2));
 	networkManager->PostQuery("requestName", "user defined query id");
 	networkManager->PostQuery("requestName", "custom queries on predefined requests", 3, "https://httpbin.org/anything");
 
-	TEST_TRUE(networkManager->TotalRequestCount() == 2, "");
+	std::stringstream telegramToken;
+	if (l::filesystem::read("tests/telegrambottoken.txt", telegramToken)) {
+		std::string query = "https://api.telegram.org/bot";
+		query += telegramToken.str();
+		query += "/sendMessage?";
+
+		std::string chatId = "6640331275"; // TradeFlowGroup
+		std::string args;
+		std::string message = "NetworkManager";
+		args += "chat_id=" + chatId;
+		args += "&text=" + message;
+
+		query += args;
+
+		auto request3 = std::make_unique<l::network::RequestStringStream>("TelegramBot", query, 25000,
+			[&](bool success, std::string_view queryArguments, l::network::RequestStringStream& request) {
+				TEST_TRUE_NO_RET(success, "");
+
+				LOG(LogInfo) << "Query arguments: '" << queryArguments << "'";
+				LOG(LogInfo) << request.GetResponse().str();
+				return l::concurrency::RunnableResult::SUCCESS;
+			}
+		);
+		networkManager->CreateRequestTemplate(std::move(request3));
+		networkManager->PostQuery("TelegramBot", args, 3);
+		TEST_TRUE(networkManager->TotalRequestCount() == 3, "");
+	}
+	else {
+		TEST_TRUE(networkManager->TotalRequestCount() == 2, "");
+	}
+
 
 	networkManager->Shutdown();