// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/geolocation/access_token_store.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/browser_thread.h"
namespace {
// The token store factory implementation expects to be used from any well-known
// chrome thread other than UI. We could use any arbitrary thread; IO is
// a good choice as this is the expected usage.
const BrowserThread::ID kExpectedClientThreadId = BrowserThread::IO;
const char* kRefServerUrl1 = "https://test.domain.example/foo?id=bar.bar";
const char* kRefServerUrl2 = "http://another.domain.example/foo?id=bar.bar#2";
class GeolocationAccessTokenStoreTest
: public InProcessBrowserTest {
public:
GeolocationAccessTokenStoreTest()
: token_to_expect_(NULL), token_to_set_(NULL) {}
void DoTestStepAndWaitForResults(
const char* ref_url, const string16* token_to_expect,
const string16* token_to_set);
void OnAccessTokenStoresLoaded(
AccessTokenStore::AccessTokenSet access_token_set);
scoped_refptr<AccessTokenStore> token_store_;
CancelableRequestConsumer request_consumer_;
GURL ref_url_;
const string16* token_to_expect_;
const string16* token_to_set_;
};
void StartTestStepFromClientThread(
scoped_refptr<AccessTokenStore>* store,
CancelableRequestConsumerBase* consumer,
AccessTokenStore::LoadAccessTokensCallbackType* callback) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId));
if (*store == NULL)
(*store) = NewChromePrefsAccessTokenStore();
(*store)->LoadAccessTokens(consumer, callback);
}
struct TokenLoadClientForTest {
void NotReachedCallback(AccessTokenStore::AccessTokenSet /*tokens*/) {
NOTREACHED() << "This request should have been canceled before callback";
}
};
void RunCancelTestInClientTread() {
ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId));
scoped_refptr<AccessTokenStore> store(NewChromePrefsAccessTokenStore());
CancelableRequestConsumer consumer;
TokenLoadClientForTest load_client;
// Single request, canceled explicitly
CancelableRequestProvider::Handle first_handle =
store->LoadAccessTokens(&consumer, NewCallback(
&load_client, &TokenLoadClientForTest::NotReachedCallback));
EXPECT_TRUE(consumer.HasPendingRequests());
// Test this handle is valid.
consumer.GetClientData(store.get(), first_handle);
store->CancelRequest(first_handle);
EXPECT_FALSE(consumer.HasPendingRequests());
// 2 requests, canceled globally.
store->LoadAccessTokens(&consumer, NewCallback(
&load_client, &TokenLoadClientForTest::NotReachedCallback));
store->LoadAccessTokens(&consumer, NewCallback(
&load_client, &TokenLoadClientForTest::NotReachedCallback));
EXPECT_TRUE(consumer.HasPendingRequests());
EXPECT_EQ(2u, consumer.PendingRequestCount());
consumer.CancelAllRequests();
EXPECT_FALSE(consumer.HasPendingRequests());
EXPECT_EQ(0u, consumer.PendingRequestCount());
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask);
}
void GeolocationAccessTokenStoreTest::DoTestStepAndWaitForResults(
const char* ref_url, const string16* token_to_expect,
const string16* token_to_set) {
ref_url_ = GURL(ref_url);
token_to_expect_ = token_to_expect;
token_to_set_ = token_to_set;
BrowserThread::PostTask(
kExpectedClientThreadId, FROM_HERE, NewRunnableFunction(
&StartTestStepFromClientThread, &token_store_, &request_consumer_,
NewCallback(this,
&GeolocationAccessTokenStoreTest::OnAccessTokenStoresLoaded)));
ui_test_utils::RunMessageLoop();
}
void GeolocationAccessTokenStoreTest::OnAccessTokenStoresLoaded(
AccessTokenStore::AccessTokenSet access_token_set) {
ASSERT_TRUE(BrowserThread::CurrentlyOn(kExpectedClientThreadId))
<< "Callback from token factory should be from the same thread as the "
"LoadAccessTokenStores request was made on";
EXPECT_TRUE(token_to_set_ || token_to_expect_) << "No work to do?";
AccessTokenStore::AccessTokenSet::const_iterator item =
access_token_set.find(ref_url_);
if (!token_to_expect_) {
EXPECT_TRUE(item == access_token_set.end());
} else {
EXPECT_FALSE(item == access_token_set.end());
EXPECT_EQ(*token_to_expect_, item->second);
}
if (token_to_set_) {
scoped_refptr<AccessTokenStore> store(
NewChromePrefsAccessTokenStore());
store->SaveAccessToken(ref_url_, *token_to_set_);
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE, new MessageLoop::QuitTask);
}
IN_PROC_BROWSER_TEST_F(GeolocationAccessTokenStoreTest, SetAcrossInstances) {
const string16 ref_token1 = ASCIIToUTF16("jksdfo90,'s#\"#1*(");
const string16 ref_token2 = ASCIIToUTF16("\1\2\3\4\5\6\7\10\11\12=023");
ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
DoTestStepAndWaitForResults(kRefServerUrl1, NULL, &ref_token1);
// Check it was set, and change to new value.
DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, &ref_token2);
// And change back.
DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token2, &ref_token1);
DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, NULL);
// Set a second server URL
DoTestStepAndWaitForResults(kRefServerUrl2, NULL, &ref_token2);
DoTestStepAndWaitForResults(kRefServerUrl2, &ref_token2, NULL);
DoTestStepAndWaitForResults(kRefServerUrl1, &ref_token1, NULL);
}
IN_PROC_BROWSER_TEST_F(GeolocationAccessTokenStoreTest, CancelRequest) {
BrowserThread::PostTask(
kExpectedClientThreadId, FROM_HERE, NewRunnableFunction(
RunCancelTestInClientTread));
ui_test_utils::RunMessageLoop();
}
} // namespace