package org.basex.server;
import static org.basex.core.Text.*;
import java.io.*;
import java.math.*;
import org.basex.*;
import org.basex.api.client.*;
import org.basex.core.*;
import org.basex.core.cmd.*;
import org.basex.core.users.*;
import org.basex.io.*;
import org.basex.util.*;
import org.basex.util.list.*;
import org.junit.*;
import org.junit.Test;
/**
* Runs the XMark tests.
*
* @author BaseX Team 2005-17, BSD License
* @author Christian Gruen
*/
public final class XMarkTest {
/** Test user. */
private static final String USER = "xmark";
/** Name of database. */
private static final String DB = "111mb";
/** Test directory. */
private static final IOFile DIR = new IOFile(Prop.TMP, "XMark");
/** Output file. */
private static final IOFile FILE = new IOFile(DIR, "master- " + DB + ".graph");
/** Maximum time per query (ms). */
private static final int MAX = 2000;
/** Queries. */
private static final String[] QUERIES = {
"let $auction := . return for $b in $auction/site/people/person[@id = \"person0\"]"
+ "return $b/name/text()",
"let $auction := . return for $b in $auction/site/open_auctions/open_auction "
+ "return <increase>{$b/bidder[1]/increase/text()}</increase>",
"let $auction := . return for $b in $auction/site/open_auctions/open_auction "
+ "where zero-or-one($b/bidder[1]/increase/text()) * 2 <= $b/bidder[last()]/increase/text() "
+ "return <increase first=\"{$b/bidder[1]/increase/text()}\" "
+ "last=\"{$b/bidder[last()]/increase/text()}\"/>",
"let $auction := . return for $b in $auction/site/open_auctions/open_auction "
+ "where some $pr1 in $b/bidder/personref[@person = \"person20\"], "
+ "$pr2 in $b/bidder/personref[@person = \"person51\"] satisfies $pr1 << $pr2 "
+ "return <history>{$b/reserve/text()}</history>",
"let $auction := . return count( for $i in $auction/site/closed_auctions/closed_auction "
+ "where $i/price/text() >= 40 return $i/price )",
"let $auction := . return for $b in $auction//site/regions return count($b//item)",
"let $auction := . return for $p in $auction/site "
+ "return count($p//description) + count($p//annotation) + count($p//emailaddress)",
"let $auction := . return for $p in $auction/site/people/person "
+ "let $a := for $t in $auction/site/closed_auctions/closed_auction "
+ "where $t/buyer/@person = $p/@id return $t "
+ "return <item person=\"{$p/name/text()}\">{count($a)}</item>",
"let $auction := . return let $ca := $auction/site/closed_auctions/closed_auction "
+ "return let $ei := $auction/site/regions/europe/item for $p in $auction/site/people/person "
+ "let $a := for $t in $ca where $p/@id = $t/buyer/@person return "
+ "let $n := for $t2 in $ei where $t/itemref/@item = $t2/@id return $t2 "
+ "return <item>{$n/name/text()}</item> return <person name=\"{$p/name/text()}\">{$a}</person>",
"let $auction := . return for $i in "
+ "distinct-values($auction/site/people/person/profile/interest/@category) "
+ "let $p := for $t in $auction/site/people/person where $t/profile/interest/@category = $i "
+ "return <personne> <statistiques> <sexe>{$t/profile/gender/text()}</sexe> "
+ "<age>{$t/profile/age/text()}</age> <education>{$t/profile/education/text()}</education> "
+ "<revenu>{fn:data($t/profile/@income)}</revenu> </statistiques> <coordonnees> "
+ "<nom>{$t/name/text()}</nom> <rue>{$t/address/street/text()}</rue> "
+ "<ville>{$t/address/city/text()}</ville> <pays>{$t/address/country/text()}</pays> "
+ "<reseau> <courrier>{$t/emailaddress/text()}</courrier> "
+ "<pagePerso>{$t/homepage/text()}</pagePerso> </reseau> </coordonnees> "
+ "<cartePaiement>{$t/creditcard/text()}</cartePaiement> </personne> "
+ "return <categorie>{<id>{$i}</id>, $p}</categorie>",
"let $auction := . return for $p in $auction/site/people/person let $l := "
+ "for $i in $auction/site/open_auctions/open_auction/initial "
+ "where $p/profile/@income > 5000 * exactly-one($i/text()) "
+ "return $i return <items name=\"{$p/name/text()}\">{count($l)}</items>",
"let $auction := . return for $p in $auction/site/people/person let $l := "
+ "for $i in $auction/site/open_auctions/open_auction/initial "
+ "where $p/profile/@income > 5000 * exactly-one($i/text()) return $i "
+ "where $p/profile/@income > 50000 "
+ "return <items person=\"{$p/profile/@income}\">{count($l)}</items>",
"let $auction := . return for $i in $auction/site/regions/australia/item "
+ "return <item name=\"{$i/name/text()}\">{$i/description}</item>",
"let $auction := . return for $i in $auction/site//item "
+ "where contains(string(exactly-one($i/description)), \"gold\") return $i/name/text()",
"let $auction := . return for $a in $auction/site/closed_auctions/closed_auction/annotation/"
+ "description/parlist/listitem/parlist/listitem/text/emph/keyword/text() "
+ "return <text>{$a}</text>",
"let $auction := . return for $a in $auction/site/closed_auctions/closed_auction "
+ "where not( empty( $a/annotation/description/parlist/listitem/parlist/listitem/text/emph/"
+ "keyword/text() ) ) return <person id=\"{$a/seller/@person}\"/>",
"let $auction := . return for $p in $auction/site/people/person "
+ "where empty($p/homepage/text()) return <person name=\"{$p/name/text()}\"/>",
"declare namespace local = \"http://www.foobar.org\"; declare function "
+ "local:convert($v as xs:decimal?) as xs:decimal? { 2.20371 * $v (: convert Dfl to Euro :) }; "
+ "let $auction := . return for $i in $auction/site/open_auctions/open_auction "
+ "return local:convert(zero-or-one($i/reserve))",
"let $auction := . return for $b in $auction/site/regions//item let $k := $b/name/text() "
+ "order by zero-or-one($b/location) ascending empty greatest return "
+ "<item name=\"{$k}\">{$b/location/text()}</item>",
"let $auction := . return <result> <preferred> {count($auction/site/people/person/profile"
+ "[@income >= 100000])} </preferred> <standard> { count( $auction/site/people/person/"
+ "profile[@income < 100000 and @income >= 30000] ) } </standard> <challenge> {"
+ "count($auction/site/people/person/profile[@income < 30000])} </challenge> <na> { "
+ "count( for $p in $auction/site/people/person where empty($p/profile/@income) return $p ) } "
+ "</na> </result>"
};
/** Server flag. */
private static BaseXServer server;
/**
* Initializes the tests.
* @throws Exception any exception
*/
@BeforeClass
public static void init() throws Exception {
// only start server if it is not already running
if(!BaseXServer.ping(StaticOptions.HOST.value(), StaticOptions.PORT.value()))
server = new BaseXServer();
try(ClientSession cs = createClient(true)) {
cs.execute("create user xmark xmark");
cs.execute("grant read on " + DB + " to xmark");
}
}
/**
* Initializes the tests.
* @throws Exception any exception
*/
@BeforeClass
public static void close() throws Exception {
// only stop server if it has not been running before starting the tests
if(server != null) server.stop();
}
/**
* Runs all tests and generates some test output.
* @throws Exception any exception
*/
@Test
public void test() throws Exception {
final IntList exclude = new IntList(new int[] { 11, 12 });
final TokenBuilder tb = new TokenBuilder().add(DB).add(Prop.NL);
try(ClientSession cs = createClient(false)) {
cs.execute(new Open(DB));
// ignore first run
System.out.println("Warming up...");
for(int i = 1; i <= 20; i++) {
if(!exclude.contains(i)) {
try(ClientQuery cq = cs.query(QUERIES[i - 1])) {
final Performance p = new Performance();
cq.execute();
System.out.println(i + ": " + p);
} catch(final BaseXException ex) {
// too slow queries will be stopped after client timeout
System.out.println(i + ": " + ex);
exclude.add(i);
}
}
}
System.out.println(Prop.NL + "Testing...");
for(int i = 1; i <= 20; i++) {
tb.add(String.format("%02d", i)).add(" ");
final BigDecimal max = BigDecimal.valueOf(MAX);
try(ClientQuery cq = cs.query(QUERIES[i - 1])) {
if(exclude.contains(i)) {
tb.add("1000000");
} else {
double min = Double.MAX_VALUE;
BigDecimal total = BigDecimal.valueOf(0);
int r = 0;
while(total.compareTo(max) < 0) {
final Performance p = new Performance();
cq.execute();
final double t = Double.parseDouble(p.getTime().replaceAll(" .*", ""));
total = total.add(BigDecimal.valueOf(t));
min = Math.min(min, t);
r++;
}
tb.add(Double.toString(min));
System.out.println(i + ": " + min + " (" + r + " runs, stopped at " + total + " ms)");
}
}
tb.add(Prop.NL);
}
}
DIR.md();
FILE.write(tb.finish());
}
/**
* Creates a client instance.
* @param admin admin user
* @return client instance
* @throws IOException I/O exception
*/
private static ClientSession createClient(final boolean admin) throws IOException {
final String user = admin ? UserText.ADMIN : USER;
return new ClientSession(S_LOCALHOST, StaticOptions.PORT.value(), user, user);
}
}