blob: 54d4af8b669c236f1815993c0670549484813894 [file] [log] [blame]
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Author: mdw@google.com (Matt Welsh)
// Unit-tests for ProxyFetch and related classes
#include "pagespeed/automatic/proxy_fetch.h"
#include "base/logging.h"
#include "net/instaweb/http/public/log_record.h"
#include "net/instaweb/http/public/logging_proto_impl.h"
#include "net/instaweb/http/public/mock_callback.h"
#include "net/instaweb/http/public/request_context.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/rewrite_test_base.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "pagespeed/kernel/base/abstract_mutex.h"
#include "pagespeed/kernel/base/function.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/null_message_handler.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/thread_system.h"
#include "pagespeed/kernel/html/html_parse_test_base.h"
#include "pagespeed/kernel/http/http_names.h"
#include "pagespeed/kernel/http/request_headers.h"
#include "pagespeed/kernel/http/response_headers.h"
#include "pagespeed/kernel/thread/thread_synchronizer.h"
#include "pagespeed/kernel/thread/worker_test_base.h"
#include "pagespeed/kernel/util/platform.h"
namespace net_instaweb {
// A stripped-down mock of ProxyFetch, used for testing PropertyCacheComplete().
class MockProxyFetch : public ProxyFetch {
public:
MockProxyFetch(AsyncFetch* async_fetch,
ProxyFetchFactory* factory,
ServerContext* server_context)
: ProxyFetch("http://www.google.com", false,
NULL, // callback
async_fetch,
NULL, // no original content fetch
GetNewRewriteDriver(server_context, async_fetch),
server_context,
NULL, // timer
factory),
complete_(false) {
response_headers()->set_status_code(HttpStatus::kOK);
}
~MockProxyFetch() { }
static RewriteDriver* GetNewRewriteDriver(ServerContext* server_context,
AsyncFetch* async_fetch) {
RewriteDriver* driver = server_context->NewRewriteDriver(
async_fetch->request_context());
RequestHeaders headers;
driver->SetRequestHeaders(headers);
return driver;
}
void PropertyCacheComplete(
ProxyFetchPropertyCallbackCollector* callback_collector) {
complete_ = true;
}
void Done(bool success) {
HandleDone(success);
}
bool complete() const { return complete_; }
RewriteDriver* driver() const { return driver_; }
private:
bool complete_;
DISALLOW_COPY_AND_ASSIGN(MockProxyFetch);
};
// A wrapper around MockProxyFetch that manages all objects on the heap and
// initializes things for no parsing and then parses a token script. You must
// NOT call Done() on the MockProxyFetch object as we do it in our destructor.
class ManagedMockProxyFetch {
public:
ManagedMockProxyFetch(ServerContext* server_context,
bool allow_options_to_be_set_by_cookies,
StringPiece sticky_query_parameters,
StringPiece sticky_query_parameters_token,
StringPiece query_params, StringPiece option_cookies) {
server_context->global_options()->ClearSignatureForTesting();
server_context->global_options()->set_allow_options_to_be_set_by_cookies(
allow_options_to_be_set_by_cookies);
server_context->global_options()->set_sticky_query_parameters(
sticky_query_parameters);
// Suppresses parsing and the invocation of mock_proxy_fetch_->Done().
server_context->global_options()->set_max_html_parse_bytes(0L);
server_context->global_options()->ComputeSignature();
message_handler_.reset(new NullMessageHandler());
async_fetch_.reset(new StringAsyncFetch(
RequestContext::NewTestRequestContext(
server_context->thread_system())));
async_fetch_->response_headers()->Add("Content-Type", "text/html");
async_fetch_->response_headers()->ComputeCaching();
async_fetch_->request_context()->set_sticky_query_parameters_token(
sticky_query_parameters_token);
fetch_factory_.reset(new ProxyFetchFactory(server_context));
mock_proxy_fetch_ = new MockProxyFetch(async_fetch_.get(),
fetch_factory_.get(),
server_context);
mock_proxy_fetch_->driver()->set_pagespeed_query_params(query_params);
mock_proxy_fetch_->driver()->set_pagespeed_option_cookies(option_cookies);
mock_proxy_fetch_->Write("<html>HTML</html>.", message_handler_.get());
mock_proxy_fetch_->Flush(message_handler_.get());
}
~ManagedMockProxyFetch() {
mock_proxy_fetch_->Done(true);
}
MockProxyFetch* mock_proxy_fetch() const { return mock_proxy_fetch_; }
private:
scoped_ptr<NullMessageHandler> message_handler_;
scoped_ptr<StringAsyncFetch> async_fetch_;
scoped_ptr<ProxyFetchFactory> fetch_factory_;
MockProxyFetch* mock_proxy_fetch_; // Not scoped_ptr as it self-deletes.
};
class ProxyFetchPropertyCallbackCollectorTest : public RewriteTestBase {
public:
void PostLookupTask() {
post_lookup_called_ = true;
}
void CheckPageNotNullPostLookupTask(
ProxyFetchPropertyCallbackCollector* collector,
WorkerTestBase::SyncPoint* sync_point) {
EXPECT_TRUE(collector->fallback_property_page() != NULL);
sync_point->Notify();
}
void AddCheckPageNotNullPostLookupTask(
ProxyFetchPropertyCallbackCollector* collector,
WorkerTestBase::SyncPoint* sync_point) {
collector->AddPostLookupTask(MakeFunction(
this,
&ProxyFetchPropertyCallbackCollectorTest::
CheckPageNotNullPostLookupTask,
collector,
sync_point));
}
protected:
ProxyFetchPropertyCallbackCollectorTest() :
thread_system_(Platform::CreateThreadSystem()),
server_context_(server_context()),
post_lookup_called_(false) {
}
scoped_ptr<ThreadSystem> thread_system_;
ServerContext* server_context_;
// Create a collector.
ProxyFetchPropertyCallbackCollector* MakeCollector() {
ProxyFetchPropertyCallbackCollector* collector =
new ProxyFetchPropertyCallbackCollector(
server_context_, RewriteTestBase::kTestDomain,
RequestContext::NewTestRequestContext(thread_system_.get()),
options(), UserAgentMatcher::kDesktop);
// Collector should not contain any PropertyPages
EXPECT_EQ(NULL, collector->ReleasePropertyPage(
ProxyFetchPropertyCallback::kPropertyCachePage));
return collector;
}
void EnableCollectorPrefix() {
ThreadSynchronizer* sync = server_context()->thread_synchronizer();
sync->EnableForPrefix(ProxyFetch::kCollectorDoneFinish);
sync->EnableForPrefix(ProxyFetch::kCollectorDetachFinish);
sync->EnableForPrefix(ProxyFetch::kCollectorConnectProxyFetchFinish);
sync->EnableForPrefix(ProxyFetch::kCollectorRequestHeadersCompleteFinish);
}
// Add a callback to the collector.
ProxyFetchPropertyCallback* AddCallback(
ProxyFetchPropertyCallbackCollector* collector,
ProxyFetchPropertyCallback::PageType page_type) {
AbstractMutex* mutex = thread_system_->NewMutex();
DCHECK(page_type == ProxyFetchPropertyCallback::kPropertyCachePage);
ProxyFetchPropertyCallback* callback =
new ProxyFetchPropertyCallback(
page_type, page_property_cache(), RewriteTestBase::kTestDomain,
"hash", UserAgentMatcher::kDesktop, collector, mutex);
EXPECT_EQ(page_type, callback->page_type());
collector->AddCallback(callback);
return callback;
}
void AddPostLookupConnectProxyFetchCallDone(
ProxyFetchPropertyCallbackCollector* collector,
MockProxyFetch* mock_proxy_fetch,
ProxyFetchPropertyCallback* callback) {
collector->AddPostLookupTask(MakeFunction(
this, &ProxyFetchPropertyCallbackCollectorTest::PostLookupTask));
collector->ConnectProxyFetch(mock_proxy_fetch);
callback->Done(true);
}
void ConnectProxyFetchAddPostLookupCallDone(
ProxyFetchPropertyCallbackCollector* collector,
MockProxyFetch* mock_proxy_fetch,
ProxyFetchPropertyCallback* callback) {
collector->ConnectProxyFetch(mock_proxy_fetch);
collector->AddPostLookupTask(MakeFunction(
this, &ProxyFetchPropertyCallbackCollectorTest::PostLookupTask));
callback->Done(true);
}
void CallDoneAddPostLookupConnectProxyFetch(
ProxyFetchPropertyCallbackCollector* collector,
MockProxyFetch* mock_proxy_fetch,
ProxyFetchPropertyCallback* callback) {
callback->Done(true);
collector->AddPostLookupTask(MakeFunction(
this, &ProxyFetchPropertyCallbackCollectorTest::PostLookupTask));
collector->ConnectProxyFetch(mock_proxy_fetch);
}
void TestAddPostlookupTask(bool add_before_done,
bool add_before_proxy_fetch) {
EnableCollectorPrefix();
scoped_ptr<ProxyFetchPropertyCallbackCollector> collector;
collector.reset(MakeCollector());
ProxyFetchPropertyCallback* page_callback = AddCallback(
collector.get(), ProxyFetchPropertyCallback::kPropertyCachePage);
ExpectStringAsyncFetch async_fetch(
true, RequestContext::NewTestRequestContext(thread_system_.get()));
ProxyFetchFactory factory(server_context_);
MockProxyFetch* mock_proxy_fetch = new MockProxyFetch(
&async_fetch, &factory, server_context_);
if (add_before_done && add_before_proxy_fetch) {
AddPostLookupConnectProxyFetchCallDone(
collector.get(), mock_proxy_fetch, page_callback);
} else if (add_before_done && !add_before_proxy_fetch) {
ConnectProxyFetchAddPostLookupCallDone(
collector.get(), mock_proxy_fetch, page_callback);
} else if (!add_before_done && add_before_proxy_fetch) {
CallDoneAddPostLookupConnectProxyFetch(
collector.get(), mock_proxy_fetch, page_callback);
} else {
// Not handled. Make this fail.
}
collector->RequestHeadersComplete();
EXPECT_TRUE(post_lookup_called_);
mock_proxy_fetch->Done(true);
}
private:
bool post_lookup_called_;
DISALLOW_COPY_AND_ASSIGN(ProxyFetchPropertyCallbackCollectorTest);
};
// Test fixture for ProxyFetch.
class ProxyFetchTest : public RewriteTestBase {
};
TEST_F(ProxyFetchTest, TestInhibitParsing) {
NullMessageHandler handler;
server_context()->global_options()->ClearSignatureForTesting();
server_context()->global_options()->set_max_html_parse_bytes(0L);
server_context()->global_options()->ComputeSignature();
StringAsyncFetch fetch(
RequestContext::NewTestRequestContext(
server_context()->thread_system()));
fetch.response_headers()->Add("Content-Type", "text/html");
fetch.response_headers()->ComputeCaching();
ProxyFetchFactory factory(server_context_);
MockProxyFetch* mock_proxy_fetch = new MockProxyFetch(
&fetch, &factory, server_context());
mock_proxy_fetch->Write("<html>HTML</html>.", &handler);
mock_proxy_fetch->Flush(&handler);
// We never parsed the HTML, but we did log HTML content type.
EXPECT_FALSE(mock_proxy_fetch->started_parse_);
{
AbstractLogRecord* log_record =
mock_proxy_fetch->request_context()->log_record();
ScopedMutex lock(log_record->mutex());
LoggingInfo* info = log_record->logging_info();
EXPECT_TRUE(info->is_html_response());
}
mock_proxy_fetch->Done(true);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, EmptyCollectorTest) {
// Test that creating an empty collector works.
EnableCollectorPrefix();
scoped_ptr<ProxyFetchPropertyCallbackCollector> collector;
collector.reset(MakeCollector());
// This should not fail
collector->Detach(HttpStatus::kUnknownStatusCode);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, DoneBeforeDetach) {
EnableCollectorPrefix();
// Test that calling Done() before Detach() works.
ProxyFetchPropertyCallbackCollector* collector = MakeCollector();
ProxyFetchPropertyCallback* callback = AddCallback(
collector, ProxyFetchPropertyCallback::kPropertyCachePage);
// callback->IsCacheValid could be called anytime before callback->Done.
// Will return true because there are no cache invalidation URL patterns.
EXPECT_TRUE(callback->IsCacheValid(1L));
// Invoke the callback.
callback->Done(true);
// Collector should now have a page property.
scoped_ptr<AbstractPropertyPage> page;
page.reset(collector->ReleaseFallbackPropertyPage());
EXPECT_TRUE(NULL != page.get());
// This should not fail - will also delete the collector.
collector->Detach(HttpStatus::kUnknownStatusCode);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, UrlInvalidDoneBeforeDetach) {
EnableCollectorPrefix();
// Invalidate all URLs cached before timestamp 2.
options_->AddUrlCacheInvalidationEntry("*", 2L, true);
// Test that calling Done() before Detach() works.
ProxyFetchPropertyCallbackCollector* collector = MakeCollector();
ProxyFetchPropertyCallback* callback = AddCallback(
collector, ProxyFetchPropertyCallback::kPropertyCachePage);
// callback->IsCacheValid could be called anytime before callback->Done.
// Will return false due to the invalidation entry.
EXPECT_FALSE(callback->IsCacheValid(1L));
// Invoke the callback.
callback->Done(true);
// Collector should now have a page property.
scoped_ptr<AbstractPropertyPage> page;
page.reset(collector->ReleaseFallbackPropertyPage());
EXPECT_TRUE(NULL != page.get());
// This should not fail - will also delete the collector.
collector->Detach(HttpStatus::kUnknownStatusCode);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, DetachBeforeDone) {
EnableCollectorPrefix();
// Test that calling Detach() before Done() works.
ProxyFetchPropertyCallbackCollector* collector = MakeCollector();
collector->RequestHeadersComplete();
ProxyFetchPropertyCallback* callback = AddCallback(
collector, ProxyFetchPropertyCallback::kPropertyCachePage);
// callback->IsCacheValid could be called anytime before callback->Done.
// Will return true because there are no cache invalidation URL patterns.
EXPECT_TRUE(callback->IsCacheValid(1L));
// Will not delete the collector since we did not call Done yet.
collector->Detach(HttpStatus::kUnknownStatusCode);
// This call is after Detach (but before callback->Done).
// ProxyFetchPropertyCallbackCollector::IsCacheValid returns false if
// detached.
EXPECT_FALSE(callback->IsCacheValid(1L));
// This will delete the collector.
callback->Done(true);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, DoneBeforeSetProxyFetch) {
EnableCollectorPrefix();
// Test that calling Done() before SetProxyFetch() works.
scoped_ptr<ProxyFetchPropertyCallbackCollector> collector;
collector.reset(MakeCollector());
ProxyFetchPropertyCallback* callback = AddCallback(
collector.get(), ProxyFetchPropertyCallback::kPropertyCachePage);
// callback->IsCacheValid could be called anytime before callback->Done.
// Will return true because there are no cache invalidation URL patterns.
EXPECT_TRUE(callback->IsCacheValid(1L));
// Invoke the callback.
callback->Done(true);
// Construct mock ProxyFetch to test SetProxyFetch().
ExpectStringAsyncFetch async_fetch(
true, RequestContext::NewTestRequestContext(thread_system_.get()));
ProxyFetchFactory factory(server_context_);
MockProxyFetch* mock_proxy_fetch = new MockProxyFetch(
&async_fetch, &factory, server_context_);
// Should not be complete since SetProxyFetch() called first.
EXPECT_FALSE(mock_proxy_fetch->complete());
// Collector should now have a page property.
scoped_ptr<AbstractPropertyPage> page;
page.reset(collector->ReleaseFallbackPropertyPage());
EXPECT_TRUE(NULL != page.get());
collector.get()->ConnectProxyFetch(mock_proxy_fetch);
// Should be complete since SetProxyFetch() called after Done().
EXPECT_TRUE(mock_proxy_fetch->complete());
// Needed for cleanup.
mock_proxy_fetch->Done(true);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, SetProxyFetchBeforeDone) {
EnableCollectorPrefix();
// Test that calling SetProxyFetch() before Done() works.
scoped_ptr<ProxyFetchPropertyCallbackCollector> collector;
collector.reset(MakeCollector());
ProxyFetchPropertyCallback* callback = AddCallback(
collector.get(), ProxyFetchPropertyCallback::kPropertyCachePage);
// Construct mock ProxyFetch to test SetProxyFetch().
ExpectStringAsyncFetch async_fetch(
true, RequestContext::NewTestRequestContext(thread_system_.get()));
ProxyFetchFactory factory(server_context_);
MockProxyFetch* mock_proxy_fetch = new MockProxyFetch(
&async_fetch, &factory, server_context_);
// callback->IsCacheValid could be called anytime before callback->Done.
// Will return true because there are no cache invalidation URL patterns.
EXPECT_TRUE(callback->IsCacheValid(1L));
collector.get()->ConnectProxyFetch(mock_proxy_fetch);
// Should not be complete since SetProxyFetch() called first.
EXPECT_FALSE(mock_proxy_fetch->complete());
EXPECT_TRUE(callback->IsCacheValid(1L));
// Now invoke the callback.
callback->Done(true);
// Collector should now have a page property.
scoped_ptr<AbstractPropertyPage> page;
page.reset(collector->ReleaseFallbackPropertyPage());
EXPECT_TRUE(NULL != page.get());
// Not yet complete since RequestHeadersComplete() not called yet.
EXPECT_FALSE(mock_proxy_fetch->complete());
collector->RequestHeadersComplete();
// Should be complete since both Done() and RequestHeadersComplete() called.
EXPECT_TRUE(mock_proxy_fetch->complete());
// Needed for cleanup.
mock_proxy_fetch->Done(true);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, PostLookupProxyFetchDone) {
TestAddPostlookupTask(true, true);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, DonePostLookupProxyFetch) {
TestAddPostlookupTask(false, true);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, ProxyFetchPostLookupDone) {
TestAddPostlookupTask(true, false);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, FallbackPagePostLookupRace) {
EnableCollectorPrefix();
// This test will check PostLookup tasks should not have Null
// fallback_property_page.
scoped_ptr<ProxyFetchPropertyCallbackCollector> collector;
collector.reset(MakeCollector());
collector->RequestHeadersComplete();
ProxyFetchPropertyCallback* page_callback = AddCallback(
collector.get(), ProxyFetchPropertyCallback::kPropertyCachePage);
ExpectStringAsyncFetch async_fetch(
true, RequestContext::NewTestRequestContext(thread_system_.get()));
ProxyFetchFactory factory(server_context_);
MockProxyFetch* mock_proxy_fetch = new MockProxyFetch(
&async_fetch, &factory, server_context_);
ThreadSystem* thread_system = server_context()->thread_system();
QueuedWorkerPool pool(1, "test", thread_system);
QueuedWorkerPool::Sequence* sequence = pool.NewSequence();
WorkerTestBase::SyncPoint sync_point(thread_system);
sequence->Add(
MakeFunction(
static_cast<ProxyFetchPropertyCallbackCollectorTest*>(this),
&ProxyFetchPropertyCallbackCollectorTest::
AddCheckPageNotNullPostLookupTask,
collector.get(), &sync_point));
page_callback->Done(true);
sync_point.Wait();
collector->ConnectProxyFetch(mock_proxy_fetch);
mock_proxy_fetch->Done(true);
}
TEST_F(ProxyFetchPropertyCallbackCollectorTest, TestOptionsValid) {
RewriteOptions* options = new RewriteOptions(thread_system_.get());
ProxyFetchPropertyCallbackCollector* collector =
new ProxyFetchPropertyCallbackCollector(
server_context_,
RewriteTestBase::kTestDomain,
RequestContext::NewTestRequestContext(thread_system_.get()),
options,
UserAgentMatcher::kDesktop);
ThreadSynchronizer* sync = server_context()->thread_synchronizer();
sync->EnableForPrefix(ProxyFetch::kCollectorFinish);
sync->EnableForPrefix(ProxyFetch::kCollectorDetachStart);
sync->EnableForPrefix(ProxyFetch::kCollectorRequestHeadersCompleteFinish);
collector->RequestHeadersComplete();
ProxyFetchPropertyCallback* page_callback = AddCallback(
collector, ProxyFetchPropertyCallback::kPropertyCachePage);
collector->Detach(HttpStatus::kUnknownStatusCode);
delete options;
collector->IsCacheValid(1L);
sync->Signal(ProxyFetch::kCollectorDetachStart);
page_callback->Done(true);
sync->Wait(ProxyFetch::kCollectorFinish);
}
TEST_F(ProxyFetchTest, TestStickyPageSpeedOptions) {
// The various options we set as cookies.
StringPieceVector pagespeed_options;
pagespeed_options.push_back("PageSpeedImageRecompressionQuality=77");
pagespeed_options.push_back("ModPagespeedImageLimitOptimizedPercent=55");
pagespeed_options.push_back("ModPagespeedCssInlineMaxBytes=19");
GoogleString cookies = JoinCollection(pagespeed_options, "&");
// Add the sticky query param as a QP to show that it's not set as a cookie.
GoogleString params = StrCat("PageSpeedStickyQueryParameters=on&", cookies);
// For producing the expected response headers cookies string.
const char kCookiesPrefix[] = "[\"";
const char kCookieSetExpires[] = "; Expires=Tue, 02 Feb 2010 19:01:26 GMT";
const char kCookieClearExpires[] = "; Expires=Thu, 01 Jan 1970 00:00:00 GMT";
const char kCookieAttrs[] = "; Domain=www.google.com; Path=/; HttpOnly";
const char kCookiesSeparator[] = "\",\"";
const char kCookiesSuffix[] = "\"]";
GoogleString current_cookies =
StrCat(kCookiesPrefix,
JoinCollection(pagespeed_options, StrCat(kCookieSetExpires,
kCookieAttrs,
kCookiesSeparator)),
kCookieSetExpires, kCookieAttrs, kCookiesSuffix);
GoogleString expired_cookies =
StrCat(kCookiesPrefix,
JoinCollection(pagespeed_options, StrCat(kCookieClearExpires,
kCookieAttrs,
kCookiesSeparator)),
kCookieClearExpires, kCookieAttrs, kCookiesSuffix);
// Strip out the values from the expiration cookies. Pardon the hackiness.
GlobalReplaceSubstring("=77;", ";", &expired_cookies);
GlobalReplaceSubstring("=55;", ";", &expired_cookies);
GlobalReplaceSubstring("=19;", ";", &expired_cookies);
// 0. Allow options to be set by cookie but don't allow them to be sticky.
{
ManagedMockProxyFetch managed_mock(server_context_, true, "", "right value",
params, "");
MockProxyFetch* mock_proxy_fetch = managed_mock.mock_proxy_fetch();
GoogleString response_cookies;
EXPECT_FALSE(mock_proxy_fetch->response_headers()->GetCookieString(
&response_cookies));
EXPECT_STREQ("", response_cookies);
}
// 1. Allow options to be set by cookie, allow them to be sticky, but don't
// ask for stickiness in the request.
{
ManagedMockProxyFetch managed_mock(server_context_, true, "right value", "",
params, "");
MockProxyFetch* mock_proxy_fetch = managed_mock.mock_proxy_fetch();
GoogleString response_cookies;
EXPECT_FALSE(mock_proxy_fetch->response_headers()->GetCookieString(
&response_cookies));
EXPECT_STREQ("", response_cookies);
}
// 2. Don't allow options to be set by cookie, allow them to be made sticky,
// don't ask for stickiness in the request, but pass in some already-set
// cookies - these should be expired for us.
{
ManagedMockProxyFetch managed_mock(server_context_, false, "right value",
"", "", cookies);
MockProxyFetch* mock_proxy_fetch = managed_mock.mock_proxy_fetch();
GoogleString response_cookies;
EXPECT_TRUE(mock_proxy_fetch->response_headers()->GetCookieString(
&response_cookies));
EXPECT_STREQ(expired_cookies, response_cookies);
}
// 3. Allow options to be set by cookie, allow them to be made sticky, and
// ask for stickiness in the request.
{
ManagedMockProxyFetch managed_mock(server_context_, true, "right value",
"right value", params, "");
MockProxyFetch* mock_proxy_fetch = managed_mock.mock_proxy_fetch();
GoogleString response_cookies;
EXPECT_TRUE(mock_proxy_fetch->response_headers()->GetCookieString(
&response_cookies));
EXPECT_STREQ(current_cookies, response_cookies);
}
// 4. Pass in some options-as-cookies without any query params or changes.
// We expect no cookies in the response as the browser has them already.
{
ManagedMockProxyFetch managed_mock(server_context_, true, "right value", "",
"", cookies);
MockProxyFetch* mock_proxy_fetch = managed_mock.mock_proxy_fetch();
GoogleString response_cookies;
EXPECT_FALSE(mock_proxy_fetch->response_headers()->GetCookieString(
&response_cookies));
EXPECT_STREQ("", response_cookies);
}
// 5. Explicitly ask for sticky options-by-cookies to be cleared.
{
ManagedMockProxyFetch managed_mock(server_context_, true, "right value",
"different value", "", cookies);
MockProxyFetch* mock_proxy_fetch = managed_mock.mock_proxy_fetch();
GoogleString response_cookies;
EXPECT_TRUE(mock_proxy_fetch->response_headers()->GetCookieString(
&response_cookies));
EXPECT_STREQ(expired_cookies, response_cookies);
}
}
} // namespace net_instaweb