~alinuxninja/nginx-edge/trunk

« back to all changes in this revision

Viewing changes to debian/modules/ngx_pagespeed/psol/include/net/instaweb/rewriter/public/rewrite_context_test_base.h

  • Committer: Vivian
  • Date: 2015-12-04 18:20:11 UTC
  • Revision ID: git-v1:a36f2bc32e884f7473b3a47040e5411306144d7d
* Do not extract psol.tar.gz

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2011 Google Inc.
3
 
 *
4
 
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 
 * you may not use this file except in compliance with the License.
6
 
 * You may obtain a copy of the License at
7
 
 *
8
 
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 
 *
10
 
 * Unless required by applicable law or agreed to in writing, software
11
 
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 
 * See the License for the specific language governing permissions and
14
 
 * limitations under the License.
15
 
 */
16
 
 
17
 
// Author: jmarantz@google.com (Joshua Marantz)
18
 
 
19
 
// Unit-test the RewriteContext class.  This is made simplest by
20
 
// setting up some dummy rewriters in our test framework.
21
 
 
22
 
#ifndef NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_CONTEXT_TEST_BASE_H_
23
 
#define NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_CONTEXT_TEST_BASE_H_
24
 
 
25
 
#include "net/instaweb/rewriter/public/rewrite_context.h"
26
 
 
27
 
#include <utility>
28
 
#include <vector>
29
 
 
30
 
#include "net/instaweb/htmlparse/public/html_element.h"
31
 
#include "net/instaweb/htmlparse/public/html_name.h"
32
 
#include "net/instaweb/htmlparse/public/html_parse_test_base.h"
33
 
#include "net/instaweb/http/public/content_type.h"
34
 
#include "net/instaweb/rewriter/public/output_resource_kind.h"
35
 
#include "net/instaweb/rewriter/public/resource.h"
36
 
#include "net/instaweb/rewriter/public/resource_combiner.h"
37
 
#include "net/instaweb/rewriter/public/resource_slot.h"
38
 
#include "net/instaweb/rewriter/public/rewrite_driver.h"
39
 
#include "net/instaweb/rewriter/public/rewrite_filter.h"
40
 
#include "net/instaweb/rewriter/public/rewrite_test_base.h"
41
 
#include "net/instaweb/rewriter/public/server_context.h"
42
 
#include "net/instaweb/rewriter/public/simple_text_filter.h"
43
 
#include "net/instaweb/rewriter/public/single_rewrite_context.h"
44
 
#include "net/instaweb/util/public/basictypes.h"
45
 
#include "net/instaweb/util/public/scoped_ptr.h"
46
 
#include "net/instaweb/util/public/string.h"
47
 
#include "net/instaweb/util/public/string_util.h"
48
 
#include "net/instaweb/util/public/timer.h"
49
 
#include "net/instaweb/util/public/url_multipart_encoder.h"
50
 
#include "net/instaweb/util/public/writer.h"
51
 
#include "net/instaweb/util/worker_test_base.h"
52
 
 
53
 
 
54
 
namespace net_instaweb {
55
 
 
56
 
class CachedResult;
57
 
class MessageHandler;
58
 
class MockScheduler;
59
 
class OutputPartitions;
60
 
class OutputResource;
61
 
class TestRewriteDriverFactory;
62
 
class UrlSegmentEncoder;
63
 
 
64
 
// Simple test filter just trims whitespace from the input resource.
65
 
class TrimWhitespaceRewriter : public SimpleTextFilter::Rewriter {
66
 
 public:
67
 
  static const char kFilterId[];
68
 
 
69
 
  explicit TrimWhitespaceRewriter(OutputResourceKind kind) : kind_(kind) {
70
 
    ClearStats();
71
 
  }
72
 
 
73
 
  // Stats
74
 
  int num_rewrites() const { return num_rewrites_; }
75
 
  void ClearStats() { num_rewrites_ = 0; }
76
 
 
77
 
 protected:
78
 
  REFCOUNT_FRIEND_DECLARATION(TrimWhitespaceRewriter);
79
 
  virtual ~TrimWhitespaceRewriter();
80
 
 
81
 
  virtual bool RewriteText(const StringPiece& url, const StringPiece& in,
82
 
                           GoogleString* out,
83
 
                           ServerContext* server_context);
84
 
  virtual HtmlElement::Attribute* FindResourceAttribute(HtmlElement* element);
85
 
  virtual OutputResourceKind kind() const { return kind_; }
86
 
  virtual const char* id() const { return kFilterId; }
87
 
