1// Copyright (C) 2013 Google Inc. 2// 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 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 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. 14 15#include "retriever.h" 16 17#include <libaddressinput/callback.h> 18#include <libaddressinput/null_storage.h> 19#include <libaddressinput/storage.h> 20#include <libaddressinput/util/scoped_ptr.h> 21 22#include <cstddef> 23#include <string> 24 25#include <gtest/gtest.h> 26 27#include "fake_downloader.h" 28#include "mock_downloader.h" 29 30#define CHECKSUM "dd63dafcbd4d5b28badfcaf86fb6fcdb" 31#define DATA "{'foo': 'bar'}" 32#define OLD_TIMESTAMP "0" 33 34namespace { 35 36using i18n::addressinput::BuildCallback; 37using i18n::addressinput::FakeDownloader; 38using i18n::addressinput::MockDownloader; 39using i18n::addressinput::NullStorage; 40using i18n::addressinput::Retriever; 41using i18n::addressinput::Storage; 42using i18n::addressinput::scoped_ptr; 43 44const char kKey[] = "data/CA/AB--fr"; 45 46// Empty data that the downloader can return. 47const char kEmptyData[] = "{}"; 48 49// The value of the data that the stale storage returns. 50const char kStaleData[] = DATA; 51 52// The actual data that the stale storage returns. 53const char kStaleWrappedData[] = "timestamp=" OLD_TIMESTAMP "\n" 54 "checksum=" CHECKSUM "\n" 55 DATA; 56 57// Tests for Retriever object. 58class RetrieverTest : public testing::Test { 59 protected: 60 RetrieverTest() 61 : retriever_(FakeDownloader::kFakeDataUrl, 62 new FakeDownloader, 63 new NullStorage), 64 success_(false), 65 key_(), 66 data_() {} 67 68 virtual ~RetrieverTest() {} 69 70 Retriever::Callback* BuildCallback() { 71 return ::BuildCallback(this, &RetrieverTest::OnDataReady); 72 } 73 74 Retriever retriever_; 75 bool success_; 76 std::string key_; 77 std::string data_; 78 79 private: 80 void OnDataReady(bool success, 81 const std::string& key, 82 const std::string& data) { 83 success_ = success; 84 key_ = key; 85 data_ = data; 86 } 87}; 88 89TEST_F(RetrieverTest, RetrieveData) { 90 scoped_ptr<Retriever::Callback> callback(BuildCallback()); 91 retriever_.Retrieve(kKey, *callback); 92 93 EXPECT_TRUE(success_); 94 EXPECT_EQ(kKey, key_); 95 EXPECT_FALSE(data_.empty()); 96 EXPECT_NE(kEmptyData, data_); 97} 98 99TEST_F(RetrieverTest, ReadDataFromStorage) { 100 scoped_ptr<Retriever::Callback> callback1(BuildCallback()); 101 retriever_.Retrieve(kKey, *callback1); 102 103 scoped_ptr<Retriever::Callback> callback2(BuildCallback()); 104 retriever_.Retrieve(kKey, *callback2); 105 106 EXPECT_TRUE(success_); 107 EXPECT_EQ(kKey, key_); 108 EXPECT_FALSE(data_.empty()); 109 EXPECT_NE(kEmptyData, data_); 110} 111 112TEST_F(RetrieverTest, MissingKeyReturnsEmptyData) { 113 static const char kMissingKey[] = "junk"; 114 115 scoped_ptr<Retriever::Callback> callback(BuildCallback()); 116 retriever_.Retrieve(kMissingKey, *callback); 117 118 EXPECT_TRUE(success_); 119 EXPECT_EQ(kMissingKey, key_); 120 EXPECT_EQ(kEmptyData, data_); 121} 122 123TEST_F(RetrieverTest, FaultyDownloader) { 124 // An empty MockDownloader will fail for any request. 125 Retriever bad_retriever(MockDownloader::kMockDataUrl, 126 new MockDownloader, 127 new NullStorage); 128 129 scoped_ptr<Retriever::Callback> callback(BuildCallback()); 130 bad_retriever.Retrieve(kKey, *callback); 131 132 EXPECT_FALSE(success_); 133 EXPECT_EQ(kKey, key_); 134 EXPECT_TRUE(data_.empty()); 135} 136 137// The storage that always returns stale data. 138class StaleStorage : public Storage { 139 public: 140 StaleStorage() : data_updated_(false) {} 141 virtual ~StaleStorage() {} 142 143 // Storage implementation. 144 virtual void Get(const std::string& key, const Callback& data_ready) const { 145 data_ready(true, key, new std::string(kStaleWrappedData)); 146 } 147 148 virtual void Put(const std::string& key, std::string* value) { 149 ASSERT_TRUE(value != NULL); 150 data_updated_ = true; 151 delete value; 152 } 153 154 bool data_updated_; 155 156 private: 157 DISALLOW_COPY_AND_ASSIGN(StaleStorage); 158}; 159 160TEST_F(RetrieverTest, UseStaleDataWhenDownloaderFails) { 161 // Owned by |resilient_retriver|. 162 StaleStorage* stale_storage = new StaleStorage; 163 // An empty MockDownloader will fail for any request. 164 Retriever resilient_retriever( 165 MockDownloader::kMockDataUrl, new MockDownloader, stale_storage); 166 167 scoped_ptr<Retriever::Callback> callback(BuildCallback()); 168 resilient_retriever.Retrieve(kKey, *callback); 169 170 EXPECT_TRUE(success_); 171 EXPECT_EQ(kKey, key_); 172 EXPECT_EQ(kStaleData, data_); 173 EXPECT_FALSE(stale_storage->data_updated_); 174} 175 176TEST_F(RetrieverTest, DoNotUseStaleDataWhenDownloaderSucceeds) { 177 // Owned by |resilient_retriver|. 178 StaleStorage* stale_storage = new StaleStorage; 179 Retriever resilient_retriever( 180 FakeDownloader::kFakeDataUrl, new FakeDownloader, stale_storage); 181 182 scoped_ptr<Retriever::Callback> callback(BuildCallback()); 183 resilient_retriever.Retrieve(kKey, *callback); 184 185 EXPECT_TRUE(success_); 186 EXPECT_EQ(kKey, key_); 187 EXPECT_FALSE(data_.empty()); 188 EXPECT_NE(kEmptyData, data_); 189 EXPECT_NE(kStaleData, data_); 190 EXPECT_TRUE(stale_storage->data_updated_); 191} 192 193} // namespace 194