Page Speed Optimization Libraries  1.7.30.3
net/instaweb/rewriter/public/rewrite_context_test_base.h
Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines