blob: 48f62c812cd900daeebaabad9cf0fbf591e43ea8 [file] [log] [blame]
Jiang Yichenf4c7d972018-02-07 16:31:271// Copyright (c) 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 "ios/net/chunked_data_stream_uploader.h"
6
7#include <array>
8#include <memory>
9
10#include "net/base/io_buffer.h"
11#include "net/base/net_errors.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14namespace net {
15
16namespace {
17const int kDefaultIOBufferSize = 1024;
18}
19
20// Mock delegate to provide data from its internal buffer.
21class MockChunkedDataStreamUploaderDelegate
22 : public ChunkedDataStreamUploader::Delegate {
23 public:
24 MockChunkedDataStreamUploaderDelegate() : data_length_(0) {}
25 ~MockChunkedDataStreamUploaderDelegate() override {}
26
27 int OnRead(char* buffer, int buffer_length) override {
28 int bytes_read = 0;
29 if (data_length_ > 0) {
30 CHECK_GE(buffer_length, data_length_);
31 memcpy(buffer, data_, data_length_);
32 bytes_read = data_length_;
33 data_length_ = 0;
34 }
35 return bytes_read;
36 }
37
38 void SetReadData(const char* data, int data_length) {
39 CHECK_GE(sizeof(data_), static_cast<size_t>(data_length));
40 memcpy(data_, data, data_length);
41 data_length_ = data_length;
42 CHECK(!memcmp(data_, data, data_length));
43 }
44
45 private:
46 char data_[kDefaultIOBufferSize];
47 int data_length_;
48};
49
50class ChunkedDataStreamUploaderTest : public testing::Test {
51 public:
52 ChunkedDataStreamUploaderTest() : callback_count(0) {
53 delegate_ = std::make_unique<MockChunkedDataStreamUploaderDelegate>();
54 uploader_owner_ =
55 std::make_unique<ChunkedDataStreamUploader>(delegate_.get());
56 uploader_ = uploader_owner_->GetWeakPtr();
57
58 uploader_owner_->Init(base::BindRepeating([](int) {}),
59 net::NetLogWithSource());
60 }
61
62 void CompletionCallback(int result) { ++callback_count; }
63
64 protected:
65 std::unique_ptr<MockChunkedDataStreamUploaderDelegate> delegate_;
66
67 std::unique_ptr<ChunkedDataStreamUploader> uploader_owner_;
68 base::WeakPtr<ChunkedDataStreamUploader> uploader_;
69
70 // Completion callback counter for each case.
71 int callback_count;
72};
73
74// Tests that data from the application layer become ready before the network
75// layer callback.
76TEST_F(ChunkedDataStreamUploaderTest, ExternalDataReadyFirst) {
77 // Application layer data is ready.
78 const char kTestData[] = "Hello world!";
79 delegate_->SetReadData(kTestData, sizeof(kTestData));
80 uploader_->UploadWhenReady(false);
81
82 // Network layer callback is called next, and the application data is expected
83 // to be read to the |buffer|.
84 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kDefaultIOBufferSize);
85 int bytes_read = uploader_->Read(
86 buffer.get(), kDefaultIOBufferSize,
87 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
88 base::Unretained(this)));
89
90 EXPECT_EQ(sizeof(kTestData), static_cast<size_t>(bytes_read));
91 EXPECT_FALSE(
92 memcmp(kTestData, buffer->data(), static_cast<size_t>(bytes_read)));
93
94 // Application finishes data upload. Called after all data has been uploaded.
95 delegate_->SetReadData("", 0);
96 uploader_->UploadWhenReady(true);
97 bytes_read = uploader_->Read(
98 buffer.get(), kDefaultIOBufferSize,
99 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
100 base::Unretained(this)));
101 EXPECT_EQ(0, bytes_read);
102 EXPECT_TRUE(uploader_->IsEOF());
103
104 // No completion callback is called because Read() call should return
105 // directly.
106 EXPECT_EQ(0, callback_count);
107}
108
109// Tests that callback from the network layer is called before the application
110// layer data available.
111TEST_F(ChunkedDataStreamUploaderTest, InternalReadReadyFirst) {
112 // Network layer callback is called and the request is pending.
113 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kDefaultIOBufferSize);
114 int ret = uploader_->Read(
115 buffer.get(), kDefaultIOBufferSize,
116 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
117 base::Unretained(this)));
118 EXPECT_EQ(ERR_IO_PENDING, ret);
119
120 // The data is writen into |buffer| once the application layer data is ready.
121 const char kTestData[] = "Hello world!";
122 delegate_->SetReadData(kTestData, sizeof(kTestData));
123 uploader_->UploadWhenReady(false);
124 EXPECT_FALSE(memcmp(kTestData, buffer->data(), sizeof(kTestData)));
125
126 // Callback is called again after a successful read.
127 ret = uploader_->Read(
128 buffer.get(), kDefaultIOBufferSize,
129 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
130 base::Unretained(this)));
131 EXPECT_EQ(ERR_IO_PENDING, ret);
132
133 // No more data is available, and the upload will be finished.
134 delegate_->SetReadData("", 0);
135 uploader_->UploadWhenReady(true);
136 EXPECT_TRUE(uploader_->IsEOF());
137
138 EXPECT_EQ(2, callback_count);
139}
140
141// Tests that null data is correctly handled when the callback comes first.
142TEST_F(ChunkedDataStreamUploaderTest, NullContentWithReadFirst) {
143 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kDefaultIOBufferSize);
144 int ret = uploader_->Read(
145 buffer.get(), kDefaultIOBufferSize,
146 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
147 base::Unretained(this)));
148 EXPECT_EQ(ERR_IO_PENDING, ret);
149
150 delegate_->SetReadData("", 0);
151 uploader_->UploadWhenReady(true);
152 EXPECT_TRUE(uploader_->IsEOF());
153
154 EXPECT_EQ(1, callback_count);
155}
156
157// Tests that null data is correctly handled when data is available first.
158TEST_F(ChunkedDataStreamUploaderTest, NullContentWithDataFirst) {
159 delegate_->SetReadData("", 0);
160 uploader_->UploadWhenReady(true);
161
162 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kDefaultIOBufferSize);
163 int bytes_read = uploader_->Read(
164 buffer.get(), kDefaultIOBufferSize,
165 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
166 base::Unretained(this)));
167 EXPECT_EQ(0, bytes_read);
168 EXPECT_TRUE(uploader_->IsEOF());
169
170 EXPECT_EQ(0, callback_count);
171}
172
173// A complex test case that the application layer data and network layer
174// callback becomes ready first reciprocally.
175TEST_F(ChunkedDataStreamUploaderTest, MixedScenarioTest) {
176 // Data comes first.
177 const char kTestData[] = "Hello world!";
178 delegate_->SetReadData(kTestData, sizeof(kTestData));
179 uploader_->UploadWhenReady(false);
180
181 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kDefaultIOBufferSize);
182 int bytes_read = uploader_->Read(
183 buffer.get(), kDefaultIOBufferSize,
184 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
185 base::Unretained(this)));
186 EXPECT_EQ(sizeof(kTestData), static_cast<size_t>(bytes_read));
187 EXPECT_FALSE(
188 memcmp(kTestData, buffer->data(), static_cast<size_t>(bytes_read)));
189
190 // Callback comes first.
191 int ret = uploader_->Read(
192 buffer.get(), kDefaultIOBufferSize,
193 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
194 base::Unretained(this)));
195 EXPECT_EQ(ERR_IO_PENDING, ret);
196
197 char test_data_long[kDefaultIOBufferSize];
198 for (int i = 0; i < static_cast<int>(sizeof(test_data_long)); ++i) {
199 test_data_long[i] = static_cast<char>(i & 0xFF);
200 }
201 delegate_->SetReadData(test_data_long, sizeof(test_data_long));
202 uploader_->UploadWhenReady(false);
203 EXPECT_FALSE(memcmp(test_data_long, buffer->data(), sizeof(test_data_long)));
204
205 // Callback comes first again.
206 ret = uploader_->Read(
207 buffer.get(), kDefaultIOBufferSize,
208 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
209 base::Unretained(this)));
210 EXPECT_EQ(ERR_IO_PENDING, ret);
211 delegate_->SetReadData(kTestData, sizeof(kTestData));
212 uploader_->UploadWhenReady(false);
213 EXPECT_FALSE(memcmp(kTestData, buffer->data(), sizeof(kTestData)));
214
215 // Finish and data comes first.
216 delegate_->SetReadData("", 0);
217 uploader_->UploadWhenReady(true);
218 bytes_read = uploader_->Read(
219 buffer.get(), kDefaultIOBufferSize,
220 base::BindRepeating(&ChunkedDataStreamUploaderTest::CompletionCallback,
221 base::Unretained(this)));
222 EXPECT_EQ(0, bytes_read);
223 EXPECT_TRUE(uploader_->IsEOF());
224
225 // Completion callback is called only after Read() returns ERR_IO_PENDING;
226 EXPECT_EQ(2, callback_count);
227}
228
229} // namespace net