// 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