OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/upload_list/upload_list.h" | 5 #include "components/upload_list/upload_list.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 | 10 |
11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
13 #include "base/files/scoped_temp_dir.h" | 13 #include "base/files/scoped_temp_dir.h" |
| 14 #include "base/macros.h" |
14 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
15 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
16 #include "base/run_loop.h" | 17 #include "base/run_loop.h" |
17 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
18 #include "base/test/sequenced_worker_pool_owner.h" | 19 #include "base/task_runner.h" |
| 20 #include "base/threading/thread.h" |
19 #include "base/time/time.h" | 21 #include "base/time/time.h" |
20 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
21 | 23 |
22 namespace { | 24 namespace { |
23 | 25 |
24 const char kTestUploadTime[] = "1234567890"; | 26 const char kTestUploadTime[] = "1234567890"; |
25 const char kTestUploadId[] = "0123456789abcdef"; | 27 const char kTestUploadId[] = "0123456789abcdef"; |
26 const char kTestLocalID[] = "fedcba9876543210"; | 28 const char kTestLocalID[] = "fedcba9876543210"; |
27 const char kTestCaptureTime[] = "2345678901"; | 29 const char kTestCaptureTime[] = "2345678901"; |
28 | 30 |
29 class UploadListTest : public testing::Test, | 31 class UploadListTest : public testing::Test, |
30 public UploadList::Delegate { | 32 public UploadList::Delegate { |
31 public: | 33 public: |
32 UploadListTest() : worker_pool_owner_(1, "UploadListTest") {} | 34 UploadListTest() : worker_thread_("UploadListTest") {} |
33 | 35 |
34 void SetUp() override { | 36 void SetUp() override { |
35 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | 37 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| 38 ASSERT_TRUE(worker_thread_.Start()); |
36 } | 39 } |
37 | 40 |
| 41 protected: |
38 void WriteUploadLog(const std::string& log_data) { | 42 void WriteUploadLog(const std::string& log_data) { |
39 ASSERT_GT(base::WriteFile(log_path(), log_data.c_str(), | 43 ASSERT_GT(base::WriteFile(log_path(), log_data.c_str(), |
40 static_cast<int>(log_data.size())), | 44 static_cast<int>(log_data.size())), |
41 0); | 45 0); |
42 } | 46 } |
43 | 47 |
44 void WaitForUploadList() { | 48 void WaitForUploadList() { |
45 base::RunLoop run_loop; | 49 base::RunLoop run_loop; |
46 quit_closure_ = run_loop.QuitClosure(); | 50 quit_closure_ = run_loop.QuitClosure(); |
47 run_loop.Run(); | 51 run_loop.Run(); |
48 } | 52 } |
49 | 53 |
50 // UploadList::Delegate: | 54 // UploadList::Delegate: |
51 void OnUploadListAvailable() override { | 55 void OnUploadListAvailable() override { |
52 ASSERT_FALSE(quit_closure_.is_null()); | 56 ASSERT_FALSE(quit_closure_.is_null()); |
53 quit_closure_.Run(); | 57 quit_closure_.Run(); |
54 } | 58 } |
55 | 59 |
56 const scoped_refptr<base::SequencedWorkerPool> worker_pool() { | 60 scoped_refptr<base::TaskRunner> task_runner() const { |
57 return worker_pool_owner_.pool(); | 61 return worker_thread_.task_runner(); |
58 } | 62 } |
| 63 |
59 base::FilePath log_path() { | 64 base::FilePath log_path() { |
60 return temp_dir_.path().Append(FILE_PATH_LITERAL("uploads.log")); | 65 return temp_dir_.path().Append(FILE_PATH_LITERAL("uploads.log")); |
61 } | 66 } |
62 | 67 |
63 private: | 68 private: |
64 base::MessageLoop message_loop_; | 69 base::MessageLoop message_loop_; |
65 base::ScopedTempDir temp_dir_; | 70 base::ScopedTempDir temp_dir_; |
66 base::SequencedWorkerPoolOwner worker_pool_owner_; | 71 base::Thread worker_thread_; |
67 base::Closure quit_closure_; | 72 base::Closure quit_closure_; |
| 73 |
| 74 DISALLOW_COPY_AND_ASSIGN(UploadListTest); |
68 }; | 75 }; |
69 | 76 |
70 // These tests test that UploadList can parse a vector of log entry strings of | 77 // These tests test that UploadList can parse a vector of log entry strings of |
71 // various formats to a vector of UploadInfo objects. See the UploadList | 78 // various formats to a vector of UploadInfo objects. See the UploadList |
72 // declaration for a description of the log entry string formats. | 79 // declaration for a description of the log entry string formats. |
73 | 80 |
74 // Test log entry string with upload time and upload ID. | 81 // Test log entry string with upload time and upload ID. |
75 // This is the format that crash reports are stored in. | 82 // This is the format that crash reports are stored in. |
76 TEST_F(UploadListTest, ParseUploadTimeUploadId) { | 83 TEST_F(UploadListTest, ParseUploadTimeUploadId) { |
77 std::string test_entry = kTestUploadTime; | 84 std::string test_entry = kTestUploadTime; |
78 test_entry += ","; | 85 test_entry += ","; |
79 test_entry.append(kTestUploadId); | 86 test_entry.append(kTestUploadId); |
80 WriteUploadLog(test_entry); | 87 WriteUploadLog(test_entry); |
81 | 88 |
82 scoped_refptr<UploadList> upload_list = | 89 scoped_refptr<UploadList> upload_list = |
83 new UploadList(this, log_path(), worker_pool()); | 90 new UploadList(this, log_path(), task_runner()); |
84 | 91 |
85 upload_list->LoadUploadListAsynchronously(); | 92 upload_list->LoadUploadListAsynchronously(); |
86 WaitForUploadList(); | 93 WaitForUploadList(); |
87 | 94 |
88 std::vector<UploadList::UploadInfo> uploads; | 95 std::vector<UploadList::UploadInfo> uploads; |
89 upload_list->GetUploads(999, &uploads); | 96 upload_list->GetUploads(999, &uploads); |
90 | 97 |
91 EXPECT_EQ(1u, uploads.size()); | 98 EXPECT_EQ(1u, uploads.size()); |
92 double time_double = uploads[0].upload_time.ToDoubleT(); | 99 double time_double = uploads[0].upload_time.ToDoubleT(); |
93 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); | 100 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); |
94 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); | 101 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); |
95 EXPECT_STREQ("", uploads[0].local_id.c_str()); | 102 EXPECT_STREQ("", uploads[0].local_id.c_str()); |
96 time_double = uploads[0].capture_time.ToDoubleT(); | 103 time_double = uploads[0].capture_time.ToDoubleT(); |
97 EXPECT_STREQ("0", base::DoubleToString(time_double).c_str()); | 104 EXPECT_STREQ("0", base::DoubleToString(time_double).c_str()); |
98 } | 105 } |
99 | 106 |
100 // Test log entry string with upload time, upload ID and local ID. | 107 // Test log entry string with upload time, upload ID and local ID. |
101 // This is the old format that WebRTC logs were stored in. | 108 // This is the old format that WebRTC logs were stored in. |
102 TEST_F(UploadListTest, ParseUploadTimeUploadIdLocalId) { | 109 TEST_F(UploadListTest, ParseUploadTimeUploadIdLocalId) { |
103 std::string test_entry = kTestUploadTime; | 110 std::string test_entry = kTestUploadTime; |
104 test_entry += ","; | 111 test_entry += ","; |
105 test_entry.append(kTestUploadId); | 112 test_entry.append(kTestUploadId); |
106 test_entry += ","; | 113 test_entry += ","; |
107 test_entry.append(kTestLocalID); | 114 test_entry.append(kTestLocalID); |
108 WriteUploadLog(test_entry); | 115 WriteUploadLog(test_entry); |
109 | 116 |
110 scoped_refptr<UploadList> upload_list = | 117 scoped_refptr<UploadList> upload_list = |
111 new UploadList(this, log_path(), worker_pool()); | 118 new UploadList(this, log_path(), task_runner()); |
112 | 119 |
113 upload_list->LoadUploadListAsynchronously(); | 120 upload_list->LoadUploadListAsynchronously(); |
114 WaitForUploadList(); | 121 WaitForUploadList(); |
115 | 122 |
116 std::vector<UploadList::UploadInfo> uploads; | 123 std::vector<UploadList::UploadInfo> uploads; |
117 upload_list->GetUploads(999, &uploads); | 124 upload_list->GetUploads(999, &uploads); |
118 | 125 |
119 EXPECT_EQ(1u, uploads.size()); | 126 EXPECT_EQ(1u, uploads.size()); |
120 double time_double = uploads[0].upload_time.ToDoubleT(); | 127 double time_double = uploads[0].upload_time.ToDoubleT(); |
121 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); | 128 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); |
122 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); | 129 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); |
123 EXPECT_STREQ(kTestLocalID, uploads[0].local_id.c_str()); | 130 EXPECT_STREQ(kTestLocalID, uploads[0].local_id.c_str()); |
124 time_double = uploads[0].capture_time.ToDoubleT(); | 131 time_double = uploads[0].capture_time.ToDoubleT(); |
125 EXPECT_STREQ("0", base::DoubleToString(time_double).c_str()); | 132 EXPECT_STREQ("0", base::DoubleToString(time_double).c_str()); |
126 } | 133 } |
127 | 134 |
128 // Test log entry string with upload time, upload ID and capture time. | 135 // Test log entry string with upload time, upload ID and capture time. |
129 // This is the format that WebRTC logs that only have been uploaded only are | 136 // This is the format that WebRTC logs that only have been uploaded only are |
130 // stored in. | 137 // stored in. |
131 TEST_F(UploadListTest, ParseUploadTimeUploadIdCaptureTime) { | 138 TEST_F(UploadListTest, ParseUploadTimeUploadIdCaptureTime) { |
132 std::string test_entry = kTestUploadTime; | 139 std::string test_entry = kTestUploadTime; |
133 test_entry += ","; | 140 test_entry += ","; |
134 test_entry.append(kTestUploadId); | 141 test_entry.append(kTestUploadId); |
135 test_entry += ",,"; | 142 test_entry += ",,"; |
136 test_entry.append(kTestCaptureTime); | 143 test_entry.append(kTestCaptureTime); |
137 WriteUploadLog(test_entry); | 144 WriteUploadLog(test_entry); |
138 | 145 |
139 scoped_refptr<UploadList> upload_list = | 146 scoped_refptr<UploadList> upload_list = |
140 new UploadList(this, log_path(), worker_pool()); | 147 new UploadList(this, log_path(), task_runner()); |
141 | 148 |
142 upload_list->LoadUploadListAsynchronously(); | 149 upload_list->LoadUploadListAsynchronously(); |
143 WaitForUploadList(); | 150 WaitForUploadList(); |
144 | 151 |
145 std::vector<UploadList::UploadInfo> uploads; | 152 std::vector<UploadList::UploadInfo> uploads; |
146 upload_list->GetUploads(999, &uploads); | 153 upload_list->GetUploads(999, &uploads); |
147 | 154 |
148 EXPECT_EQ(1u, uploads.size()); | 155 EXPECT_EQ(1u, uploads.size()); |
149 double time_double = uploads[0].upload_time.ToDoubleT(); | 156 double time_double = uploads[0].upload_time.ToDoubleT(); |
150 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); | 157 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); |
151 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); | 158 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); |
152 EXPECT_STREQ("", uploads[0].local_id.c_str()); | 159 EXPECT_STREQ("", uploads[0].local_id.c_str()); |
153 time_double = uploads[0].capture_time.ToDoubleT(); | 160 time_double = uploads[0].capture_time.ToDoubleT(); |
154 EXPECT_STREQ(kTestCaptureTime, base::DoubleToString(time_double).c_str()); | 161 EXPECT_STREQ(kTestCaptureTime, base::DoubleToString(time_double).c_str()); |
155 } | 162 } |
156 | 163 |
157 // Test log entry string with local ID and capture time. | 164 // Test log entry string with local ID and capture time. |
158 // This is the format that WebRTC logs that only are stored locally are stored | 165 // This is the format that WebRTC logs that only are stored locally are stored |
159 // in. | 166 // in. |
160 TEST_F(UploadListTest, ParseLocalIdCaptureTime) { | 167 TEST_F(UploadListTest, ParseLocalIdCaptureTime) { |
161 std::string test_entry = ",,"; | 168 std::string test_entry = ",,"; |
162 test_entry.append(kTestLocalID); | 169 test_entry.append(kTestLocalID); |
163 test_entry += ","; | 170 test_entry += ","; |
164 test_entry.append(kTestCaptureTime); | 171 test_entry.append(kTestCaptureTime); |
165 WriteUploadLog(test_entry); | 172 WriteUploadLog(test_entry); |
166 | 173 |
167 scoped_refptr<UploadList> upload_list = | 174 scoped_refptr<UploadList> upload_list = |
168 new UploadList(this, log_path(), worker_pool()); | 175 new UploadList(this, log_path(), task_runner()); |
169 | 176 |
170 upload_list->LoadUploadListAsynchronously(); | 177 upload_list->LoadUploadListAsynchronously(); |
171 WaitForUploadList(); | 178 WaitForUploadList(); |
172 | 179 |
173 std::vector<UploadList::UploadInfo> uploads; | 180 std::vector<UploadList::UploadInfo> uploads; |
174 upload_list->GetUploads(999, &uploads); | 181 upload_list->GetUploads(999, &uploads); |
175 | 182 |
176 EXPECT_EQ(1u, uploads.size()); | 183 EXPECT_EQ(1u, uploads.size()); |
177 double time_double = uploads[0].upload_time.ToDoubleT(); | 184 double time_double = uploads[0].upload_time.ToDoubleT(); |
178 EXPECT_STREQ("0", base::DoubleToString(time_double).c_str()); | 185 EXPECT_STREQ("0", base::DoubleToString(time_double).c_str()); |
(...skipping 11 matching lines...) Expand all Loading... |
190 std::string test_entry = kTestUploadTime; | 197 std::string test_entry = kTestUploadTime; |
191 test_entry += ","; | 198 test_entry += ","; |
192 test_entry.append(kTestUploadId); | 199 test_entry.append(kTestUploadId); |
193 test_entry += ","; | 200 test_entry += ","; |
194 test_entry.append(kTestLocalID); | 201 test_entry.append(kTestLocalID); |
195 test_entry += ","; | 202 test_entry += ","; |
196 test_entry.append(kTestCaptureTime); | 203 test_entry.append(kTestCaptureTime); |
197 WriteUploadLog(test_entry); | 204 WriteUploadLog(test_entry); |
198 | 205 |
199 scoped_refptr<UploadList> upload_list = | 206 scoped_refptr<UploadList> upload_list = |
200 new UploadList(this, log_path(), worker_pool()); | 207 new UploadList(this, log_path(), task_runner()); |
201 | 208 |
202 upload_list->LoadUploadListAsynchronously(); | 209 upload_list->LoadUploadListAsynchronously(); |
203 WaitForUploadList(); | 210 WaitForUploadList(); |
204 | 211 |
205 std::vector<UploadList::UploadInfo> uploads; | 212 std::vector<UploadList::UploadInfo> uploads; |
206 upload_list->GetUploads(999, &uploads); | 213 upload_list->GetUploads(999, &uploads); |
207 | 214 |
208 EXPECT_EQ(1u, uploads.size()); | 215 EXPECT_EQ(1u, uploads.size()); |
209 double time_double = uploads[0].upload_time.ToDoubleT(); | 216 double time_double = uploads[0].upload_time.ToDoubleT(); |
210 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); | 217 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); |
(...skipping 11 matching lines...) Expand all Loading... |
222 test_entry.append(kTestUploadId); | 229 test_entry.append(kTestUploadId); |
223 test_entry += ","; | 230 test_entry += ","; |
224 test_entry.append(kTestLocalID); | 231 test_entry.append(kTestLocalID); |
225 test_entry += ","; | 232 test_entry += ","; |
226 test_entry.append(kTestCaptureTime); | 233 test_entry.append(kTestCaptureTime); |
227 test_entry += "\n"; | 234 test_entry += "\n"; |
228 } | 235 } |
229 WriteUploadLog(test_entry); | 236 WriteUploadLog(test_entry); |
230 | 237 |
231 scoped_refptr<UploadList> upload_list = | 238 scoped_refptr<UploadList> upload_list = |
232 new UploadList(this, log_path(), worker_pool()); | 239 new UploadList(this, log_path(), task_runner()); |
233 | 240 |
234 upload_list->LoadUploadListAsynchronously(); | 241 upload_list->LoadUploadListAsynchronously(); |
235 WaitForUploadList(); | 242 WaitForUploadList(); |
236 | 243 |
237 std::vector<UploadList::UploadInfo> uploads; | 244 std::vector<UploadList::UploadInfo> uploads; |
238 upload_list->GetUploads(999, &uploads); | 245 upload_list->GetUploads(999, &uploads); |
239 | 246 |
240 EXPECT_EQ(4u, uploads.size()); | 247 EXPECT_EQ(4u, uploads.size()); |
241 for (size_t i = 0; i < uploads.size(); ++i) { | 248 for (size_t i = 0; i < uploads.size(); ++i) { |
242 double time_double = uploads[i].upload_time.ToDoubleT(); | 249 double time_double = uploads[i].upload_time.ToDoubleT(); |
(...skipping 16 matching lines...) Expand all Loading... |
259 test_entry += ","; | 266 test_entry += ","; |
260 test_entry.append(kTestCaptureTime); | 267 test_entry.append(kTestCaptureTime); |
261 test_entry += ","; | 268 test_entry += ","; |
262 test_entry.append(base::IntToString( | 269 test_entry.append(base::IntToString( |
263 static_cast<int>(UploadList::UploadInfo::State::Uploaded))); | 270 static_cast<int>(UploadList::UploadInfo::State::Uploaded))); |
264 test_entry += "\n"; | 271 test_entry += "\n"; |
265 } | 272 } |
266 WriteUploadLog(test_entry); | 273 WriteUploadLog(test_entry); |
267 | 274 |
268 scoped_refptr<UploadList> upload_list = | 275 scoped_refptr<UploadList> upload_list = |
269 new UploadList(this, log_path(), worker_pool()); | 276 new UploadList(this, log_path(), task_runner()); |
270 | 277 |
271 upload_list->LoadUploadListAsynchronously(); | 278 upload_list->LoadUploadListAsynchronously(); |
272 WaitForUploadList(); | 279 WaitForUploadList(); |
273 | 280 |
274 std::vector<UploadList::UploadInfo> uploads; | 281 std::vector<UploadList::UploadInfo> uploads; |
275 upload_list->GetUploads(999, &uploads); | 282 upload_list->GetUploads(999, &uploads); |
276 | 283 |
277 EXPECT_EQ(4u, uploads.size()); | 284 EXPECT_EQ(4u, uploads.size()); |
278 for (size_t i = 0; i < uploads.size(); ++i) { | 285 for (size_t i = 0; i < uploads.size(); ++i) { |
279 double time_double = uploads[i].upload_time.ToDoubleT(); | 286 double time_double = uploads[i].upload_time.ToDoubleT(); |
(...skipping 11 matching lines...) Expand all Loading... |
291 std::string test_entry = kTestUploadTime; | 298 std::string test_entry = kTestUploadTime; |
292 test_entry += ","; | 299 test_entry += ","; |
293 test_entry.append(kTestUploadId); | 300 test_entry.append(kTestUploadId); |
294 test_entry += ","; | 301 test_entry += ","; |
295 test_entry.append(kTestLocalID); | 302 test_entry.append(kTestLocalID); |
296 test_entry += ","; | 303 test_entry += ","; |
297 test_entry.append(kTestCaptureTime); | 304 test_entry.append(kTestCaptureTime); |
298 WriteUploadLog(test_entry); | 305 WriteUploadLog(test_entry); |
299 | 306 |
300 scoped_refptr<UploadList> upload_list = | 307 scoped_refptr<UploadList> upload_list = |
301 new UploadList(this, log_path(), worker_pool()); | 308 new UploadList(this, log_path(), task_runner()); |
302 | 309 |
303 // Queue up a bunch of loads, waiting only for the first one to complete. | 310 // Queue up a bunch of loads, waiting only for the first one to complete. |
304 // Clearing the delegate prevents the QuitClosure from being Run more than | 311 // Clearing the delegate prevents the QuitClosure from being Run more than |
305 // once. | 312 // once. |
306 for (int i = 1; i <= 20; ++i) { | 313 for (int i = 1; i <= 20; ++i) { |
307 upload_list->LoadUploadListAsynchronously(); | 314 upload_list->LoadUploadListAsynchronously(); |
308 } | 315 } |
309 WaitForUploadList(); | 316 WaitForUploadList(); |
310 upload_list->ClearDelegate(); | 317 upload_list->ClearDelegate(); |
311 | 318 |
312 // Read the list a few times to try and race one of the loads above. | 319 // Read the list a few times to try and race one of the loads above. |
313 for (int i = 1; i <= 4; ++i) { | 320 for (int i = 1; i <= 4; ++i) { |
314 std::vector<UploadList::UploadInfo> uploads; | 321 std::vector<UploadList::UploadInfo> uploads; |
315 upload_list->GetUploads(999, &uploads); | 322 upload_list->GetUploads(999, &uploads); |
316 | 323 |
317 EXPECT_EQ(1u, uploads.size()); | 324 EXPECT_EQ(1u, uploads.size()); |
318 double time_double = uploads[0].upload_time.ToDoubleT(); | 325 double time_double = uploads[0].upload_time.ToDoubleT(); |
319 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); | 326 EXPECT_STREQ(kTestUploadTime, base::DoubleToString(time_double).c_str()); |
320 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); | 327 EXPECT_STREQ(kTestUploadId, uploads[0].upload_id.c_str()); |
321 EXPECT_STREQ(kTestLocalID, uploads[0].local_id.c_str()); | 328 EXPECT_STREQ(kTestLocalID, uploads[0].local_id.c_str()); |
322 time_double = uploads[0].capture_time.ToDoubleT(); | 329 time_double = uploads[0].capture_time.ToDoubleT(); |
323 EXPECT_STREQ(kTestCaptureTime, base::DoubleToString(time_double).c_str()); | 330 EXPECT_STREQ(kTestCaptureTime, base::DoubleToString(time_double).c_str()); |
324 } | 331 } |
325 } | 332 } |
326 | 333 |
327 } // namespace | 334 } // namespace |
OLD | NEW |