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 std::string Wrap(const std::string& data,
48 const std::string& checksum,
49 const std::string& timestamp) {
50 return data + "\n" + "checksum=" + checksum + "\n" + "timestamp=" + timestamp;
55 // Tests for Retriever object.
56 class RetrieverTest : public testing::Test {
64 ResetRetriever(FakeDownloader::kFakeDataUrl);
67 virtual ~RetrieverTest() {}
69 scoped_ptr<Retriever::Callback> BuildCallback() {
70 return ::i18n::addressinput::BuildCallback(
71 this, &RetrieverTest::OnDataReady);
74 void ResetRetriever(const std::string& url) {
75 storage_ = new FakeStorage;
78 scoped_ptr<Downloader>(new FakeDownloader),
79 scoped_ptr<Storage>(storage_)));
82 std::string GetUrlForKey(const std::string& key) {
83 return retriever_->GetUrlForKey(key);
86 std::string GetKeyForUrl(const std::string& url) {
87 return retriever_->GetKeyForUrl(url);
90 Storage* storage_; // Owned by |retriever_|.
91 scoped_ptr<Retriever> retriever_;
97 void OnDataReady(bool success,
98 const std::string& key,
99 const std::string& data) {
106 TEST_F(RetrieverTest, RetrieveData) {
107 retriever_->Retrieve(kKey, BuildCallback());
109 EXPECT_TRUE(success_);
110 EXPECT_EQ(kKey, key_);
111 EXPECT_FALSE(data_.empty());
112 EXPECT_NE(kEmptyData, data_);
115 TEST_F(RetrieverTest, ReadDataFromStorage) {
116 retriever_->Retrieve(kKey, BuildCallback());
117 retriever_->Retrieve(kKey, BuildCallback());
119 EXPECT_TRUE(success_);
120 EXPECT_EQ(kKey, key_);
121 EXPECT_FALSE(data_.empty());
122 EXPECT_NE(kEmptyData, data_);
125 TEST_F(RetrieverTest, MissingKeyReturnsEmptyData) {
126 static const char kMissingKey[] = "junk";
128 retriever_->Retrieve(kMissingKey, BuildCallback());
130 EXPECT_TRUE(success_);
131 EXPECT_EQ(kMissingKey, key_);
132 EXPECT_EQ(kEmptyData, data_);
135 // The downloader that always fails.
136 class FaultyDownloader : public Downloader {
138 FaultyDownloader() {}
139 virtual ~FaultyDownloader() {}
141 // Downloader implementation.
142 virtual void Download(const std::string& url,
143 scoped_ptr<Callback> downloaded) {
144 (*downloaded)(false, url, make_scoped_ptr(new std::string("garbage")));
148 TEST_F(RetrieverTest, FaultyDownloader) {
149 Retriever bad_retriever(FakeDownloader::kFakeDataUrl,
150 scoped_ptr<Downloader>(new FaultyDownloader),
151 scoped_ptr<Storage>(new FakeStorage));
152 bad_retriever.Retrieve(kKey, BuildCallback());
154 EXPECT_FALSE(success_);
155 EXPECT_EQ(kKey, key_);
156 EXPECT_TRUE(data_.empty());
159 TEST_F(RetrieverTest, FaultyDownloaderFallback) {
160 Retriever bad_retriever(FakeDownloader::kFakeDataUrl,
161 scoped_ptr<Downloader>(new FaultyDownloader),
162 scoped_ptr<Storage>(new FakeStorage));
163 const char kFallbackDataKey[] = "data/US";
164 bad_retriever.Retrieve(kFallbackDataKey, BuildCallback());
166 EXPECT_TRUE(success_);
167 EXPECT_EQ(kFallbackDataKey, key_);
168 EXPECT_FALSE(data_.empty());
169 EXPECT_NE(kEmptyData, data_);
172 TEST_F(RetrieverTest, NoChecksumAndTimestampWillRedownload) {
173 storage_->Put(kKey, kEmptyData);
174 retriever_->Retrieve(kKey, BuildCallback());
175 EXPECT_TRUE(success_);
176 EXPECT_EQ(kKey, key_);
177 EXPECT_FALSE(data_.empty());
178 EXPECT_NE(kEmptyData, data_);
181 TEST_F(RetrieverTest, ChecksumAndTimestampWillNotRedownload) {
183 Wrap(kEmptyData, kEmptyDataChecksum, TimeToString(time(NULL))));
184 retriever_->Retrieve(kKey, BuildCallback());
185 EXPECT_TRUE(success_);
186 EXPECT_EQ(kKey, key_);
187 EXPECT_EQ(kEmptyData, data_);
190 TEST_F(RetrieverTest, OldTimestampWillRedownload) {
191 storage_->Put(kKey, Wrap(kEmptyData, kEmptyDataChecksum, "0"));
192 retriever_->Retrieve(kKey, BuildCallback());
193 EXPECT_TRUE(success_);
194 EXPECT_EQ(kKey, key_);
195 EXPECT_FALSE(data_.empty());
196 EXPECT_NE(kEmptyData, data_);
199 TEST_F(RetrieverTest, OldTimestampOkIfDownloadFails) {
200 storage_ = new FakeStorage;
201 Retriever bad_retriever(FakeDownloader::kFakeDataUrl,
202 scoped_ptr<Downloader>(new FaultyDownloader),
203 scoped_ptr<Storage>(storage_));
204 storage_->Put(kKey, Wrap(kEmptyData, kEmptyDataChecksum, "0"));
205 bad_retriever.Retrieve(kKey, BuildCallback());
206 EXPECT_TRUE(success_);
207 EXPECT_EQ(kKey, key_);
208 EXPECT_EQ(kEmptyData, data_);
211 TEST_F(RetrieverTest, WrongChecksumWillRedownload) {
212 static const char kNonEmptyData[] = "{\"non-empty\": \"data\"}";
215 Wrap(kNonEmptyData, kEmptyDataChecksum, TimeToString(time(NULL))));
216 retriever_->Retrieve(kKey, BuildCallback());
217 EXPECT_TRUE(success_);
218 EXPECT_EQ(kKey, key_);
219 EXPECT_FALSE(data_.empty());
220 EXPECT_NE(kNonEmptyData, data_);
223 // The downloader that doesn't get back to you.
224 class HangingDownloader : public Downloader {
226 HangingDownloader() {}
227 virtual ~HangingDownloader() {}
229 // Downloader implementation.
230 virtual void Download(const std::string& url,
231 scoped_ptr<Callback> downloaded) {}
234 TEST_F(RetrieverTest, RequestsDontStack) {
235 Retriever slow_retriever(FakeDownloader::kFakeDataUrl,
236 scoped_ptr<Downloader>(new HangingDownloader),
237 scoped_ptr<Storage>(new FakeStorage));
239 slow_retriever.Retrieve(kKey, BuildCallback());
240 EXPECT_FALSE(success_);
241 EXPECT_TRUE(key_.empty());
243 EXPECT_NO_FATAL_FAILURE(slow_retriever.Retrieve(kKey, BuildCallback()));
246 TEST_F(RetrieverTest, GetUrlForKey) {
247 ResetRetriever("test:///");
248 EXPECT_EQ("test:///", GetUrlForKey(""));
249 EXPECT_EQ("test:///data", GetUrlForKey("data"));
250 EXPECT_EQ("test:///data/US", GetUrlForKey("data/US"));
251 EXPECT_EQ("test:///data/CA--fr", GetUrlForKey("data/CA--fr"));
254 TEST_F(RetrieverTest, GetKeyForUrl) {
255 ResetRetriever("test:///");
256 EXPECT_EQ("", GetKeyForUrl("test://"));
257 EXPECT_EQ("", GetKeyForUrl("http://www.google.com/"));
258 EXPECT_EQ("", GetKeyForUrl(""));
259 EXPECT_EQ("", GetKeyForUrl("test:///"));
260 EXPECT_EQ("data", GetKeyForUrl("test:///data"));
261 EXPECT_EQ("data/US", GetKeyForUrl("test:///data/US"));
262 EXPECT_EQ("data/CA--fr", GetKeyForUrl("test:///data/CA--fr"));
265 TEST_F(RetrieverTest, NullCallbackNoCrash) {
266 ASSERT_NO_FATAL_FAILURE(
267 retriever_->Retrieve(kKey, scoped_ptr<Retriever::Callback>()));
268 ASSERT_NO_FATAL_FAILURE(
269 retriever_->Retrieve(kKey, scoped_ptr<Retriever::Callback>()));
272 } // namespace addressinput