blob: be9aa5581570e1bf8ef0054157dc4d4551016e5a [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>
8#include <queue>
9#include <string>
10#include <utility>
11#include <vector>
12
13#include "base/bind.h"
14#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 =
29 base::MakeUnique<remoting::CompoundBuffer>();
30 buffer->Append(new net::WrappedIOBuffer(data.data()), data.size());
31 return buffer;
32}
33
34} // namespace
35
36namespace remoting {
37
38class FakeFileProxyWrapper : public FileProxyWrapper {
39 public:
40 FakeFileProxyWrapper();
41 ~FakeFileProxyWrapper() override;
42
43 // FileProxyWrapper implementation.
44 void Init(StatusCallback status_callback) override;
45 void CreateFile(const base::FilePath& directory,
46 const std::string& filename) override;
47 void WriteChunk(std::unique_ptr<CompoundBuffer> buffer) override;
48 void Close() override;
49 void Cancel() override;
50 State state() override;
51
52 void RunStatusCallback(
53 base::Optional<protocol::FileTransferResponse_ErrorCode> error);
54 const std::string& filename();
55 std::queue<std::vector<char>> chunks();
56
57 private:
58 State state_ = kUninitialized;
59 StatusCallback status_callback_;
60 std::string filename_;
61 std::queue<std::vector<char>> chunks_;
62};
63
64class FileTransferMessageHandlerTest : public testing::Test {
65 public:
66 FileTransferMessageHandlerTest();
67 ~FileTransferMessageHandlerTest() override;
68
69 // testing::Test implementation.
70 void SetUp() override;
71 void TearDown() override;
72
73 protected:
74 const std::string kTestDataOne = "this is the first test string";
75 const std::string kTestDataTwo = "this is the second test string";
76
77 std::unique_ptr<protocol::FakeMessagePipe> fake_pipe_;
78 protocol::FileTransferRequest fake_request_;
79 std::string fake_request_string_;
80};
81
82FakeFileProxyWrapper::FakeFileProxyWrapper() = default;
83FakeFileProxyWrapper::~FakeFileProxyWrapper() = default;
84
85void FakeFileProxyWrapper::Init(StatusCallback status_callback) {
86 ASSERT_EQ(state_, kUninitialized);
87 state_ = kInitialized;
88
89 status_callback_ = std::move(status_callback);
90}
91
92void FakeFileProxyWrapper::CreateFile(const base::FilePath& directory,
93 const std::string& filename) {
94 ASSERT_EQ(state_, kInitialized);
95 state_ = kFileCreated;
96
97 filename_ = filename;
98}
99
100void FakeFileProxyWrapper::WriteChunk(std::unique_ptr<CompoundBuffer> buffer) {
101 ASSERT_EQ(state_, kFileCreated);
102
103 std::vector<char> data;
104 data.resize(buffer->total_bytes());
105 buffer->CopyTo(data.data(), data.size());
106 chunks_.push(data);
107}
108
109void FakeFileProxyWrapper::Close() {
110 ASSERT_EQ(state_, kFileCreated);
111 state_ = kClosed;
112}
113
114void FakeFileProxyWrapper::Cancel() {
115 state_ = kFailed;
116}
117
118FileProxyWrapper::State FakeFileProxyWrapper::state() {
119 return state_;
120}
121
122void FakeFileProxyWrapper::RunStatusCallback(
123 base::Optional<protocol::FileTransferResponse_ErrorCode> error) {
124 std::move(status_callback_).Run(state_, error);
125}
126
127const std::string& FakeFileProxyWrapper::filename() {
128 return filename_;
129}
130
131std::queue<std::vector<char>> FakeFileProxyWrapper::chunks() {
132 return chunks_;
133}
134
135FileTransferMessageHandlerTest::FileTransferMessageHandlerTest() = default;
136FileTransferMessageHandlerTest::~FileTransferMessageHandlerTest() = default;
137
138void FileTransferMessageHandlerTest::SetUp() {
139 fake_pipe_ =
140 base::WrapUnique(new protocol::FakeMessagePipe(false /* asynchronous */));
141
142 fake_request_ = protocol::FileTransferRequest();
143 fake_request_.set_filename(kTestFilename);
144 fake_request_.set_filesize(kTestDataOne.size() + kTestDataTwo.size());
145 fake_request_.SerializeToString(&fake_request_string_);
146}
147
148void FileTransferMessageHandlerTest::TearDown() {}
149
150// Verify that the message handler creates, writes to, and closes a
151// FileProxyWrapper without errors when given valid input.
152TEST_F(FileTransferMessageHandlerTest, WriteTwoChunks) {
153 std::unique_ptr<FakeFileProxyWrapper> file_proxy_wrapper =
154 base::MakeUnique<FakeFileProxyWrapper>();
155 // |file_proxy_wrapper_ptr| is valid until fake_pipe_->ClosePipe() is called.
156 FakeFileProxyWrapper* file_proxy_wrapper_ptr = file_proxy_wrapper.get();
157
158 // This will delete itself when fake_pipe_->ClosePipe() is called.
159 new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(),
160 std::move(file_proxy_wrapper));
161
162 fake_pipe_->OpenPipe();
163 fake_pipe_->Receive(ToBuffer(fake_request_string_));
164 fake_pipe_->Receive(ToBuffer(kTestDataOne));
165 fake_pipe_->Receive(ToBuffer(kTestDataTwo));
166
167 file_proxy_wrapper_ptr->RunStatusCallback(
168 base::Optional<protocol::FileTransferResponse_ErrorCode>());
169
170 std::queue<std::vector<char>> actual_chunks =
171 file_proxy_wrapper_ptr->chunks();
172
173 fake_pipe_->ClosePipe();
174 file_proxy_wrapper_ptr = nullptr;
175
176 std::queue<std::vector<char>> expected_chunks;
177 expected_chunks.push(
178 std::vector<char>(kTestDataOne.begin(), kTestDataOne.end()));
179 expected_chunks.push(
180 std::vector<char>(kTestDataTwo.begin(), kTestDataTwo.end()));
181 ASSERT_EQ(expected_chunks, actual_chunks);
182
183 const std::queue<std::string>& actual_sent_messages =
184 fake_pipe_->sent_messages();
185 protocol::FileTransferResponse expected_response;
186 expected_response.set_state(
187 protocol::FileTransferResponse_TransferState_DONE);
188 expected_response.set_total_bytes_written(fake_request_.filesize());
189 std::string expected_response_string;
190 expected_response.SerializeToString(&expected_response_string);
191 std::queue<std::string> expected_sent_messages;
192 expected_sent_messages.push(expected_response_string);
193 ASSERT_EQ(expected_sent_messages, actual_sent_messages);
194}
195
196// Verifies that the message handler sends an error protobuf when
197// FileProxyWrapper returns an error.
198TEST_F(FileTransferMessageHandlerTest, FileProxyError) {
199 std::unique_ptr<FakeFileProxyWrapper> file_proxy_wrapper =
200 base::MakeUnique<FakeFileProxyWrapper>();
201 // |file_proxy_wrapper_ptr| is valid until fake_pipe_->ClosePipe() is called.
202 FakeFileProxyWrapper* file_proxy_wrapper_ptr = file_proxy_wrapper.get();
203
204 protocol::FileTransferResponse_ErrorCode fake_error =
205 protocol::FileTransferResponse_ErrorCode_FILE_IO_ERROR;
206
207 // This will delete itself when fake_pipe_->ClosePipe() is called.
208 new FileTransferMessageHandler(kTestDatachannelName, fake_pipe_->Wrap(),
209 std::move(file_proxy_wrapper));
210
211 fake_pipe_->OpenPipe();
212 fake_pipe_->Receive(ToBuffer(fake_request_string_));
213 fake_pipe_->Receive(ToBuffer(kTestDataOne));
214
215 file_proxy_wrapper_ptr->Cancel();
216 file_proxy_wrapper_ptr->RunStatusCallback(
217 base::Optional<protocol::FileTransferResponse_ErrorCode>(fake_error));
218
219 fake_pipe_->ClosePipe();
220 file_proxy_wrapper_ptr = nullptr;
221
222 const std::queue<std::string>& actual_sent_messages =
223 fake_pipe_->sent_messages();
224 protocol::FileTransferResponse expected_response;
225 expected_response.set_error(fake_error);
226 std::string expected_response_string;
227 expected_response.SerializeToString(&expected_response_string);
228 std::queue<std::string> expected_sent_messages;
229 expected_sent_messages.push(expected_response_string);
230 ASSERT_EQ(expected_sent_messages, actual_sent_messages);
231}
232
233} // namespace remoting