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