  virtual const char* name() const { return "TrimWhitespace"; }
88
 
 
89
 
 private:
90
 
  OutputResourceKind kind_;
91
 
 
92
 
  int num_rewrites_;
93
 
 
94
 
  DISALLOW_COPY_AND_ASSIGN(TrimWhitespaceRewriter);
95
 
};
96
 
 
97
 
// Test filter that replaces a CSS resource URL with a corresponding Pagespeed
98
 
// resource URL.  When that URL is requested, it will invoke a rewriter that
99
 
// trims whitespace in the line of serving.  Does not require or expect the
100
 
// resource to be fetched or loaded from cache at rewrite time.
101
 
class TrimWhitespaceSyncFilter : public SimpleTextFilter {
102
 
 public:
103
 
  static const char kFilterId[];
104
 
 
105
 
  explicit TrimWhitespaceSyncFilter(OutputResourceKind kind,
106
 
                                    RewriteDriver* driver)
107
 
      : SimpleTextFilter(new TrimWhitespaceRewriter(kind), driver) {
108
 
  }
109
 
  virtual ~TrimWhitespaceSyncFilter();
110
 
 
111
 
  virtual void StartElementImpl(HtmlElement* element);
112
 
  virtual const char* id() const { return kFilterId; }
113
 
  virtual const char* name() const { return "TrimWhitespaceSync"; }
114
 
 
115
 
 private:
116
 
  DISALLOW_COPY_AND_ASSIGN(TrimWhitespaceSyncFilter);
117
 
};
118
 
 
119
 
// A similarly structured test-filter: this one just upper-cases its text.
120
 
class UpperCaseRewriter : public SimpleTextFilter::Rewriter {
121
 
 public:
122
 
  static const char kFilterId[];
123
 
 
124
 
  explicit UpperCaseRewriter(OutputResourceKind kind)
125
 
      : kind_(kind), num_rewrites_(0) {}
126
 
  static SimpleTextFilter* MakeFilter(OutputResourceKind kind,
127
 
                                      RewriteDriver* driver,
128
 
                                      UpperCaseRewriter** rewriter_out) {
129
 
    *rewriter_out = new UpperCaseRewriter(kind);
130
 
    return new SimpleTextFilter(*rewriter_out, driver);
131
 
  }
132
 
 
133
 
  int num_rewrites() const { return num_rewrites_; }
134
 
  void ClearStats() { num_rewrites_ = 0; }
135
 
 
136
 
 protected:
137
 
  REFCOUNT_FRIEND_DECLARATION(UpperCaseRewriter);
138
 
  virtual ~UpperCaseRewriter();
139
 
 
140
 
  virtual bool RewriteText(const StringPiece& url, const StringPiece& in,
141
 
                           GoogleString* out,
142
 
                           ServerContext* server_context) {
143
 
    ++num_rewrites_;
144
 
    in.CopyToString(out);
145
 
    UpperString(out);
146
 
    return in != *out;
147
 
  }
148
 
  virtual HtmlElement::Attribute* FindResourceAttribute(HtmlElement* element) {
149
 
    if (element->keyword() == HtmlName::kLink) {
150
 
      return element->FindAttribute(HtmlName::kHref);
151
 
    }
152
 
    return NULL;
153
 
  }
154
 
  virtual OutputResourceKind kind() const { return kind_; }
155
 
  virtual const char* id() const { return kFilterId; }
156
 
  virtual const char* name() const { return "UpperCase"; }
157
 
 
158
 
 private:
159
 
  OutputResourceKind kind_;
160
 
  int num_rewrites_;
161
 
 
162
 
  DISALLOW_COPY_AND_ASSIGN(UpperCaseRewriter);
163
 
};
164
 
 
165
 
// Filter that contains nested resources that must themselves
166
 
// be rewritten.
167
 
class NestedFilter : public RewriteFilter {
168
 
 public:
169
 
  // For use with NestedFilter constructor
170
 
  static const bool kExpectNestedRewritesSucceed = true;
171
 
  static const bool kExpectNestedRewritesFail = false;
172
 
 
173
 
  static const char kFilterId[];
174
 
 
175
 
  NestedFilter(RewriteDriver* driver, SimpleTextFilter* upper_filter,
176
 
               UpperCaseRewriter* upper_rewriter, bool expected_nested_result)
177
 
      : RewriteFilter(driver), upper_filter_(upper_filter),
178
 
        upper_rewriter_(upper_rewriter), chain_(false),
179
 
        check_nested_rewrite_result_(true),
180
 
