ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

369 lines
9.4 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
  4. //
  5. // See accompanying file COPYING.TXT file for licensing details.
  6. //
  7. ///////////////////////////////////////////////////////////////////////////////
  8. #include <cppcms/service.h>
  9. #include <cppcms/application.h>
  10. #include <cppcms/applications_pool.h>
  11. #include <cppcms/http_request.h>
  12. #include <cppcms/http_response.h>
  13. #include <cppcms/http_context.h>
  14. #include <cppcms/url_dispatcher.h>
  15. #include <cppcms/mount_point.h>
  16. #include <booster/aio/deadline_timer.h>
  17. #include <booster/posix_time.h>
  18. #include <cppcms/json.h>
  19. #include <booster/thread.h>
  20. #include <iostream>
  21. #include "client.h"
  22. #include <sstream>
  23. #include <booster/log.h>
  24. #include "test.h"
  25. int g_fail;
  26. #define TESTNT(x) do { if(x) break; std::cerr << "FAIL: " #x " in line: " << __LINE__ << std::endl; g_fail = 1; return; } while(0)
  27. booster::thread_specific_ptr<int> g_thread_id;
  28. booster::mutex g_id_lock;
  29. int g_thread_id_counter=1000;
  30. struct thread_submitter {
  31. thread_submitter(cppcms::service &srv) : srv_(&srv) {}
  32. void operator()() const
  33. {
  34. runner r(*srv_);
  35. booster::thread t(r);
  36. t.detach();
  37. }
  38. cppcms::service *srv_;
  39. };
  40. void set_thread_id(int v)
  41. {
  42. g_thread_id.reset(new int(v));
  43. }
  44. int get_thread_id()
  45. {
  46. if(g_thread_id.get()==0) {
  47. booster::unique_lock<booster::mutex> guard(g_id_lock);
  48. int new_id = ++g_thread_id_counter;
  49. set_thread_id(new_id);
  50. }
  51. return *g_thread_id;
  52. }
  53. class counter {
  54. typedef booster::unique_lock<booster::mutex> guard;
  55. counter() :
  56. current(0),
  57. max(0),
  58. total(0)
  59. {
  60. }
  61. public:
  62. static counter *instance(std::string const &name)
  63. {
  64. static const int max = 20;
  65. static int curr;
  66. static counter all[max];
  67. for(int i=0;i<curr;i++)
  68. if(all[i].name==name)
  69. return all + i;
  70. assert(curr < max);
  71. all[curr].name = name;
  72. return all + curr++;
  73. }
  74. void print(std::ostream &out)
  75. {
  76. guard g(lock_);
  77. out<< "name="<<name<<"\n"
  78. "current="<<current<<"\n"
  79. "total="<<total<<"\n"
  80. "max="<<max;
  81. }
  82. std::string name;
  83. int current;
  84. int max;
  85. int total;
  86. int inc() {
  87. guard g(lock_);
  88. int r = ++total;
  89. current++;
  90. if(max < current)
  91. max = current;
  92. return r;
  93. }
  94. void dec()
  95. {
  96. guard g(lock_);
  97. current--;
  98. }
  99. private:
  100. booster::mutex lock_;
  101. };
  102. class unit_test : public cppcms::application {
  103. public:
  104. unit_test(cppcms::service &s,counter *c) :
  105. cppcms::application(s),
  106. c_(c),
  107. id_(0),
  108. original_thread_id_(0)
  109. {
  110. id_ = c_->inc();
  111. original_thread_id_ = get_thread_id();
  112. }
  113. ~unit_test()
  114. {
  115. c_->dec();
  116. }
  117. void main(std::string path)
  118. {
  119. double sleep_for = atof(request().get("sleep").c_str());
  120. BOOSTER_DEBUG("cppcms") << "--------- GOT " << path << " for " << sleep_for << " from " << id_ << " in " << get_thread_id();
  121. booster::ptime::sleep(booster::ptime::from_number(sleep_for));
  122. std::ostringstream ss;
  123. ss <<
  124. "url=" << request().script_name() << path << "\n"
  125. "thread_id=" << get_thread_id() << "\n"
  126. "original_thread_id=" << original_thread_id_ << "\n"
  127. "app_id="<<id_;
  128. BOOSTER_DEBUG("cppcms") << "RESPONSE " << path << " from " << id_ << "\n" << ss.str() ;
  129. response().out() << ss.str();
  130. }
  131. private:
  132. counter *c_;
  133. int id_;
  134. int original_thread_id_;
  135. };
  136. std::map<std::string,booster::weak_ptr<cppcms::application_specific_pool> > weak_pools;
  137. class tester : public cppcms::application {
  138. public:
  139. tester(cppcms::service &srv) : cppcms::application(srv) {}
  140. void main(std::string name)
  141. {
  142. if(name=="/stats")
  143. counter::instance(request().get("id"))->print(response().out());
  144. else if(name=="/unmount") {
  145. std::string id = request().get("id");
  146. bool exists_before = weak_pools[id].lock();
  147. service().applications_pool().unmount(weak_pools[id]);
  148. bool exists_after = weak_pools[id].lock();
  149. response().out()<<"unmount=" << id << "\n"
  150. "before="<<exists_before <<"\n"
  151. "after="<<exists_after;
  152. }
  153. else if(name=="/install") {
  154. app_ = new unit_test(service(),counter::instance("/async/temporary"));
  155. service().applications_pool().mount(app_,cppcms::mount_point("/async","/temporary",0));
  156. response().out()<<"install=1";
  157. }
  158. else if(name=="/uninstall") {
  159. response().out()<<"install=0";
  160. app_ = 0;
  161. }
  162. }
  163. private:
  164. booster::intrusive_ptr<cppcms::application> app_;
  165. };
  166. struct marker {
  167. marker(std::string const &name) : name_(name) {}
  168. booster::shared_ptr<cppcms::application_specific_pool> const &operator | (booster::shared_ptr<cppcms::application_specific_pool> const &in)
  169. {
  170. weak_pools[name_] = in;
  171. return in;
  172. }
  173. std::string name_;
  174. };
  175. struct pools {
  176. booster::weak_ptr<cppcms::application_specific_pool> sync,async;
  177. bool async_requested;
  178. pools() : async_requested(false) {}
  179. };
  180. class sender : public cppcms::application {
  181. public:
  182. struct src_prop {
  183. bool src_async;
  184. bool src_created;
  185. bool src_to_app;
  186. };
  187. sender(cppcms::service &srv,pools *p) :
  188. cppcms::application(srv),
  189. pools_(p)
  190. {
  191. }
  192. void main(std::string url)
  193. {
  194. if(url!="/sender") {
  195. src_prop *p = context().get_specific<src_prop>();
  196. TESTNT(p);
  197. response().out() << "async=" << is_asynchronous() << "\n"
  198. "src_async=" << p->src_async <<"\n"
  199. "src_created="<< p->src_created <<"\n"
  200. "src_to_app=" << p->src_to_app <<"\n"
  201. "path=" << url<<"\n"
  202. ;
  203. return;
  204. }
  205. src_prop *p=new src_prop();
  206. context().reset_specific<src_prop>(p);
  207. bool to_app = request().get("to_app")=="1";
  208. p->src_to_app = to_app;
  209. p->src_async = is_asynchronous();
  210. p->src_created = false;
  211. booster::shared_ptr<cppcms::application_specific_pool> tgt;
  212. if(request().get("to")=="sync")
  213. tgt = pools_->sync.lock();
  214. else
  215. tgt = pools_->async.lock();
  216. booster::shared_ptr<cppcms::http::context> ctx = release_context();
  217. TESTNT(tgt);
  218. if(!to_app) {
  219. ctx->submit_to_pool(tgt,"/pool");
  220. return;
  221. }
  222. booster::intrusive_ptr<cppcms::application> app;
  223. app =tgt->asynchronous_application_by_io_service(service().get_io_service());
  224. if(!app) {
  225. app = tgt->asynchronous_application_by_io_service(service().get_io_service(),service());
  226. p->src_created=true;
  227. }
  228. TESTNT(app);
  229. ctx->submit_to_asynchronous_application(app,"/app");
  230. }
  231. private:
  232. pools *pools_;
  233. };
  234. int main(int argc,char **argv)
  235. {
  236. try {
  237. {
  238. using cppcms::mount_point;
  239. cppcms::service srv(argc,argv);
  240. set_thread_id(1);
  241. srv.applications_pool().mount(
  242. marker("/sync") | cppcms::create_pool<unit_test>(counter::instance("/sync")),
  243. mount_point("/sync","",0),
  244. cppcms::app::synchronous);
  245. srv.applications_pool().mount(
  246. cppcms::create_pool<unit_test>(counter::instance("/sync/work")),
  247. mount_point("/sync","/work",0),
  248. cppcms::app::synchronous);
  249. srv.applications_pool().mount(
  250. marker("/sync/prepopulated") | cppcms::create_pool<unit_test>(counter::instance("/sync/prepopulated")),
  251. mount_point("/sync","/prepopulated",0),
  252. cppcms::app::synchronous | cppcms::app::prepopulated);
  253. srv.applications_pool().mount(
  254. marker("/sync/tss") | cppcms::create_pool<unit_test>(counter::instance("/sync/tss")),
  255. mount_point("/sync","/tss",0),
  256. cppcms::app::synchronous | cppcms::app::thread_specific);
  257. srv.applications_pool().mount(
  258. cppcms::applications_factory<unit_test>(counter::instance("/sync/legacy")),
  259. mount_point("/sync","/legacy",0));
  260. srv.applications_pool().mount(
  261. marker("/async") | cppcms::create_pool<unit_test>(counter::instance("/async")),
  262. mount_point("/async","",0),
  263. cppcms::app::asynchronous);
  264. srv.applications_pool().mount(
  265. marker("/async/prepopulated") | cppcms::create_pool<unit_test>(counter::instance("/async/prepopulated")),
  266. mount_point("/async","/prepopulated",0),
  267. cppcms::app::asynchronous | cppcms::app::prepopulated);
  268. booster::intrusive_ptr<cppcms::application> app = new unit_test(srv,counter::instance("/async/legacy"));
  269. srv.applications_pool().mount(
  270. app,
  271. mount_point("/async","/legacy",0));
  272. counter::instance("/async/temporary");
  273. srv.applications_pool().mount(cppcms::create_pool<tester>(),mount_point("/test"),cppcms::app::asynchronous);
  274. pools p;
  275. {
  276. booster::shared_ptr<cppcms::application_specific_pool> tmp;
  277. srv.applications_pool().mount(
  278. (tmp=cppcms::create_pool<sender>(&p)),
  279. mount_point("/async","/sender",0),
  280. cppcms::app::asynchronous);
  281. p.async = tmp;
  282. }
  283. {
  284. booster::shared_ptr<cppcms::application_specific_pool> tmp;
  285. srv.applications_pool().mount(
  286. (tmp=cppcms::create_pool<sender>(&p)),
  287. mount_point("/sync","/sender",0),
  288. cppcms::app::synchronous);
  289. p.sync = tmp;
  290. }
  291. srv.after_fork(thread_submitter(srv));
  292. srv.run();
  293. weak_pools.clear();
  294. }
  295. std::cout << "Test all deleted" << std::endl;
  296. TEST(counter::instance("/sync")->current == 0);
  297. TEST(counter::instance("/sync/prepopulated")->current == 0);
  298. TEST(counter::instance("/sync/tss")->current == 0);
  299. TEST(counter::instance("/sync/legacy")->current == 0);
  300. TEST(counter::instance("/async")->current == 0);
  301. TEST(counter::instance("/async/prepopulated")->current == 0);
  302. TEST(counter::instance("/async/legacy")->current == 0);
  303. std::cout << "Done" << std::endl;
  304. }
  305. catch(std::exception const &e) {
  306. std::cerr << e.what() << std::endl;
  307. return EXIT_FAILURE;
  308. }
  309. if(run_ok && !g_fail) {
  310. std::cout << "Full Test: Ok" << std::endl;
  311. return EXIT_SUCCESS;
  312. }
  313. else {
  314. std::cout << "FAILED" << std::endl;
  315. return EXIT_FAILURE;
  316. }
  317. }