/** * Test sending of HTTP GET requests. * * @throws Exception exception */ @Test public void postGet() throws Exception { // GET1 - just send a GET request try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get' href='" + REST_ROOT + "'/>"), ctx)) { final Value v = qp.value(); checkResponse(v, 2, HttpURLConnection.HTTP_OK); assertEquals(NodeType.DOC, v.itemAt(1).type); } // GET2 - with override-media-type='text/plain' try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='get' override-media-type='text/plain'/>", REST_ROOT), ctx)) { final Value v = qp.value(); checkResponse(v, 2, HttpURLConnection.HTTP_OK); assertEquals(AtomType.STR, v.itemAt(1).type); } // Get3 - with status-only='true' try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get' status-only='true'/>", REST_ROOT), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_OK); } }
/** * Test digest authentication. * * @throws Exception exception */ @Test public void digest() throws Exception { // correct credentials try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request xmlns:http='http://expath.org/ns/http-client' method='GET' " + "send-authorization='true' auth-method='Digest' username='******' password='******' " + "href='" + REST_ROOT + "'/>"), ctx)) { checkResponse(qp.value(), 2, HttpURLConnection.HTTP_OK); } // wrong credentials try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request xmlns:http='http://expath.org/ns/http-client' method='GET' " + "send-authorization='true' auth-method='Digest' username='******' password='******' " + "href='" + REST_ROOT + "?query=()'/>") + "[. instance of node()][@status = '401']", ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_UNAUTHORIZED); } }
/** * Test sending of HTTP POST requests. * * @throws Exception exception */ @Test public void putPost() throws Exception { // PUT - query try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='put' status-only='true'>" + "<http:body media-type='text/xml'>" + BOOKS + "</http:body>" + "</http:request>", RESTURL), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_CREATED); } // POST - query try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='post'>" + "<http:body media-type='application/xml'>" + "<query xmlns='" + Prop.URL + "/rest'>" + "<text><![CDATA[<x>1</x>]]></text>" + "</query>" + "</http:body>" + "</http:request>", RESTURL), ctx)) { checkResponse(qp.value(), 2, HttpURLConnection.HTTP_OK); } // Execute the same query but with content set from $bodies try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='post'>" + "<http:body media-type='application/xml'/>" + "</http:request>", RESTURL, "<query xmlns='" + Prop.URL + "/rest'>" + "<text><![CDATA[<x>1</x>]]></text>" + "</query>"), ctx)) { checkResponse(qp.value(), 2, HttpURLConnection.HTTP_OK); } }
/** Tests the specified instance. */ @Test public void test() { final StringBuilder sb = new StringBuilder(); int fail = 0; for (final Object[] qu : queries) { final boolean correct = qu.length == 3; final String query = qu[correct ? 2 : 1].toString(); final Value cmp = correct ? (Value) qu[1] : null; final QueryProcessor qp = new QueryProcessor(query, context); try { final Value val = qp.value(); if (!correct || !new DeepCompare().equal(val, cmp)) { sb.append("[" + qu[0] + "] " + query); String s = correct && cmp.size() != 1 ? "#" + cmp.size() : ""; sb.append("\n[E" + s + "] "); if (correct) { final String cp = cmp.toString(); sb.append('\''); sb.append(cp.length() > 1000 ? cp.substring(0, 1000) + "..." : cp); sb.append('\''); } else { sb.append("error"); } final TokenBuilder types = new TokenBuilder(); for (final Item it : val) types.add(it.type.toString()).add(" "); s = val.size() == 1 ? "" : "#" + val.size(); sb.append("\n[F" + s + "] '" + val + "', " + types + details() + '\n'); ++fail; } } catch (final Exception ex) { final String msg = ex.getMessage(); if (correct || msg == null || msg.contains("mailman")) { final String cp = correct && cmp.data() != null ? cmp.toString() : "()"; sb.append( "[" + qu[0] + "] " + query + "\n[E] " + cp + "\n[F] " + (msg == null ? Util.className(ex) : msg.replaceAll("\r\n?|\n", " ")) + ' ' + details() + '\n'); ex.printStackTrace(); ++fail; } } finally { qp.close(); } } if (fail != 0) fail(fail + " Errors. [E] = expected, [F] = found:\n" + sb.toString().trim()); }
/** * Tests an erroneous query. * * @throws Exception exception */ @Test public void error() throws Exception { try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='get'/>", RESTURL + "unknown") + "[1]/@status/data()", ctx)) { assertEquals("404", qp.value().serialize().toString()); } }
/** * Evaluates the the input files and assigns the result to the specified variables. * * @param nod variables * @param var documents * @param pth file path * @param qp query processor * @throws Exception exception */ private void eval(final Nodes nod, final Nodes var, final String pth, final QueryProcessor qp) throws Exception { for (int c = 0; c < nod.size(); ++c) { final String file = pth + string(data.atom(nod.list[c])) + IO.XQSUFFIX; final String in = read(new IOFile(queries + file)); final QueryProcessor xq = new QueryProcessor(in, context); final Value val = xq.value(); qp.bind(string(data.atom(var.list[c])), val); xq.close(); } }
/** * Test sending of HTTP DELETE requests. * * @throws Exception exception */ @Test public void postDelete() throws Exception { // add document to be deleted try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='put'>" + "<http:body media-type='text/xml'><ToBeDeleted/></http:body>" + "</http:request>", RESTURL), ctx)) { qp.value(); } // DELETE try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args("<http:request method='delete' status-only='true'/>", RESTURL), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_OK); } }
/** * Test sending of HTTP PUT requests. * * @throws Exception exception */ @Test public void put() throws Exception { try (final QueryProcessor qp = new QueryProcessor( _HTTP_SEND_REQUEST.args( "<http:request method='put' status-only='true'>" + "<http:body media-type='text/xml'>" + BOOKS + "</http:body>" + "</http:request>", RESTURL), ctx)) { checkResponse(qp.value(), 1, HttpURLConnection.HTTP_CREATED); } }
/** Test query. Detects malformed namespace hierarchy. */ @Test @Ignore public void xuty0004() { final String query = "declare variable $input-context external;" + "let $source as node()* := (" + " <status>on leave</status>," + " <!-- for 6 months -->" + " )," + " $target := $input-context/works[1]/employee[1]" + "return insert nodes $source into $target"; try (final QueryProcessor qp = new QueryProcessor(query, context)) { qp.value(); } catch (final QueryException ex) { assertEquals("XUTY0004", ex.error().code); } fail("should throw XUTY0004"); }
/** * Parses the specified test case. * * @param root root node * @throws Exception exception * @return true if the query, specified by {@link #single}, was evaluated */ private boolean parse(final Nodes root) throws Exception { final String pth = text("@FilePath", root); final String outname = text("@name", root); if (single != null && !outname.startsWith(single)) return true; final Performance perf = new Performance(); if (verbose) Util.out("- " + outname); boolean inspect = false; boolean correct = true; final Nodes nodes = states(root); for (int n = 0; n < nodes.size(); ++n) { final Nodes state = new Nodes(nodes.list[n], nodes.data); final String inname = text("*:query/@name", state); context.query = new IOFile(queries + pth + inname + IO.XQSUFFIX); final String in = read(context.query); String er = null; ItemCache iter = null; boolean doc = true; final Nodes cont = nodes("*:contextItem", state); Nodes curr = null; if (cont.size() != 0) { final Data d = Check.check(context, srcs.get(string(data.atom(cont.list[0])))); curr = new Nodes(d.doc(), d); curr.root = true; } context.prop.set(Prop.QUERYINFO, compile); final QueryProcessor xq = new QueryProcessor(in, curr, context); context.prop.set(Prop.QUERYINFO, false); // limit result sizes to 1MB final ArrayOutput ao = new ArrayOutput(); final TokenBuilder files = new TokenBuilder(); try { files.add( file(nodes("*:input-file", state), nodes("*:input-file/@variable", state), xq, n == 0)); files.add(file(nodes("*:defaultCollection", state), null, xq, n == 0)); var(nodes("*:input-URI", state), nodes("*:input-URI/@variable", state), xq); eval(nodes("*:input-query/@name", state), nodes("*:input-query/@variable", state), pth, xq); parse(xq, state); for (final int p : nodes("*:module", root).list) { final String uri = text("@namespace", new Nodes(p, data)); final String file = mods.get(string(data.atom(p))) + IO.XQSUFFIX; xq.module(file, uri); } // evaluate and serialize query final SerializerProp sp = new SerializerProp(); sp.set(SerializerProp.S_INDENT, context.prop.is(Prop.CHOP) ? DataText.YES : DataText.NO); final XMLSerializer xml = new XMLSerializer(ao, sp); iter = xq.value().cache(); for (Item it; (it = iter.next()) != null; ) { doc &= it.type == NodeType.DOC; it.serialize(xml); } xml.close(); } catch (final Exception ex) { if (!(ex instanceof QueryException || ex instanceof IOException)) { System.err.println("\n*** " + outname + " ***"); System.err.println(in + "\n"); ex.printStackTrace(); } er = ex.getMessage(); if (er.startsWith(STOPPED)) er = er.substring(er.indexOf('\n') + 1); if (er.startsWith("[")) er = er.replaceAll("\\[(.*?)\\] (.*)", "$1 $2"); // unexpected error - dump stack trace } // print compilation steps if (compile) { Util.errln("---------------------------------------------------------"); Util.err(xq.info()); Util.errln(in); } final Nodes expOut = nodes("*:output-file/text()", state); final TokenList result = new TokenList(); for (int o = 0; o < expOut.size(); ++o) { final String resFile = string(data.atom(expOut.list[o])); final IOFile exp = new IOFile(expected + pth + resFile); result.add(read(exp)); } final Nodes cmpFiles = nodes("*:output-file/@compare", state); boolean xml = false; boolean frag = false; boolean ignore = false; for (int o = 0; o < cmpFiles.size(); ++o) { final byte[] type = data.atom(cmpFiles.list[o]); xml |= eq(type, XML); frag |= eq(type, FRAGMENT); ignore |= eq(type, IGNORE); } String expError = text("*:expected-error/text()", state); final StringBuilder log = new StringBuilder(pth + inname + IO.XQSUFFIX); if (files.size() != 0) { log.append(" ["); log.append(files); log.append("]"); } log.append(NL); /** Remove comments. */ log.append(norm(in)); log.append(NL); final String logStr = log.toString(); // skip queries with variable results final boolean print = currTime || !logStr.contains("current-"); boolean correctError = false; if (er != null && (expOut.size() == 0 || !expError.isEmpty())) { expError = error(pth + outname, expError); final String code = er.substring(0, Math.min(8, er.length())); for (final String e : SLASH.split(expError)) { if (code.equals(e)) { correctError = true; break; } } } if (correctError) { if (print) { logOK.append(logStr); logOK.append("[Right] "); logOK.append(norm(er)); logOK.append(NL); logOK.append(NL); addLog(pth, outname + ".log", er); } ++ok; } else if (er == null) { int s = -1; final int rs = result.size(); while (!ignore && ++s < rs) { inspect |= s < cmpFiles.list.length && eq(data.atom(cmpFiles.list[s]), INSPECT); final byte[] res = result.get(s), actual = ao.toArray(); if (res.length == ao.size() && eq(res, actual)) break; if (xml || frag) { iter.reset(); try { final ItemCache ic = toIter(string(res).replaceAll("^<\\?xml.*?\\?>", "").trim(), frag); if (FNSimple.deep(null, iter, ic)) break; ic.reset(); final ItemCache ia = toIter(string(actual), frag); if (FNSimple.deep(null, ia, ic)) break; } catch (final Throwable ex) { System.err.println("\n" + outname + ":"); ex.printStackTrace(); } } } if ((rs > 0 || !expError.isEmpty()) && s == rs && !inspect) { if (print) { if (expOut.size() == 0) result.add(error(pth + outname, expError)); logErr.append(logStr); logErr.append("[" + testid + " ] "); logErr.append(norm(string(result.get(0)))); logErr.append(NL); logErr.append("[Wrong] "); logErr.append(norm(ao.toString())); logErr.append(NL); logErr.append(NL); addLog(pth, outname + (xml ? IO.XMLSUFFIX : ".txt"), ao.toString()); } correct = false; ++err; } else { if (print) { logOK.append(logStr); logOK.append("[Right] "); logOK.append(norm(ao.toString())); logOK.append(NL); logOK.append(NL); addLog(pth, outname + (xml ? IO.XMLSUFFIX : ".txt"), ao.toString()); } ++ok; } } else { if (expOut.size() == 0 || !expError.isEmpty()) { if (print) { logOK2.append(logStr); logOK2.append("[" + testid + " ] "); logOK2.append(norm(expError)); logOK2.append(NL); logOK2.append("[Rght?] "); logOK2.append(norm(er)); logOK2.append(NL); logOK2.append(NL); addLog(pth, outname + ".log", er); } ++ok2; } else { if (print) { logErr2.append(logStr); logErr2.append("[" + testid + " ] "); logErr2.append(norm(string(result.get(0)))); logErr2.append(NL); logErr2.append("[Wrong] "); logErr2.append(norm(er)); logErr2.append(NL); logErr2.append(NL); addLog(pth, outname + ".log", er); } correct = false; ++err2; } } if (curr != null) Close.close(curr.data, context); xq.close(); } if (reporting) { logReport.append(" <test-case name=\""); logReport.append(outname); logReport.append("\" result='"); logReport.append(correct ? "pass" : "fail"); if (inspect) logReport.append("' todo='inspect"); logReport.append("'/>"); logReport.append(NL); } // print verbose/timing information final long nano = perf.getTime(); final boolean slow = nano / 1000000 > timer; if (verbose) { if (slow) Util.out(": " + Performance.getTimer(nano, 1)); Util.outln(); } else if (slow) { Util.out(NL + "- " + outname + ": " + Performance.getTimer(nano, 1)); } return single == null || !outname.equals(single); }