        expected_nested_rewrite_result_(expected_nested_result) {
181
 
    ClearStats();
182
 
  }
183
 
 
184
 
  // Stats
185
 
  int num_top_rewrites() const { return num_top_rewrites_; }
186
 
  int num_sub_rewrites() const { return upper_rewriter_->num_rewrites(); }
187
 
 
188
 
  void ClearStats() {
189
 
    num_top_rewrites_ = 0;
190
 
    upper_rewriter_->ClearStats();
191
 
  }
192
 
 
193
 
  // Set this to true to create a chain of nested rewrites on the same slot.
194
 
  void set_chain(bool x) { chain_ = x; }
195
 
 
196
 
  bool expected_nested_rewrite_result() const {
197
 
    return expected_nested_rewrite_result_;
198
 
  }
199
 
 
200
 
  void set_expected_nested_rewrite_result(bool x) {
201
 
    expected_nested_rewrite_result_ = x;
202
 
  }
203
 
 
204
 
  void set_check_nested_rewrite_result(bool x) {
205
 
    check_nested_rewrite_result_ = x;
206
 
  }
207
 
 
208
 
 protected:
209
 
  virtual ~NestedFilter();
210
 
 
211
 
  class NestedSlot : public ResourceSlot {
212
 
   public:
213
 
    explicit NestedSlot(const ResourcePtr& resource) : ResourceSlot(resource) {}
214
 
    virtual HtmlElement* element() const { return NULL; }
215
 
    virtual void Render() {}
216
 
    virtual GoogleString LocationString() { return "nested:"; }
217
 
  };
218
 
 
219
 
  class Context : public SingleRewriteContext {
220
 
   public:
221
 
    Context(RewriteDriver* driver, NestedFilter* filter, bool chain)
222
 
        : SingleRewriteContext(driver, NULL, NULL),
223
 
          filter_(filter),
224
 
          chain_(chain) {
225
 
    }
226
 
    virtual ~Context();
227
 
    virtual void RewriteSingle(
228
 
        const ResourcePtr& input, const OutputResourcePtr& output);
229
 
    virtual void Harvest();
230
 
 
231
 
   protected:
232
 
    virtual const char* id() const { return kFilterId; }
233
 
    virtual OutputResourceKind kind() const { return kRewrittenResource; }
234
 
 
235
 
   private:
236
 
    std::vector<GoogleString*> strings_;
237
 
    NestedFilter* filter_;
238
 
    bool chain_;
239
 
    ResourceSlotVector nested_slots_;
240
 
 
241
 
    DISALLOW_COPY_AND_ASSIGN(Context);
242
 
  };
243
 
 
244
 
  RewriteContext* MakeRewriteContext() {
245
 
    return new Context(driver(), this, chain_);
246
 
  }
247
 
 
248
 
  void StartElementImpl(HtmlElement* element);
249
 
  SimpleTextFilter* upper_filter() { return upper_filter_; }
250
 
 
251
 
  virtual const char* id() const { return kFilterId; }
252
 
  virtual const char* Name() const { return "NestedFilter"; }
253
 
  virtual void StartDocumentImpl() {}
254
 
  virtual void EndElementImpl(HtmlElement* element) {}
255
 
 
256
 
 private:
257
 
  // Upper-casing filter we also invoke.
258
 
  SimpleTextFilter* upper_filter_;
259
 
  UpperCaseRewriter* upper_rewriter_;
260
 
  bool chain_;
261
 
 
262
 
  // Whether to check the result of the nested rewrites.
263
 
  bool check_nested_rewrite_result_;
264
 
  // Whether we expect nested rewrites to be successful.
265
 
  bool expected_nested_rewrite_result_;
266
 
 
267
 
  // Stats
268
 
  int num_top_rewrites_;
269
 
 
270
 
  DISALLOW_COPY_AND_ASSIGN(NestedFilter);
271
 
};
272
 
 
273
 
// Simple version of CombineCssFilter.
274
 
//
275
 
// Concatenates all CSS files loaded from <link> tags into a single output.
276
 
// Does not consider barriers, @import statements, absolutification, etc.
277
 
class CombiningFilter : public RewriteFilter {
278
 
 public:
279
 
  static const char kFilterId[];
280
 
 
281
 
  CombiningFilter(RewriteDriver* driver,
282
 
                  MockScheduler* scheduler,
283
 
                  int64 rewrite_delay_ms);
284
 
  virtual ~CombiningFilter();
285
 
 
286
 
  class Combiner : public ResourceCombiner {
287
 
   public:
288
 
    Combiner(RewriteDriver* driver, RewriteFilter* filter)
289
 
