/////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) // // See accompanying file COPYING.TXT file for licensing details. // /////////////////////////////////////////////////////////////////////////////// #include "tc_test_content.h" #include #include #include #include #include #include #include "dummy_api.h" #include "test.h" #include #include #include struct mydata : public cppcms::serializable { int x; int y; mydata(int a=0,int b=0) : x(a), y(b) {} void serialize(cppcms::archive &a) { a & x & y; } }; class test_app : public cppcms::application { public: test_app(cppcms::service &srv) : cppcms::application(srv), srv_(srv) { } ~test_app() { release_context(); } void set_context(bool gzip=false) { std::map env; env["HTTP_HOST"]="www.example.com"; env["SCRIPT_NAME"]="/foo"; env["PATH_INFO"]="/bar"; env["REQUEST_METHOD"]="GET"; if(gzip) env["HTTP_ACCEPT_ENCODING"]="gzip, deflate"; booster::shared_ptr api(new dummy_api(srv_,env,output_)); booster::shared_ptr cnt(new cppcms::http::context(api)); assign_context(cnt); response().io_mode(cppcms::http::response::normal); output_.clear(); } std::string str() { response().finalize(); size_t from = output_.find("\r\n\r\n"); std::string result; if(from==std::string::npos) { result = output_; gzip_ = false; } else { result = output_.substr(from+4); gzip_ = output_.substr(0,from).find("gzip")!=std::string::npos; } output_.clear(); return result; } void test_basic() { std::cout << "- Page Basic" << std::endl; set_context(false); TEST(cache().has_cache()); TEST(!cache().fetch_page("test")); response().out() << "test"; cache().add_trigger("x"); cache().store_page("test"); TEST(str()=="test"); set_context(false); TEST(cache_size()==1); TEST(cache().fetch_page("test")); TEST(str()=="test"); set_context(false); cache().rise("x"); TEST(cache_size() == 0); TEST(!cache().fetch_page("test")); cache().add_trigger("x"); response().out() << "test2"; cache().reset(); // reset works cache().store_page("test",2); TEST(str()=="test2"); set_context(false); cache().rise("x"); TEST(cache_size() == 1); TEST(cache().fetch_page("test")); TEST(str() == "test2"); booster::ptime::millisleep(3000); set_context(false); TEST(cache().fetch_page("test")==false); cache().clear(); release_context(); } void test_gzip() { std::cout << "- Page Gzip" << std::endl; set_context(true); cache().clear(); TEST(request().getenv("HTTP_ACCEPT_ENCODING") == "gzip, deflate"); TEST(request().getenv(std::string("HTTP_ACCEPT_ENCODING")) == "gzip, deflate"); cache().fetch_page("test"); response().out() << "gzip"; cache().store_page("test"); TEST(str().substr(0,2)=="\x1f\x8b"); TEST(gzip_); set_context(false); TEST(request().getenv("HTTP_ACCEPT_ENCODING") == ""); TEST(cache_size() == 1); TEST(cache().fetch_page("test") ==false); response().out() << "gzip"; cache().store_page("test"); TEST(str() == "gzip"); TEST(!gzip_); set_context(false); TEST(cache().fetch_page("test")); TEST(str()=="gzip"); TEST(!gzip_); set_context(true); TEST(cache().fetch_page("test")); TEST(str().substr(0,2)=="\x1f\x8b"); TEST(gzip_); set_context(false); TEST(cache_size()==2); cache().clear(); TEST(cache_size()==0); release_context(); } void test_objects() { std::cout << "- Data Object" << std::endl; set_context(false); { std::cout << "-- With Triggers Full API" << std::endl; { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d(1,2); std::set t1,t2; t1.insert("k1"); t2.insert("k2"); cache().store_frame("foo","bar",t1); cache().store_data("dat",d,t2); TEST(tr.detach().size()==4); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d; std::string tmp; TEST(cache().fetch_frame("foo",tmp)); TEST(cache().fetch_data("dat",d)); TEST(d.x==1 && d.y==2); TEST(tmp=="bar"); std::set tg=tr.detach(); TEST(tg.size()==4); TEST(tg.count("foo")==1); TEST(tg.count("dat")==1); TEST(tg.count("k1")==1); TEST(tg.count("k2")==1); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d; std::string tmp; TEST(cache().fetch_frame("foo",tmp,true)); TEST(cache().fetch_data("dat",d,true)); TEST(d.x==1 && d.y==2); TEST(tmp=="bar"); TEST(tr.detach().size()==0); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d(4,5); cache().store_frame("foo","baz",-1); cache().store_data("dat",d,-1); TEST(tr.detach().size()==2); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d; std::string tmp; TEST(cache().fetch_frame("foo",tmp)); TEST(cache().fetch_data("dat",d)); TEST(d.x==4 && d.y==5); TEST(tmp=="baz"); std::set tg=tr.detach(); TEST(tg.size()==2); TEST(tg.count("foo")==1); TEST(tg.count("dat")==1); } } cache().clear(); { std::cout << "-- Without Triggers" << std::endl; { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d(1,2); cache().store_frame("foo","bar",std::set(),-1,true); cache().store_data("dat",d,std::set(),-1,true); TEST(tr.detach().size()==0); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d; std::string tmp; TEST(cache().fetch_frame("foo",tmp,true)); TEST(cache().fetch_data("dat",d,true)); TEST(d.x==1 && d.y==2); TEST(tmp=="bar"); TEST(tr.detach().size()==0); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d; std::string tmp; TEST(cache().fetch_frame("foo",tmp)); TEST(cache().fetch_data("dat",d)); TEST(d.x==1 && d.y==2); TEST(tmp=="bar"); TEST(tr.detach().size()==2); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d(4,5); cache().store_frame("foo","baz",-1,true); cache().store_data("dat",d,-1,true); TEST(tr.detach().size()==0); } { cache().reset(); cppcms::triggers_recorder tr(cache()); mydata d; std::string tmp; TEST(cache().fetch_frame("foo",tmp,true)); TEST(cache().fetch_data("dat",d,true)); TEST(d.x==4 && d.y==5); TEST(tmp=="baz"); TEST(tr.detach().size()==0); } } cache().clear(); { std::cout << "-- Timeouts" << std::endl; { cache().reset(); mydata d1(1,2); mydata d2(4,5); cache().store_frame("foo1","baz1",std::set(),2,true); cache().store_data("dat1",d1,std::set(),2,true); cache().store_frame("foo2","baz2",2,true); cache().store_data("dat2",d2,2,true); } { cache().reset(); mydata d1,d2; std::string t1,t2; TEST(cache().fetch_frame("foo1",t1,true)); TEST(cache().fetch_frame("foo2",t2,true)); TEST(cache().fetch_data("dat1",d1,true)); TEST(cache().fetch_data("dat2",d2,true)); TEST(d1.x==1 && d1.y==2); TEST(d2.x==4 && d2.y==5); TEST(t1=="baz1"); TEST(t2=="baz2"); } booster::ptime::millisleep(3000); { cache().reset(); mydata d1,d2; std::string t1,t2; TEST(!cache().fetch_frame("foo1",t1,true)); TEST(!cache().fetch_frame("foo2",t2,true)); TEST(!cache().fetch_data("dat1",d1,true)); TEST(!cache().fetch_data("dat2",d2,true)); } } } unsigned cache_size() { unsigned keys,triggers; TEST(cache().stats(keys,triggers)); return keys; } private: std::string output_; bool gzip_; cppcms::service &srv_; }; void test_independent(cppcms::service &srv) { std::cout << "- Context independent cache test\n"; // normal ops cppcms::cache_interface cache(srv); cache.clear(); unsigned n=0,m; TEST(cache.stats(n,m)); TEST(n==0); cache.store_frame("a","b"); TEST(cache.stats(n,m)); TEST(n==1); std::string tmp; TEST(cache.fetch_frame("a",tmp)); TEST(tmp=="b"); cache.rise("a"); TEST(!cache.fetch_frame("a",tmp)); TEST(cache.stats(n,m)); TEST(n==0); // Does not crash without a context TEST(cache.fetch_page("x") == false); cache.store_page("y"); } int main() { try { cppcms::json::value cfg; cfg["cache"]["backend"]="thread_shared"; cfg["cache"]["limit"]=100; cppcms::service srv(cfg); test_app app(srv); app.set_context(); app.test_basic(); app.test_gzip(); app.test_objects(); test_independent(srv); } catch(std::exception const &e) { std::cerr << "Fail " << e.what() << std::endl; return 1; } std::cout << "Ok" << std::endl; return 0; }