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 // delete dir
30 Dir dir = {};
31 
32 class CacheAltReadAgain2 : public CacheTestHandler
33 {
34 public:
CacheAltReadAgain2(size_t size,const char * url)35   CacheAltReadAgain2(size_t size, const char *url) : CacheTestHandler()
36   {
37     auto rt = new CacheReadTest(size, this, url);
38 
39     rt->mutex = this->mutex;
40     this->_rt = rt;
41     SET_HANDLER(&CacheAltReadAgain2::start_test);
42   }
43 
44   int
start_test(int event,void * e)45   start_test(int event, void *e)
46   {
47     REQUIRE(event == EVENT_IMMEDIATE);
48     this_ethread()->schedule_imm(this->_rt);
49     return 0;
50   }
51 
52   void
handle_cache_event(int event,CacheTestBase * base)53   handle_cache_event(int event, CacheTestBase *base) override
54   {
55     switch (event) {
56     case CACHE_EVENT_OPEN_READ:
57       base->do_io_read();
58       validate_content_type(base);
59       break;
60     case VC_EVENT_READ_READY:
61       base->reenable();
62       break;
63     case VC_EVENT_READ_COMPLETE:
64       base->close();
65       delete this;
66       break;
67     default:
68       REQUIRE(false);
69       break;
70     }
71   }
72 
73   void
validate_content_type(CacheTestBase * base)74   validate_content_type(CacheTestBase *base)
75   {
76     auto rt = dynamic_cast<CacheReadTest *>(base);
77     REQUIRE(rt);
78     MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
79     REQUIRE(field);
80     int len;
81     const char *value = field->value_get(&len);
82     REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0);
83   }
84 };
85 
86 class CacheAltReadAgain : public CacheTestHandler
87 {
88 public:
CacheAltReadAgain(size_t size,const char * url)89   CacheAltReadAgain(size_t size, const char *url) : CacheTestHandler()
90   {
91     auto rt = new CacheReadTest(size, this, url);
92 
93     rt->mutex = this->mutex;
94 
95     rt->info.destroy();
96 
97     rt->info.create();
98     build_hdrs(rt->info, url, "application/x-javascript");
99 
100     this->_rt = rt;
101 
102     SET_HANDLER(&CacheAltReadAgain::start_test);
103   }
104 
105   int
start_test(int event,void * e)106   start_test(int event, void *e)
107   {
108     REQUIRE(event == EVENT_IMMEDIATE);
109     // sleep for a while to wait for writer close
110     this_ethread()->schedule_imm(this->_rt);
111     return 0;
112   }
113 
114   void
handle_cache_event(int event,CacheTestBase * base)115   handle_cache_event(int event, CacheTestBase *base) override
116   {
117     switch (event) {
118     case CACHE_EVENT_OPEN_READ_FAILED:
119       delete this;
120       break;
121     default:
122       REQUIRE(false);
123       break;
124     }
125   }
126 
127   void
validate_content_type(CacheTestBase * base)128   validate_content_type(CacheTestBase *base)
129   {
130     auto rt = dynamic_cast<CacheReadTest *>(base);
131     REQUIRE(rt);
132     MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
133     REQUIRE(field);
134     int len;
135     const char *value = field->value_get(&len);
136     REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0);
137   }
138 };
139 
140 class CacheAltTest_S_to_L_remove_L : public CacheTestHandler
141 {
142 public:
CacheAltTest_S_to_L_remove_L(size_t size,const char * url)143   CacheAltTest_S_to_L_remove_L(size_t size, const char *url) : CacheTestHandler()
144   {
145     auto rt = new CacheReadTest(size, this, url);
146     auto wt = new CacheWriteTest(size, this, url);
147 
148     rt->info.destroy();
149     wt->info.destroy();
150 
151     rt->info.create();
152     wt->info.create();
153 
154     build_hdrs(rt->info, url, "application/x-javascript");
155     build_hdrs(wt->info, url, "application/x-javascript");
156 
157     this->_rt = rt;
158     this->_wt = wt;
159 
160     this->_rt->mutex = this->mutex;
161     this->_wt->mutex = this->mutex;
162 
163     SET_HANDLER(&CacheAltTest_S_to_L_remove_L::start_test);
164   }
165 
166   int
start_test(int event,void * e)167   start_test(int event, void *e)
168   {
169     REQUIRE(event == EVENT_IMMEDIATE);
170     this_ethread()->schedule_imm(this->_wt);
171     return 0;
172   }
173 
174   void
handle_cache_event(int event,CacheTestBase * base)175   handle_cache_event(int event, CacheTestBase *base) override
176   {
177     switch (event) {
178     case CACHE_EVENT_OPEN_WRITE:
179       base->do_io_write();
180       break;
181     case VC_EVENT_WRITE_READY:
182       base->reenable();
183       break;
184     case VC_EVENT_WRITE_COMPLETE:
185       this->_wt->close();
186       this->_wt = nullptr;
187       // to make sure writer successfully write the final doc done. we need to schedule
188       // to wait for some while. This time should be large than cache_config_mutex_retry_delay
189       this_ethread()->schedule_in(this->_rt, HRTIME_SECONDS(1));
190       break;
191     case CACHE_EVENT_OPEN_READ:
192       base->do_io_read();
193       validate_content_type(base);
194       break;
195     case VC_EVENT_READ_READY:
196       base->reenable();
197       break;
198     case VC_EVENT_READ_COMPLETE:
199       delete_earliest_dir(base->vc);
200       base->close();
201       delete this;
202       break;
203     default:
204       REQUIRE(false);
205       break;
206     }
207   }
208 
209   void
validate_content_type(CacheTestBase * base)210   validate_content_type(CacheTestBase *base)
211   {
212     auto rt = dynamic_cast<CacheReadTest *>(base);
213     REQUIRE(rt);
214     MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE);
215     REQUIRE(field);
216     int len;
217     const char *value = field->value_get(&len);
218     REQUIRE(memcmp(value, "application/x-javascript", len) == 0);
219   }
220 
221   void
delete_earliest_dir(CacheVC * vc)222   delete_earliest_dir(CacheVC *vc)
223   {
224     CacheKey key        = {};
225     Dir *last_collision = nullptr;
226     SCOPED_MUTEX_LOCK(lock, vc->vol->mutex, this->mutex->thread_holding);
227     vc->vector.data[1].alternate.object_key_get(&key);
228     REQUIRE(dir_probe(&key, vc->vol, &dir, &last_collision) != 0);
229     REQUIRE(dir_delete(&key, vc->vol, &dir));
230   }
231 };
232 
233 class CacheAltInit : public CacheInit
234 {
235 public:
CacheAltInit()236   CacheAltInit() {}
237   int
cache_init_success_callback(int event,void * e)238   cache_init_success_callback(int event, void *e) override
239   {
240     CacheTestHandler *h              = new CacheTestHandler(SMALL_FILE, "http://www.scw11.com");
241     CacheAltTest_S_to_L_remove_L *ls = new CacheAltTest_S_to_L_remove_L(LARGE_FILE, "http://www.scw11.com");
242     CacheAltReadAgain *read          = new CacheAltReadAgain(LARGE_FILE, "http://www.scw11.com");
243     CacheAltReadAgain2 *read2        = new CacheAltReadAgain2(SMALL_FILE, "http://www.scw11.com");
244     TerminalTest *tt                 = new TerminalTest;
245 
246     h->add(ls);
247     h->add(read); // read again
248     h->add(read2);
249     h->add(tt);
250     this_ethread()->schedule_imm(h);
251     delete this;
252     return 0;
253   }
254 };
255 
256 TEST_CASE("cache write -> read", "cache")
257 {
258   init_cache(256 * 1024 * 1024);
259   // large write test
260   CacheAltInit *init = new CacheAltInit;
261 
262   this_ethread()->schedule_imm(init);
263   this_thread()->execute();
264 }
265