        : ResourceCombiner(
290
 
            driver, kContentTypeCss.file_extension() + 1, filter) {
291
 
    }
292
 
    OutputResourcePtr MakeOutput() {
293
 
      return Combine(rewrite_driver_->message_handler());
294
 
    }
295
 
    bool Write(const ResourceVector& in, const OutputResourcePtr& out) {
296
 
      return WriteCombination(in, out, rewrite_driver_->message_handler());
297
 
    }
298
 
 
299
 
    virtual bool WritePiece(int index, const Resource* input,
300
 
                            OutputResource* combination,
301
 
                            Writer* writer, MessageHandler* handler) {
302
 
      writer->Write(prefix_, handler);
303
 
      return ResourceCombiner::WritePiece(
304
 
          index, input, combination, writer, handler);
305
 
    }
306
 
 
307
 
    void set_prefix(const GoogleString& prefix) { prefix_ = prefix; }
308
 
 
309
 
   private:
310
 
    virtual const ContentType* CombinationContentType() {
311
 
      return &kContentTypeCss;
312
 
    }
313
 
 
314
 
    GoogleString prefix_;
315
 
  };
316
 
 
317
 
  virtual const char* id() const { return kFilterId; }
318
 
 
319
 
  class Context : public RewriteContext {
320
 
   public:
321
 
    Context(RewriteDriver* driver, CombiningFilter* filter,
322
 
            MockScheduler* scheduler);
323
 
 
324
 
    void AddElement(HtmlElement* element, HtmlElement::Attribute* href,
325
 
                    const ResourcePtr& resource) {
326
 
      ResourceSlotPtr slot(Driver()->GetSlot(resource, element, href));
327
 
      AddSlot(slot);
328
 
    }
329
 
 
330
 
   protected:
331
 
    virtual bool Partition(OutputPartitions* partitions,
332
 
                           OutputResourceVector* outputs);
333
 
 
334
 
    virtual void Rewrite(int partition_index,
335
 
                         CachedResult* partition,
336
 
                         const OutputResourcePtr& output);
337
 
    virtual bool OptimizationOnly() const {
338
 
      return filter_->optimization_only();
339
 
    }
340
 
 
341
 
    void DoRewrite(int partition_index,
342
 
                   CachedResult* partition,
343
 
                   OutputResourcePtr output);
344
 
    virtual void Render();
345
 
    virtual void WillNotRender();
346
 
    virtual void Cancel();
347
 
    void DisableRemovedSlots(CachedResult* partition);
348
 
    virtual const UrlSegmentEncoder* encoder() const { return &encoder_; }
349
 
    virtual const char* id() const { return kFilterId; }
350
 
    virtual OutputResourceKind kind() const {
351
 
      return filter_->on_the_fly_ ? kOnTheFlyResource : kRewrittenResource;
352
 
    }
353
 
 
354
 
   private:
355
 
    Combiner combiner_;
356
 
    UrlMultipartEncoder encoder_;
357
 
    MockScheduler* scheduler_;
358
 
    int64 time_at_start_of_rewrite_us_;
359
 
    CombiningFilter* filter_;
360
 
  };
361
 
 
362
 
  virtual void StartDocumentImpl() {}
363
 
  virtual void StartElementImpl(HtmlElement* element);
364
 
  virtual void Flush() {
365
 
    if (context_.get() != NULL) {
366
 
      driver()->InitiateRewrite(context_.release());
367
 
    }
368
 
  }
369
 
 
370
 
  virtual void EndElementImpl(HtmlElement* element) {}
371
 
  virtual const char* Name() const { return "Combining"; }
372
 
  RewriteContext* MakeRewriteContext() {
373
 
    return new Context(driver(), this, scheduler_);
374
 
  }
375
 
  virtual const UrlSegmentEncoder* encoder() const { return &encoder_; }
376
 
 
377
 
  virtual bool ComputeOnTheFly() const { return on_the_fly_; }
378
 
 
379
 
  int num_rewrites() const { return num_rewrites_; }
380
 
  int num_render() const { return num_render_; }
381
 
  int num_will_not_render() const { return num_will_not_render_; }
382
 
  int num_cancel() const { return num_cancel_; }
383
 
 
384
 
  void ClearStats() { num_rewrites_ = 0; }
385
 
  int64 rewrite_delay_ms() const { return rewrite_delay_ms_; }
386
 
  void set_rewrite_block_on(WorkerTestBase::SyncPoint* sync) {
387
 
    rewrite_block_on_ = sync;
388
 
  }
389
 
 
390
 
