1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/bind.h"
6#include "base/bind_helpers.h"
7#include "base/strings/string_util.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/geolocation/chrome_access_token_store.h"
10#include "chrome/test/base/in_process_browser_test.h"
11#include "chrome/test/base/ui_test_utils.h"
12#include "content/public/browser/access_token_store.h"
13#include "content/public/test/test_browser_thread.h"
14
15using content::AccessTokenStore;
16using content::BrowserThread;
17
18namespace {
19
20// The token store factory implementation expects to be used from any well-known
21// chrome thread other than UI. We could use any arbitrary thread; IO is
22// a good choice as this is the expected usage.
23const BrowserThread::ID kExpectedClientThreadId = BrowserThread::IO;
24const char* kRefServerUrl1 = "https://test.domain.example/foo?id=bar.bar";
25const char* kRefServerUrl2 = "http://another.domain.example/foo?id=bar.bar#2";
26const char* kOldDefaultNetworkProviderUrl = "https://www.google.com/loc/json";
27
28class GeolocationAccessTokenStoreTest
29    : public InProcessBrowserTest {
30 public:
31  GeolocationAccessTokenStoreTest()
32      : token_to_expect_(NULL), token_to_set_(NULL) {}
33
34  void DoTestStepAndWaitForResults(
35      const char* ref_url, const base::string16* token_to_expect,
36      const base::string16* token_to_set);
37
38  void OnAccessTokenStoresLoaded(
39      AccessTokenStore::AccessTokenSet access_token_set,
40      net::URLRequestContextGetter* context_getter);
41
42  scoped_refptr<AccessTokenStore> token_store_;
43  GURL ref_url_;
44  const base::string16* token_to_expect_;
45  const base::string16* token_to_set_;
46};
47
48void StartTestStepFromClientThread(
49    scoped_refptr<AccessTokenStore>* store,
50    const AccessTokenStore::LoadAccessTokensCallbackType& callback) {
51  ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId));
52  if (store->get() == NULL)
53    (*store) = new ChromeAccessTokenStore();
54  (*store)->LoadAccessTokens(callback);
55}
56
57struct TokenLoadClientForTest {
58  void NotReachedCallback(AccessTokenStore::AccessTokenSet /*tokens*/,
59                          net::URLRequestContextGetter* /*context_getter*/) {
60    NOTREACHED() << "This request should have been canceled before callback";
61  }
62};
63
64void GeolocationAccessTokenStoreTest::DoTestStepAndWaitForResults(
65    const char* ref_url, const base::string16* token_to_expect,
66    const base::string16* token_to_set) {
67  ref_url_ = GURL(ref_url);
68  token_to_expect_ = token_to_expect;
69  token_to_set_ = token_to_set;
70
71  BrowserThread::PostTask(
72      kExpectedClientThreadId, FROM_HERE,
73      base::Bind(
74          &StartTestStepFromClientThread,
75          &token_store_,
76          base::Bind(
77              &GeolocationAccessTokenStoreTest::OnAccessTokenStoresLoaded,
78              base::Unretained(this))));
79  content::RunMessageLoop();
80}
81
82void GeolocationAccessTokenStoreTest::OnAccessTokenStoresLoaded(
83    AccessTokenStore::AccessTokenSet access_token_set,
84    net::URLRequestContextGetter* context_getter) {
85  ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId))
86      << "Callback from token factory should be from the same thread as the "
87         "LoadAccessTokenStores request was made on";
88  DCHECK(context_getter);
89  AccessTokenStore::AccessTokenSet::const_iterator item =
90      access_token_set.find(ref_url_);
91  if (!token_to_expect_) {
92    EXPECT_TRUE(item == access_token_set.end());
93  } else {
94    EXPECT_FALSE(item == access_token_set.end());
95    EXPECT_EQ(*token_to_expect_, item->second);
96  }
97
98  if (token_to_set_) {
99    scoped_refptr<AccessTokenStore> store(new ChromeAccessTokenStore());
100    store->SaveAccessToken(ref_url_, *token_to_set_);
101  }
102  BrowserThread::PostTask(
103      BrowserThread::UI, FROM_HERE, base::MessageLoop::QuitClosure());
104}
105
106IN_PROC_BROWSER_TEST_F(GeolocationAccessTokenStoreTest, SetAcrossInstances) {
107  const base::string16 ref_token1 = base::ASCIIToUTF16("jksdfo90,'s#\"#1*(");
108  const base::string16 ref_token2 =
109      base::ASCIIToUTF16("\1\2\3\4\5\6\7\10\11\12=023");
110  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
111
112  DoTestStepAndWaitForResults(kRefServerUrl1, NULL, &ref_token1);
113  // Check it was set, and change to new value.
114  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, &ref_token2);
115  // And change back.
116  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token2, &ref_token1);
117  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, NULL);
118
119  // Set a second server URL
120  DoTestStepAndWaitForResults(kRefServerUrl2, NULL, &ref_token2);
121  DoTestStepAndWaitForResults(kRefServerUrl2, &ref_token2, NULL);
122  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, NULL);
123}
124
125IN_PROC_BROWSER_TEST_F(GeolocationAccessTokenStoreTest, OldUrlRemoval) {
126  const base::string16 ref_token1 = base::ASCIIToUTF16("jksdfo90,'s#\"#1*(");
127  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
128
129  // Set a token for the old default network provider url.
130  DoTestStepAndWaitForResults(kOldDefaultNetworkProviderUrl,
131                              NULL, &ref_token1);
132  // Check that the token related to the old default network provider url
133  // was deleted.
134  DoTestStepAndWaitForResults(kOldDefaultNetworkProviderUrl,
135                              NULL, NULL);
136}
137
138}  // namespace
139