Page Speed Optimization Libraries
1.8.31.3
|
00001 /* 00002 * Copyright 2011 Google Inc. 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http:///www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00018 00021 00022 #ifndef NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_CONTEXT_TEST_BASE_H_ 00023 #define NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_CONTEXT_TEST_BASE_H_ 00024 00025 #include "net/instaweb/rewriter/public/rewrite_context.h" 00026 00027 #include <utility> 00028 #include <vector> 00029 00030 #include "net/instaweb/htmlparse/public/html_element.h" 00031 #include "net/instaweb/htmlparse/public/html_name.h" 00032 #include "net/instaweb/htmlparse/public/html_parse_test_base.h" 00033 #include "net/instaweb/http/public/content_type.h" 00034 #include "net/instaweb/rewriter/public/output_resource_kind.h" 00035 #include "net/instaweb/rewriter/public/resource.h" 00036 #include "net/instaweb/rewriter/public/resource_combiner.h" 00037 #include "net/instaweb/rewriter/public/resource_slot.h" 00038 #include "net/instaweb/rewriter/public/rewrite_driver.h" 00039 #include "net/instaweb/rewriter/public/rewrite_filter.h" 00040 #include "net/instaweb/rewriter/public/rewrite_test_base.h" 00041 #include "net/instaweb/rewriter/public/server_context.h" 00042 #include "net/instaweb/rewriter/public/simple_text_filter.h" 00043 #include "net/instaweb/rewriter/public/single_rewrite_context.h" 00044 #include "net/instaweb/util/public/basictypes.h" 00045 #include "net/instaweb/util/public/scoped_ptr.h" 00046 #include "net/instaweb/util/public/string.h" 00047 #include "net/instaweb/util/public/string_util.h" 00048 #include "net/instaweb/util/public/timer.h" 00049 #include "net/instaweb/util/public/url_multipart_encoder.h" 00050 #include "net/instaweb/util/public/writer.h" 00051 #include "net/instaweb/util/worker_test_base.h" 00052 00053 00054 namespace net_instaweb { 00055 00056 class CachedResult; 00057 class MessageHandler; 00058 class MockScheduler; 00059 class OutputPartitions; 00060 class OutputResource; 00061 class TestRewriteDriverFactory; 00062 class UrlSegmentEncoder; 00063 00065 class TrimWhitespaceRewriter : public SimpleTextFilter::Rewriter { 00066 public: 00067 static const char kFilterId[]; 00068 00069 explicit TrimWhitespaceRewriter(OutputResourceKind kind) : kind_(kind) { 00070 ClearStats(); 00071 } 00072 00074 int num_rewrites() const { return num_rewrites_; } 00075 void ClearStats() { num_rewrites_ = 0; } 00076 00077 protected: 00078 REFCOUNT_FRIEND_DECLARATION(TrimWhitespaceRewriter); 00079 virtual ~TrimWhitespaceRewriter(); 00080 00081 virtual bool RewriteText(const StringPiece& url, const StringPiece& in, 00082 GoogleString* out, 00083 ServerContext* server_context); 00084 virtual HtmlElement::Attribute* FindResourceAttribute(HtmlElement* element); 00085 virtual OutputResourceKind kind() const { return kind_; } 00086 virtual const char* id() const { return kFilterId; } 00087 virtual const char* name() const { return "TrimWhitespace"; } 00088 00089 private: 00090 OutputResourceKind kind_; 00091 00092 int num_rewrites_; 00093 00094 DISALLOW_COPY_AND_ASSIGN(TrimWhitespaceRewriter); 00095 }; 00096 00101 class TrimWhitespaceSyncFilter : public SimpleTextFilter { 00102 public: 00103 static const char kFilterId[]; 00104 00105 explicit TrimWhitespaceSyncFilter(OutputResourceKind kind, 00106 RewriteDriver* driver) 00107 : SimpleTextFilter(new TrimWhitespaceRewriter(kind), driver) { 00108 } 00109 virtual ~TrimWhitespaceSyncFilter(); 00110 00111 virtual void StartElementImpl(HtmlElement* element); 00112 virtual const char* id() const { return kFilterId; } 00113 virtual const char* name() const { return "TrimWhitespaceSync"; } 00114 00115 private: 00116 DISALLOW_COPY_AND_ASSIGN(TrimWhitespaceSyncFilter); 00117 }; 00118 00120 class UpperCaseRewriter : public SimpleTextFilter::Rewriter { 00121 public: 00122 static const char kFilterId[]; 00123 00124 explicit UpperCaseRewriter(OutputResourceKind kind) 00125 : kind_(kind), num_rewrites_(0) {} 00126 static SimpleTextFilter* MakeFilter(OutputResourceKind kind, 00127 RewriteDriver* driver, 00128 UpperCaseRewriter** rewriter_out) { 00129 *rewriter_out = new UpperCaseRewriter(kind); 00130 return new SimpleTextFilter(*rewriter_out, driver); 00131 } 00132 00133 int num_rewrites() const { return num_rewrites_; } 00134 void ClearStats() { num_rewrites_ = 0; } 00135 00136 protected: 00137 REFCOUNT_FRIEND_DECLARATION(UpperCaseRewriter); 00138 virtual ~UpperCaseRewriter(); 00139 00140 virtual bool RewriteText(const StringPiece& url, const StringPiece& in, 00141 GoogleString* out, 00142 ServerContext* server_context) { 00143 ++num_rewrites_; 00144 in.CopyToString(out); 00145 UpperString(out); 00146 return in != *out; 00147 } 00148 virtual HtmlElement::Attribute* FindResourceAttribute(HtmlElement* element) { 00149 if (element->keyword() == HtmlName::kLink) { 00150 return element->FindAttribute(HtmlName::kHref); 00151 } 00152 return NULL; 00153 } 00154 virtual OutputResourceKind kind() const { return kind_; } 00155 virtual const char* id() const { return kFilterId; } 00156 virtual const char* name() const { return "UpperCase"; } 00157 00158 private: 00159 OutputResourceKind kind_; 00160 int num_rewrites_; 00161 00162 DISALLOW_COPY_AND_ASSIGN(UpperCaseRewriter); 00163 }; 00164 00167 class NestedFilter : public RewriteFilter { 00168 public: 00170 static const bool kExpectNestedRewritesSucceed = true; 00171 static const bool kExpectNestedRewritesFail = false; 00172 00173 static const char kFilterId[]; 00174 00175 NestedFilter(RewriteDriver* driver, SimpleTextFilter* upper_filter, 00176 UpperCaseRewriter* upper_rewriter, bool expected_nested_result) 00177 : RewriteFilter(driver), upper_filter_(upper_filter), 00178 upper_rewriter_(upper_rewriter), chain_(false), 00179 check_nested_rewrite_result_(true), 00180 expected_nested_rewrite_result_(expected_nested_result) { 00181 ClearStats(); 00182 } 00183 00185 int num_top_rewrites() const { return num_top_rewrites_; } 00186 int num_sub_rewrites() const { return upper_rewriter_->num_rewrites(); } 00187 00188 void ClearStats() { 00189 num_top_rewrites_ = 0; 00190 upper_rewriter_->ClearStats(); 00191 } 00192 00194 void set_chain(bool x) { chain_ = x; } 00195 00196 bool expected_nested_rewrite_result() const { 00197 return expected_nested_rewrite_result_; 00198 } 00199 00200 void set_expected_nested_rewrite_result(bool x) { 00201 expected_nested_rewrite_result_ = x; 00202 } 00203 00204 void set_check_nested_rewrite_result(bool x) { 00205 check_nested_rewrite_result_ = x; 00206 } 00207 00208 protected: 00209 virtual ~NestedFilter(); 00210 00211 class NestedSlot : public ResourceSlot { 00212 public: 00213 explicit NestedSlot(const ResourcePtr& resource) : ResourceSlot(resource) {} 00214 virtual void Render() {} 00215 virtual GoogleString LocationString() { return "nested:"; } 00216 }; 00217 00218 class Context : public SingleRewriteContext { 00219 public: 00220 Context(RewriteDriver* driver, NestedFilter* filter, bool chain) 00221 : SingleRewriteContext(driver, NULL, NULL), 00222 filter_(filter), 00223 chain_(chain) { 00224 } 00225 virtual ~Context(); 00226 virtual void RewriteSingle( 00227 const ResourcePtr& input, const OutputResourcePtr& output); 00228 virtual void Harvest(); 00229 00230 protected: 00231 virtual const char* id() const { return kFilterId; } 00232 virtual OutputResourceKind kind() const { return kRewrittenResource; } 00233 00234 private: 00235 std::vector<GoogleString*> strings_; 00236 NestedFilter* filter_; 00237 bool chain_; 00238 ResourceSlotVector nested_slots_; 00239 00240 DISALLOW_COPY_AND_ASSIGN(Context); 00241 }; 00242 00243 RewriteContext* MakeRewriteContext() { 00244 return new Context(driver(), this, chain_); 00245 } 00246 00247 void StartElementImpl(HtmlElement* element); 00248 SimpleTextFilter* upper_filter() { return upper_filter_; } 00249 00250 virtual const char* id() const { return kFilterId; } 00251 virtual const char* Name() const { return "NestedFilter"; } 00252 virtual void StartDocumentImpl() {} 00253 virtual void EndElementImpl(HtmlElement* element) {} 00254 00255 private: 00257 SimpleTextFilter* upper_filter_; 00258 UpperCaseRewriter* upper_rewriter_; 00259 bool chain_; 00260 00262 bool check_nested_rewrite_result_; 00264 bool expected_nested_rewrite_result_; 00265 00267 int num_top_rewrites_; 00268 00269 DISALLOW_COPY_AND_ASSIGN(NestedFilter); 00270 }; 00271 00276 class CombiningFilter : public RewriteFilter { 00277 public: 00278 static const char kFilterId[]; 00279 00280 CombiningFilter(RewriteDriver* driver, 00281 MockScheduler* scheduler, 00282 int64 rewrite_delay_ms); 00283 virtual ~CombiningFilter(); 00284 00285 class Combiner : public ResourceCombiner { 00286 public: 00287 Combiner(RewriteDriver* driver, RewriteFilter* filter) 00288 : ResourceCombiner( 00289 driver, kContentTypeCss.file_extension() + 1, filter) { 00290 } 00291 OutputResourcePtr MakeOutput() { 00292 return Combine(rewrite_driver_->message_handler()); 00293 } 00294 bool Write(const ResourceVector& in, const OutputResourcePtr& out) { 00295 return WriteCombination(in, out, rewrite_driver_->message_handler()); 00296 } 00297 00298 virtual bool WritePiece(int index, const Resource* input, 00299 OutputResource* combination, 00300 Writer* writer, MessageHandler* handler) { 00301 writer->Write(prefix_, handler); 00302 return ResourceCombiner::WritePiece( 00303 index, input, combination, writer, handler); 00304 } 00305 00306 void set_prefix(const GoogleString& prefix) { prefix_ = prefix; } 00307 00308 private: 00309 virtual const ContentType* CombinationContentType() { 00310 return &kContentTypeCss; 00311 } 00312 00313 GoogleString prefix_; 00314 }; 00315 00316 virtual const char* id() const { return kFilterId; } 00317 00318 class Context : public RewriteContext { 00319 public: 00320 Context(RewriteDriver* driver, CombiningFilter* filter, 00321 MockScheduler* scheduler); 00322 00323 void AddElement(HtmlElement* element, HtmlElement::Attribute* href, 00324 const ResourcePtr& resource) { 00325 ResourceSlotPtr slot(Driver()->GetSlot(resource, element, href)); 00326 AddSlot(slot); 00327 } 00328 00329 protected: 00330 virtual bool Partition(OutputPartitions* partitions, 00331 OutputResourceVector* outputs); 00332 00333 virtual void Rewrite(int partition_index, 00334 CachedResult* partition, 00335 const OutputResourcePtr& output); 00336 virtual bool OptimizationOnly() const { 00337 return filter_->optimization_only(); 00338 } 00339 00340 void DoRewrite(int partition_index, 00341 CachedResult* partition, 00342 OutputResourcePtr output); 00343 virtual void Render(); 00344 virtual void WillNotRender(); 00345 virtual void Cancel(); 00346 void DisableRemovedSlots(CachedResult* partition); 00347 virtual const UrlSegmentEncoder* encoder() const { return &encoder_; } 00348 virtual const char* id() const { return kFilterId; } 00349 virtual OutputResourceKind kind() const { 00350 return filter_->on_the_fly_ ? kOnTheFlyResource : kRewrittenResource; 00351 } 00352 00353 private: 00354 Combiner combiner_; 00355 UrlMultipartEncoder encoder_; 00356 MockScheduler* scheduler_; 00357 int64 time_at_start_of_rewrite_us_; 00358 CombiningFilter* filter_; 00359 }; 00360 00361 virtual void StartDocumentImpl() {} 00362 virtual void StartElementImpl(HtmlElement* element); 00363 virtual void Flush() { 00364 if (context_.get() != NULL) { 00365 driver()->InitiateRewrite(context_.release()); 00366 } 00367 } 00368 00369 virtual void EndElementImpl(HtmlElement* element) {} 00370 virtual const char* Name() const { return "Combining"; } 00371 RewriteContext* MakeRewriteContext() { 00372 return new Context(driver(), this, scheduler_); 00373 } 00374 virtual const UrlSegmentEncoder* encoder() const { return &encoder_; } 00375 00376 virtual bool ComputeOnTheFly() const { return on_the_fly_; } 00377 00378 int num_rewrites() const { return num_rewrites_; } 00379 int num_render() const { return num_render_; } 00380 int num_will_not_render() const { return num_will_not_render_; } 00381 int num_cancel() const { return num_cancel_; } 00382 00383 void ClearStats() { num_rewrites_ = 0; } 00384 int64 rewrite_delay_ms() const { return rewrite_delay_ms_; } 00385 void set_rewrite_block_on(WorkerTestBase::SyncPoint* sync) { 00386 rewrite_block_on_ = sync; 00387 } 00388 00389 void set_rewrite_signal_on(WorkerTestBase::SyncPoint* sync) { 00390 rewrite_signal_on_ = sync; 00391 } 00392 00394 void set_prefix(const GoogleString& prefix) { prefix_ = prefix; } 00395 00396 void set_on_the_fly(bool v) { on_the_fly_ = v; } 00397 00398 void set_disable_successors(bool v) { disable_successors_ = v; } 00399 00400 bool optimization_only() const { return optimization_only_; } 00401 void set_optimization_only(bool o) { optimization_only_ = o; } 00402 00403 private: 00404 friend class Context; 00405 00406 scoped_ptr<Context> context_; 00407 UrlMultipartEncoder encoder_; 00408 MockScheduler* scheduler_; 00409 int num_rewrites_; 00410 int num_render_; 00411 int num_will_not_render_; 00412 int num_cancel_; 00413 int64 rewrite_delay_ms_; 00414 00417 WorkerTestBase::SyncPoint* rewrite_block_on_; 00418 00422 WorkerTestBase::SyncPoint* rewrite_signal_on_; 00423 GoogleString prefix_; 00424 bool on_the_fly_; 00425 bool optimization_only_; 00426 00427 bool disable_successors_; 00428 00429 00430 DISALLOW_COPY_AND_ASSIGN(CombiningFilter); 00431 }; 00432 00433 class RewriteContextTestBase : public RewriteTestBase { 00434 protected: 00435 static const int64 kRewriteDeadlineMs = 20; 00436 00439 static const int64 kOriginTtlMs = 12 * Timer::kMinuteMs; 00442 static const int64 kLowOriginTtlMs = 5 * Timer::kSecondMs; 00443 00446 GoogleString OriginTtlMaxAge() { 00447 return StrCat("max-age=", Integer64ToString( 00448 kOriginTtlMs / Timer::kSecondMs)); 00449 } 00450 00451 RewriteContextTestBase( 00452 std::pair<TestRewriteDriverFactory*, TestRewriteDriverFactory*> factories) 00453 : RewriteTestBase(factories) {} 00454 RewriteContextTestBase() {} 00455 virtual ~RewriteContextTestBase(); 00456 00457 virtual void SetUp(); 00458 virtual void TearDown(); 00459 virtual bool AddBody() const { return false; } 00460 virtual void ClearStats(); 00461 00462 void InitResources() { InitResourcesToDomain(kTestDomain); } 00463 void InitResourcesToDomain(const char* domain); 00464 void InitTrimFilters(OutputResourceKind kind); 00465 void InitUpperFilter(OutputResourceKind kind, RewriteDriver* rewrite_driver); 00466 void InitCombiningFilter(int64 rewrite_delay_ms); 00467 void InitNestedFilter(bool expected_nested_rewrite_result); 00468 00469 TrimWhitespaceRewriter* trim_filter_; 00470 TrimWhitespaceRewriter* other_trim_filter_; 00471 CombiningFilter* combining_filter_; 00472 NestedFilter* nested_filter_; 00473 }; 00474 00475 } 00476 00477 #endif ///< NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_CONTEXT_TEST_BASE_H_