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