This is an automated email from the ASF dual-hosted git repository. scw00 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push: new 768bcf8 Adds Cache test suits 768bcf8 is described below commit 768bcf8cf9b7d6fc36ec9145aed0ae1d9879e056 Author: scw00 <sc...@apache.org> AuthorDate: Fri Mar 15 22:21:12 2019 +0800 Adds Cache test suits --- .gitignore | 3 + iocore/cache/Makefile.am | 124 ++++++ iocore/cache/test/CacheTestHandler.cc | 76 ++++ iocore/cache/test/CacheTestHandler.h | 99 +++++ iocore/cache/test/main.cc | 273 +++++++++++++ iocore/cache/test/main.h | 232 +++++++++++ iocore/cache/test/storage.config | Bin 0 -> 24 bytes iocore/cache/test/stub.cc | 264 +++++++++++++ iocore/cache/test/test_Alternate_L_to_S.cc | 191 +++++++++ .../cache/test/test_Alternate_L_to_S_remove_L.cc | 260 +++++++++++++ .../cache/test/test_Alternate_L_to_S_remove_S.cc | 261 +++++++++++++ iocore/cache/test/test_Alternate_S_to_L.cc | 191 +++++++++ .../cache/test/test_Alternate_S_to_L_remove_L.cc | 264 +++++++++++++ .../cache/test/test_Alternate_S_to_L_remove_S.cc | 262 +++++++++++++ iocore/cache/test/test_Cache.cc | 55 +++ iocore/cache/test/test_RWW.cc | 429 +++++++++++++++++++++ iocore/cache/test/var/trafficserver/guard.txt | 24 ++ 17 files changed, 3008 insertions(+) diff --git a/.gitignore b/.gitignore index 0c7f285..3b85d10 100644 --- a/.gitignore +++ b/.gitignore @@ -178,3 +178,6 @@ RELEASE # autest tests/env-test/ + +iocore/cache/test_* +iocore/cache/test/var/trafficserver/cache.db diff --git a/iocore/cache/Makefile.am b/iocore/cache/Makefile.am index ed05579..a9993a3 100644 --- a/iocore/cache/Makefile.am +++ b/iocore/cache/Makefile.am @@ -66,6 +66,130 @@ libinkcache_a_SOURCES += \ P_CacheTest.h endif +TESTS = $(check_PROGRAMS) + +test_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + $(iocore_include_dirs) \ + -I$(abs_top_srcdir)/include \ + -I$(abs_top_srcdir)/lib \ + -I$(abs_top_srcdir)/proxy \ + -I$(abs_top_srcdir)/proxy/http \ + -I$(abs_top_srcdir)/proxy/http2 \ + -I$(abs_top_srcdir)/proxy/http3 \ + -I$(abs_top_srcdir)/proxy/logging \ + -I$(abs_top_srcdir)/proxy/http/remap \ + -I$(abs_top_srcdir)/proxy/hdrs \ + -I$(abs_top_srcdir)/proxy/shared \ + -I$(abs_top_srcdir)/mgmt \ + -I$(abs_top_srcdir)/mgmt/utils \ + -I$(abs_top_srcdir)/tests/include \ + $(TS_INCLUDES) \ + @OPENSSL_INCLUDES@ + +test_LDADD = \ + $(top_builddir)/src/tscpp/util/libtscpputil.la \ + $(top_builddir)/iocore/cache/libinkcache.a \ + $(top_builddir)/proxy/libproxy.a \ + $(top_builddir)/proxy/http/libhttp.a \ + $(top_builddir)/proxy/http/remap/libhttp_remap.a \ + $(top_builddir)/proxy/libproxy.a \ + $(top_builddir)/iocore/net/libinknet.a \ + $(top_builddir)/iocore/dns/libinkdns.a \ + $(top_builddir)/iocore/hostdb/libinkhostdb.a \ + $(top_builddir)/proxy/logging/liblogging.a \ + $(top_builddir)/proxy/hdrs/libhdrs.a \ + $(top_builddir)/proxy/logging/liblogcollation.a \ + $(top_builddir)/proxy/shared/libdiagsconfig.a \ + $(top_builddir)/mgmt/libmgmt_p.la \ + $(top_builddir)/iocore/utils/libinkutils.a \ + $(top_builddir)/iocore/aio/libinkaio.a \ + $(top_builddir)/src/tscore/libtscore.la \ + $(top_builddir)/lib/records/librecords_p.a \ + $(top_builddir)/iocore/eventsystem/libinkevent.a \ + $(top_builddir)/lib/tsconfig/libtsconfig.la \ + @HWLOC_LIBS@ \ + @LIBPCRE@ \ + @LIBRESOLV@ \ + @LIBZ@ \ + @LIBLZMA@ \ + @LIBPROFILER@ \ + @OPENSSL_LIBS@ \ + @YAMLCPP_LIBS@ \ + -lm + + +check_PROGRAMS = \ + test_Cache \ + test_RWW \ + test_Alternate_L_to_S \ + test_Alternate_S_to_L \ + test_Alternate_L_to_S_remove_L \ + test_Alternate_L_to_S_remove_S \ + test_Alternate_S_to_L_remove_S \ + test_Alternate_S_to_L_remove_L + +test_main_SOURCES = \ + ./test/main.cc \ + ./test/stub.cc \ + ./test/CacheTestHandler.cc + +test_Cache_CPPFLAGS = $(test_CPPFLAGS) +test_Cache_LDFLAGS = @AM_LDFLAGS@ +test_Cache_LDADD = $(test_LDADD) +test_Cache_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_Cache.cc + +test_RWW_CPPFLAGS = $(test_CPPFLAGS) +test_RWW_LDFLAGS = @AM_LDFLAGS@ +test_RWW_LDADD = $(test_LDADD) +test_RWW_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_RWW.cc + +test_Alternate_L_to_S_CPPFLAGS = $(test_CPPFLAGS) +test_Alternate_L_to_S_LDFLAGS = @AM_LDFLAGS@ +test_Alternate_L_to_S_LDADD = $(test_LDADD) +test_Alternate_L_to_S_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_Alternate_L_to_S.cc + +test_Alternate_S_to_L_CPPFLAGS = $(test_CPPFLAGS) +test_Alternate_S_to_L_LDFLAGS = @AM_LDFLAGS@ +test_Alternate_S_to_L_LDADD = $(test_LDADD) +test_Alternate_S_to_L_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_Alternate_S_to_L.cc + +test_Alternate_L_to_S_remove_L_CPPFLAGS = $(test_CPPFLAGS) +test_Alternate_L_to_S_remove_L_LDFLAGS = @AM_LDFLAGS@ +test_Alternate_L_to_S_remove_L_LDADD = $(test_LDADD) +test_Alternate_L_to_S_remove_L_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_Alternate_L_to_S_remove_L.cc + +test_Alternate_L_to_S_remove_S_CPPFLAGS = $(test_CPPFLAGS) +test_Alternate_L_to_S_remove_S_LDFLAGS = @AM_LDFLAGS@ +test_Alternate_L_to_S_remove_S_LDADD = $(test_LDADD) +test_Alternate_L_to_S_remove_S_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_Alternate_L_to_S_remove_S.cc + +test_Alternate_S_to_L_remove_S_CPPFLAGS = $(test_CPPFLAGS) +test_Alternate_S_to_L_remove_S_LDFLAGS = @AM_LDFLAGS@ +test_Alternate_S_to_L_remove_S_LDADD = $(test_LDADD) +test_Alternate_S_to_L_remove_S_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_Alternate_S_to_L_remove_S.cc + +test_Alternate_S_to_L_remove_L_CPPFLAGS = $(test_CPPFLAGS) +test_Alternate_S_to_L_remove_L_LDFLAGS = @AM_LDFLAGS@ +test_Alternate_S_to_L_remove_L_LDADD = $(test_LDADD) +test_Alternate_S_to_L_remove_L_SOURCES = \ + $(test_main_SOURCES) \ + ./test/test_Alternate_S_to_L_remove_L.cc + include $(top_srcdir)/build/tidy.mk clang-tidy-local: $(DIST_SOURCES) diff --git a/iocore/cache/test/CacheTestHandler.cc b/iocore/cache/test/CacheTestHandler.cc new file mode 100644 index 0000000..72cecea --- /dev/null +++ b/iocore/cache/test/CacheTestHandler.cc @@ -0,0 +1,76 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + 1 test_Cache.cc + X distributed with this work for additional information regarding copyright ownership. The ASF licenses this + file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "main.h" +#include "CacheTestHandler.h" + +TestContChain::TestContChain() : Continuation(new_ProxyMutex()) {} + +CacheTestHandler::CacheTestHandler(size_t size, const char *url) +{ + this->_wt = new CacheWriteTest(size, this, url); + this->_rt = new CacheReadTest(size, this, url); + + this->_wt->mutex = this->mutex; + this->_rt->mutex = this->mutex; + SET_HANDLER(&CacheTestHandler::start_test); +} + +void +CacheTestHandler::handle_cache_event(int event, CacheTestBase *base) +{ + REQUIRE(base != nullptr); + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + break; + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_READ_READY: + case VC_EVENT_WRITE_READY: + REQUIRE(base->vc != nullptr); + REQUIRE(base->vio != nullptr); + base->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + this_ethread()->schedule_imm(this->_rt); + base->close(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + base->close(); + delete this; + break; + } + return; +} + +int +CacheTestHandler::start_test(int event, void *e) +{ + this_ethread()->schedule_imm(this->_wt); + return 0; +} diff --git a/iocore/cache/test/CacheTestHandler.h b/iocore/cache/test/CacheTestHandler.h new file mode 100644 index 0000000..3d2c1a0 --- /dev/null +++ b/iocore/cache/test/CacheTestHandler.h @@ -0,0 +1,99 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +void test_done(); + +#define TEST_DONE() test_done(); +#define T_DONE 1 +#define T_CONT 1 + +#define DEFAULT_URL "http://www.scw00.com/" + +#include <cstddef> + +class CacheTestBase; + +struct TestContChain : public Continuation { + TestContChain(); + virtual ~TestContChain() { this->next_test(); } + + void + add(TestContChain *n) + { + TestContChain *p = this; + while (p->next) { + p = p->next; + } + p->next = n; + } + + bool + next_test() + { + if (!this->next) { + return false; + } + + this_ethread()->schedule_imm(this->next); + return true; + } + + TestContChain *next = nullptr; +}; + +class CacheTestHandler : public TestContChain +{ +public: + CacheTestHandler() = default; + CacheTestHandler(size_t size, const char *url = DEFAULT_URL); + + int start_test(int event, void *e); + + virtual void handle_cache_event(int event, CacheTestBase *base); + +protected: + CacheTestBase *_rt = nullptr; + CacheTestBase *_wt = nullptr; +}; + +class TerminalTest : public CacheTestHandler +{ +public: + TerminalTest() { SET_HANDLER(&TerminalTest::terminal_event); } + ~TerminalTest() { TEST_DONE(); } + + int + terminal_event(int event, void *e) + { + delete this; + return 0; + } + + void + handle_cache_event(int event, CacheTestBase *e) override + { + delete this; + } +}; diff --git a/iocore/cache/test/main.cc b/iocore/cache/test/main.cc new file mode 100644 index 0000000..c62cd3f --- /dev/null +++ b/iocore/cache/test/main.cc @@ -0,0 +1,273 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define CATCH_CONFIG_MAIN +#include "main.h" + +#define THREADS 1 +#define DIAGS_LOG_FILE "diags.log" + +char working_dir[1024] = {0}; +void +test_done() +{ + shutdown_event_system = true; +} + +const char *GLOBAL_DATA = (char *)ats_malloc(10 * 1024 * 1024 + 3); // 10M + +struct EventProcessorListener : Catch::TestEventListenerBase { + using TestEventListenerBase::TestEventListenerBase; // inherit constructor + + virtual void + testRunStarting(Catch::TestRunInfo const &testRunInfo) override + { + getcwd(working_dir, 1024); + BaseLogFile *base_log_file = new BaseLogFile("stderr"); + diags = new Diags(testRunInfo.name.c_str(), "*" /* tags */, "" /* actions */, base_log_file); + diags->activate_taglist("cache.*|agg.*|locks", DiagsTagType_Debug); + diags->config.enabled[DiagsTagType_Debug] = true; + diags->show_location = SHOW_LOCATION_DEBUG; + + mime_init(); + Layout::create(); + RecProcessInit(RECM_STAND_ALONE); + LibRecordsConfigInit(); + ink_net_init(ts::ModuleVersion(1, 0, ts::ModuleVersion::PRIVATE)); + ink_assert(GLOBAL_DATA != nullptr); + + netProcessor.init(); + eventProcessor.start(THREADS); + + ink_aio_init(AIO_MODULE_PUBLIC_VERSION); + + EThread *thread = new EThread(); + thread->set_specific(); + init_buffer_allocators(0); + + Layout::get()->sysconfdir = std::string_view("./test"); + Layout::get()->prefix = std::string_view("./test"); + ::remove("./test/var/trafficserver/cache.db"); + } +}; +CATCH_REGISTER_LISTENER(EventProcessorListener); + +extern Store theCacheStore; + +void +init_cache(size_t size, const char *name) +{ + ink_cache_init(ts::ModuleVersion(1, 0, ts::ModuleVersion::PRIVATE)); + cacheProcessor.start(); +} + +void +build_hdrs(HTTPInfo &info, const char *url, const char *content_type) +{ + HTTPHdr req; + HTTPHdr resp; + HTTPParser parser; + int err = -1; + char buf[1024] = {0}; + const char *start = buf; + char *p = buf; + + REQUIRE(url != nullptr); + + p += sprintf(p, "GET %s HTTP/1.1\n", url); + p += sprintf(p, "User-Agent: curl/7.47.0\n"); + p += sprintf(p, "Accept: %s\n", content_type); + p += sprintf(p, "Vary: Content-type\n"); + p += sprintf(p, "Proxy-Connection: Keep-Alive\n\n"); + + req.create(HTTP_TYPE_REQUEST); + http_parser_init(&parser); + + while (true) { + err = req.parse_req(&parser, &start, p, true); + if (err != PARSE_RESULT_CONT) { + break; + } + } + + ink_assert(err == PARSE_RESULT_DONE); + + memset(buf, 0, sizeof(buf)); + p = buf; + + if (content_type == nullptr) { + content_type = "application/octet-stream"; + } + + p = buf; + p += sprintf(p, "HTTP/1.1 200 OK\n"); + p += sprintf(p, "Content-Type: %s\n", content_type); + p += sprintf(p, "Expires: Fri, 15 Mar 2219 08:55:45 GMT\n"); + p += sprintf(p, "Last-Modified: Thu, 14 Mar 2019 08:47:40 GMT\n\n"); + + resp.create(HTTP_TYPE_RESPONSE); + http_parser_init(&parser); + start = buf; + + while (true) { + err = resp.parse_resp(&parser, &start, p, true); + if (err != PARSE_RESULT_CONT) { + break; + } + } + ink_assert(err == PARSE_RESULT_DONE); + + info.request_set(&req); + info.response_set(&resp); + + req.destroy(); + resp.destroy(); +} + +HttpCacheKey +generate_key(HTTPInfo &info) +{ + HttpCacheKey key; + Cache::generate_key(&key, info.request_get()->url_get(), 1); + return key; +} + +void +CacheWriteTest::fill_data() +{ + size_t size = std::min(WRITE_LIMIT, this->_size); + auto n = this->_write_buffer->write(this->_cursor, size); + this->_size -= n; + this->_cursor += n; +} + +int +CacheWriteTest::write_event(int event, void *e) +{ + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + this->vc = (CacheVC *)e; + /* fall through */ + case CACHE_EVENT_OPEN_WRITE_FAILED: + this->process_event(event); + break; + case VC_EVENT_WRITE_READY: + this->process_event(event); + this->fill_data(); + break; + case VC_EVENT_WRITE_COMPLETE: + this->process_event(event); + break; + default: + this->close(); + CHECK(false); + break; + } + return 0; +} + +void +CacheWriteTest::do_io_write(size_t size) +{ + if (size == 0) { + size = this->_size; + } + this->vc->set_http_info(&this->info); + this->vio = this->vc->do_io_write(this, size, this->_write_buffer->alloc_reader()); +} + +int +CacheWriteTest::start_test(int event, void *e) +{ + Debug("cache test", "start write test"); + + HttpCacheKey key; + key = generate_key(this->info); + + SET_HANDLER(&CacheWriteTest::write_event); + cacheProcessor.open_write(this, 0, &key, (CacheHTTPHdr *)this->info.request_get(), nullptr); + return 0; +} + +int +CacheReadTest::read_event(int event, void *e) +{ + switch (event) { + case CACHE_EVENT_OPEN_READ: + this->vc = (CacheVC *)e; + /* fall through */ + case CACHE_EVENT_OPEN_READ_FAILED: + this->process_event(event); + break; + case VC_EVENT_READ_READY: { + while (this->_reader->block_read_avail()) { + auto str = this->_reader->block_read_view(); + if (memcmp(str.data(), this->_cursor, str.size()) == 0) { + this->_reader->consume(str.size()); + this->_cursor += str.size(); + this->process_event(event); + } else { + CHECK(false); + this->close(); + TEST_DONE(); + break; + } + } + break; + } + case VC_EVENT_ERROR: + case VC_EVENT_EOS: + case VC_EVENT_READ_COMPLETE: + this->process_event(event); + break; + default: + CHECK(false); + this->close(); + break; + } + return 0; +} + +void +CacheReadTest::do_io_read(size_t size) +{ + if (size == 0) { + size = this->_size; + } + this->vc->get_http_info(&this->read_http_info); + this->vio = this->vc->do_io_read(this, size, this->_read_buffer); +} + +int +CacheReadTest::start_test(int event, void *e) +{ + Debug("cache test", "start read test"); + HttpCacheKey key; + key = generate_key(this->info); + + SET_HANDLER(&CacheReadTest::read_event); + cacheProcessor.open_read(this, &key, (CacheHTTPHdr *)this->info.request_get(), &this->params); + return 0; +} + +constexpr size_t WRITE_LIMIT = 1024 * 3; diff --git a/iocore/cache/test/main.h b/iocore/cache/test/main.h new file mode 100644 index 0000000..b4dc4ee --- /dev/null +++ b/iocore/cache/test/main.h @@ -0,0 +1,232 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#pragma once + +#include <cstddef> + +#include "catch.hpp" + +#include "tscore/I_Layout.h" +#include "tscore/Diags.h" + +#include "RecordsConfig.h" +#include "records/I_RecProcess.h" +#include "P_AIO.h" +#include "P_CacheDisk.h" +#include "P_Net.h" +#include "test/CacheTestHandler.h" +#include "P_Cache.h" + +#include <queue> + +// redefine BUILD PREFIX +#ifdef TS_BUILD_PREFIX +#undef TS_BUILD_PREFIX +#endif +#define TS_BUILD_PREFIX "./test" + +#ifdef TS_BUILD_EXEC_PREFIX +#undef TS_BUILD_EXEC_PREFIX +#endif +#define TS_BUILD_EXEC_PREFIX "./test" + +#ifdef TS_BUILD_SYSCONFDIR +#undef TS_BUILD_SYSCONFDIR +#endif +#define TS_BUILD_SYSCONFDIR "./test" + +#define SLEEP_TIME 20000 + +void init_cache(size_t size, const char *name = "cache.db"); +void build_hdrs(HTTPInfo &info, const char *url, const char *content_type = "text/html;charset=utf-8"); + +HttpCacheKey generate_key(HTTPInfo &info); + +extern const char *GLOBAL_DATA; +extern size_t const WRITE_LIMIT; + +class CacheInit : public Continuation +{ +public: + CacheInit() : Continuation(new_ProxyMutex()) { SET_HANDLER(&CacheInit::init_event); } + + int + start_event(int event, void *e) + { + Debug("cache_test", "cache init successfully"); + this->cache_init_success_callback(event, e); + return 0; + } + + int + init_event(int event, void *e) + { + switch (event) { + case EVENT_INTERVAL: + case EVENT_IMMEDIATE: + if (!CacheProcessor::IsCacheReady(CACHE_FRAG_TYPE_HTTP)) { + this_ethread()->schedule_in(this, SLEEP_TIME); + } else { + SET_HANDLER(&CacheInit::start_event); + this->handleEvent(event, e); + } + return 0; + default: + CHECK(false); + TEST_DONE(); + return 0; + } + + return 0; + } + + virtual int cache_init_success_callback(int event, void *e) = 0; + + virtual ~CacheInit() {} +}; + +class CacheTestBase : public Continuation +{ +public: + CacheTestBase(CacheTestHandler *test_handler) : Continuation(new_ProxyMutex()), test_handler(test_handler) + { + SET_HANDLER(&CacheTestBase::init_handler); + } + + int + init_handler(int event, void *e) + { + this->start_test(event, e); + return 0; + } + + // test entrance + virtual int start_test(int event, void *e) = 0; + + void + process_event(int event) + { + this->test_handler->handle_cache_event(event, this); + } + + virtual void + reenable() + { + if (this->vio) { + this->vio->reenable(); + } + } + + int + terminal_event(int event, void *e) + { + delete this; + return 0; + } + + void + close(int error = -1) + { + if (this->vc) { + this->vc->do_io_close(error); + this->vc = nullptr; + this->vio = nullptr; + } + + SET_HANDLER(&CacheTestBase::terminal_event); + if (!this->terminal) { + this->terminal = this_ethread()->schedule_imm(this); + } + } + + virtual void + do_io_read(size_t size = 0) + { + REQUIRE(!"should not be called"); + } + + virtual void + do_io_write(size_t size = 0) + { + REQUIRE(!"should not be called"); + } + + Event *terminal = nullptr; + CacheVC *vc = nullptr; + VIO *vio = nullptr; + CacheTestHandler *test_handler = nullptr; +}; + +class CacheWriteTest : public CacheTestBase +{ +public: + CacheWriteTest(size_t size, CacheTestHandler *cont, const char *url = "http://www.scw00.com/") : CacheTestBase(cont), _size(size) + { + this->_cursor = (char *)GLOBAL_DATA; + this->_write_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + + this->info.create(); + build_hdrs(this->info, url); + } + + int start_test(int event, void *e) override; + int write_event(int event, void *e); + void fill_data(); + void do_io_write(size_t size = 0) override; + + HTTPInfo info; + +private: + size_t _size = 0; + char *_cursor = nullptr; + MIOBuffer *_write_buffer = nullptr; +}; + +class CacheReadTest : public CacheTestBase +{ +public: + CacheReadTest(size_t size, CacheTestHandler *cont, const char *url = "http://www.scw00.com/") : CacheTestBase(cont), _size(size) + { + this->_cursor = (char *)GLOBAL_DATA; + this->_read_buffer = new_MIOBuffer(BUFFER_SIZE_INDEX_4K); + this->_reader = this->_read_buffer->alloc_reader(); + + this->info.create(); + build_hdrs(this->info, url); + } + + int start_test(int event, void *e) override; + int read_event(int event, void *e); + void do_io_read(size_t size = 0) override; + + HTTPInfo info; + HTTPInfo *read_http_info = nullptr; + +private: + size_t _size = 0; + char *_cursor = nullptr; + MIOBuffer *_read_buffer = nullptr; + IOBufferReader *_reader = nullptr; + OverridableHttpConfigParams params; +}; diff --git a/iocore/cache/test/storage.config b/iocore/cache/test/storage.config new file mode 100644 index 0000000..d86334e Binary files /dev/null and b/iocore/cache/test/storage.config differ diff --git a/iocore/cache/test/stub.cc b/iocore/cache/test/stub.cc new file mode 100644 index 0000000..d6710ec --- /dev/null +++ b/iocore/cache/test/stub.cc @@ -0,0 +1,264 @@ +/** @file + + Stub file for linking libinknet.a from unit tests + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "HttpSessionManager.h" +#include "HttpBodyFactory.h" +#include "DiagsConfig.h" +#include "ts/InkAPIPrivateIOCore.h" + +void +initialize_thread_for_http_sessions(EThread *, int) +{ + ink_assert(false); +} + +#include "InkAPIInternal.h" +void +APIHooks::append(INKContInternal *cont) +{ +} + +int +APIHook::invoke(int, void *) +{ + ink_assert(false); + return 0; +} + +APIHook * +APIHook::next() const +{ + ink_assert(false); + return nullptr; +} + +APIHook * +APIHooks::get() const +{ + return nullptr; +} + +void +APIHooks::prepend(INKContInternal *cont) +{ +} + +void +APIHooks::clear() +{ +} + +void +ConfigUpdateCbTable::invoke(const char * /* name ATS_UNUSED */) +{ + ink_release_assert(false); +} + +HttpAPIHooks *http_global_hooks = nullptr; +SslAPIHooks *ssl_hooks = nullptr; +LifecycleAPIHooks *lifecycle_hooks = nullptr; +ConfigUpdateCbTable *global_config_cbs = nullptr; + +HttpBodyFactory *body_factory = nullptr; + +intmax_t +ts::svtoi(TextView src, TextView *out, int base) +{ + intmax_t zret = 0; + + if (out) { + out->clear(); + } + if (!(0 <= base && base <= 36)) { + return 0; + } + if (src.ltrim_if(&isspace) && src) { + const char *start = src.data(); + int8_t v; + bool neg = false; + if ('-' == *src) { + ++src; + neg = true; + } + // If base is 0, it wasn't specified - check for standard base prefixes + if (0 == base) { + base = 10; + if ('0' == *src) { + ++src; + base = 8; + if (src && ('x' == *src || 'X' == *src)) { + ++src; + base = 16; + } + } + } + + // For performance in common cases, use the templated conversion. + switch (base) { + case 8: + zret = svto_radix<8>(src); + break; + case 10: + zret = svto_radix<10>(src); + break; + case 16: + zret = svto_radix<16>(src); + break; + default: + while (src.size() && (0 <= (v = svtoi_convert[static_cast<unsigned char>(*src)])) && v < base) { + auto n = zret * base + v; + if (n < zret) { + zret = std::numeric_limits<uintmax_t>::max(); + break; // overflow, stop parsing. + } + zret = n; + ++src; + } + break; + } + + if (out && (src.data() > (neg ? start + 1 : start))) { + out->assign(start, src.data()); + } + + if (neg) { + zret = -zret; + } + } + return zret; +} + +void +HostStatus::setHostStatus(const char *name, HostStatus_t status, const unsigned int down_time, const char *reason) +{ +} + +HostStatus_t +HostStatus::getHostStatus(const char *name) +{ + return (HostStatus_t)0; +} + +void +HostStatus::createHostStat(const char *name) +{ +} + +HostStatus::HostStatus() {} + +HostStatus::~HostStatus() {} + +int auto_clear_hostdb_flag = 0; +bool ts_is_draining = false; + +void +INKVConnInternal::do_io_close(int error) +{ +} + +void +INKVConnInternal::do_io_shutdown(ShutdownHowTo_t howto) +{ +} + +VIO * +INKVConnInternal::do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner) +{ + return nullptr; +} + +VIO * +INKVConnInternal::do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) +{ + return nullptr; +} + +void +INKVConnInternal::destroy() +{ +} + +void +INKVConnInternal::free() +{ +} + +void +INKVConnInternal::clear() +{ +} + +void +INKVConnInternal::reenable(VIO * /* vio ATS_UNUSED */) +{ +} + +bool +INKVConnInternal::get_data(int id, void *data) +{ + return false; +} + +bool +INKVConnInternal::set_data(int id, void *data) +{ + return false; +} + +void +INKVConnInternal::do_io_transform(VConnection *vc) +{ +} + +void +INKContInternal::handle_event_count(int event) +{ +} + +void +INKVConnInternal::retry(unsigned int delay) +{ +} + +INKContInternal::INKContInternal(TSEventFunc funcp, TSMutex mutexp) : DummyVConnection((ProxyMutex *)mutexp) {} + +INKContInternal::INKContInternal() : DummyVConnection(nullptr) {} + +void +INKContInternal::destroy() +{ +} + +void +INKContInternal::clear() +{ +} + +void +INKContInternal::free() +{ +} + +INKVConnInternal::INKVConnInternal() : INKContInternal() {} + +INKVConnInternal::INKVConnInternal(TSEventFunc funcp, TSMutex mutexp) : INKContInternal(funcp, mutexp) {} diff --git a/iocore/cache/test/test_Alternate_L_to_S.cc b/iocore/cache/test/test_Alternate_L_to_S.cc new file mode 100644 index 0000000..6d4656a --- /dev/null +++ b/iocore/cache/test/test_Alternate_L_to_S.cc @@ -0,0 +1,191 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +#include "main.h" + +class CacheAltReadAgain : public CacheTestHandler +{ +public: + CacheAltReadAgain(size_t size, const char *url) : CacheTestHandler() + { + this->_rt = new CacheReadTest(size, this, url); + this->_rt->mutex = this->mutex; + + SET_HANDLER(&CacheAltReadAgain::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class CacheAltTest_L_to_S : public CacheTestHandler +{ +public: + CacheAltTest_L_to_S(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + auto wt = new CacheWriteTest(size, this, url); + + rt->info.destroy(); + wt->info.destroy(); + + rt->info.create(); + wt->info.create(); + + build_hdrs(rt->info, url, "application/x-javascript"); + build_hdrs(wt->info, url, "application/x-javascript"); + + this->_rt = rt; + this->_wt = wt; + + this->_rt->mutex = this->mutex; + this->_wt->mutex = this->mutex; + + SET_HANDLER(&CacheAltTest_L_to_S::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_wt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + base->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + this->_wt->close(); + this->_wt = nullptr; + this_ethread()->schedule_imm(this->_rt); + break; + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + +private: + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } +}; + +class CacheAltInit : public CacheInit +{ +public: + CacheAltInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheTestHandler *h = new CacheTestHandler(LARGE_FILE, "http://www.scw11.com"); + CacheAltTest_L_to_S *ls = new CacheAltTest_L_to_S(SMALL_FILE, "http://www.scw11.com"); + CacheAltReadAgain *read = new CacheAltReadAgain(LARGE_FILE, "http://www.scw11.com"); + TerminalTest *tt = new TerminalTest; + + h->add(ls); + h->add(read); // read again + h->add(tt); + this_ethread()->schedule_imm(h); + delete this; + return 0; + } +}; + +TEST_CASE("cache write -> read", "cache") +{ + init_cache(256 * 1024 * 1024); + // large write test + CacheAltInit *init = new CacheAltInit; + + this_ethread()->schedule_imm(init); + this_thread()->execute(); +} diff --git a/iocore/cache/test/test_Alternate_L_to_S_remove_L.cc b/iocore/cache/test/test_Alternate_L_to_S_remove_L.cc new file mode 100644 index 0000000..f1167c7 --- /dev/null +++ b/iocore/cache/test/test_Alternate_L_to_S_remove_L.cc @@ -0,0 +1,260 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +#include "main.h" + +// delete dir +Dir dir = {}; + +class CacheAltReadAgain2 : public CacheTestHandler +{ +public: + CacheAltReadAgain2(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + + rt->mutex = this->mutex; + + rt->info.destroy(); + + rt->info.create(); + build_hdrs(rt->info, url, "application/x-javascript"); + + this->_rt = rt; + + SET_HANDLER(&CacheAltReadAgain2::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } +}; + +class CacheAltReadAgain : public CacheTestHandler +{ +public: + CacheAltReadAgain(size_t size, const char *url) : CacheTestHandler() + { + this->_rt = new CacheReadTest(size, this, url); + this->_rt->mutex = this->mutex; + + SET_HANDLER(&CacheAltReadAgain::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ_FAILED: + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class CacheAltTest_L_to_S_remove_L : public CacheTestHandler +{ +public: + CacheAltTest_L_to_S_remove_L(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + auto wt = new CacheWriteTest(size, this, url); + + rt->info.destroy(); + wt->info.destroy(); + + rt->info.create(); + wt->info.create(); + + build_hdrs(rt->info, url, "application/x-javascript"); + build_hdrs(wt->info, url, "application/x-javascript"); + + this->_rt = rt; + this->_wt = wt; + + this->_rt->mutex = this->mutex; + this->_wt->mutex = this->mutex; + + SET_HANDLER(&CacheAltTest_L_to_S_remove_L::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_wt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + base->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + this->_wt->close(); + this->_wt = nullptr; + this_ethread()->schedule_imm(this->_rt); + break; + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + delete_earliest_dir(base->vc); + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } + + void + delete_earliest_dir(CacheVC *vc) + { + CacheKey key = {}; + Dir *last_collision = nullptr; + SCOPED_MUTEX_LOCK(lock, vc->vol->mutex, this->mutex->thread_holding); + vc->vector.data[0].alternate.object_key_get(&key); + REQUIRE(dir_probe(&key, vc->vol, &dir, &last_collision) != 0); + REQUIRE(dir_delete(&key, vc->vol, &dir)); + } +}; + +class CacheAltInit : public CacheInit +{ +public: + CacheAltInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheTestHandler *h = new CacheTestHandler(LARGE_FILE, "http://www.scw11.com"); + CacheAltTest_L_to_S_remove_L *ls = new CacheAltTest_L_to_S_remove_L(SMALL_FILE, "http://www.scw11.com"); + CacheAltReadAgain *read = new CacheAltReadAgain(LARGE_FILE, "http://www.scw11.com"); + CacheAltReadAgain2 *read2 = new CacheAltReadAgain2(SMALL_FILE, "http://www.scw11.com"); + TerminalTest *tt = new TerminalTest; + + h->add(ls); + h->add(read); // read again + h->add(read2); + h->add(tt); + this_ethread()->schedule_imm(h); + delete this; + return 0; + } +}; + +TEST_CASE("cache write -> read", "cache") +{ + init_cache(256 * 1024 * 1024); + // large write test + CacheAltInit *init = new CacheAltInit; + + this_ethread()->schedule_imm(init); + this_thread()->execute(); +} diff --git a/iocore/cache/test/test_Alternate_L_to_S_remove_S.cc b/iocore/cache/test/test_Alternate_L_to_S_remove_S.cc new file mode 100644 index 0000000..f2a4844 --- /dev/null +++ b/iocore/cache/test/test_Alternate_L_to_S_remove_S.cc @@ -0,0 +1,261 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +#include "main.h" + +// delete dir +Dir dir = {}; + +class CacheAltReadAgain2 : public CacheTestHandler +{ +public: + CacheAltReadAgain2(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + + rt->mutex = this->mutex; + this->_rt = rt; + SET_HANDLER(&CacheAltReadAgain2::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class CacheAltReadAgain : public CacheTestHandler +{ +public: + CacheAltReadAgain(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + + rt->mutex = this->mutex; + + rt->info.destroy(); + + rt->info.create(); + build_hdrs(rt->info, url, "application/x-javascript"); + + this->_rt = rt; + + SET_HANDLER(&CacheAltReadAgain::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ_FAILED: + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class CacheAltTest_L_to_S_remove_S : public CacheTestHandler +{ +public: + CacheAltTest_L_to_S_remove_S(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + auto wt = new CacheWriteTest(size, this, url); + + rt->info.destroy(); + wt->info.destroy(); + + rt->info.create(); + wt->info.create(); + + build_hdrs(rt->info, url, "application/x-javascript"); + build_hdrs(wt->info, url, "application/x-javascript"); + + this->_rt = rt; + this->_wt = wt; + + this->_rt->mutex = this->mutex; + this->_wt->mutex = this->mutex; + + SET_HANDLER(&CacheAltTest_L_to_S_remove_S::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_wt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + base->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + this->_wt->close(); + this->_wt = nullptr; + this_ethread()->schedule_imm(this->_rt); + break; + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + delete_earliest_dir(base->vc); + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } + + void + delete_earliest_dir(CacheVC *vc) + { + CacheKey key = {}; + Dir *last_collision = nullptr; + SCOPED_MUTEX_LOCK(lock, vc->vol->mutex, this->mutex->thread_holding); + vc->vector.data[1].alternate.object_key_get(&key); + REQUIRE(dir_probe(&key, vc->vol, &dir, &last_collision) != 0); + REQUIRE(dir_delete(&key, vc->vol, &dir)); + } +}; + +class CacheAltInit : public CacheInit +{ +public: + CacheAltInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheTestHandler *h = new CacheTestHandler(LARGE_FILE, "http://www.scw11.com"); + CacheAltTest_L_to_S_remove_S *ls = new CacheAltTest_L_to_S_remove_S(SMALL_FILE, "http://www.scw11.com"); + CacheAltReadAgain *read = new CacheAltReadAgain(SMALL_FILE, "http://www.scw11.com"); + CacheAltReadAgain2 *read2 = new CacheAltReadAgain2(LARGE_FILE, "http://www.scw11.com"); + TerminalTest *tt = new TerminalTest; + + h->add(ls); + h->add(read); // read again + h->add(read2); + h->add(tt); + this_ethread()->schedule_imm(h); + delete this; + return 0; + } +}; + +TEST_CASE("cache write -> read", "cache") +{ + init_cache(256 * 1024 * 1024); + // large write test + CacheAltInit *init = new CacheAltInit; + + this_ethread()->schedule_imm(init); + this_thread()->execute(); +} diff --git a/iocore/cache/test/test_Alternate_S_to_L.cc b/iocore/cache/test/test_Alternate_S_to_L.cc new file mode 100644 index 0000000..097b61b --- /dev/null +++ b/iocore/cache/test/test_Alternate_S_to_L.cc @@ -0,0 +1,191 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +#include "main.h" + +class CacheAltReadAgain : public CacheTestHandler +{ +public: + CacheAltReadAgain(size_t size, const char *url) : CacheTestHandler() + { + this->_rt = new CacheReadTest(size, this, url); + this->_rt->mutex = this->mutex; + + SET_HANDLER(&CacheAltReadAgain::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class CacheAltTest_L_to_S : public CacheTestHandler +{ +public: + CacheAltTest_L_to_S(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + auto wt = new CacheWriteTest(size, this, url); + + rt->info.destroy(); + wt->info.destroy(); + + rt->info.create(); + wt->info.create(); + + build_hdrs(rt->info, url, "application/x-javascript"); + build_hdrs(wt->info, url, "application/x-javascript"); + + this->_rt = rt; + this->_wt = wt; + + this->_rt->mutex = this->mutex; + this->_wt->mutex = this->mutex; + + SET_HANDLER(&CacheAltTest_L_to_S::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_wt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + base->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + this->_wt->close(); + this->_wt = nullptr; + this_ethread()->schedule_imm(this->_rt); + break; + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + +private: + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } +}; + +class CacheAltInit : public CacheInit +{ +public: + CacheAltInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheTestHandler *h = new CacheTestHandler(SMALL_FILE, "http://www.scw11.com"); + CacheAltTest_L_to_S *ls = new CacheAltTest_L_to_S(LARGE_FILE, "http://www.scw11.com"); + CacheAltReadAgain *read = new CacheAltReadAgain(SMALL_FILE, "http://www.scw11.com"); + TerminalTest *tt = new TerminalTest; + + h->add(ls); + h->add(read); // read again + h->add(tt); + this_ethread()->schedule_imm(h); + delete this; + return 0; + } +}; + +TEST_CASE("cache write -> read", "cache") +{ + init_cache(256 * 1024 * 1024); + // large write test + CacheAltInit *init = new CacheAltInit; + + this_ethread()->schedule_imm(init); + this_thread()->execute(); +} diff --git a/iocore/cache/test/test_Alternate_S_to_L_remove_L.cc b/iocore/cache/test/test_Alternate_S_to_L_remove_L.cc new file mode 100644 index 0000000..282224b --- /dev/null +++ b/iocore/cache/test/test_Alternate_S_to_L_remove_L.cc @@ -0,0 +1,264 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +#include "main.h" + +// delete dir +Dir dir = {}; + +class CacheAltReadAgain2 : public CacheTestHandler +{ +public: + CacheAltReadAgain2(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + + rt->mutex = this->mutex; + this->_rt = rt; + SET_HANDLER(&CacheAltReadAgain2::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class CacheAltReadAgain : public CacheTestHandler +{ +public: + CacheAltReadAgain(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + + rt->mutex = this->mutex; + + rt->info.destroy(); + + rt->info.create(); + build_hdrs(rt->info, url, "application/x-javascript"); + + this->_rt = rt; + + SET_HANDLER(&CacheAltReadAgain::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + // sleep for a while to wait for writer close + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ_FAILED: + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class CacheAltTest_S_to_L_remove_L : public CacheTestHandler +{ +public: + CacheAltTest_S_to_L_remove_L(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + auto wt = new CacheWriteTest(size, this, url); + + rt->info.destroy(); + wt->info.destroy(); + + rt->info.create(); + wt->info.create(); + + build_hdrs(rt->info, url, "application/x-javascript"); + build_hdrs(wt->info, url, "application/x-javascript"); + + this->_rt = rt; + this->_wt = wt; + + this->_rt->mutex = this->mutex; + this->_wt->mutex = this->mutex; + + SET_HANDLER(&CacheAltTest_S_to_L_remove_L::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_wt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + base->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + this->_wt->close(); + this->_wt = nullptr; + // to make sure writer successfully write the final doc done. we need to schedule + // to wait for some while. This time should be large than cache_config_mutex_retry_delay + this_ethread()->schedule_in(this->_rt, HRTIME_SECONDS(1)); + break; + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + delete_earliest_dir(base->vc); + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } + + void + delete_earliest_dir(CacheVC *vc) + { + CacheKey key = {}; + Dir *last_collision = nullptr; + SCOPED_MUTEX_LOCK(lock, vc->vol->mutex, this->mutex->thread_holding); + vc->vector.data[1].alternate.object_key_get(&key); + REQUIRE(dir_probe(&key, vc->vol, &dir, &last_collision) != 0); + REQUIRE(dir_delete(&key, vc->vol, &dir)); + } +}; + +class CacheAltInit : public CacheInit +{ +public: + CacheAltInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheTestHandler *h = new CacheTestHandler(SMALL_FILE, "http://www.scw11.com"); + CacheAltTest_S_to_L_remove_L *ls = new CacheAltTest_S_to_L_remove_L(LARGE_FILE, "http://www.scw11.com"); + CacheAltReadAgain *read = new CacheAltReadAgain(LARGE_FILE, "http://www.scw11.com"); + CacheAltReadAgain2 *read2 = new CacheAltReadAgain2(SMALL_FILE, "http://www.scw11.com"); + TerminalTest *tt = new TerminalTest; + + h->add(ls); + h->add(read); // read again + h->add(read2); + h->add(tt); + this_ethread()->schedule_imm(h); + delete this; + return 0; + } +}; + +TEST_CASE("cache write -> read", "cache") +{ + init_cache(256 * 1024 * 1024); + // large write test + CacheAltInit *init = new CacheAltInit; + + this_ethread()->schedule_imm(init); + this_thread()->execute(); +} diff --git a/iocore/cache/test/test_Alternate_S_to_L_remove_S.cc b/iocore/cache/test/test_Alternate_S_to_L_remove_S.cc new file mode 100644 index 0000000..96a1e7c --- /dev/null +++ b/iocore/cache/test/test_Alternate_S_to_L_remove_S.cc @@ -0,0 +1,262 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +#include "main.h" + +// delete dir +Dir dir = {}; + +class CacheAltReadAgain2 : public CacheTestHandler +{ +public: + CacheAltReadAgain2(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + + rt->mutex = this->mutex; + + rt->info.destroy(); + + rt->info.create(); + build_hdrs(rt->info, url, "application/x-javascript"); + + this->_rt = rt; + + SET_HANDLER(&CacheAltReadAgain2::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } +}; + +class CacheAltReadAgain : public CacheTestHandler +{ +public: + CacheAltReadAgain(size_t size, const char *url) : CacheTestHandler() + { + this->_rt = new CacheReadTest(size, this, url); + this->_rt->mutex = this->mutex; + + SET_HANDLER(&CacheAltReadAgain::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_rt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_READ_FAILED: + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "text/html;charset=utf-8", len) == 0); + } +}; + +class test_Alternate_S_to_L_remove_S : public CacheTestHandler +{ +public: + test_Alternate_S_to_L_remove_S(size_t size, const char *url) : CacheTestHandler() + { + auto rt = new CacheReadTest(size, this, url); + auto wt = new CacheWriteTest(size, this, url); + + rt->info.destroy(); + wt->info.destroy(); + + rt->info.create(); + wt->info.create(); + + build_hdrs(rt->info, url, "application/x-javascript"); + build_hdrs(wt->info, url, "application/x-javascript"); + + this->_rt = rt; + this->_wt = wt; + + this->_rt->mutex = this->mutex; + this->_wt->mutex = this->mutex; + + SET_HANDLER(&test_Alternate_S_to_L_remove_S::start_test); + } + + int + start_test(int event, void *e) + { + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_wt); + return 0; + } + + virtual void + handle_cache_event(int event, CacheTestBase *base) + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + base->reenable(); + break; + case VC_EVENT_WRITE_COMPLETE: + this->_wt->close(); + this->_wt = nullptr; + // to make sure writer successfully write the final doc done. we need to schedule + // to wait for some while. This time should be large than cache_config_mutex_retry_delay + this_ethread()->schedule_in(this->_rt, HRTIME_SECONDS(1)); + break; + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + validate_content_type(base); + break; + case VC_EVENT_READ_READY: + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + delete_earliest_dir(base->vc); + base->close(); + delete this; + break; + default: + REQUIRE(false); + break; + } + } + + void + validate_content_type(CacheTestBase *base) + { + auto rt = dynamic_cast<CacheReadTest *>(base); + REQUIRE(rt); + MIMEField *field = rt->read_http_info->m_alt->m_response_hdr.field_find(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE); + REQUIRE(field); + int len; + const char *value = field->value_get(&len); + REQUIRE(memcmp(value, "application/x-javascript", len) == 0); + } + + void + delete_earliest_dir(CacheVC *vc) + { + CacheKey key = {}; + Dir *last_collision = nullptr; + SCOPED_MUTEX_LOCK(lock, vc->vol->mutex, this->mutex->thread_holding); + vc->vector.data[0].alternate.object_key_get(&key); + REQUIRE(dir_probe(&key, vc->vol, &dir, &last_collision) != 0); + REQUIRE(dir_delete(&key, vc->vol, &dir)); + } +}; + +class CacheAltInit : public CacheInit +{ +public: + CacheAltInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheTestHandler *h = new CacheTestHandler(SMALL_FILE, "http://www.scw11.com"); + test_Alternate_S_to_L_remove_S *ls = new test_Alternate_S_to_L_remove_S(LARGE_FILE, "http://www.scw11.com"); + CacheAltReadAgain *read = new CacheAltReadAgain(SMALL_FILE, "http://www.scw11.com"); + CacheAltReadAgain2 *read2 = new CacheAltReadAgain2(LARGE_FILE, "http://www.scw11.com"); + TerminalTest *tt = new TerminalTest; + + h->add(ls); + h->add(read); // read again + h->add(read2); + h->add(tt); + this_ethread()->schedule_imm(h); + delete this; + return 0; + } +}; + +TEST_CASE("cache write -> read", "cache") +{ + init_cache(256 * 1024 * 1024); + // large write test + CacheAltInit *init = new CacheAltInit; + + this_ethread()->schedule_imm(init); + this_thread()->execute(); +} diff --git a/iocore/cache/test/test_Cache.cc b/iocore/cache/test/test_Cache.cc new file mode 100644 index 0000000..63284f5 --- /dev/null +++ b/iocore/cache/test/test_Cache.cc @@ -0,0 +1,55 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#include "main.h" + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +class CacheCommInit : public CacheInit +{ +public: + CacheCommInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheTestHandler *h = new CacheTestHandler(LARGE_FILE); + CacheTestHandler *h2 = new CacheTestHandler(SMALL_FILE, "http://www.scw11.com"); + TerminalTest *tt = new TerminalTest; + h->add(h2); + h->add(tt); + this_ethread()->schedule_imm(h); + delete this; + return 0; + } +}; + +TEST_CASE("cache write -> read", "cache") +{ + init_cache(256 * 1024 * 1024); + // large write test + CacheCommInit *init = new CacheCommInit; + + this_ethread()->schedule_imm(init); + this_thread()->execute(); +} diff --git a/iocore/cache/test/test_RWW.cc b/iocore/cache/test/test_RWW.cc new file mode 100644 index 0000000..167cf1e --- /dev/null +++ b/iocore/cache/test/test_RWW.cc @@ -0,0 +1,429 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#define LARGE_FILE 10 * 1024 * 1024 +#define SMALL_FILE 10 * 1024 + +#define DEFAULT_URL "http://www.scw00.com/" + +#include "main.h" + +class CacheRWWTest; + +struct SimpleCont : public Continuation { + SimpleCont(CacheTestBase *base) : base(base) + { + REQUIRE(base != nullptr); + SET_HANDLER(&SimpleCont::handle_event); + this->mutex = base->mutex; + } + + int + handle_event(int event, void *data) + { + Debug("cache_rww_test", "cache write reenable"); + base->reenable(); + delete this; + return 0; + } + + CacheTestBase *base = nullptr; +}; + +class CacheRWWTest : public CacheTestHandler +{ +public: + CacheRWWTest(size_t size, const char *url = DEFAULT_URL) : CacheTestHandler(), _size(size) + { + if (size != LARGE_FILE && size != SMALL_FILE) { + REQUIRE(!"size should be LARGE_FILE or SMALL_FILE"); + } + + this->_rt = new CacheReadTest(size, this, url); + this->_wt = new CacheWriteTest(size, this, url); + + this->_rt->mutex = this->mutex; + this->_wt->mutex = this->mutex; + + SET_HANDLER(&CacheRWWTest::start_test); + } + + void handle_cache_event(int event, CacheTestBase *e) override; + int start_test(int event, void *e); + + virtual void process_read_event(int event, CacheTestBase *base); + virtual void process_write_event(int event, CacheTestBase *base); + + void + close_write(int error = -1) + { + if (!this->_wt) { + return; + } + + this->_wt->close(error); + this->_wt = nullptr; + } + + void + close_read(int error = -1) + { + if (!this->_rt) { + return; + } + + this->_rt->close(error); + this->_rt = nullptr; + } + +protected: + size_t _size = 0; + Event *_read_event = nullptr; + bool _is_read_start = false; + CacheTestBase *_rt = nullptr; + CacheTestBase *_wt = nullptr; +}; + +int +CacheRWWTest::start_test(int event, void *e) +{ + REQUIRE(event == EVENT_IMMEDIATE); + this_ethread()->schedule_imm(this->_wt); + return 0; +} + +void +CacheRWWTest::process_write_event(int event, CacheTestBase *base) +{ + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + // schedule read test imm + if (this->_size != SMALL_FILE && !this->_wt->vc->fragment) { + Debug("cache_rww_test", "cache write reenable"); + base->reenable(); + return; + } + + if (!this->_is_read_start) { + if (!this->_read_event) { + this->_read_event = this_ethread()->schedule_imm(this->_rt); + } + return; + } + + // stop writing for a while and wait for reading + // data->vio->reenable(); + this_ethread()->schedule_imm(new SimpleCont(base)); + break; + case VC_EVENT_WRITE_COMPLETE: + this->close_write(); + + break; + default: + REQUIRE(event == 0); + REQUIRE(false); + this->close_write(); + this->close_read(); + return; + } + + if (this->_rt) { + this->_rt->reenable(); + } +} + +void +CacheRWWTest::process_read_event(int event, CacheTestBase *base) +{ + switch (event) { + case CACHE_EVENT_OPEN_READ: + base->do_io_read(); + break; + case VC_EVENT_READ_READY: + Debug("cache_rww_test", "cache read reenable"); + this->_read_event = nullptr; + this->_is_read_start = true; + base->reenable(); + break; + case VC_EVENT_READ_COMPLETE: + this->close_read(); + return; + + default: + REQUIRE(false); + this->close_write(); + this->close_read(); + return; + } + + if (this->_wt) { + this->_wt->reenable(); + } +} + +void +CacheRWWTest::handle_cache_event(int event, CacheTestBase *base) +{ + REQUIRE(base != nullptr); + + switch (event) { + case CACHE_EVENT_OPEN_WRITE_FAILED: + case CACHE_EVENT_OPEN_WRITE: + case VC_EVENT_WRITE_READY: + case VC_EVENT_WRITE_COMPLETE: + this->process_write_event(event, base); + break; + case CACHE_EVENT_OPEN_READ: + case CACHE_EVENT_OPEN_READ_FAILED: + case VC_EVENT_ERROR: + case VC_EVENT_EOS: + case VC_EVENT_READ_READY: + case VC_EVENT_READ_COMPLETE: + this->process_read_event(event, base); + break; + default: + REQUIRE(false); + this->close_write(); + this->close_read(); + break; + } + + if (this->_wt == nullptr && this->_rt == nullptr) { + delete this; + } + + return; +} + +class CacheRWWErrorTest : public CacheRWWTest +{ +public: + CacheRWWErrorTest(size_t size, const char *url = DEFAULT_URL) : CacheRWWTest(size, url) {} + void + process_write_event(int event, CacheTestBase *base) override + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + if (this->_size != SMALL_FILE && !this->_wt->vc->fragment) { + Debug("cache_rww_test", "cache write reenable"); + base->reenable(); + return; + } + + if (!this->_is_read_start) { + if (!this->_read_event) { + this->_read_event = this_ethread()->schedule_imm(this->_rt); + } + return; + } else { + this->close_write(100); + return; + } + this_ethread()->schedule_imm(new SimpleCont(base)); + break; + + case VC_EVENT_WRITE_COMPLETE: + REQUIRE(!"should not happen because the writter aborted"); + this->close_read(); + this->close_write(); + break; + default: + REQUIRE(false); + delete this; + return; + } + } + + void + process_read_event(int event, CacheTestBase *base) override + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + this->_read_event = nullptr; + this->_is_read_start = true; + base->do_io_read(); + break; + case CACHE_EVENT_OPEN_READ_FAILED: + REQUIRE(this->_size == SMALL_FILE); + this->close_read(); + return; + case VC_EVENT_READ_READY: + base->reenable(); + if (this->_wt) { + this->_wt->reenable(); + } + return; + + case VC_EVENT_READ_COMPLETE: + REQUIRE(!"should not happen because the writter aborted"); + this->close_read(); + this->close_write(); + break; + case VC_EVENT_ERROR: + case VC_EVENT_EOS: + if (this->_size == LARGE_FILE) { + REQUIRE(base->vio->ndone >= 1 * 1024 * 1024 - sizeof(Doc)); + } else { + REQUIRE(base->vio->ndone == 0); + } + this->close_read(); + break; + default: + REQUIRE(event == 0); + this->close_read(); + this->close_write(); + break; + } + } + +private: + bool _is_read_start = false; +}; + +class CacheRWWEOSTest : public CacheRWWTest +{ +public: + CacheRWWEOSTest(size_t size, const char *url = DEFAULT_URL) : CacheRWWTest(size, url) {} + /* + * test this code in openReadMain + * if (writer_done()) { + last_collision = nullptr; + while (dir_probe(&earliest_key, vol, &dir, &last_collision)) { + // write complete. this could be reached the size we set in do_io_write or someone call do_io_close with -1 (-1 means write + success) flag if (dir_offset(&dir) == dir_offset(&earliest_dir)) { DDebug("cache_read_agg", "%p: key: %X ReadMain complete: %d", + this, first_key.slice32(1), (int)vio.ndone); doc_len = vio.ndone; goto Leos; + } + } + // writer abort. server crash. someone call do_io_close() with error flag + DDebug("cache_read_agg", "%p: key: %X ReadMain writer aborted: %d", this, first_key.slice32(1), (int)vio.ndone); + goto Lerror; + } + * + */ + + void + process_write_event(int event, CacheTestBase *base) override + { + switch (event) { + case CACHE_EVENT_OPEN_WRITE: + base->do_io_write(); + break; + case VC_EVENT_WRITE_READY: + if (this->_size != SMALL_FILE && !this->_wt->vc->fragment) { + Debug("cache_rww_test", "cache write reenable"); + base->reenable(); + return; + } + + if (!this->_is_read_start) { + if (!this->_read_event) { + this->_read_event = this_ethread()->schedule_imm(this->_rt); + } + return; + } + this_ethread()->schedule_imm(new SimpleCont(base)); + break; + + case VC_EVENT_WRITE_COMPLETE: + this->close_write(); + break; + default: + REQUIRE(false); + delete this; + return; + } + } + + void + process_read_event(int event, CacheTestBase *base) override + { + switch (event) { + case CACHE_EVENT_OPEN_READ: + this->_read_event = nullptr; + this->_is_read_start = true; + base->do_io_read(UINT32_MAX); + break; + case VC_EVENT_READ_READY: + base->reenable(); + if (this->_wt) { + this->_wt->reenable(); + } + return; + + case VC_EVENT_READ_COMPLETE: + REQUIRE(!"should not happen because the writter aborted"); + this->close_read(); + this->close_write(); + break; + case VC_EVENT_EOS: + this->close_write(); + this->close_read(); + break; + default: + REQUIRE(event == 0); + this->close_read(); + this->close_write(); + break; + } + } + +private: + bool _is_read_start = false; +}; + +class CacheRWWCacheInit : public CacheInit +{ +public: + CacheRWWCacheInit() {} + int + cache_init_success_callback(int event, void *e) override + { + CacheRWWTest *crww = new CacheRWWTest(LARGE_FILE); + CacheRWWErrorTest *crww_l = new CacheRWWErrorTest(LARGE_FILE, "http://www.scw22.com/"); + CacheRWWEOSTest *crww_eos = new CacheRWWEOSTest(LARGE_FILE, "ttp://www.scw44.com/"); + TerminalTest *tt = new TerminalTest(); + + crww->add(crww_l); + crww->add(crww_eos); + crww->add(tt); + this_ethread()->schedule_imm(crww); + delete this; + return 0; + } +}; + +TEST_CASE("cache rww", "cache") +{ + init_cache(256 * 1024 * 1024); + cache_config_target_fragment_size = 1 * 1024 * 1024; + CacheRWWCacheInit *init = new CacheRWWCacheInit(); + + this_ethread()->schedule_imm(init); + this_ethread()->execute(); +} diff --git a/iocore/cache/test/var/trafficserver/guard.txt b/iocore/cache/test/var/trafficserver/guard.txt new file mode 100644 index 0000000..8fe3629 --- /dev/null +++ b/iocore/cache/test/var/trafficserver/guard.txt @@ -0,0 +1,24 @@ +/** @file + + A brief file description + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +This is guard file for this empty dir