blob: e0cf5890104c0de2a2f67d80300355874499cda7 [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.
*/
// Authors: mmohabey@google.com (Megha Mohabey)
// rahulbansal@google.com (Rahul Bansal)
#include "net/instaweb/rewriter/public/cache_html_filter.h"
#include "net/instaweb/rewriter/public/blink_util.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/test_rewrite_driver_factory.h"
#include "net/instaweb/util/public/mock_property_page.h"
#include "net/instaweb/util/public/property_cache.h"
#include "pagespeed/kernel/base/gtest.h"
#include "pagespeed/kernel/base/mock_timer.h"
#include "pagespeed/kernel/base/scoped_ptr.h"
#include "pagespeed/kernel/base/string_util.h"
#include "pagespeed/kernel/base/string_writer.h"
#include "pagespeed/kernel/http/http_names.h"
#include "pagespeed/kernel/http/response_headers.h"
namespace net_instaweb {
namespace {
const int64 kCacheTimeMs =
RewriteOptions::kDefaultPrioritizeVisibleContentCacheTimeMs;
const char kRequestUrl[] = "http://www.test.com";
const char kRequestUrlWithPath[] = "http://www.test.com/path";
const char kHtmlInput[] =
"<html>"
"<body>\n"
"<noscript></noscript>"
"<div CLASS=\"An \t \r \n item\">"
"<script></script>"
"</div>"
"<div> abcd"
"<span class=\"Item again\"></span>"
"</div>"
"<div id=\"header\"> This is the header </div>"
"<div id=\"container\" class>"
"<div><span class=\"item\"></span></div>"
"<h2 Id=\"beforeItems\"> This is before Items </h2>"
"<div class=\"another item here\">"
"<img src=\"image1\">"
"<img src=\"image2\">"
"</div>"
"<div class=\"item\">"
"<img src=\"image3\">"
"<div class=\"item\">"
"<img src=\"image4\">"
"</div>"
"</div>"
"</div>";
const char kExpectedOutput[] =
"<script>pagespeed.panelLoader.loadCookies([\"helo=world; path=/\"]);</script>" // NOLINT
"<script>pagespeed.panelLoader.loadNonCacheableObject({\"panel-id-0.0\":{\"instance_html\":\"<div CLASS=\\\"An \\t \\r \\n item\\\"><script><\\/script></div>\",\"xpath\":\"//div[2]\"}}\n);</script>" // NOLINT
"<script>pagespeed.panelLoader.loadNonCacheableObject({\"panel-id-0.1\":{\"instance_html\":\"<span class=\\\"Item again\\\"></span>\",\"xpath\":\"//div[3]/span[1]\"}}\n);</script>" // NOLINT
"<script>pagespeed.panelLoader.loadNonCacheableObject({\"panel-id-0.2\":{\"instance_html\":\"<span class=\\\"item\\\"></span>\",\"xpath\":\"//div[@id=\\\"container\\\"]/div[1]/span[1]\"}}\n);</script>" // NOLINT
"<script>pagespeed.panelLoader.loadNonCacheableObject({\"panel-id-1.0\":{\"instance_html\":\"<h2 Id=\\\"beforeItems\\\"> This is before Items </h2>\",\"xpath\":\"//div[@id=\\\"container\\\"]/h2[2]\"}}\n);</script>" // NOLINT
"<script>pagespeed.panelLoader.loadNonCacheableObject({\"panel-id-0.3\":{\"instance_html\":\"<div class=\\\"another item here\\\"><img src=\\\"image1\\\"><img src=\\\"image2\\\"></div>\",\"xpath\":\"//div[@id=\\\"container\\\"]/div[3]\"}}\n);</script>" // NOLINT
"<script>pagespeed.panelLoader.loadNonCacheableObject({\"panel-id-0.4\":{\"instance_html\":\"<div class=\\\"item\\\"><img src=\\\"image3\\\"><div class=\\\"item\\\"><img src=\\\"image4\\\"></div></div>\",\"xpath\":\"//div[@id=\\\"container\\\"]/div[4]\"}}\n);</script>" // NOLINT
"<script>pagespeed.panelLoader.bufferNonCriticalData({});</script>";
} // namespace
class CacheHtmlFilterTest : public RewriteTestBase {
public:
CacheHtmlFilterTest() {}
virtual void SetUp() {
delete options_;
options_ = new RewriteOptions(factory()->thread_system());
options_->DisableFilter(RewriteOptions::kHtmlWriterFilter);
RewriteTestBase::SetUp();
rewrite_driver()->SetWriter(&write_to_string_);
cache_html_filter_ = new CacheHtmlFilter(rewrite_driver());
html_writer_filter_.reset(cache_html_filter_);
rewrite_driver()->AddFilter(html_writer_filter_.get());
response_headers_.set_status_code(HttpStatus::kOK);
response_headers_.SetDateAndCaching(MockTimer::kApr_5_2010_ms, 0);
response_headers_.Add(HttpAttributes::kSetCookie, "helo=world; path=/");
rewrite_driver()->set_response_headers_ptr(&response_headers_);
PopulatePropertyCache();
}
void PopulatePropertyCache() {
PropertyCache* property_cache = page_property_cache();
property_cache->set_enabled(true);
SetupCohort(property_cache, BlinkUtil::kBlinkCohort);
SetupCohort(property_cache, RewriteDriver::kDomCohort);
MockPropertyPage* page = NewMockPage(kRequestUrl);
rewrite_driver()->set_property_page(page);
property_cache->Read(page);
}
void Validate(const StringPiece& url, const GoogleString& html_input,
const GoogleString& expected) {
ParseUrl(url, html_input);
EXPECT_EQ(expected, output_buffer_) << "Test url:" << url;
output_buffer_.clear();
}
bool IsCacheHtmlInfoInPropertyCache() {
PropertyCache* property_cache = page_property_cache();
const PropertyCache::Cohort* cohort = property_cache->GetCohort(
BlinkUtil::kBlinkCohort);
PropertyValue* value = rewrite_driver()->property_page()->GetProperty(
cohort, BlinkUtil::kCacheHtmlRewriterInfo);
return value != NULL && value->has_value();
}
protected:
CacheHtmlFilter* cache_html_filter_;
ResponseHeaders response_headers_;
private:
DISALLOW_COPY_AND_ASSIGN(CacheHtmlFilterTest);
};
TEST_F(CacheHtmlFilterTest, SendNonCacheable) {
options_->set_non_cacheables_for_cache_partial_html(
"class=\"item\",id='beforeItems'");
Validate(kRequestUrl, kHtmlInput, kExpectedOutput);
}
TEST_F(CacheHtmlFilterTest, SendNonCacheableWithMultipleFamilies) {
options_->set_non_cacheables_for_cache_partial_html(
"class=item,id=beforeItems");
Validate(kRequestUrlWithPath, kHtmlInput, kExpectedOutput);
}
TEST_F(CacheHtmlFilterTest, SendOnlyCookies) {
rewrite_driver()->set_flushed_cached_html(false);
GoogleString json_expected_output =
"<script>pagespeed.panelLoader.loadCookies([\"helo=world; path=/\"]);"
"</script>"
"<script>pagespeed.panelLoader.bufferNonCriticalData({});</script>";
Validate(kRequestUrl, kHtmlInput, json_expected_output);
}
} // namespace net_instaweb