blob: 608f1e985c8c5e68e228004cf439097f3b2a97bf [file] [log] [blame]
Joseph Arhar10e5edd2017-08-28 22:12:501// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/host/file_transfer_message_handler.h"
6
7#include <memory>
Joseph Arhar10e5edd2017-08-28 22:12:508#include <string>
9#include <utility>
10#include <vector>
11
12#include "base/bind.h"
Brett Wilsonb02c0a22017-09-25 22:34:4213#include "base/containers/queue.h"
Joseph Arhar10e5edd2017-08-28 22:12:5014#include "base/memory/ptr_util.h"
15#include "net/base/io_buffer.h"
16#include "remoting/base/compound_buffer.h"
17#include "remoting/host/file_proxy_wrapper.h"
18#include "remoting/protocol/fake_message_pipe.h"
19#include "remoting/protocol/fake_message_pipe_wrapper.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22namespace {
23
24constexpr char kTestDatachannelName[] = "filetransfer-test";
25constexpr char kTestFilename[] = "test-file.txt";
26
27std::unique_ptr<remoting::CompoundBuffer> ToBuffer(const std::string& data) {
28 std::unique_ptr<remoting::CompoundBuffer> buffer =
Jinho Bang138fde32018-01-18 23:13:4229 std::make_unique<remoting::CompoundBuffer>();
Joseph Arhar10e5edd2017-08-28 22:12:5030 buffer->Append(new net::WrappedIOBuffer(data.data()), data.size());
31 return buffer;
32}
33
Brett Wilsonb02c0a22017-09-25 22:34:4234// base::queue doesn't provide operator==.
35template <typename T>
36bool QueuesEqual(const base::queue<T>& a, const base::queue<T>& b) {
37 if (a.size() != b.size())
38 return false;
39
40 auto a_copy = a;
41 auto b_copy = b;
42 while (!a_copy.empty()) {
43 if (a_copy.front() != b_copy.front())
44 return false;
45 a_copy.pop();
46 b_copy.pop();
47 }
48 return true;
49}
50
Joseph Arhar10e5edd2017-08-28 22:12:5051} // namespace
52
53namespace remoting {
54
55class FakeFileProxyWrapper : public FileProxyWrapper {
56 public:
57 FakeFileProxyWrapper();
58 ~FakeFileProxyWrapper() override;
59
60 // FileProxyWrapper implementation.
61 void Init(StatusCallback status_callback) override;
62 void CreateFile(const base::FilePath& directory,
63 const std::string& filename) override;
Joseph Arhar6f84f282017-09-08 19:19:3464 void OpenFile(const base::FilePath& filepath,
65 OpenFileCallback open_callback) override;
Joseph Arhar10e5edd2017-08-28 22:12:5066 void WriteChunk(std::unique_ptr<CompoundBuffer> buffer) override;
Joseph Arhar6f84f282017-09-08 19:19:3467 void ReadChunk(uint64_t chunk_size, ReadCallback read_callback) override;
Joseph Arhar10e5edd2017-08-28 22:12:5068 void Close() override;
69 void Cancel() override;
70 State state() override;
71
72 void RunStatusCallback(
73 base::Optional<protocol::FileTransferResponse_ErrorCode> error);
74 const std::string& filename();
Brett Wilsonb02c0a22017-09-25 22:34:4275 base::queue<std::vector<char>> chunks();
Joseph Arhar10e5edd2017-08-28 22:12:5076
77 private:
78 State state_ = kUninitialized;
79 StatusCallback status_callback_;
80 std::string filename_;
Brett Wilsonb02c0a22017-09-25 22:34:4281 base::queue<std::vector<char>> chunks_;
Joseph Arhar10e5edd2017-08-28 22:12:5082};
83
84class FileTransferMessageHandlerTest : public testing::Test {
85 public:
86 FileTransferMessageHandlerTest();
87 ~FileTransferMessageHandlerTest() override;
88
89 // testing::Test implementation.
90 void SetUp() override;
91 void TearDown() override;
92
93 protected:
94 const std::string kTestDataOne = "this is the first test string";
95 const std::string kTestDataTwo = "this is the second test string";
96
97 std::unique_ptr<protocol::FakeMessagePipe> fake_pipe_;
98 protocol::FileTransferRequest fake_request_;
99 std::string fake_request_string_;
100};
101
102FakeFileProxyWrapper::FakeFileProxyWrapper() = default;
103FakeFileProxyWrapper::~FakeFileProxyWrapper() = default;
104
105void FakeFileProxyWrapper::Init(StatusCallback status_callback) {
106 ASSERT_EQ(state_, kUninitialized);
107 state_ = kInitialized;
108
109 status_callback_ = std::move(status_callback);
110}
111
112void FakeFileProxyWrapper::CreateFile(const base::FilePath& directory,
113 const std::string& filename) {
114 ASSERT_EQ(state_, kInitialized);
Joseph Arhar6f84f282017-09-08 19:19:34115 state_ = kReady;
Joseph Arhar10e5edd2017-08-28 22:12:50116
117 filename_ = filename;
118}
119
Joseph Arhar6f84f282017-09-08 19:19:34120void FakeFileProxyWrapper::OpenFile(const base::FilePath& filepath,
121 OpenFileCallback open_callback) {
122 ASSERT_EQ(state_, kInitialized);
123 state_ = kReady;
124
125 // TODO(jarhar): Implement fake file reading.
126}
127
Joseph Arhar10e5edd2017-08-28 22:12:50128void FakeFileProxyWrapper::WriteChunk(std::unique_ptr<CompoundBuffer> buffer) {
Joseph Arhar6f84f282017-09-08 19:19:34129 ASSERT_EQ(state_, kReady);
Joseph Arhar10e5edd2017-08-28 22:12:50130
131 std::vector<char> data;
132 data.resize(buffer->total_bytes());
133 buffer->CopyTo(data.data(), data.size());
134 chunks_.push(data);
135}
136
Joseph Arhar6f84f282017-09-08 19:19:34137void FakeFileProxyWrapper::ReadChunk(uint64_t chunk_size,
138 ReadCallback read_callback) {
139 ASSERT_EQ(state_, kReady);
140
141 // TODO(jarhar): Implement fake file reading.
142}
143
Joseph Arhar10e5edd2017-08-28 22:12:50144void FakeFileProxyWrapper::Close() {
Joseph Arhar6f84f282017-09-08 19:19:34145 ASSERT_EQ(state_, kReady);
Joseph Arhar10e5edd2017-08-28 22:12:50146 state_ = kClosed;
147}
148
149void FakeFileProxyWrapper::Cancel() {
150 state_ = kFailed;
151}
152
153FileProxyWrapper::State FakeFileProxyWrapper::state() {
154 return state_;
155}
156
157void FakeFileProxyWrapper::RunStatusCallback(
158 base::Optional<protocol::FileTransferResponse_ErrorCode> error) {
159 std::move(status_callback_).Run(state_, error);
160}
161
162const std::string& FakeFileProxyWrapper::filename() {
163 return filename_;
164}
165
Brett Wilsonb02c0a22017-09-25 22:34:42166base::queue<std::vector<char>> FakeFileProxyWrapper::chunks() {
Joseph Arhar10e5edd2017-08-28 22:12:50167 return chunks_;
168}
169
170FileTransferMessageHandlerTest::FileTransferMessageHandlerTest() = default;
171FileTransferMessageHandlerTest::~FileTransferMessageHandlerTest() = default;
172
173void FileTransferMessageHandlerTest::SetUp() {
174 fake_pipe_ =
175 base::WrapUnique(new protocol::FakeMessagePipe(false /* asynchronous */));
176
177 fake_request_ = protocol::FileTransferRequest();
178 fake_request_.set_filename(kTestFilename);
179 fake_request_.set_filesize(kTestDataOne.size() + kTestDataTwo.size());
180 fake_request_.SerializeToString(&fake_request_string_);
181}
182
183void FileTransferMessageHandlerTest::TearDown() {}
184
185// Verify that the message handler creates, writes to, and closes a
186// FileProxyWrapper without errors when given valid input.
187TEST_F(FileTransferMessageHandlerTest, WriteTwoChunks) {
188 std::unique_ptr<FakeFileProxyWrapper> file_proxy_wrapper =
Jinho Bang138fde32018-01-18 23:13:42189 std::make_unique<FakeFileProxyWrapper>();
Joseph Arhar10e5edd2017-08-28 22:12:50190 // |file_proxy_wrapper_ptr| is valid until fake_pipe_->ClosePipe() is called.
191 FakeFileProxyWrapper* file_proxy_wrapper_ptr = file_proxy_wrapper.get();
192
193 // This will delete itself when fake_pipe_->ClosePipe() is called.
194 new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(),
195 std::move(file_proxy_wrapper));
196
197 fake_pipe_->OpenPipe();
198 fake_pipe_->Receive(ToBuffer(fake_request_string_));
199 fake_pipe_->Receive(ToBuffer(kTestDataOne));
200 fake_pipe_->Receive(ToBuffer(kTestDataTwo));
201
202 file_proxy_wrapper_ptr->RunStatusCallback(
203 base::Optional<protocol::FileTransferResponse_ErrorCode>());
204
Brett Wilsonb02c0a22017-09-25 22:34:42205 base::queue<std::vector<char>> actual_chunks =
Joseph Arhar10e5edd2017-08-28 22:12:50206 file_proxy_wrapper_ptr->chunks();
207
208 fake_pipe_->ClosePipe();
209 file_proxy_wrapper_ptr = nullptr;
210
Brett Wilsonb02c0a22017-09-25 22:34:42211 base::queue<std::vector<char>> expected_chunks;
Joseph Arhar10e5edd2017-08-28 22:12:50212 expected_chunks.push(
213 std::vector<char>(kTestDataOne.begin(), kTestDataOne.end()));
214 expected_chunks.push(
215 std::vector<char>(kTestDataTwo.begin(), kTestDataTwo.end()));
Brett Wilsonb02c0a22017-09-25 22:34:42216 ASSERT_TRUE(QueuesEqual(expected_chunks, actual_chunks));
Joseph Arhar10e5edd2017-08-28 22:12:50217
Brett Wilsonb02c0a22017-09-25 22:34:42218 const base::queue<std::string>& actual_sent_messages =
Joseph Arhar10e5edd2017-08-28 22:12:50219 fake_pipe_->sent_messages();
220 protocol::FileTransferResponse expected_response;
221 expected_response.set_state(
222 protocol::FileTransferResponse_TransferState_DONE);
223 expected_response.set_total_bytes_written(fake_request_.filesize());
224 std::string expected_response_string;
225 expected_response.SerializeToString(&expected_response_string);
Brett Wilsonb02c0a22017-09-25 22:34:42226 base::queue<std::string> expected_sent_messages;
Joseph Arhar10e5edd2017-08-28 22:12:50227 expected_sent_messages.push(expected_response_string);
Brett Wilsonb02c0a22017-09-25 22:34:42228 ASSERT_TRUE(QueuesEqual(expected_sent_messages, actual_sent_messages));
Joseph Arhar10e5edd2017-08-28 22:12:50229}
230
231// Verifies that the message handler sends an error protobuf when
232// FileProxyWrapper returns an error.
233TEST_F(FileTransferMessageHandlerTest, FileProxyError) {
234 std::unique_ptr<FakeFileProxyWrapper> file_proxy_wrapper =
Jinho Bang138fde32018-01-18 23:13:42235 std::make_unique<FakeFileProxyWrapper>();
Joseph Arhar10e5edd2017-08-28 22:12:50236 // |file_proxy_wrapper_ptr| is valid until fake_pipe_->ClosePipe() is called.
237 FakeFileProxyWrapper* file_proxy_wrapper_ptr = file_proxy_wrapper.get();
238
239 protocol::FileTransferResponse_ErrorCode fake_error =
240 protocol::FileTransferResponse_ErrorCode_FILE_IO_ERROR;
241
242 // This will delete itself when fake_pipe_->ClosePipe() is called.
243 new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(),
244 std::move(file_proxy_wrapper));
245
246 fake_pipe_->OpenPipe();
247 fake_pipe_->Receive(ToBuffer(fake_request_string_));
248 fake_pipe_->Receive(ToBuffer(kTestDataOne));
249
250 file_proxy_wrapper_ptr->Cancel();
251 file_proxy_wrapper_ptr->RunStatusCallback(
252 base::Optional<protocol::FileTransferResponse_ErrorCode>(fake_error));
253
254 fake_pipe_->ClosePipe();
255 file_proxy_wrapper_ptr = nullptr;
256
Brett Wilsonb02c0a22017-09-25 22:34:42257 const base::queue<std::string>& actual_sent_messages =
Joseph Arhar10e5edd2017-08-28 22:12:50258 fake_pipe_->sent_messages();
259 protocol::FileTransferResponse expected_response;
260 expected_response.set_error(fake_error);
261 std::string expected_response_string;
262 expected_response.SerializeToString(&expected_response_string);
Brett Wilsonb02c0a22017-09-25 22:34:42263 base::queue<std::string> expected_sent_messages;
Joseph Arhar10e5edd2017-08-28 22:12:50264 expected_sent_messages.push(expected_response_string);
Brett Wilsonb02c0a22017-09-25 22:34:42265 ASSERT_TRUE(QueuesEqual(expected_sent_messages, actual_sent_messages));
Joseph Arhar10e5edd2017-08-28 22:12:50266}
267
268} // namespace remoting