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