f41b982009-05-07Martin Stjernholm // This is a roxen module. Copyright © 2000 - 2009, Roxen IS.
a7cbff2000-11-11Martin Nilsson  #include <module.h> inherit "module";
0917d32013-03-04Anders Johansson constant cvs_version = "$Id$";
a7cbff2000-11-11Martin Nilsson constant thread_safe = 1;
58aedc2001-09-25Marcus Wellhardh constant module_type = MODULE_TAG|MODULE_PROVIDER;
a7cbff2000-11-11Martin Nilsson constant module_name = "Roxen self test module"; constant module_doc = "Tests Roxen WebServer.";
f1d3fd2000-12-10Martin Nilsson constant is_roxen_tester_module = 1;
a7cbff2000-11-11Martin Nilsson  Configuration conf;
1d7f6d2000-11-12Martin Nilsson Stdio.File index_file; Protocol port;
d8910b2008-08-06Martin Stjernholm RoxenModule rxmlparser;
a7cbff2000-11-11Martin Nilsson 
5834132001-01-31Per Hedbor int verbose;
58aedc2001-09-25Marcus Wellhardh private int running; private int finished; int is_running() { return running; } int is_not_finished() { return !finished; } int is_ready_to_start() { int ready = 1; foreach(roxen.configurations, Configuration config) if(config->call_provider("roxen_test", "is_running")) ready = 0; return ready; } int is_last_test_configuration() { foreach(roxen.configurations, Configuration config) if(config->call_provider("roxen_test", "is_not_finished")) return 0; return 1; }
0d967f2008-08-07Martin Stjernholm int tests, ltests, test_num;
a93f592018-05-15Karl Gustav Sterneberg int lskipped;
58aedc2001-09-25Marcus Wellhardh int fails, lfails;
d8910b2008-08-06Martin Stjernholm int pass; string tag_test_data;
b36cbb2010-11-01Martin Stjernholm int bkgr_fails;
36d1b92010-11-19Martin Jonsson void background_failure() { // Called in all configurations/instances of this module, by // describe_backtrace() (roxenloader.pike), in self test mode. We // need to check whether it's for us or not by checking if we're // running currently.
6c313b2012-02-14Martin Stjernholm  if (is_running()) { // Log something to make these easier to locate in the noisy test logs. report_error ("################ Background failure\n");
36d1b92010-11-19Martin Jonsson  bkgr_fails++;
6c313b2012-02-14Martin Stjernholm  }
36d1b92010-11-19Martin Jonsson }
58aedc2001-09-25Marcus Wellhardh 
fa92d22011-03-29Martin Stjernholm void schedule_tests (int|float delay, function func, mixed... args) { // Run the tests in a normal handler thread so that real background // jobs can run as usual. call_out (roxen.handle, delay, lambda (function func, array args) { // Meddle with the busy_threads counter, so that this // handler thread running the tests doesn't delay the // background jobs. roxen->busy_threads--; mixed err = catch (func (@args)); roxen->busy_threads++; if (err) throw (err); }, func, args); }
6fc7c82012-02-14Martin Stjernholm void schedule_tests_single_thread (int|float delay, function func, mixed... args) { // The opposite of schedule_tests, i.e. tries to ensure no other // jobs gets executed in parallel by either background_run or a // roxen.handle. call_out (lambda (function func, array args) { roxen->hold_handler_threads(); mixed err = catch (func (@args)); roxen->release_handler_threads (0); if (err) throw (err); }, delay, func, args); }
58aedc2001-09-25Marcus Wellhardh int do_continue(int _tests, int _fails) { if(finished) return 0;
36d1b92010-11-19Martin Jonsson  running = 1;
58aedc2001-09-25Marcus Wellhardh  tests += _tests; fails += _fails;
fa92d22011-03-29Martin Stjernholm  schedule_tests (0.5, do_tests);
58aedc2001-09-25Marcus Wellhardh  return 1; } string query_provides() { return "roxen_test"; } void create() { defvar("selftestdir", "etc/test", "Self test directory", TYPE_STRING); }
5834132001-01-31Per Hedbor 
7cad992001-02-01Per Hedbor void start(int n, Configuration c) {
a7cbff2000-11-11Martin Nilsson  conf=c;
1d7f6d2000-11-12Martin Nilsson  index_file = Stdio.File();
58aedc2001-09-25Marcus Wellhardh 
d8910b2008-08-06Martin Stjernholm  module_dependencies (0, ({"rxmlparse"}), 1); rxmlparser = conf->find_module ("rxmlparse");
58aedc2001-09-25Marcus Wellhardh  if(is_ready_to_start()) { running = 1;
fa92d22011-03-29Martin Stjernholm  schedule_tests (0.5, do_tests);
58aedc2001-09-25Marcus Wellhardh  }
a7cbff2000-11-11Martin Nilsson }
d8910b2008-08-06Martin Stjernholm void set_id_path (RequestID fake_id, string path)
7cad992001-02-01Per Hedbor {
d8910b2008-08-06Martin Stjernholm  fake_id->set_url("http://localhost:17369" + path); string realpath = combine_path_unix (query("selftestdir"), "filesystem" + path); if (file_stat (realpath)) fake_id->realfile = realpath;
211b172000-11-11Martin Nilsson }
fc40392008-08-15Martin Stjernholm protected string ignore_errors = 0;
84e0712001-11-21Martin Stjernholm 
c559792001-09-19Martin Nilsson string rxml_error(RXML.Backtrace err, RXML.Type type) { // if(verbose) // werror(describe_backtrace(err)+"\n");
84e0712001-11-21Martin Stjernholm  if (ignore_errors && ignore_errors == err->type) return "";
c559792001-09-19Martin Nilsson  return sprintf("[Error (%s): %s]", err->type, String.trim_all_whites(replace(err->msg, "\n", ""))); }
211b172000-11-11Martin Nilsson string canon_html(string in) {
e8f6402001-06-18Martin Stjernholm  return Roxen.get_xml_parser()->_set_tag_callback ( lambda (Parser.HTML p, string tag) { int xml = tag[-2] == '/'; string ut = p->tag_name(); mapping args = p->tag_args(); foreach (sort (map (indices (args), lower_case)), string arg) ut += " " + arg + "='" + args[arg] + "'"; if(xml) ut+="/"; return ({"<", ut, ">"}); })->finish (in)->read();
a7cbff2000-11-11Martin Nilsson }
3aa85f2008-08-06Martin Stjernholm string strip_silly_ws (string in) // Silly whitespace is defined to be any whitespace next to tags, // comments, processing instructions, and at the beginning or end of // the whole string. { return Roxen.get_xml_parser()->_set_data_callback ( lambda (Parser.HTML p, string data) { return ({String.trim_all_whites (data)}); })->finish (in)->read(); }
211b172000-11-11Martin Nilsson  // --- XML-based test files -------------------------------
53e7cc2008-10-07Martin Stjernholm void xml_set_module_var(Parser.HTML file_parser, mapping m, string c) {
58aedc2001-09-25Marcus Wellhardh  conf->find_module(m->module)->getvar(m->variable)->set(c); return; }
53e7cc2008-10-07Martin Stjernholm void xml_add_module(Parser.HTML file_parser, mapping m, string c) {
2058c92001-03-29Martin Nilsson  conf->enable_module(c);
a7cbff2000-11-11Martin Nilsson  return; }
53e7cc2008-10-07Martin Stjernholm void xml_drop_module(Parser.HTML file_parser, mapping m, string c) {
2058c92001-03-29Martin Nilsson  conf->disable_module(c);
a7cbff2000-11-11Martin Nilsson  return; }
53e7cc2008-10-07Martin Stjernholm void xml_dummy(Parser.HTML file_parser, mapping m, string c) {
be82202001-11-07Henrik Grubbström (Grubba)  return; }
53e7cc2008-10-07Martin Stjernholm void xml_use_module(Parser.HTML file_parser, mapping m, string c,
e8f6402001-06-18Martin Stjernholm  mapping ignored, multiset(string) used_modules) { conf->enable_module(c); used_modules[c] = 1; return; }
53e7cc2008-10-07Martin Stjernholm void xml_test(Parser.HTML file_parser, mapping args, string c, mapping(int:RXML.PCode) p_code_cache) {
a7cbff2000-11-11Martin Nilsson 
235f772008-10-26Martin Stjernholm  if (roxen.is_shutting_down()) return;
0d967f2008-08-07Martin Stjernholm  test_num++; RXML.PCode p_code = p_code_cache[test_num];
d8910b2008-08-06Martin Stjernholm  if (pass == 2 && !p_code) return; // Not a test that produced p-code.
a7cbff2000-11-11Martin Nilsson  ltests++; tests++;
48ed3d2000-11-12Martin Nilsson 
e152de2008-09-28Martin Stjernholm  string rxml=""; mixed res;
5834132001-01-31Per Hedbor  string indent( int l, string what ) { array q = what/"\n"; // if( q[-1] == "" ) q = q[..sizeof(q)-2]; string i = (" "*l+"| "); return i+q*("\n"+i)+"\n"; };
7d61d52001-09-04Martin Nilsson 
5834132001-01-31Per Hedbor  string test_error( string message, mixed ... args ) { if( sizeof( args ) ) message = sprintf( message, @args );
0d967f2008-08-07Martin Stjernholm  message = (pass == 2 ? "[Pass 2 (p-code)] " : "[Pass 1 (source)] ") + message;
5834132001-01-31Per Hedbor  if( verbose ) if( strlen( rxml ) ) report_debug("FAIL\n" );
6c313b2012-02-14Martin Stjernholm  report_error (indent (2, sprintf ("################ Error at line %d:",
53e7cc2008-10-07Martin Stjernholm  file_parser->at_line())));
5834132001-01-31Per Hedbor  if( strlen( rxml ) ) report_debug( indent(2, rxml ) ); rxml="";
6c313b2012-02-14Martin Stjernholm  report_error( indent(2, message ) );
5834132001-01-31Per Hedbor  };
7d61d52001-09-04Martin Nilsson 
5834132001-01-31Per Hedbor  string test_ok( ) { rxml = ""; if( verbose ) report_debug( "PASS\n" ); };
7d61d52001-09-04Martin Nilsson 
5834132001-01-31Per Hedbor  string test_test( string test ) { if( verbose && strlen( rxml ) ) test_ok(); rxml = test; if( verbose ) {
d8910b2008-08-06Martin Stjernholm  report_debug( "%4d %-69s (pass %d) ", ltests, sprintf("%O", test)[..68], pass);
5834132001-01-31Per Hedbor  } };
e8f6402001-06-18Martin Stjernholm 
d8910b2008-08-06Martin Stjernholm  RequestID id = roxen.InternalRequestID(); id->conf = conf; id->prot = "HTTP"; id->supports = (< "images" >); id->client = ({ "RoxenTest" });
61f5c02009-02-20Jonas Wallden  id->misc->pref_languages = PrefLanguages();
d8910b2008-08-06Martin Stjernholm  id->misc->pref_languages->set_sorted( ({"sv","en","bräk"}) ); NOCACHE(); set_id_path (id, "/index.html");
3aa85f2008-08-06Martin Stjernholm  int no_canon, no_strip_silly_ws;
03b3692000-12-30Martin Nilsson  Parser.HTML parser =
e8f6402001-06-18Martin Stjernholm  Roxen.get_xml_parser()->
03b3692000-12-30Martin Nilsson  add_containers( ([ "rxml" :
85860c2001-03-24Martin Nilsson  lambda(object t, mapping m, string c) {
5834132001-01-31Per Hedbor  test_test( c );
d8910b2008-08-06Martin Stjernholm  id->misc->stat = conf->stat_file ("/index.html", id);
e8f6402001-06-18Martin Stjernholm  mixed err = catch {
84e0712001-11-21Martin Stjernholm  ignore_errors = m["ignore-errors"];
d8910b2008-08-06Martin Stjernholm  if (pass == 1) {
4123ab2001-07-25Martin Stjernholm  RXML.Type type = m->type ? RXML.t_type->encode (m->type) ( conf->default_content_type->parser_prog) : conf->default_content_type; if (m->parser) type = type (RXML.t_parser->encode (m->parser)); RXML.Parser parser = Roxen.get_rxml_parser (id, type, 1);
d8910b2008-08-06Martin Stjernholm  parser->context->add_scope ("test", (["pass": 1]));
e8f6402001-06-18Martin Stjernholm  parser->write_end (rxml);
2e5cd42008-11-02Martin Stjernholm #ifdef GAUGE_RXML_TESTS werror ("Line %d: Test took %.3f us (pass 1)\n", file_parser->at_line(), gauge (res = parser->eval()) * 1e9); #else
e8f6402001-06-18Martin Stjernholm  res = parser->eval();
2e5cd42008-11-02Martin Stjernholm #endif
8a01da2001-08-21Martin Stjernholm  parser->p_code->finish();
e8f6402001-06-18Martin Stjernholm  p_code_cache[ltests] = parser->p_code; }
4123ab2001-07-25Martin Stjernholm  else { RXML.Context ctx = p_code->new_context (id);
d8910b2008-08-06Martin Stjernholm  ctx->add_scope ("test", (["pass": 2]));
2e5cd42008-11-02Martin Stjernholm #ifdef GAUGE_RXML_TESTS werror ("Line %d: Test took %.3f us (pass 2)\n", file_parser->at_line(), gauge (res = p_code->eval (ctx)) * 1e9); #else
4123ab2001-07-25Martin Stjernholm  res = p_code->eval (ctx);
2e5cd42008-11-02Martin Stjernholm #endif
4123ab2001-07-25Martin Stjernholm  }
e8f6402001-06-18Martin Stjernholm  };
84e0712001-11-21Martin Stjernholm  ignore_errors = 0; if(err && (!m["ignore-errors"] || !objectp (err) || !err->is_RXML_Backtrace || err->type != m["ignore-errors"]))
5834132001-01-31Per Hedbor  {
b139fd2012-02-14Martin Stjernholm  // Use master()->describe_backtrace() to bypass // background_failure() and avoid counting this // error twice. test_error("Failed (backtrace): %s", master()->describe_backtrace(err));
03b3692000-12-30Martin Nilsson  throw(1); }
3aa85f2008-08-06Martin Stjernholm 
e152de2008-09-28Martin Stjernholm  if(stringp (res) && !args["no-canon"])
03b3692000-12-30Martin Nilsson  res = canon_html(res);
4d7b372001-02-01Per Hedbor  else no_canon = 1;
e152de2008-09-28Martin Stjernholm  if (stringp (res) && !args["no-strip-ws"])
3aa85f2008-08-06Martin Stjernholm  res = strip_silly_ws (res); else no_strip_silly_ws = 1;
03b3692000-12-30Martin Nilsson  },
d8910b2008-08-06Martin Stjernholm  "test-in-file": lambda(object t, mapping m, string c) { test_test (tag_test_data = c); set_id_path (id, m->file); int logerrorsr = rxmlparser->query("logerrorsr"); int quietr = rxmlparser->query("quietr"); if(m["ignore-rxml-run-error"]) { rxmlparser->getvar("logerrorsr")->set(0); rxmlparser->getvar("quietr")->set(1); } res = conf->try_get_file(m->file, id); if(m["ignore-rxml-run-error"]) { rxmlparser->getvar("logerrorsr")->set(logerrorsr); rxmlparser->getvar("quietr")->set(quietr); }
e152de2008-09-28Martin Stjernholm  if(stringp (res) && !args["no-canon"])
d8910b2008-08-06Martin Stjernholm  res = canon_html(res); else no_canon = 1;
e152de2008-09-28Martin Stjernholm  if (stringp (res) && !args["no-strip-ws"])
3aa85f2008-08-06Martin Stjernholm  res = strip_silly_ws (res); else no_strip_silly_ws = 1;
d8910b2008-08-06Martin Stjernholm  },
03b3692000-12-30Martin Nilsson  "result" :
85860c2001-03-24Martin Nilsson  lambda(object t, mapping m, string c) {
62a2e42001-07-25Martin Stjernholm  if (!m->pass || (int) m->pass == pass) {
4123ab2001-07-25Martin Stjernholm  if (m->type || m->parser) { RXML.Type type = m->type ? RXML.t_type->encode (m->type) : conf->default_content_type (RXML.PNone); if (m->parser) type = type (RXML.t_parser->encode (m->parser)); RXML.Parser parser = Roxen.get_rxml_parser (id, type, 1); parser->context->add_scope ("test", (["pass": pass])); parser->write_end (c); c = parser->eval(); } if( !no_canon ) c = canon_html( c );
3aa85f2008-08-06Martin Stjernholm  if (!no_strip_silly_ws) c = strip_silly_ws (c);
53e7cc2008-10-07Martin Stjernholm  if (m->not ? res == c : res != c) {
ae250c2008-09-13Martin Stjernholm  test_error("Failed\n(got: %O\nexpected: %O)\n", res, c);
4123ab2001-07-25Martin Stjernholm  throw(1); } test_ok( );
03b3692000-12-30Martin Nilsson  } },
e152de2008-09-28Martin Stjernholm 
03b3692000-12-30Martin Nilsson  "glob" :
85860c2001-03-24Martin Nilsson  lambda(object t, mapping m, string c) {
53e7cc2008-10-07Martin Stjernholm  if (m->not ? glob(c, res) : !glob(c, res)) {
ae250c2008-09-13Martin Stjernholm  test_error("Failed\n(result %O\ndoes not match %O)\n", res, c);
03b3692000-12-30Martin Nilsson  throw(1); }
5834132001-01-31Per Hedbor  test_ok( );
03b3692000-12-30Martin Nilsson  },
e152de2008-09-28Martin Stjernholm 
03b3692000-12-30Martin Nilsson  "has-value" :
85860c2001-03-24Martin Nilsson  lambda(object t, mapping m, string c) {
53e7cc2008-10-07Martin Stjernholm  if (m->not ? has_value(res, c) : !has_value(res, c)) {
ae250c2008-09-13Martin Stjernholm  test_error("Failed\n(result %O\ndoes not contain %O)\n", res, c);
85860c2001-03-24Martin Nilsson  throw(1); } test_ok( ); },
e152de2008-09-28Martin Stjernholm 
85860c2001-03-24Martin Nilsson  "regexp" : lambda(object t, mapping m, string c) {
53e7cc2008-10-07Martin Stjernholm  if (m->not ? Regexp(c)->match(res) : !Regexp(c)->match(res)) {
ae250c2008-09-13Martin Stjernholm  test_error("Failed\n(result %O\ndoes not match %O)\n", res, c);
03b3692000-12-30Martin Nilsson  throw(1); }
5834132001-01-31Per Hedbor  test_ok( );
03b3692000-12-30Martin Nilsson  },
e152de2008-09-28Martin Stjernholm  "equal": lambda(object t, mapping m, string c) { c = "constant c = (" + c + ");"; program p; if (mixed err = catch (p = compile_string (c))) { test_error ("Failed\n(failed to compile %O)\n", c); throw (1); } mixed v; if (mixed err = catch (v = p()->c)) { test_error ("Failed\n(failed to clone and " "get value from %O)\n", c); throw (1); }
53e7cc2008-10-07Martin Stjernholm  if (m->not ? equal (res, v) : !equal (res, v)) {
e152de2008-09-28Martin Stjernholm  test_error("Failed\n(result %O\ndoes not match %O)\n", res, v); throw(1); } test_ok( ); },
3f61a02001-08-29Martin Nilsson  "pike" : lambda(object t, mapping m, string c) { c = "string test(string res) {\n" + c + "\n}"; object test; mixed err = catch { test = compile_string(c)(); }; if(err) { int i; c = map(c/"\n", lambda(string in) { return sprintf("%3d: %s", ++i, in); }) * "\n";
b139fd2012-02-14Martin Stjernholm  // Use master()->describe_backtrace() to bypass // background_failure() and avoid counting this // error twice. test_error ("Error while compiling test\n%s\n\n" "Backtrace:\n%s\n", c, master()->describe_backtrace(err));
3f61a02001-08-29Martin Nilsson  throw(1); } string r = test->test(res); if(r) { test_error("Failed (%s)\n", r); throw(1); } test_ok( ); },
5834132001-01-31Per Hedbor  ]) )
e152de2008-09-28Martin Stjernholm 
85860c2001-03-24Martin Nilsson  ->add_tags( ([ "add" : lambda(object t, mapping m, string c) {
5834132001-01-31Per Hedbor  switch(m->what) { default: test_error("Could not <add> %O; " "unknown variable.\n", m->what);
6c313b2012-02-14Martin Stjernholm  throw (1);
5834132001-01-31Per Hedbor  break; case "prestate": id->prestate[m->name] = 1; break; case "variable": id->variables[m->name] = m->value || m->name; break;
5e3e502001-04-21Martin Nilsson  case "rvariable": if(m->split && m->value) id->real_variables[m->name] = m->value / m->split; else id->real_variables[m->name] = ({ m->value || m->name }); break;
5834132001-01-31Per Hedbor  case "cookies": id->cookies[m->name] = m->value || ""; break; case "supports": id->supports[m->name] = 1; break; case "config": id->config[m->name] = 1; break; case "client_var": id->client_var[m->name] = m->value || ""; break;
5e3e502001-04-21Martin Nilsson  case "misc": id->misc[m->name] = m->value || "1"; break;
e8f6402001-06-18Martin Stjernholm // case "define": // id->misc->defines[m->name] = m->value || 1; // break;
5e3e502001-04-21Martin Nilsson  case "not_query": id->not_query = m->value; break; case "query": id->query = m->value; break;
d0611d2001-04-21Martin Nilsson  case "request_header": id->request_headers[m->name] = m->value;
c559792001-09-19Martin Nilsson  break;
5834132001-01-31Per Hedbor  } },
c559792001-09-19Martin Nilsson  "login" : lambda(Parser.HTML p, mapping m) {
d8910b2008-08-06Martin Stjernholm  id->realauth = m->user + ":" + m->password;
c559792001-09-19Martin Nilsson  id->request_headers->authorization =
c2a6502012-11-08Jonas Wallden  "Basic " + MIME.encode_base64 (id->realauth, 1);
c559792001-09-19Martin Nilsson  conf->authenticate(id); },
c9e5f22001-05-20Martin Nilsson  ]) );
03b3692000-12-30Martin Nilsson 
2998c62004-06-23Martin Stjernholm  if( mixed error = catch(parser->finish(c)) ) { if (error != 1)
b139fd2012-02-14Martin Stjernholm  // Use master()->describe_backtrace() to bypass background_failure() and // avoid counting this error twice. test_error ("Failed to parse test: " + master()->describe_backtrace (error));
a7cbff2000-11-11Martin Nilsson  fails++; lfails++; }
5834132001-01-31Per Hedbor  if( verbose && strlen( rxml ) ) test_ok();
03b3692000-12-30Martin Nilsson  return;
a7cbff2000-11-11Martin Nilsson }
a93f592018-05-15Karl Gustav Sterneberg mixed xml_testsuite(Parser.HTML file_parser, mapping args, string c, mapping(int:RXML.PCode) p_code_cache) { if (roxen.is_shutting_down()) { return ({}); // Stop parsing. } string env = args["if-not-env"]; if (env && getenv(env)) { if (pass == 1) { report_debug("Skipping tests since env. var %s is defined.\n", env); // Count number of tests we are skipping. Roxen.get_xml_parser()->add_quote_tag ("!--", "", "--") ->add_tags ((["test": lambda () { lskipped++; }])) ->finish (c); } return ({}); // Stop parsing. } return c; // Continue to parse content withing this tag. }
01432e2001-08-10Marcus Wellhardh class TagTestData { inherit RXML.Tag; constant name = "test-data";
9462892011-03-29Martin Stjernholm  constant flags = RXML.FLAG_DONT_CACHE_RESULT;
01432e2001-08-10Marcus Wellhardh  array(RXML.Type) result_types = ({RXML.t_html (RXML.PXml)});
9462892011-03-29Martin Stjernholm 
01432e2001-08-10Marcus Wellhardh  class Frame { inherit RXML.Frame; array do_return(RequestID id) {
58aedc2001-09-25Marcus Wellhardh  return ({ tag_test_data||"" });
01432e2001-08-10Marcus Wellhardh  } } }
85860c2001-03-24Martin Nilsson void xml_comment(object t, mapping m, string c) {
ca4ede2001-02-06Martin Nilsson  if(verbose) report_debug(c + (c[-1]=='\n'?"":"\n"));
a7cbff2000-11-11Martin Nilsson } void run_xml_tests(string data) {
e8f6402001-06-18Martin Stjernholm  mapping(int:RXML.PCode) p_code_cache = ([]); multiset(string) used_modules = (<>);
a7cbff2000-11-11Martin Nilsson 
bf6e282008-11-26Martin Stjernholm  // El cheapo xml header parser. if (has_prefix (data, "<?xml")) { sscanf (data, "%[^\n]", string s); if (sscanf (s, "%*sencoding=\"%s\"", s) == 2)
50aa162015-04-28Jonas Walldén  data = Charset.decoder (s)->feed (data)->drain();
bf6e282008-11-26Martin Stjernholm  }
a7cbff2000-11-11Martin Nilsson  ltests=0; lfails=0;
a93f592018-05-15Karl Gustav Sterneberg  lskipped=0;
0d967f2008-08-07Martin Stjernholm  test_num = 0;
d8910b2008-08-06Martin Stjernholm  pass = 1;
e8f6402001-06-18Martin Stjernholm  Roxen.get_xml_parser()->add_containers( ([ "add-module" : xml_add_module,
be82202001-11-07Henrik Grubbström (Grubba)  "drop-module" : xml_dummy /* xml_drop_module */,
e8f6402001-06-18Martin Stjernholm  "use-module": xml_use_module,
a93f592018-05-15Karl Gustav Sterneberg  "testsuite" : xml_testsuite,
e8f6402001-06-18Martin Stjernholm  "test" : xml_test, "comment": xml_comment, ]) )-> set_extra (p_code_cache, used_modules)-> finish(data);
235f772008-10-26Martin Stjernholm  if (roxen.is_shutting_down()) return;
cc9b3e2004-02-20Martin Stjernholm  int test_tags = 0; Roxen.get_xml_parser()->add_quote_tag ("!--", "", "--")
d8910b2008-08-06Martin Stjernholm  ->add_tags ((["test": lambda () {test_tags++;}]))
cc9b3e2004-02-20Martin Stjernholm  ->finish (data);
a93f592018-05-15Karl Gustav Sterneberg  if(test_tags != (ltests + lskipped))
cc9b3e2004-02-20Martin Stjernholm  report_warning("Possibly XML error in testsuite - " "got %d test tags but did %d tests.\n", test_tags, ltests);
e8f6402001-06-18Martin Stjernholm  // Go through them again, evaluation from the p-code this time.
0d967f2008-08-07Martin Stjernholm  test_num = 0;
d8910b2008-08-06Martin Stjernholm  pass = 2;
e8f6402001-06-18Martin Stjernholm  Roxen.get_xml_parser()->add_containers( ([
be82202001-11-07Henrik Grubbström (Grubba)  "add-module" : xml_dummy /* xml_add_module */,
e8f6402001-06-18Martin Stjernholm  "drop-module" : xml_drop_module,
a93f592018-05-15Karl Gustav Sterneberg  "testsuite" : xml_testsuite,
e8f6402001-06-18Martin Stjernholm  "test" : xml_test, "comment": xml_comment, ]) )-> set_extra (p_code_cache, used_modules)-> finish(data);
235f772008-10-26Martin Stjernholm  if (roxen.is_shutting_down()) return;
e8f6402001-06-18Martin Stjernholm  foreach (indices (used_modules), string modname) conf->disable_module (modname);
a93f592018-05-15Karl Gustav Sterneberg  report_debug("Did %d tests, failed on %d, skipped %d%s.\n", ltests, lfails, lskipped, bkgr_fails ?
b36cbb2010-11-01Martin Stjernholm  ", detected " + bkgr_fails + " background failures" : ""); if (bkgr_fails) { fails += bkgr_fails; bkgr_fails = 0; }
25fd8a2011-03-29Martin Stjernholm  continue_run_tests();
a7cbff2000-11-11Martin Nilsson }
3fc2ec2001-05-17Martin Nilsson  // --- Pike test files -----------------------
7cad992001-02-01Per Hedbor void run_pike_tests(object test, string path) { void update_num_tests(int tsts, int fail) { tests+=tsts; fails+=fail;
b36cbb2010-11-01Martin Stjernholm  report_debug("Did %d tests, failed on %d%s.\n", tsts, fail, bkgr_fails ? ", detected " + bkgr_fails + " background failures" : ""); if (bkgr_fails) { fails += bkgr_fails; bkgr_fails = 0; }
25fd8a2011-03-29Martin Stjernholm  continue_run_tests();
7cad992001-02-01Per Hedbor  };
f1d3fd2000-12-10Martin Nilsson  if(!test) return;
fa92d22011-03-29Martin Stjernholm 
2998c62004-06-23Martin Stjernholm  if( mixed error = catch(test->low_run_tests(conf, update_num_tests)) ) { if (error != 1) throw (error);
7cad992001-02-01Per Hedbor  update_num_tests( 1, 1 );
2998c62004-06-23Martin Stjernholm  }
f1d3fd2000-12-10Martin Nilsson }
211b172000-11-11Martin Nilsson  // --- Mission control ------------------------
25fd8a2011-03-29Martin Stjernholm array(string) test_files;
e659ea2001-01-31Per Hedbor 
25fd8a2011-03-29Martin Stjernholm void continue_run_tests( )
7cad992001-02-01Per Hedbor {
25fd8a2011-03-29Martin Stjernholm  if (sizeof (test_files)) { string file = test_files[0]; test_files = test_files[1..]; report_debug("\nRunning test %s\n",file); if (has_suffix (file, ".xml"))
e659ea2001-01-31Per Hedbor  {
213f102012-02-14Martin Stjernholm  string data = Stdio.read_file(file); int single_thread; // If the file contains a pi <?single-thread?> then it's run with the // handler threads disabled (see the single_thread constant in // pike_test_common.pike). Roxen.get_xml_parser()->add_quote_tag ("?single-thread", lambda() {single_thread = 1;}, "?") ->finish (data); if (single_thread) schedule_tests_single_thread (0, run_xml_tests, data); else schedule_tests (0, run_xml_tests, data);
25fd8a2011-03-29Martin Stjernholm  return; } else // Pike test. { object test; mixed error; tests++; if( error=catch( test=compile_file(file)( verbose ) ) ) {
b139fd2012-02-14Martin Stjernholm  // Use master()->describe_backtrace() to bypass background_failure() // and avoid counting this error twice.
6c313b2012-02-14Martin Stjernholm  report_error("################ Failed to compile %s:\n%s", file,
b139fd2012-02-14Martin Stjernholm  master()->describe_backtrace(error));
25fd8a2011-03-29Martin Stjernholm  fails++;
7cad992001-02-01Per Hedbor  }
25fd8a2011-03-29Martin Stjernholm  else
5834132001-01-31Per Hedbor  {
6fc7c82012-02-14Martin Stjernholm  if (test->single_thread) schedule_tests_single_thread (0, run_pike_tests, test, file); else schedule_tests (0, run_pike_tests,test,file);
25fd8a2011-03-29Martin Stjernholm  return;
5834132001-01-31Per Hedbor  }
a7cbff2000-11-11Martin Nilsson  }
5834132001-01-31Per Hedbor  }
25fd8a2011-03-29Martin Stjernholm 
58aedc2001-09-25Marcus Wellhardh  running = 0; finished = 1; if(is_last_test_configuration()) {
b36cbb2010-11-01Martin Stjernholm  // Note that e.g. the distmaker parses this string. report_debug("\nDid a grand total of %d tests, %d failed.\n\n",
58aedc2001-09-25Marcus Wellhardh  tests, fails);
02ee102004-06-09Jonas Wallden  roxen.restart(0, fails > 127 ? 127 : fails);
58aedc2001-09-25Marcus Wellhardh  } else foreach(roxen.configurations, Configuration config) if(config->call_provider("roxen_test", "do_continue", tests, fails)) return;
7cad992001-02-01Per Hedbor }
a7cbff2000-11-11Martin Nilsson 
7cad992001-02-01Per Hedbor void do_tests() { if(time() - roxen->start_time < 2 ) {
fa92d22011-03-29Martin Stjernholm  schedule_tests (0.2, do_tests);
f1d3fd2000-12-10Martin Nilsson  return; }
25fd8a2011-03-29Martin Stjernholm  report_debug("\nStarting roxen self test in %s\n", query("selftestdir")); array(string) tests_to_run = Getopt.find_option(roxen.argv, 0,({"tests"}),0,"" )/","; foreach( tests_to_run; int i; string p ) if( !has_prefix(p, "RoxenTest_") ) tests_to_run[i] = "RoxenTest_" + p;
a7cbff2000-11-11Martin Nilsson 
e8f6402001-06-18Martin Stjernholm  verbose = !!Getopt.find_option(roxen.argv, 0,({"tests-verbose"}),0, 0 );
c559792001-09-19Martin Nilsson  conf->rxml_tag_set->handle_run_error = rxml_error; conf->rxml_tag_set->handle_parse_error = rxml_error;
25fd8a2011-03-29Martin Stjernholm  test_files = ({}); mapping(string:int) matched_pos = ([]); ADT.Stack file_stack = ADT.Stack();
7cad992001-02-01Per Hedbor  file_stack->push( 0 );
58aedc2001-09-25Marcus Wellhardh  file_stack->push( combine_path(query("selftestdir"), "tests" ));
25fd8a2011-03-29Martin Stjernholm  file_loop: while( string file = file_stack->pop() ) { if( Stdio.Stat st = file_stat( file ) ) { if( file!="CVS" && st->isdir ) { string dir = file+"/"; foreach( get_dir( dir ), string f ) file_stack->push( dir+f ); } else if( glob("*/RoxenTest_*", file ) && file[-1]!='~') { foreach( tests_to_run; int i; string p ) { if( glob( "*/"+p+"*", file ) ) { if (has_suffix (file, ".xml") || has_suffix (file, ".pike")) { test_files += ({file}); matched_pos[file] = i; } continue file_loop; } } report_debug( "Skipped test %s\n", file); } } } // The order should not be significant ... test_files = Array.shuffle (test_files); // ... but let the caller control the order in case it turns out to be. sort (map (test_files, matched_pos), test_files); schedule_tests (0, continue_run_tests);
a7cbff2000-11-11Martin Nilsson }
f1d3fd2000-12-10Martin Nilsson  // --- Some tags used in the RXML tests ---------------
9ec53f2001-06-21Martin Nilsson class EntityDyn {
e8bcb12001-04-02Martin Nilsson  inherit RXML.Value; int i; mixed rxml_var_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
9ec53f2001-06-21Martin Nilsson  if(c->current_scope() && RXML.get_var("x")) return ENCODE_RXML_INT(i++, type); return ENCODE_RXML_INT(0, type);
e8bcb12001-04-02Martin Nilsson  } }
90bf6f2001-04-08Martin Nilsson class EntityCVal(string val) { inherit RXML.Value;
2234f72006-01-11Martin Stjernholm  mixed rxml_const_eval(RXML.Context c, string var, string scope_name) { return val;
90bf6f2001-04-08Martin Nilsson  } } class EntityVVal(string val) { inherit RXML.Value; mixed rxml_var_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { return ENCODE_RXML_TEXT(val, type); } }
79b9082006-12-12Martin Stjernholm class TestNull { inherit RXML.Nil; constant is_RXML_encodable = 1; string _sprintf (int flag) {return flag == 'O' && "TestNull()";} }
f1d3fd2000-12-10Martin Nilsson class TagEmitTESTER { inherit RXML.Tag; constant name = "emit"; constant plugin_name = "TESTER";
feb0832002-10-15Martin Stjernholm  array(mapping(string:mixed)) get_dataset(mapping m, RequestID id) {
8e31242000-12-12Martin Nilsson  switch(m->test) {
097c6f2003-10-06Martin Stjernholm  case "6": return ({(["integer": 17, "float": 17.0, "string": "foo", "array": ({1, 2.0, "3"}), "multiset": (<1, 2.0, "3">), "mapping": ([1: "one", 2.0: 2, "3": 3]), "object": class {}(), "program": class {}, "zero_integer": 0, "zero_float": 0.0, "empty_string": "", "empty_array": ({}), "empty_multiset": (<>), "empty_mapping": ([]), "zero_int_array": ({0}), "zero_float_array": ({0.0}), "empty_string_array": ({""}), "empty_array_array": ({({})}), ])});
feb0832002-10-15Martin Stjernholm  case "5": return ({(["v": EntityVVal ("<&>"), "c": EntityCVal ("<&>")])});
90bf6f2001-04-08Martin Nilsson  case "4": return ({ ([ "a":"1", "b":EntityCVal("aa"), "c":EntityVVal("ca") ]), ([ "a":"2", "b":EntityCVal("ba"), "c":EntityVVal("cb") ]), ([ "a":"3", "b":EntityCVal("ab"), "c":EntityVVal("ba") ]), });
e8bcb12001-04-02Martin Nilsson  case "3":
37b8452004-03-30Martin Stjernholm  return ({ (["data":"a"]), (["data":RXML.nil]),
79b9082006-12-12Martin Stjernholm  (["data":TestNull()]),
37b8452004-03-30Martin Stjernholm  (["data":RXML.empty]),
9f6f802011-11-14Martin Stjernholm  (["data":EntityDyn()]), (["data": Val.null]), });
e8bcb12001-04-02Martin Nilsson 
8e31242000-12-12Martin Nilsson  case "2": return map( "aa,a,aa,a,bb,b,cc,c,aa,a,dd,d,ee,e,aa,a,a,a,aa"/",", lambda(string in) { return (["data":in]); } ); case "1": default: return ({
54a8dc2002-06-18Martin Stjernholm  ([ "a":"kex", "b":"foo", "c":1, "d":"12foo", "e":"-8", "f": "0" ]), ([ "a":"kex", "b":"boo", "c":2, "d":"foo", "e":"8", "f": "-6.4" ]), ([ "a":"krut", "b":"gazonk", "c":3, "d":"5foo33a", "e":"11", "f": "1e6" ]), ([ "a":"kox", "c":4, "d":"5foo4a", "e":"-11", "f": "0.23" ])
8e31242000-12-12Martin Nilsson  }); }
f1d3fd2000-12-10Martin Nilsson  } }
34acc82001-03-15Martin Nilsson  class TagOEmitTESTER { inherit TagEmitTESTER; inherit "emit_object"; constant plugin_name = "OTESTER"; class MyEmit (array(mapping) dataset) { inherit EmitObject; int pos; private mapping(string:mixed) really_get_row() { return pos<sizeof(dataset)?dataset[pos++]:0; } } EmitObject get_dataset(mapping m, RequestID id) { return MyEmit( ::get_dataset(m,id) ); } }
de45652001-05-31Martin Nilsson  class TagSEmitTESTER { inherit TagEmitTESTER; constant plugin_name = "STESTER"; constant skiprows = 1; constant maxrows = 1; constant sort = 1; }
3f61a02001-08-29Martin Nilsson  class TagTestSleep { inherit RXML.Tag; constant name = "testsleep"; class Frame { inherit RXML.Frame; array do_return(RequestID id) { sleep((int)args->time); } } }
2f25682001-09-13Martin Stjernholm 
7614392009-07-02Martin Stjernholm class TagTestArgs { inherit RXML.Tag; constant name = "test-args"; array(RXML.Type) result_types = ({RXML.t_mapping}); mapping(string:RXML.Type) req_arg_types = ([ "req-string": RXML.t_string (RXML.PEnt), "req-int": RXML.t_int (RXML.PEnt), ]); mapping(string:RXML.Type) opt_arg_types = ([ "opt-string": RXML.t_string (RXML.PEnt), "opt-int": RXML.t_int (RXML.PEnt), "opt-float": RXML.t_float (RXML.PEnt), ]); class Frame { inherit RXML.Frame; array do_return() { result = args; } } }
33edf22009-07-13Martin Stjernholm class TagTestContentReq { inherit RXML.Tag; constant name = "test-required-content"; RXML.Type content_type = RXML.t_any (RXML.PXml); array(RXML.Type) result_types = ({RXML.t_any}); int flags = RXML.FLAG_CONTENT_VAL_REQ; class Frame { inherit RXML.Frame; } }
2f25682001-09-13Martin Stjernholm class TagTestMisc { inherit RXML.Tag; constant name = "test-misc"; class Frame { inherit RXML.Frame; array do_return() { if (args->set) RXML_CONTEXT->set_misc (args->set, content); else if (args["set-prog"]) RXML_CONTEXT->set_misc (TagTestMisc, content); else if (args->get) return ({RXML_CONTEXT->misc[args->get]}); else if (args["get-prog"]) return ({RXML_CONTEXT->misc[TagTestMisc]}); return ({}); } } }
84e0712001-11-21Martin Stjernholm  class TagRunError { inherit RXML.Tag; constant name = "run-error"; class Frame { inherit RXML.Frame; array do_return() { run_error (args->message || "A test run error"); } } }