  void set_rewrite_signal_on(WorkerTestBase::SyncPoint* sync) {
391
 
    rewrite_signal_on_ = sync;
392
 
  }
393
 
 
394
 
  // Each entry in combination will be prefixed with this.
395
 
  void set_prefix(const GoogleString& prefix) { prefix_ = prefix; }
396
 
 
397
 
  void set_on_the_fly(bool v) { on_the_fly_ = v; }
398
 
 
399
 
  void set_disable_successors(bool v) { disable_successors_ = v; }
400
 
 
401
 
  bool optimization_only() const { return optimization_only_; }
402
 
  void set_optimization_only(bool o) { optimization_only_ = o; }
403
 
 
404
 
 private:
405
 
  friend class Context;
406
 
 
407
 
  scoped_ptr<Context> context_;
408
 
  UrlMultipartEncoder encoder_;
409
 
  MockScheduler* scheduler_;
410
 
  int num_rewrites_;
411
 
  int num_render_;
412
 
  int num_will_not_render_;
413
 
  int num_cancel_;
414
 
  int64 rewrite_delay_ms_;
415
 
 
416
 
  // If this is non-NULL, the actual rewriting will block until this is
417
 
  // signaled. Applied before rewrite_delay_ms_
418
 
  WorkerTestBase::SyncPoint* rewrite_block_on_;
419
 
 
420
 
  // If this is non-NULL, this will be signaled the moment rewrite is called
421
 
  // on the context, before rewrite_block_on_ and rewrite_delay_ms_ are
422
 
  // applied.
423
 
  WorkerTestBase::SyncPoint* rewrite_signal_on_;
424
 
  GoogleString prefix_;
425
 
  bool on_the_fly_;  // If true, will act as an on-the-fly filter.
426
 
  bool optimization_only_;  // If false, will disable load-shedding and fetch
427
 
                            // rewrite deadlines.
428
 
  bool disable_successors_;  // if true, will disable successors for all
429
 
                             // slots, not just mutated ones.
430
 
 
431
 
  DISALLOW_COPY_AND_ASSIGN(CombiningFilter);
432
 
};
433
 
 
434
 
class RewriteContextTestBase : public RewriteTestBase {
435
 
 protected:
436
 
  static const int64 kRewriteDeadlineMs = 20;
437
 
 
438
 
  // Use a TTL value other than the implicit value, so we are sure we are using
439
 
  // the original TTL value.
440
 
  static const int64 kOriginTtlMs = 12 * Timer::kMinuteMs;
441
 
  // An TTL value that is lower than the default implicit TTL value (300
442
 
  // seconds).
443
 
  static const int64 kLowOriginTtlMs = 5 * Timer::kSecondMs;
444
 
 
445
 
  // Use a TTL value other than the implicit value, so we are sure we are using
446
 
  // the original TTL value.
447
 
  GoogleString OriginTtlMaxAge() {
448
 
    return StrCat("max-age=", Integer64ToString(
449
 
        kOriginTtlMs / Timer::kSecondMs));
450
 
  }
451
 
 
452
 
  RewriteContextTestBase(
453
 
      std::pair<TestRewriteDriverFactory*, TestRewriteDriverFactory*> factories)
454
 
      : RewriteTestBase(factories) {}
455
 
  RewriteContextTestBase() {}
456
 
  virtual ~RewriteContextTestBase();
457
 
 
458
 
  virtual void SetUp();
459
 
  virtual void TearDown();
460
 
  virtual bool AddBody() const { return false; }
461
 
  virtual void ClearStats();
462
 
 
463
 
  void InitResources() { InitResourcesToDomain(kTestDomain); }
464
 
  void InitResourcesToDomain(const char* domain);
465
 
  void InitTrimFilters(OutputResourceKind kind);
466
 
  void InitUpperFilter(OutputResourceKind kind, RewriteDriver* rewrite_driver);
467
 
  void InitCombiningFilter(int64 rewrite_delay_ms);
468
 
  void InitNestedFilter(bool expected_nested_rewrite_result);
469
 
 
470
 
  TrimWhitespaceRewriter* trim_filter_;
471
 
  TrimWhitespaceRewriter* other_trim_filter_;
472
 
  CombiningFilter* combining_filter_;
473
 
  NestedFilter* nested_filter_;
474
 
};
475
 
 
476
 
}  // namespace net_instaweb
477
 
 
478
 
#endif  // NET_INSTAWEB_REWRITER_PUBLIC_REWRITE_CONTEXT_TEST_BASE_H_