1// Copyright (c) 2010 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 "content/browser/geolocation/access_token_store.h"
6
7#include "base/string_util.h"
8#include "base/utf_string_conversions.h"
9#include "chrome/test/in_process_browser_test.h"
10#include "chrome/test/ui_test_utils.h"
11#include "content/browser/browser_thread.h"
12
13namespace {
14
15// The token store factory implementation expects to be used from any well-known
16// chrome thread other than UI. We could use any arbitrary thread; IO is
17// a good choice as this is the expected usage.
18const BrowserThread::ID kExpectedClientThreadId = BrowserThread::IO;
19const char* kRefServerUrl1 = "https://test.domain.example/foo?id=bar.bar";
20const char* kRefServerUrl2 = "http://another.domain.example/foo?id=bar.bar#2";
21
22class GeolocationAccessTokenStoreTest
23    : public InProcessBrowserTest {
24 public:
25  GeolocationAccessTokenStoreTest()
26      : token_to_expect_(NULL), token_to_set_(NULL) {}
27
28  void DoTestStepAndWaitForResults(
29      const char* ref_url, const string16* token_to_expect,
30      const string16* token_to_set);
31
32  void OnAccessTokenStoresLoaded(
33        AccessTokenStore::AccessTokenSet access_token_set);
34
35  scoped_refptr<AccessTokenStore> token_store_;
36  CancelableRequestConsumer request_consumer_;
37  GURL ref_url_;
38  const string16* token_to_expect_;
39  const string16* token_to_set_;
40};
41
42void StartTestStepFromClientThread(
43    scoped_refptr<AccessTokenStore>* store,
44    CancelableRequestConsumerBase* consumer,
45    AccessTokenStore::LoadAccessTokensCallbackType* callback) {
46  ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId));
47  if (*store == NULL)
48    (*store) = NewChromePrefsAccessTokenStore();
49  (*store)->LoadAccessTokens(consumer, callback);
50}
51
52struct TokenLoadClientForTest {
53  void NotReachedCallback(AccessTokenStore::AccessTokenSet /*tokens*/) {
54    NOTREACHED() << "This request should have been canceled before callback";
55  }
56};
57
58void RunCancelTestInClientTread() {
59  ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId));
60  scoped_refptr<AccessTokenStore> store(NewChromePrefsAccessTokenStore());
61  CancelableRequestConsumer consumer;
62  TokenLoadClientForTest load_client;
63
64  // Single request, canceled explicitly
65  CancelableRequestProvider::Handle first_handle =
66      store->LoadAccessTokens(&consumer, NewCallback(
67          &load_client, &TokenLoadClientForTest::NotReachedCallback));
68  EXPECT_TRUE(consumer.HasPendingRequests());
69  // Test this handle is valid.
70  consumer.GetClientData(store.get(), first_handle);
71  store->CancelRequest(first_handle);
72  EXPECT_FALSE(consumer.HasPendingRequests());
73
74  // 2 requests, canceled globally.
75  store->LoadAccessTokens(&consumer, NewCallback(
76      &load_client, &TokenLoadClientForTest::NotReachedCallback));
77  store->LoadAccessTokens(&consumer, NewCallback(
78      &load_client, &TokenLoadClientForTest::NotReachedCallback));
79  EXPECT_TRUE(consumer.HasPendingRequests());
80  EXPECT_EQ(2u, consumer.PendingRequestCount());
81  consumer.CancelAllRequests();
82  EXPECT_FALSE(consumer.HasPendingRequests());
83  EXPECT_EQ(0u, consumer.PendingRequestCount());
84
85  BrowserThread::PostTask(
86      BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask);
87}
88
89void GeolocationAccessTokenStoreTest::DoTestStepAndWaitForResults(
90    const char* ref_url, const string16* token_to_expect,
91    const string16* token_to_set) {
92  ref_url_ = GURL(ref_url);
93  token_to_expect_ = token_to_expect;
94  token_to_set_ = token_to_set;
95
96  BrowserThread::PostTask(
97      kExpectedClientThreadId, FROM_HERE, NewRunnableFunction(
98          &StartTestStepFromClientThread, &token_store_, &request_consumer_,
99          NewCallback(this,
100              &GeolocationAccessTokenStoreTest::OnAccessTokenStoresLoaded)));
101  ui_test_utils::RunMessageLoop();
102}
103
104void GeolocationAccessTokenStoreTest::OnAccessTokenStoresLoaded(
105    AccessTokenStore::AccessTokenSet access_token_set) {
106  ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId))
107      << "Callback from token factory should be from the same thread as the "
108         "LoadAccessTokenStores request was made on";
109  EXPECT_TRUE(token_to_set_ || token_to_expect_) << "No work to do?";
110  AccessTokenStore::AccessTokenSet::const_iterator item =
111      access_token_set.find(ref_url_);
112  if (!token_to_expect_) {
113    EXPECT_TRUE(item == access_token_set.end());
114  } else {
115    EXPECT_FALSE(item == access_token_set.end());
116    EXPECT_EQ(*token_to_expect_, item->second);
117  }
118
119  if (token_to_set_) {
120    scoped_refptr<AccessTokenStore> store(
121        NewChromePrefsAccessTokenStore());
122    store->SaveAccessToken(ref_url_, *token_to_set_);
123  }
124  BrowserThread::PostTask(
125      BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask);
126}
127
128IN_PROC_BROWSER_TEST_F(GeolocationAccessTokenStoreTest, SetAcrossInstances) {
129  const string16 ref_token1 = ASCIIToUTF16("jksdfo90,'s#\"#1*(");
130  const string16 ref_token2 = ASCIIToUTF16("\1\2\3\4\5\6\7\10\11\12=023");
131  ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
132
133  DoTestStepAndWaitForResults(kRefServerUrl1, NULL, &ref_token1);
134  // Check it was set, and change to new value.
135  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, &ref_token2);
136  // And change back.
137  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token2, &ref_token1);
138  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, NULL);
139
140  // Set a second server URL
141  DoTestStepAndWaitForResults(kRefServerUrl2, NULL, &ref_token2);
142  DoTestStepAndWaitForResults(kRefServerUrl2, &ref_token2, NULL);
143  DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, NULL);
144}
145
146IN_PROC_BROWSER_TEST_F(GeolocationAccessTokenStoreTest, CancelRequest) {
147  BrowserThread::PostTask(
148      kExpectedClientThreadId, FROM_HERE, NewRunnableFunction(
149          RunCancelTestInClientTread));
150  ui_test_utils::RunMessageLoop();
151}
152
153}  // namespace
154