1 // Copyright (C) 2013 Google Inc.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include "retriever.h"
17 #include <libaddressinput/callback.h>
18 #include <libaddressinput/downloader.h>
19 #include <libaddressinput/storage.h>
20 #include <libaddressinput/util/scoped_ptr.h>
26 #include <gtest/gtest.h>
28 #include "fake_downloader.h"
29 #include "fake_storage.h"
30 #include "region_data_constants.h"
31 #include "time_to_string.h"
34 namespace addressinput {
38 const char kKey[] = "data/CA";
40 // Empty data that the downloader can return.
41 const char kEmptyData[] = "{}";
43 // The MD5 checksum for kEmptyData. Retriever uses MD5 to validate data
45 const char kEmptyDataChecksum[] = "99914b932bd37a50b983c5e7c90ae93b";
47 scoped_ptr<std::string> Wrap(const std::string& data,
48 const std::string& checksum,
49 const std::string& timestamp) {
50 return make_scoped_ptr(new std::string(
51 data + "\n" + "checksum=" + checksum + "\n" + "timestamp=" + timestamp));
56 // Tests for Retriever object.
57 class RetrieverTest : public testing::Test {
65 ResetRetriever(FakeDownloader::kFakeDataUrl);
68 virtual ~RetrieverTest() {}
70 scoped_ptr<Retriever::Callback> BuildCallback() {
71 return ::i18n::addressinput::BuildCallback(
72 this, &RetrieverTest::OnDataReady);
75 void ResetRetriever(const std::string& url) {
76 storage_ = new FakeStorage;
79 scoped_ptr<Downloader>(new FakeDownloader),
80 scoped_ptr<Storage>(storage_)));
83 std::string GetUrlForKey(const std::string& key) {
84 return retriever_->GetUrlForKey(key);
87 std::string GetKeyForUrl(const std::string& url) {
88 return retriever_->GetKeyForUrl(url);
91 Storage* storage_; // Owned by |retriever_|.
92 scoped_ptr<Retriever> retriever_;
98 void OnDataReady(bool success,
99 const std::string& key,
100 const std::string& data) {
107 TEST_F(RetrieverTest, RetrieveData) {
108 retriever_->Retrieve(kKey, BuildCallback());
110 EXPECT_TRUE(success_);
111 EXPECT_EQ(kKey, key_);
112 EXPECT_FALSE(data_.empty());
113 EXPECT_NE(kEmptyData, data_);
116 TEST_F(RetrieverTest, ReadDataFromStorage) {
117 retriever_->Retrieve(kKey, BuildCallback());
118 retriever_->Retrieve(kKey, BuildCallback());
120 EXPECT_TRUE(success_);
121 EXPECT_EQ(kKey, key_);
122 EXPECT_FALSE(data_.empty());
123 EXPECT_NE(kEmptyData, data_);
126 TEST_F(RetrieverTest, MissingKeyReturnsEmptyData) {
127 static const char kMissingKey[] = "junk";
129 retriever_->Retrieve(kMissingKey, BuildCallback());
131 EXPECT_TRUE(success_);
132 EXPECT_EQ(kMissingKey, key_);
133 EXPECT_EQ(kEmptyData, data_);
136 // The downloader that always fails.
137 class FaultyDownloader : public Downloader {
139 FaultyDownloader() {}
140 virtual ~FaultyDownloader() {}
142 // Downloader implementation.
143 virtual void Download(const std::string& url,
144 scoped_ptr<Callback> downloaded) {
145 (*downloaded)(false, url, make_scoped_ptr(new std::string("garbage")));
149 TEST_F(RetrieverTest, FaultyDownloader) {
150 Retriever bad_retriever(FakeDownloader::kFakeDataUrl,
151 scoped_ptr<Downloader>(new FaultyDownloader),
152 scoped_ptr<Storage>(new FakeStorage));
153 bad_retriever.Retrieve(kKey, BuildCallback());
155 EXPECT_FALSE(success_);
156 EXPECT_EQ(kKey, key_);
157 EXPECT_TRUE(data_.empty());
160 TEST_F(RetrieverTest, FaultyDownloaderFallback) {
161 Retriever bad_retriever(FakeDownloader::kFakeDataUrl,
162 scoped_ptr<Downloader>(new FaultyDownloader),
163 scoped_ptr<Storage>(new FakeStorage));
164 const char kFallbackDataKey[] = "data/US";
165 bad_retriever.Retrieve(kFallbackDataKey, BuildCallback());
167 EXPECT_TRUE(success_);
168 EXPECT_EQ(kFallbackDataKey, key_);
169 EXPECT_FALSE(data_.empty());
170 EXPECT_NE(kEmptyData, data_);
173 TEST_F(RetrieverTest, NoChecksumAndTimestampWillRedownload) {
174 storage_->Put(kKey, make_scoped_ptr(new std::string(kEmptyData)));
175 retriever_->Retrieve(kKey, BuildCallback());
176 EXPECT_TRUE(success_);
177 EXPECT_EQ(kKey, key_);
178 EXPECT_FALSE(data_.empty());
179 EXPECT_NE(kEmptyData, data_);
182 TEST_F(RetrieverTest, ChecksumAndTimestampWillNotRedownload) {
184 Wrap(kEmptyData, kEmptyDataChecksum, TimeToString(time(NULL))));
185 retriever_->Retrieve(kKey, BuildCallback());
186 EXPECT_TRUE(success_);
187 EXPECT_EQ(kKey, key_);
188 EXPECT_EQ(kEmptyData, data_);
191 TEST_F(RetrieverTest, OldTimestampWillRedownload) {
192 storage_->Put(kKey, Wrap(kEmptyData, kEmptyDataChecksum, "0"));
193 retriever_->Retrieve(kKey, BuildCallback());
194 EXPECT_TRUE(success_);
195 EXPECT_EQ(kKey, key_);
196 EXPECT_FALSE(data_.empty());
197 EXPECT_NE(kEmptyData, data_);
200 TEST_F(RetrieverTest, OldTimestampOkIfDownloadFails) {
201 storage_ = new FakeStorage;
202 Retriever bad_retriever(FakeDownloader::kFakeDataUrl,
203 scoped_ptr<Downloader>(new FaultyDownloader),
204 scoped_ptr<Storage>(storage_));
205 storage_->Put(kKey, Wrap(kEmptyData, kEmptyDataChecksum, "0"));
206 bad_retriever.Retrieve(kKey, BuildCallback());
207 EXPECT_TRUE(success_);
208 EXPECT_EQ(kKey, key_);
209 EXPECT_EQ(kEmptyData, data_);
212 TEST_F(RetrieverTest, WrongChecksumWillRedownload) {
213 static const char kNonEmptyData[] = "{\"non-empty\": \"data\"}";
216 Wrap(kNonEmptyData, kEmptyDataChecksum, TimeToString(time(NULL))));
217 retriever_->Retrieve(kKey, BuildCallback());
218 EXPECT_TRUE(success_);
219 EXPECT_EQ(kKey, key_);
220 EXPECT_FALSE(data_.empty());
221 EXPECT_NE(kNonEmptyData, data_);
224 // The downloader that doesn't get back to you.
225 class HangingDownloader : public Downloader {
227 HangingDownloader() {}
228 virtual ~HangingDownloader() {}
230 // Downloader implementation.
231 virtual void Download(const std::string& url,
232 scoped_ptr<Callback> downloaded) {}
235 TEST_F(RetrieverTest, RequestsDontStack) {
236 Retriever slow_retriever(FakeDownloader::kFakeDataUrl,
237 scoped_ptr<Downloader>(new HangingDownloader),
238 scoped_ptr<Storage>(new FakeStorage));
240 slow_retriever.Retrieve(kKey, BuildCallback());
241 EXPECT_FALSE(success_);
242 EXPECT_TRUE(key_.empty());
244 EXPECT_NO_FATAL_FAILURE(slow_retriever.Retrieve(kKey, BuildCallback()));
247 TEST_F(RetrieverTest, GetUrlForKey) {
248 ResetRetriever("test:///");
249 EXPECT_EQ("test:///", GetUrlForKey(""));
250 EXPECT_EQ("test:///data", GetUrlForKey("data"));
251 EXPECT_EQ("test:///data/US", GetUrlForKey("data/US"));
252 EXPECT_EQ("test:///data/CA--fr", GetUrlForKey("data/CA--fr"));
255 TEST_F(RetrieverTest, GetKeyForUrl) {
256 ResetRetriever("test:///");
257 EXPECT_EQ("", GetKeyForUrl("test://"));
258 EXPECT_EQ("", GetKeyForUrl("http://www.google.com/"));
259 EXPECT_EQ("", GetKeyForUrl(""));
260 EXPECT_EQ("", GetKeyForUrl("test:///"));
261 EXPECT_EQ("data", GetKeyForUrl("test:///data"));
262 EXPECT_EQ("data/US", GetKeyForUrl("test:///data/US"));
263 EXPECT_EQ("data/CA--fr", GetKeyForUrl("test:///data/CA--fr"));
266 TEST_F(RetrieverTest, NullCallbackNoCrash) {
267 ASSERT_NO_FATAL_FAILURE(
268 retriever_->Retrieve(kKey, scoped_ptr<Retriever::Callback>()));
269 ASSERT_NO_FATAL_FAILURE(
270 retriever_->Retrieve(kKey, scoped_ptr<Retriever::Callback>()));
273 } // namespace addressinput