1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #define LARGE_FILE 10 * 1024 * 1024
25 #define SMALL_FILE 10 * 1024
26 
27 #include "main.h"
28 
29 class CacheUpdateReadAgain : public CacheTestHandler
30 {
31 public:
CacheUpdateReadAgain(size_t size,const char * url)32   CacheUpdateReadAgain(size_t size, const char *url) : CacheTestHandler()
33   {
34     auto rt   = new CacheReadTest(size, this, url);
35     rt->mutex = this->mutex;
36 
37     rt->info.destroy();
38     rt->info.create();
39     build_hdrs(rt->info, url, "application/x-javascript");
40 
41     this->_rt = rt;
42 
43     SET_HANDLER(&CacheUpdateReadAgain::start_test);
44   }
45 
46   int
start_test(int event,void * e)47   start_test(int event, void *e)
48   {
49     REQUIRE(event == EVENT_IMMEDIATE);
50     this_ethread()->schedule_imm(this->_rt);
51     return 0;
52   }
53 
54   void
handle_cache_event(int event,CacheTestBase * base)55   handle_cache_event(int event, CacheTestBase *base) override
56   {
57     switch (event) {
58     case CACHE_EVENT_OPEN_READ:
59       base->do_io_read();
60       this->validate_content_type(base);
61       this->check_fragment_table(base);
62       break;
63     case VC_EVENT_READ_READY:
64       base->reenable();
65       break;
66     case VC_EVENT_READ_COMPLETE:
67       base->close();
68       delete this;
69       break;
70     default:
71       REQUIRE(false);
72       break;
73     }
74   }
75 
76   void
validate_content_type(CacheTestBase * base)77   validate_content_type(CacheTestBase *base)
78   {
79     auto rt = dynamic_cast<CacheReadTest *>(base);
80     REQUIRE(rt);
81     MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
82     REQUIRE(field);
83     int len;
84     const char *value = field->value_get(&len);
85     REQUIRE(memcmp(value, "application/x-javascript", len) == 0);
86   }
87 
88   void
check_fragment_table(CacheTestBase * base)89   check_fragment_table(CacheTestBase *base)
90   {
91     REQUIRE(base->vc->alternate.get_frag_table() != nullptr);
92     REQUIRE(base->vc->alternate.get_frag_offset_count() != 0);
93   }
94 };
95 
96 class CacheUpdateHeader : public CacheTestHandler
97 {
98 public:
CacheUpdateHeader(size_t read_size,const char * url)99   CacheUpdateHeader(size_t read_size, const char *url)
100   {
101     auto rt = new CacheReadTest(read_size, this, url);
102     auto wt = new CacheWriteTest(read_size, this, url);
103 
104     wt->info.destroy();
105     wt->info.create();
106     build_hdrs(wt->info, url, "application/x-javascript");
107 
108     this->_rt = rt;
109     this->_wt = wt;
110 
111     this->_rt->mutex = this->mutex;
112     this->_wt->mutex = this->mutex;
113 
114     SET_HANDLER(&CacheUpdateHeader::start_test);
115   }
116 
117   int
start_test(int event,void * e)118   start_test(int event, void *e)
119   {
120     REQUIRE(event == EVENT_IMMEDIATE);
121     this_ethread()->schedule_imm(this->_rt);
122     return 0;
123   }
124 
125   void
handle_cache_event(int event,CacheTestBase * base)126   handle_cache_event(int event, CacheTestBase *base) override
127   {
128     CacheWriteTest *wt = static_cast<CacheWriteTest *>(this->_wt);
129     switch (event) {
130     case CACHE_EVENT_OPEN_WRITE:
131       base->do_io_write();
132       // commit the header change
133       this->_wt->close();
134       this->_wt = nullptr;
135       delete this;
136       break;
137     case CACHE_EVENT_OPEN_READ:
138       base->do_io_read();
139       wt->old_info.copy(static_cast<HTTPInfo *>(&base->vc->alternate));
140       break;
141     case VC_EVENT_READ_READY:
142       base->reenable();
143       break;
144     case VC_EVENT_READ_COMPLETE:
145       this->_rt->close();
146       this->_rt = nullptr;
147       this_ethread()->schedule_imm(this->_wt);
148       break;
149     default:
150       REQUIRE(false);
151       break;
152     }
153   }
154 };
155 
156 class CacheUpdateInit : public CacheInit
157 {
158 public:
CacheUpdateInit()159   CacheUpdateInit() {}
160   int
cache_init_success_callback(int event,void * e)161   cache_init_success_callback(int event, void *e) override
162   {
163     CacheTestHandler *h        = new CacheTestHandler(LARGE_FILE, "http://www.scw11.com");
164     CacheUpdateHeader *update  = new CacheUpdateHeader(LARGE_FILE, "http://www.scw11.com");
165     CacheUpdateReadAgain *read = new CacheUpdateReadAgain(LARGE_FILE, "http://www.scw11.com");
166     TerminalTest *tt           = new TerminalTest;
167 
168     h->add(update);
169     h->add(read); // read again
170     h->add(tt);
171     this_ethread()->schedule_imm(h);
172     delete this;
173     return 0;
174   }
175 };
176 
177 TEST_CASE("cache write -> read", "cache")
178 {
179   init_cache(256 * 1024 * 1024);
180   // large write test
181   CacheUpdateInit *init = new CacheUpdateInit;
182 
183   this_ethread()->schedule_imm(init);
184   this_thread()->execute();
185 }
186