| /* |
| * Copyright 2010 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: abliss@google.com (Adam Bliss) |
| |
| // Base class for tests which want a ServerContext. |
| |
| #ifndef NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_TEST_BASE_H_ |
| #define NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_TEST_BASE_H_ |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "net/instaweb/http/public/http_cache.h" |
| #include "net/instaweb/http/public/http_value.h" |
| #include "net/instaweb/http/public/logging_proto.h" |
| #include "net/instaweb/http/public/logging_proto_impl.h" |
| #include "net/instaweb/http/public/mock_url_fetcher.h" |
| #include "net/instaweb/http/public/request_context.h" |
| #include "net/instaweb/rewriter/public/resource.h" |
| #include "net/instaweb/rewriter/public/resource_namer.h" |
| // We need to include rewrite_driver.h due to covariant return of html_parse() |
| #include "net/instaweb/rewriter/public/rewrite_driver.h" |
| #include "net/instaweb/rewriter/public/rewrite_options.h" |
| #include "net/instaweb/rewriter/public/server_context.h" |
| #include "net/instaweb/rewriter/public/test_distributed_fetcher.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/basictypes.h" |
| #include "pagespeed/kernel/base/hasher.h" |
| #include "pagespeed/kernel/base/md5_hasher.h" |
| #include "pagespeed/kernel/base/mem_file_system.h" |
| #include "pagespeed/kernel/base/message_handler.h" |
| #include "pagespeed/kernel/base/mock_hasher.h" |
| #include "pagespeed/kernel/base/mock_message_handler.h" |
| // We need to include mock_timer.h to allow upcast to Timer*. |
| #include "pagespeed/kernel/base/mock_timer.h" |
| #include "pagespeed/kernel/base/scoped_ptr.h" |
| #include "pagespeed/kernel/base/statistics.h" |
| #include "pagespeed/kernel/base/string.h" |
| #include "pagespeed/kernel/base/string_util.h" |
| #include "pagespeed/kernel/base/timer.h" |
| #include "pagespeed/kernel/html/html_parse_test_base.h" |
| #include "pagespeed/kernel/html/html_writer_filter.h" |
| #include "pagespeed/kernel/http/content_type.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/http/user_agent_matcher.h" |
| #include "pagespeed/kernel/util/url_segment_encoder.h" |
| #include "pagespeed/opt/logging/request_timing_info.h" |
| |
| |
| |
| namespace net_instaweb { |
| |
| class AbstractLogRecord; |
| class CountingUrlAsyncFetcher; |
| class DelayCache; |
| class LRUCache; |
| class MockLogRecord; |
| class MockScheduler; |
| class ProcessContext; |
| class RewriteFilter; |
| class WaitUrlAsyncFetcher; |
| |
| class RewriteOptionsTestBase : public HtmlParseTestBaseNoAlloc { |
| protected: |
| RewriteOptionsTestBase() { |
| RewriteOptions::Initialize(); |
| } |
| ~RewriteOptionsTestBase() { |
| RewriteOptions::Terminate(); |
| } |
| }; |
| |
| class RewriteTestBase : public RewriteOptionsTestBase { |
| public: |
| static const char kTestData[]; // Testdata directory. |
| |
| // Beaconing key values used when downstream caching is enabled. |
| static const char kConfiguredBeaconingKey[]; |
| static const char kWrongBeaconingKey[]; |
| |
| // Specifies which server should be "active" in that rewrites and fetches |
| // will use it. The data members affected are those returned by: |
| // - factory() / other_factory() |
| // - server_context() / other_server_context() |
| // - rewrite_driver() / other_rewrite_driver() |
| // - options() / other_options() |
| enum ActiveServerFlag { |
| kPrimary, // Use the normal data members. |
| kSecondary, // Use all the other_ data members. |
| }; |
| |
| RewriteTestBase(); |
| explicit RewriteTestBase(Statistics* statistics); |
| |
| // Specifies alternate factories to be initialized on construction. |
| // By default, TestRewriteDriverFactory is used, but you can employ |
| // your own subclass of TestRewriteDriverFactory using this |
| // constructor. If you do, you probably also want to override |
| // MakeTestFactory. |
| explicit RewriteTestBase(std::pair<TestRewriteDriverFactory*, |
| TestRewriteDriverFactory*> factories); |
| virtual ~RewriteTestBase(); |
| |
| virtual void SetUp(); |
| virtual void TearDown(); |
| |
| // In this set of tests, we will provide explicit body tags, so |
| // the test harness should not add them in for our convenience. |
| // It can go ahead and add the <html> and </html>, however. |
| virtual bool AddBody() const { return false; } |
| |
| // Makes a TestRewriteDriverFactory. This can be overridden in |
| // subclasses if you need a factory with special properties. |
| // |
| // TODO(jmarantz): This is currently only used in |
| // ServeResourceFromNewContext, but should be used for factory_ and |
| // other_factory_. This would requuire a refactor, because those |
| // are created at construction; too early for subclass overrides to |
| // take effect. To deal with that, an alternate constructor is |
| // provided above so that the proper sort of factories can be passed in. |
| virtual TestRewriteDriverFactory* MakeTestFactory(); |
| |
| // Adds kRecompressJpeg, kRecompressPng, kRecompressWebp, kConvertPngToJpeg, |
| // kConvertJpegToWebp and kConvertGifToPng. |
| void AddRecompressImageFilters(); |
| |
| // Add a single rewrite filter to rewrite_driver_. |
| void AddFilter(RewriteOptions::Filter filter); |
| |
| // Add a single rewrite filter to other_rewrite_driver_. |
| void AddOtherFilter(RewriteOptions::Filter filter); |
| |
| // Add a custom rewrite filter (one without a corresponding option) |
| // to rewrite_driver and enable it. |
| void AddRewriteFilter(RewriteFilter* filter); |
| |
| // Adds a custom rewriter filter but does not register it for HTML |
| // rewriting, only for fetches. |
| void AddFetchOnlyRewriteFilter(RewriteFilter* filter); |
| |
| // Add a custom rewrite filter (one without a corresponding option) |
| // to other_rewrite_driver and enable it. |
| void AddOtherRewriteFilter(RewriteFilter* filter); |
| |
| // Sets the active context URL for purposes of XS checks of fetches |
| // on the main rewrite driver. |
| void SetBaseUrlForFetch(const StringPiece& url); |
| |
| // Populates request-headers based on the current user-agent and |
| // the attributes added via AddRequestAttribute and installs them |
| // into rewrite_driver_. |
| void SetDriverRequestHeaders(); |
| |
| // Enable downstream caching feature and set up the downstream cache |
| // rebeaconing key. |
| void SetDownstreamCacheDirectives( |
| StringPiece downstream_cache_purge_method, |
| StringPiece downstream_cache_purge_location_prefix, |
| StringPiece rebeaconing_key); |
| |
| // Set ShouldBeacon request header to the specified value. |
| void SetShouldBeaconHeader(StringPiece rebeaconing_key); |
| |
| ResourcePtr CreateResource(const StringPiece& base, const StringPiece& url); |
| |
| // Returns the main factory Timer*, which can be used for calling NowUs and |
| // NowMs. To set the time, use (Advance|Set)Time(Ms|Us), which wake up any |
| // scheduler alarms. See also AdjustTimeUsWithoutWakingAlarms which should |
| // be used with extreme care. |
| Timer* timer() { return factory()->mock_timer(); } |
| |
| // Append default headers to the given string. |
| void AppendDefaultHeaders(const ContentType& content_type, |
| GoogleString* text); |
| |
| // Like above, but also include a Link: <..>; rel="canonical" header. |
| void AppendDefaultHeadersWithCanonical(const ContentType& content_type, |
| StringPiece canonical_url, |
| GoogleString* text); |
| |
| // Append default headers to the given string, including |
| // X-Original-Content-Length for tests that depend on this. |
| void AppendDefaultHeaders(const ContentType& content_type, |
| int64 original_content_length, |
| GoogleString* text); |
| |
| void ServeResourceFromManyContexts(const GoogleString& resource_url, |
| const StringPiece& expected_content); |
| |
| void ServeResourceFromManyContextsWithUA( |
| const GoogleString& resource_url, |
| const StringPiece& expected_content, |
| const StringPiece& user_agent); |
| |
| // Test that a resource can be served from an new server that has not already |
| // constructed it. |
| void ServeResourceFromNewContext( |
| const GoogleString& resource_url, |
| const StringPiece& expected_content); |
| |
| // This definition is required by HtmlParseTestBase which defines this as |
| // pure abstract, so that the test subclass can define how it instantiates |
| // HtmlParse. |
| virtual RewriteDriver* html_parse() { return rewrite_driver_; } |
| |
| // Set default headers for a resource with content_type and Cache ttl_sec. |
| void DefaultResponseHeaders(const ContentType& content_type, int64 ttl_sec, |
| ResponseHeaders* response_headers); |
| |
| // Helper function to test resource fetching, returning true if the fetch |
| // succeeded, and modifying content. It is up to the caller to EXPECT_TRUE |
| // on the status and EXPECT_EQ on the content. |
| bool FetchResource(const StringPiece& path, const StringPiece& filter_id, |
| const StringPiece& name, const StringPiece& ext, |
| GoogleString* content); |
| bool FetchResource(const StringPiece& path, const StringPiece& filter_id, |
| const StringPiece& name, const StringPiece& ext, |
| GoogleString* content, ResponseHeaders* response); |
| |
| bool FetchResourceUrl(const StringPiece& url, GoogleString* content, |
| ResponseHeaders* response); |
| bool FetchResourceUrl(const StringPiece& url, |
| RequestHeaders* request_headers, |
| GoogleString* content, |
| ResponseHeaders* response_headers); |
| bool FetchResourceUrl(const StringPiece& url, GoogleString* content); |
| |
| // Just check if we can fetch a resource successfully, ignore response. |
| bool TryFetchResource(const StringPiece& url); |
| |
| // Use managed rewrite drivers for the test so that we see the same behavior |
| // in tests that we see in real servers. By default, tests use unmanaged |
| // drivers so that _test.cc files can add options after the driver was created |
| // and before the filters are added. |
| void SetUseManagedRewriteDrivers(bool use_managed_rewrite_drivers); |
| |
| GoogleString CssLinkHref(const StringPiece& url) { |
| return StrCat("<link rel=stylesheet href=", url, ">"); |
| } |
| |
| // Representation for a CSS <link> tag. |
| class CssLink { |
| public: |
| CssLink(const StringPiece& url, const StringPiece& content, |
| const StringPiece& media, bool supply_mock); |
| |
| // A vector of CssLink* should know how to accumulate and add. |
| class Vector : public std::vector<CssLink*> { |
| public: |
| ~Vector(); |
| void Add(const StringPiece& url, const StringPiece& content, |
| const StringPiece& media, bool supply_mock); |
| }; |
| |
| // Parses a combined CSS elementand provides the segments from which |
| // it came. |
| bool DecomposeCombinedUrl(StringPiece base_url, GoogleString* base, |
| StringVector* segments, MessageHandler* handler); |
| |
| GoogleString url_; |
| GoogleString content_; |
| GoogleString media_; |
| bool supply_mock_; |
| }; |
| |
| // Collects the hrefs for all CSS <link>s on the page. |
| void CollectCssLinks(const StringPiece& id, const StringPiece& html, |
| StringVector* css_links); |
| |
| // Collects all information about CSS links into a CssLink::Vector. |
| void CollectCssLinks(const StringPiece& id, const StringPiece& html, |
| CssLink::Vector* css_links); |
| |
| // Encode the given name (path + leaf) using the given pagespeed attributes. |
| void EncodePathAndLeaf(const StringPiece& filter_id, |
| const StringPiece& hash, |
| const StringVector& name_vector, |
| const StringPiece& ext, |
| ResourceNamer* namer); |
| |
| StringVector MultiUrl(const StringPiece& url1) { |
| StringVector v; |
| v.push_back(url1.as_string()); |
| return v; |
| } |
| |
| StringVector MultiUrl(const StringPiece& url1, const StringPiece& url2) { |
| StringVector v; |
| v.push_back(url1.as_string()); |
| v.push_back(url2.as_string()); |
| return v; |
| } |
| |
| StringVector MultiUrl(const StringPiece& url1, const StringPiece& url2, |
| const StringPiece& url3) { |
| StringVector v; |
| v.push_back(url1.as_string()); |
| v.push_back(url2.as_string()); |
| v.push_back(url3.as_string()); |
| return v; |
| } |
| |
| StringVector MultiUrl(const StringPiece& url1, const StringPiece& url2, |
| const StringPiece& url3, const StringPiece& url4) { |
| StringVector v; |
| v.push_back(url1.as_string()); |
| v.push_back(url2.as_string()); |
| v.push_back(url3.as_string()); |
| v.push_back(url4.as_string()); |
| return v; |
| } |
| |
| // Helper function to encode a resource name from its pieces using whatever |
| // encoding we are testing, either UrlNamer or TestUrlNamer. |
| GoogleString Encode(const StringPiece& path, |
| const StringPiece& filter_id, |
| const StringPiece& hash, |
| const StringPiece& name, |
| const StringPiece& ext) { |
| return Encode(path, filter_id, hash, MultiUrl(name), ext); |
| } |
| GoogleString Encode(const StringPiece& path, |
| const StringPiece& filter_id, |
| const StringPiece& hash, |
| const StringVector& name_vector, |
| const StringPiece& ext); |
| |
| // Same as Encode but specifically using UrlNamer not TestUrlNamer. |
| GoogleString EncodeNormal(const StringPiece& path, |
| const StringPiece& filter_id, |
| const StringPiece& hash, |
| const StringPiece& name, |
| const StringPiece& ext) { |
| return EncodeNormal(path, filter_id, hash, MultiUrl(name), ext); |
| } |
| GoogleString EncodeNormal(const StringPiece& path, |
| const StringPiece& filter_id, |
| const StringPiece& hash, |
| const StringVector& name_vector, |
| const StringPiece& ext); |
| |
| // Same as Encode but specifying the base URL (which is used by TestUrlNamer |
| // but is unused by UrlNamer so for it results in exactly the same as Encode). |
| GoogleString EncodeWithBase(const StringPiece& base, |
| const StringPiece& path, |
| const StringPiece& filter_id, |
| const StringPiece& hash, |
| const StringPiece& name, |
| const StringPiece& ext) { |
| return EncodeWithBase(base, path, filter_id, hash, MultiUrl(name), ext); |
| } |
| GoogleString EncodeWithBase(const StringPiece& base, |
| const StringPiece& path, |
| const StringPiece& filter_id, |
| const StringPiece& hash, |
| const StringVector& name_vector, |
| const StringPiece& ext); |
| |
| // Encode image with width and height. Use -1 for either width or height to |
| // omit it from the encoding. |
| GoogleString EncodeImage(int width, int height, |
| StringPiece filename, StringPiece hash, |
| StringPiece rewritten_ext); |
| |
| // Takes an already-encoded URL and adds options to to it. |
| GoogleString AddOptionsToEncodedUrl(const StringPiece& url, |
| const StringPiece& options); |
| |
| // If append_new_suffix is true, appends new_suffix to old_url. |
| // If append_new_suffix is false, replaces old_suffix at the end of old_url |
| // with new_suffix. |
| // Either way, precondition: old_url ends with old_suffix |
| static GoogleString ChangeSuffix( |
| StringPiece old_url, bool append_new_suffix, |
| StringPiece old_suffix, StringPiece new_suffix); |
| |
| // Overrides the async fetcher on the primary context to be a |
| // wait fetcher which permits delaying callback invocation. |
| // CallFetcherCallbacks can then be called to let the fetches complete |
| // and call the callbacks. |
| void SetupWaitFetcher(); |
| void CallFetcherCallbacks(); |
| void OtherCallFetcherCallbacks(); |
| RewriteOptions* options() const { return options_; } |
| RewriteOptions* other_options() const { return other_options_; } |
| |
| // Set the RewriteOptions to be returned by the RewriteOptionsManager. |
| void SetRewriteOptions(RewriteOptions* opts); |
| |
| // Authorizes a domain to options()->domain_lawyer(), recomputing |
| // the options signature if necessary. |
| bool AddDomain(StringPiece domain); |
| |
| // Adds an origin domain mapping to options()->domain_lawyer(), recomputing |
| // the options signature if necessary. |
| bool AddOriginDomainMapping(StringPiece to_domain, StringPiece from_domain); |
| |
| // Adds a rewrite domain mapping to options()->domain_lawyer(), recomputing |
| // the options signature if necessary. |
| bool AddRewriteDomainMapping(StringPiece to_domain, StringPiece from_domain); |
| |
| // Adds a shard to options()->domain_lawyer(), recomputing the options |
| // signature if necessary. |
| bool AddShard(StringPiece domain, StringPiece shards); |
| |
| // Helper method to test all manner of resource serving from a filter. |
| void TestServeFiles(const ContentType* content_type, |
| const StringPiece& filter_id, |
| const StringPiece& rewritten_ext, |
| const StringPiece& orig_name, |
| const StringPiece& orig_content, |
| const StringPiece& rewritten_name, |
| const StringPiece& rewritten_content); |
| |
| // Check that when we have a cache miss for a pagespeed resource we set |
| // headers to reduce the chance of it being interpreted as html. |
| void ValidateFallbackHeaderSanitization(StringPiece filter_id); |
| |
| TestRewriteDriverFactory* factory() { return factory_.get(); } |
| TestRewriteDriverFactory* other_factory() { return other_factory_.get(); } |
| |
| void UseMd5Hasher() { |
| server_context_->set_hasher(&md5_hasher_); |
| server_context_->http_cache()->set_hasher(&md5_hasher_); |
| other_server_context_->set_hasher(&md5_hasher_); |
| other_server_context_->http_cache()->set_hasher(&md5_hasher_); |
| } |
| |
| |
| void SetDefaultLongCacheHeaders(const ContentType* content_type, |
| ResponseHeaders* header) { |
| server_context_->SetDefaultLongCacheHeaders( |
| content_type, StringPiece(), StringPiece(), header); |
| } |
| |
| void SetFetchResponse(const StringPiece& url, |
| const ResponseHeaders& response_header, |
| const StringPiece& response_body) { |
| mock_url_fetcher()->SetResponse(url, response_header, response_body); |
| } |
| |
| // Add content to mock fetcher (with default headers). |
| void SetResponseWithDefaultHeaders(const StringPiece& relative_url, |
| const ContentType& content_type, |
| const StringPiece& content, |
| int64 ttl_sec); |
| |
| // Load a test file (from testdata/) into 'contents', returning false on |
| // failure. |
| bool LoadFile(const StringPiece& filename, GoogleString* contents); |
| |
| // Add the contents of a file to mock fetcher (with default headers). |
| void AddFileToMockFetcher(const StringPiece& url, |
| const StringPiece& filename, |
| const ContentType& content_type, int64 ttl_sec); |
| |
| void AddToResponse(const StringPiece& url, |
| const StringPiece& name, |
| const StringPiece& value) { |
| mock_url_fetcher()->AddToResponse(url, name, value); |
| } |
| |
| void SetFetchResponse404(const StringPiece& url); |
| |
| void SetFetchFailOnUnexpected(bool fail) { |
| mock_url_fetcher()->set_fail_on_unexpected(fail); |
| } |
| void FetcherUpdateDateHeaders() { |
| mock_url_fetcher()->set_timer(timer()); |
| mock_url_fetcher()->set_update_date_headers(true); |
| } |
| void ClearFetcherResponses() { mock_url_fetcher()->Clear(); } |
| |
| virtual void ClearStats(); |
| |
| // Calls Clear() on the rewrite driver and does any other necessary |
| // clean-up so the driver is okay for a test to reuse. |
| // |
| // Removes pending request-header attributes added via AddRequestAttribute. |
| void ClearRewriteDriver(); |
| |
| MockUrlFetcher* mock_url_fetcher() { |
| return &mock_url_fetcher_; |
| } |
| TestDistributedFetcher* test_distributed_fetcher() { |
| return &test_distributed_fetcher_; |
| } |
| Hasher* hasher() { return server_context_->hasher(); } |
| DelayCache* delay_cache() { return factory_->delay_cache(); } |
| LRUCache* lru_cache() { return factory_->lru_cache(); } |
| Statistics* statistics() { return factory_->statistics(); } |
| MemFileSystem* file_system() { return factory_->mem_file_system(); } |
| HTTPCache* http_cache() { return server_context_->http_cache(); } |
| PropertyCache* page_property_cache() { |
| return server_context_->page_property_cache(); |
| } |
| MockMessageHandler* message_handler() { |
| return factory_->mock_message_handler(); |
| } |
| |
| // TODO(jmarantz): These abstractions are not satisfactory long-term |
| // where we want to have driver-lifetime in tests be reflective of |
| // how servers work. But for now we use these accessors. |
| // |
| // Note that the *rewrite_driver() methods are not valid during |
| // construction, so any test classes that need to use them must |
| // do so from SetUp() methods. |
| RewriteDriver* rewrite_driver() { return rewrite_driver_; } |
| RewriteDriver* other_rewrite_driver() { return other_rewrite_driver_; } |
| |
| // The scheduler used by rewrite_driver |
| MockScheduler* mock_scheduler() { return factory_->mock_scheduler(); } |
| |
| int64 start_time_ms() const { return factory_->kStartTimeMs; } |
| |
| bool ReadFile(const char* filename, GoogleString* contents) { |
| return file_system()->ReadFile(filename, contents, message_handler()); |
| } |
| bool WriteFile(const char* filename, const StringPiece& contents) { |
| return file_system()->WriteFile(filename, contents, message_handler()); |
| } |
| |
| ServerContext* server_context() { return server_context_; } |
| ServerContext* other_server_context() { return other_server_context_; } |
| CountingUrlAsyncFetcher* counting_url_async_fetcher() { |
| return factory_->counting_url_async_fetcher(); |
| } |
| CountingUrlAsyncFetcher* counting_distributed_fetcher() { |
| return factory_->counting_distributed_async_fetcher(); |
| } |
| void SetMockHashValue(const GoogleString& value) { |
| factory_->mock_hasher()->set_hash_value(value); |
| } |
| |
| void SetCacheDelayUs(int64 delay_us); |
| |
| // Creates a RewriteDriver using the passed-in options, object, but |
| // does *not* finalize the driver. This gives individual _test.cc |
| // files the chance to add filters to the options prior to calling |
| // driver->AddFilters(). |
| RewriteDriver* MakeDriver(ServerContext* server_context, |
| RewriteOptions* options); |
| |
| // Converts a potentially relative URL off kTestDomain to absolute if needed. |
| GoogleString AbsolutifyUrl(const StringPiece& in); |
| |
| // Tests that non-caching-related response-header attributes are propagated |
| // to output resources. |
| // |
| // 'name' is the name of the resource. |
| void TestRetainExtraHeaders(const StringPiece& name, |
| const StringPiece& filter_id, |
| const StringPiece& ext); |
| |
| // Find the segment-encoder for the filter found via 'id'. Some |
| // test filters are not registered with RewriteDriver so for those |
| // we use the default encoder. |
| const UrlSegmentEncoder* FindEncoder(const StringPiece& id) const; |
| |
| // Switch url namers as specified. |
| void SetUseTestUrlNamer(bool use_test_url_namer); |
| |
| // Helper function which instantiates an encoder, collects the |
| // required arguments and calls the virtual Encode(). |
| GoogleString EncodeCssName(const StringPiece& name, |
| bool supports_webp, |
| bool can_inline); |
| |
| // Helper function for legacy tests that used this now-extinct interface. |
| // In general we don't support this flow in production but we rely on it |
| // in tests for obliquely covering some cases relating to resource pathnames. |
| bool ReadIfCached(const ResourcePtr& resource); |
| |
| // Variation on ReadIfCached that is used when we expect the resource |
| // not to be in present in cache, but instead we are looking to |
| // initiate the resource-rewrite process so that a subsequent call |
| // to ReadIfCached succeeds. |
| void InitiateResourceRead(const ResourcePtr& resource); |
| |
| // While our production cache model is non-blocking, we use an in-memory LRU |
| // for tests that calls its callback directly from Get. Thus we can make |
| // a convenient blocking cache wrapper to make it easier to write tests. |
| HTTPCache::FindResult HttpBlockingFind( |
| const GoogleString& key, HTTPCache* http_cache, HTTPValue* value_out, |
| ResponseHeaders* headers); |
| |
| // The same as the above function, but doesn't need an HTTPValue or |
| // ResponseHeaders. |
| HTTPCache::FindResult HttpBlockingFindStatus( |
| const GoogleString& key, HTTPCache* http_cache); |
| |
| // Same as above, but with options (for invalidation checks) |
| HTTPCache::FindResult HttpBlockingFindWithOptions( |
| const RewriteOptions* options, |
| const GoogleString& key, HTTPCache* http_cache, HTTPValue* value_out, |
| ResponseHeaders* headers); |
| |
| // Sets the response-headers Content-Type to "application/xhtml+xml". |
| void SetXhtmlMimetype() { SetMimetype("application/xhtml+xml"); } |
| |
| // Sets the response-headers Content-Type to "text/html". |
| void SetHtmlMimetype() { SetMimetype("text/html"); } |
| |
| // Sets the response-headers Content-Type as specified. |
| void SetMimetype(const StringPiece& mimetype); |
| |
| // Verifies that the specified URL can be fetched from HTTP cache, and that |
| // its cache TTL and contents are as specified. |
| void CheckFetchFromHttpCache( |
| StringPiece url, |
| StringPiece expected_contents, |
| int64 expected_expiration_ms); |
| |
| // Setup statistics for the given cohort and add it to the give PropertyCache. |
| const PropertyCache::Cohort* SetupCohort( |
| PropertyCache* cache, const GoogleString& cohort) { |
| return factory()->SetupCohort(cache, cohort); |
| } |
| |
| // Configure the other_server_context_ to use the same LRU cache as the |
| // primary server context. |
| void SetupSharedCache(); |
| |
| // Returns a new mock property page for the page property cache. |
| MockPropertyPage* NewMockPage(const StringPiece& url, |
| const StringPiece& options_signature_hash, |
| UserAgentMatcher::DeviceType device_type) { |
| return new MockPropertyPage( |
| server_context_->thread_system(), |
| server_context_->page_property_cache(), |
| url, |
| options_signature_hash, |
| UserAgentMatcher::DeviceTypeSuffix(device_type)); |
| } |
| |
| MockPropertyPage* NewMockPage(const StringPiece& url) { |
| return NewMockPage(url, "hash", UserAgentMatcher::kDesktop); |
| } |
| |
| // Sets MockLogRecord in the driver's request_context. |
| void SetMockLogRecord(); |
| |
| // Returns the MockLogRecord in the driver. |
| MockLogRecord* mock_log_record(); |
| |
| // Helper methods to return js/html snippets related to lazyload images. |
| GoogleString GetLazyloadScriptHtml(); |
| GoogleString GetLazyloadPostscriptHtml(); |
| |
| // Sets the server-scoped invalidation timestamp. Time is advanced by |
| // 1 second both before and after invalidation. E.g. if the current time |
| // is 100000 milliseconds at the time this is called, the invalidation |
| // timestamp will be at 101000 milliseconds, and time will be rolled |
| // forward to 102000 on exit from this function. |
| void SetCacheInvalidationTimestamp(); |
| |
| // Sets the invalidation timestamp for a URL pattern. Time is advanced by |
| // in the same manner as for SetCacheInvalidationTimestamp above. |
| void SetCacheInvalidationTimestampForUrl( |
| StringPiece url, bool ignores_metadata_and_pcache); |
| |
| // Changes the way cache-purges are implemented for non-wildcards to |
| // avoid flushing the entire metadata cache and instead match each |
| // metadata Input against the invalidation-set. |
| void EnableCachePurge(); |
| |
| // Enables the debug flag, which is often done on a test-by-test basis. |
| void EnableDebug(); |
| |
| // Enable debugging and set expected_debug_message used by DebugMessage. |
| // Occurrences of %url% in the message will be replaced by the argument |
| // to DebugMessage. |
| void DebugWithMessage(StringPiece expected_debug_message) { |
| EnableDebug(); |
| |
| expected_debug_message.CopyToString(&debug_message_); |
| } |
| |
| // Return the debug message if it was set by DebugWithMessage, empty string |
| // otherwise. Inserts url for %url% if needed, attempting to resolve it |
| // against kTestDomain first, and using url exactly as passed if resolving it |
| // doesn't return a valid url. |
| GoogleString DebugMessage(StringPiece url); |
| |
| // Returns a process context needed for any tests to instantiate factories |
| // explicitly. |
| static const ProcessContext& process_context(); |
| |
| protected: |
| // Common values for HttpBlockingFind* result. |
| const HTTPCache::FindResult kFoundResult; |
| const HTTPCache::FindResult kNotFoundResult; |
| |
| void Init(); |
| |
| // Override this if the test fixture needs to use a different RequestContext |
| // subclass. |
| virtual RequestContextPtr CreateRequestContext(); |
| |
| // Calls callbacks on given wait fetcher, making sure to properly synchronize |
| // with async rewrite flows given driver. |
| void CallFetcherCallbacksForDriver(WaitUrlAsyncFetcher* fetcher, |
| RewriteDriver* driver); |
| |
| // Populate the given headers based on the content type and original |
| // content length information. |
| void PopulateDefaultHeaders(const ContentType& content_type, |
| int64 original_content_length, |
| ResponseHeaders* headers); |
| |
| // Set the "active" server to that specified; the active server is used for |
| // rewriting and serving pages. |
| void SetActiveServer(ActiveServerFlag server_to_use); |
| |
| // Advances time forward using the mock scheduler. Note that time is not |
| // advanced directly in the mock_timer; the scheduler must be used. |
| void AdvanceTimeUs(int64 delay_ms); |
| void AdvanceTimeMs(int64 delay_ms) { AdvanceTimeUs(delay_ms * Timer::kMsUs); } |
| void SetTimeUs(int64 time_us); |
| void SetTimeMs(int64 time_ms) { SetTimeUs(time_ms * Timer::kMsUs); } |
| |
| // Adjusts time ignoring any scheduler callbacks. Use with caution. |
| void AdjustTimeUsWithoutWakingAlarms(int64 time_us); |
| |
| // Accessor for TimingInfo. |
| const RequestTimingInfo& timing_info(); |
| RequestTimingInfo* mutable_timing_info(); |
| |
| // Convenience method to pull the logging info proto out of the current |
| // request context's log record. The request context owns the log record, and |
| // if the log record has a non-NULL mutex, it will need to be locked |
| // for this call. |
| LoggingInfo* logging_info(); |
| |
| // Convenience method to extract read-only metadata_cache_info. |
| const MetadataCacheInfo& metadata_cache_info() { |
| return logging_info()->metadata_cache_info(); |
| } |
| |
| // Convenience method for retrieving the computed applied rewriters string |
| // from the current request context's log record. Thread-safe. |
| GoogleString AppliedRewriterStringFromLog(); |
| |
| // Convenience method for verifying that the rewriter info entries have |
| // expected values. |
| void VerifyRewriterInfoEntry(AbstractLogRecord* log_record, |
| const GoogleString& id, |
| int url_index, |
| int rewriter_info_index, |
| int rewriter_info_size, |
| int url_list_size, |
| const GoogleString& url); |
| |
| // Sets current_user_agent_ |
| void SetCurrentUserAgent(const StringPiece& user_agent) { |
| current_user_agent_ = user_agent; |
| } |
| |
| // Sets up user-agent and request-header to allow webp processing. |
| void SetupForWebp() { |
| SetCurrentUserAgent("webp"); |
| AddRequestAttribute(HttpAttributes::kAccept, "image/webp"); |
| } |
| |
| void SetupForWebpLossless() { |
| SetCurrentUserAgent("webp-la"); |
| AddRequestAttribute(HttpAttributes::kAccept, "image/webp"); |
| } |
| |
| void SetupForWebpAnimated() { |
| SetCurrentUserAgent("webp-animated"); |
| AddRequestAttribute(HttpAttributes::kAccept, "image/webp"); |
| } |
| |
| // Adds an attribute to be populated later into a RequestHeaders* object, |
| // along with the user-agent. Note that these attributes stay in the |
| // test-class until ClearRewriteDriver is called. |
| void AddRequestAttribute(StringPiece name, StringPiece value); |
| |
| // Populates a RequestHeaders* object with al |
| void PopulateRequestHeaders(RequestHeaders* request_headers); |
| |
| // Override HtmlParseTestBaseNoAlloc::ParseUrl to populate the |
| // request-headers into rewrite_driver_ before running filters. |
| virtual void ParseUrl(StringPiece url, StringPiece html_input); |
| |
| GoogleString ExpectedNonce(); |
| |
| // When reaching into a cache that backs an HTTP cache you need a cache key |
| // that includes the fragment. |
| GoogleString HttpCacheKey(StringPiece url) { |
| return http_cache()->CompositeKey(url, rewrite_driver_->CacheFragment()); |
| } |
| |
| // Returns the value of a TimedVariable, specified by name. |
| int TimedValue(StringPiece name); |
| |
| // The mock fetchers & stats are global across all Factories used in the |
| // tests. |
| MockUrlFetcher mock_url_fetcher_; |
| TestDistributedFetcher test_distributed_fetcher_; |
| scoped_ptr<Statistics> statistics_; |
| |
| // We have two independent RewriteDrivers representing two completely |
| // separate servers for the same domain (say behind a load-balancer). |
| // |
| // Server A runs rewrite_driver_ and will be used to rewrite pages and |
| // serves the rewritten resources. |
| scoped_ptr<TestRewriteDriverFactory> factory_; |
| scoped_ptr<TestRewriteDriverFactory> other_factory_; |
| ServerContext* server_context_; |
| RewriteDriver* rewrite_driver_; |
| ServerContext* other_server_context_; |
| RewriteDriver* other_rewrite_driver_; |
| scoped_ptr<HtmlWriterFilter> other_html_writer_filter_; |
| ActiveServerFlag active_server_; |
| bool use_managed_rewrite_drivers_; |
| StringPiece current_user_agent_; |
| StringVector request_attribute_names_; |
| StringVector request_attribute_values_; |
| |
| MD5Hasher md5_hasher_; |
| |
| RewriteOptions* options_; // owned by rewrite_driver_. |
| RewriteOptions* other_options_; // owned by other_rewrite_driver_. |
| UrlSegmentEncoder default_encoder_; |
| ResponseHeaders response_headers_; |
| const GoogleString kEtag0; // Etag with a 0 hash. |
| uint64 expected_nonce_; |
| |
| GoogleString debug_message_; // Message used by DebugMessage |
| |
| private: |
| void ValidateFallbackHeaderSanitizationHelper( |
| StringPiece filter_id, StringPiece origin_content_type, bool expect_load); |
| }; |
| |
| } // namespace net_instaweb |
| |
| #endif // NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_TEST_BASE_H_ |