You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by rv...@apache.org on 2015/01/14 11:31:12 UTC

[10/93] [abbrv] [partial] jena git commit: Maven modules for Fuseki2

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/webapp/manage.html
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/webapp/manage.html b/jena-fuseki2/jena-fuseki-core/src/main/webapp/manage.html
new file mode 100644
index 0000000..3ee53f4
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/webapp/manage.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Apache Jena Fuseki - manage dataset</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
+    <link href="css/font-awesome.min.css" rel="stylesheet" media="screen">
+    <link href="css/codemirror.css" rel="stylesheet" media="screen">
+    <link href="css/qonsole.css" rel="stylesheet" media="screen">
+    <link href="css/jquery.dataTables.css" rel="stylesheet" media="screen">
+    <link href="css/fui.css" rel="stylesheet" media="screen">
+
+    <script data-main="js/app/main.manage.js" src="js/lib/require.min.js"></script>
+
+    <!--[if lt IE 9]>
+      <script src="js/lib/html5shiv.js"></script>
+      <script src="js/lib/respond.min.js"></script>
+    <![endif]-->
+  </head>
+  <body>
+    <nav class="navbar navbar-default" role="navigation">
+      <div class="container">
+        <div class="row">
+          <!-- Brand and toggle get grouped for better mobile display -->
+          <div class="navbar-header">
+            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
+              <span class="sr-only">Toggle navigation</span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="index.html">
+              <img src="images/jena-logo-notext-small.png" alt="Apache Jena logo" title="Apache Jena" />
+              <div>Apache<br />Jena<br /><strong>Fuseki</strong></div>
+            </a>
+          </div>
+
+          <!-- Collect the nav links, forms, and other content for toggling -->
+          <div class="collapse navbar-collapse navbar-ex1-collapse">
+            <ul class="nav navbar-nav">
+              <li class=""><a href="index.html"><i class="fa fa-home"></i></a></li>
+              <li class=""><a href="dataset.html"><i class="fa fa-database"></i> dataset</a></li>
+              <li class="active"><a href="manage.html"><i class="fa fa-cogs"></i> manage datasets</a></li>
+              <li class=""><a href="services.html"><i class="fa fa-wrench"></i> services</a></li>
+              <li class=""><a href="documentation.html"><i class="fa fa-info-circle"></i> help</a></li>
+            </ul>
+            <ul class="nav navbar-nav navbar-right">
+              <li class="status-indicator">
+                <div>Server<br />status:</div>
+              </li>
+              <li class="status-indicator">
+                <a class="" href="admin/server-log.html" id="server-status-light" title="current server status">
+                  <span class="server-up"></span>
+                </a>
+              </li>
+            </ul>
+          </div><!-- /.navbar-collapse -->
+        </div><!-- /row -->
+      </div><!-- /container -->
+    </nav>
+
+    <div class="container">
+
+      <div class="row">
+        <div class="col-md-12">
+          <h2>
+            Manage datasets
+          </h2>
+          <p>Perform management actions on existing datasets, including backup,
+          or add a new dataset.
+          </p>
+        </div>
+      </div> <!-- /.row -->
+
+      <div class="row">
+        <div class="col-md-12">
+          <div class="dataset-selector-container"></div>
+        </div>
+      </div>
+
+      <div class="row">
+        <div class="col-md-12">
+          <div class="content-frame">
+            <ul class="nav nav-tabs">
+              <li><a href="#datasets" data-toggle="tab"><i class='fa fa-database'></i> existing datasets</a></li>
+              <li><a href="#new-dataset" data-toggle="tab"><i class='fa fa-plus-circle'></i> add new dataset</a></li>
+            </ul>
+
+            <!-- Tab panes -->
+            <div class="tab-content">
+              <div class="tab-pane" id="datasets">
+                <div id="dataset-management"></div>
+              </div> <!-- /.tab-pane -->
+
+              <div class="tab-pane" id="new-dataset">
+                <div id="dataset-simple-create"></div>
+              </div> <!-- /.tab-pane -->
+            </div> <!-- /.tab-content -->
+          </div> <!-- /.content-frame -->
+
+        </div> <!-- /.col-md-12 -->
+      </div> <!-- /.row -->
+    </div> <!--/.container -->
+
+
+  </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/webapp/services.html
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/webapp/services.html b/jena-fuseki2/jena-fuseki-core/src/main/webapp/services.html
new file mode 100644
index 0000000..b0020fb
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/webapp/services.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Apache Jena Fuseki - services</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
+    <link href="css/font-awesome.min.css" rel="stylesheet" media="screen">
+    <link href="css/codemirror.css" rel="stylesheet" media="screen">
+    <link href="css/qonsole.css" rel="stylesheet" media="screen">
+    <link href="css/jquery.dataTables.css" rel="stylesheet" media="screen">
+    <link href="css/fui.css" rel="stylesheet" media="screen">
+
+    <script data-main="js/app/main.index.js" src="js/lib/require.min.js"></script>
+
+    <!--[if lt IE 9]>
+      <script src="js/lib/html5shiv.js"></script>
+      <script src="js/lib/respond.min.js"></script>
+    <![endif]-->
+  </head>
+  <body>
+    <nav class="navbar navbar-default" role="navigation">
+      <div class="container">
+        <div class="row">
+          <!-- Brand and toggle get grouped for better mobile display -->
+          <div class="navbar-header">
+            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
+              <span class="sr-only">Toggle navigation</span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="index.html">
+              <img src="images/jena-logo-notext-small.png" alt="Apache Jena logo" title="Apache Jena" />
+              <div>Apache<br />Jena<br /><strong>Fuseki</strong></div>
+            </a>
+          </div>
+
+          <!-- Collect the nav links, forms, and other content for toggling -->
+          <div class="collapse navbar-collapse navbar-ex1-collapse">
+            <ul class="nav navbar-nav">
+              <li class=""><a href="index.html"><i class="fa fa-home"></i></a></li>
+              <li class=""><a href="dataset.html"><i class="fa fa-database"></i> dataset</a></li>
+              <li class=""><a href="manage.html"><i class="fa fa-cogs"></i> manage datasets</a></li>
+              <li class="active"><a href="services.html"><i class="fa fa-wrench"></i> services</a></li>
+              <li class=""><a href="documentation.html"><i class="fa fa-info-circle"></i> help</a></li>
+            </ul>
+            <ul class="nav navbar-nav navbar-right">
+              <li class="status-indicator">
+                <div>Server<br />status:</div>
+              </li>
+              <li class="status-indicator">
+                <a class="" href="admin/server-log.html" id="server-status-light" title="current server status">
+                  <span class="server-up"></span>
+                </a>
+              </li>
+            </ul>
+          </div><!-- /.navbar-collapse -->
+        </div><!-- /row -->
+      </div><!-- /container -->
+    </nav>
+
+    <div class="container">
+
+      <div class="row">
+        <div class="col-md-12">
+          <h2>
+            Inspect dataset
+          </h2>
+        </div>
+      </div>
+
+    </div>
+
+  </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/webapp/test/test-fuseki-config.ttl
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/webapp/test/test-fuseki-config.ttl b/jena-fuseki2/jena-fuseki-core/src/main/webapp/test/test-fuseki-config.ttl
new file mode 100644
index 0000000..190676a
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/webapp/test/test-fuseki-config.ttl
@@ -0,0 +1,27 @@
+# Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0
+
+@prefix :        <#> .
+@prefix fuseki:  <http://jena.apache.org/fuseki#> .
+@prefix rdf:     <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+
+@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix tdb:     <http://jena.hpl.hp.com/2008/tdb#> .
+@prefix ja:      <http://jena.hpl.hp.com/2005/11/Assembler#> .
+
+## ---------------------------------------------------------------
+## Updatable in-memory dataset.
+
+<#service1> rdf:type fuseki:Service ;
+    # URI of the dataset -- http://host:port/ds
+    fuseki:name                        "test-service" ;
+    fuseki:serviceQuery                "sparql" ;
+    fuseki:serviceQuery                "query" ;
+    fuseki:serviceUpdate               "update" ;
+    fuseki:serviceUpload               "upload" ;
+    fuseki:serviceReadWriteGraphStore  "data" ;
+    fuseki:serviceReadGraphStore       "get" ;
+    fuseki:dataset                     <#dataset> ;
+    .
+
+## In-memory, initially empty.
+<#dataset> rdf:type ja:RDFDataset .

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/webapp/validate.html
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/webapp/validate.html b/jena-fuseki2/jena-fuseki-core/src/main/webapp/validate.html
new file mode 100644
index 0000000..82b13e2
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/webapp/validate.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Apache Jena Fuseki - validation</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
+    <link href="css/font-awesome.min.css" rel="stylesheet" media="screen">
+    <link href="css/codemirror.css" rel="stylesheet" media="screen">
+    <link href="css/qonsole.css" rel="stylesheet" media="screen">
+    <link href="css/jquery.dataTables.css" rel="stylesheet" media="screen">
+    <link href="css/fui.css" rel="stylesheet" media="screen">
+
+    <script data-main="js/app/main.validation.js" src="js/lib/require.min.js"></script>
+
+    <!--[if lt IE 9]>
+      <script src="../js/lib/html5shiv.js"></script>
+      <script src="../js/lib/respond.min.js"></script>
+    <![endif]-->
+  </head>
+  <body>
+    <nav class="navbar navbar-default" role="navigation">
+      <div class="container">
+        <div class="row">
+          <!-- Brand and toggle get grouped for better mobile display -->
+          <div class="navbar-header">
+            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
+              <span class="sr-only">Toggle navigation</span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+              <span class="icon-bar"></span>
+            </button>
+            <a class="navbar-brand" href="index.html">
+              <img src="images/jena-logo-notext-small.png" alt="Apache Jena logo" title="Apache Jena" />
+              <div>Apache<br />Jena<br /><strong>Fuseki</strong></div>
+            </a>
+          </div>
+
+          <!-- Collect the nav links, forms, and other content for toggling -->
+          <div class="collapse navbar-collapse navbar-ex1-collapse">
+            <ul class="nav navbar-nav">
+              <li class=""><a href="index.html"><i class="fa fa-home"></i></a></li>
+              <li class=""><a href="query.html"><i class="fa fa-question-circle"></i> query</a></li>
+              <li class="active"><a href="validate.html"><i class="fa fa-check-circle"></i> validate</a></li>
+              <li class="admin"><a href="admin-data-management.html"><i class="fa fa-cogs"></i> administer</a></li>
+              <li class="admin"><a href="admin-stats.html"><i class="fa fa-dashboard"></i> stats</a></li>
+              <li class="admin"><a href="admin-logs.html"><i class="fa fa-book"></i> logs</a></li>
+              <li class=""><a href="documentation.html"><i class="fa fa-info-circle"></i> help</a></li>
+            </ul>
+            <ul class="nav navbar-nav navbar-right">
+              <li class="status-indicator">
+                <div>Server<br />status:</div>
+              </li>
+              <li class="status-indicator">
+                <a class="" href="admin/server-log.html" id="server-status-light" title="current server status">
+                  <span class="server-up"></span>
+                </a>
+              </li>
+            </ul>
+          </div><!-- /.navbar-collapse -->
+        </div><!-- /row -->
+      </div><!-- /container -->
+    </nav>
+
+    <div class="container">
+      <div class="row">
+        <h1>Fuseki &ndash; validation</h1>
+        <p>Use this page to validate SPARQL queries or RDF data.</p>
+        <p class="text-danger">Forthcoming feature &ndash; not yet working.</p>
+
+
+        <div class="validation qonsole">
+          <div class="col-md-12 well">
+            <div class="query-edit">
+              <div id="query-edit-cm" class=""></div>
+            </div>
+            <div class="query-chrome">
+              <form class="form-inline" role="form">
+                <div class="validate-as-options options-list">
+                  <h2>Validate as:</h2>
+                  <ul class="list-inline">
+                    <li><a class="btn btn-custom2 btn-sm active validate-as-option" data-toggle="button" data-validate-as="sparql">SPARQL</a></li>
+                    <li><a class="btn btn-custom2 btn-sm  validate-as-option" data-toggle="button" data-validate-as="arq">SPARQL extended syntax</a></li>
+                    <li><a class="btn btn-custom2 btn-sm validate-as-option" data-toggle="button" data-validate-as="Turtle">Turtle</a></li>
+                    <li><a class="btn btn-custom2 btn-sm validate-as-option" data-toggle="button" data-validate-as="TriG">TriG</a></li>
+                    <li><a class="btn btn-custom2 btn-sm validate-as-option" data-toggle="button" data-validate-as="N-Triples">N-Triples</a></li>
+                    <li><a class="btn btn-custom2 btn-sm validate-as-option" data-toggle="button" data-validate-as="N-Quads">N-Quads</a></li>
+                  </ul>
+                </div><!-- /.validate-as-options -->
+
+                <div class="output-format-options options-list">
+                  <h2>Output format:</h2>
+                  <ul class="list-inline">
+                    <li><a class="btn btn-custom2 btn-sm" data-toggle="button" data-output-format="formatted">SPARQL</a></li>
+                    <li><a class="btn btn-custom2 btn-sm active" data-toggle="button" data-output-format="algebra">SPARQL algebra</a></li>
+                    <li><a class="btn btn-custom2 btn-sm" data-toggle="button" data-output-format="algebra-quads">SPARQL algebra (quads)</a></li>
+                    <li><a class="btn btn-custom2 btn-sm" data-toggle="button" data-output-format="algebra-opt">SPARQL algebra (with optimizations)</a></li>
+                    <li><a class="btn btn-custom2 btn-sm" data-toggle="button" data-output-format="algebra-opt-quads">SPARQL algebra (quads, with optimizations)</a></li>
+                  </ul>
+                </div><!-- /.output-format-options -->
+
+                <div class="row">
+                  <div class="col-md-3 col-md-offset-1">
+                    <a href="#" class="btn btn-success perform-validation">perform validation</a>
+                  </div>
+                </div>
+
+              </form>
+            </div>
+          </div>
+
+          <!-- results -->
+          <div id="results-block" class="row validation-output">
+            <div class="col-md-12">
+              <div class="well">
+                <div class="row">
+                  <div class="col-md-12">
+                    <span class="loadingSpinner hidden">
+                      <img src="images/wait30.gif" alt="waiting for server action to complete" />
+                    </span>
+                    <span class="timeTaken hidden"></span>
+                  </div>
+                </div>
+                <div class="row">
+                  <div class="col-md-12" id="results">
+                    <h2 class="col-md-12">Validation output</h2>
+                    <div class="query-edit">
+                      <div id="validation-output-cm" class=""></div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <div class="row clearfix"></div>
+
+          <footer>
+          </footer>
+        </div><!-- /.validation-->
+      </div><!-- /.row -->
+    </div><!-- /.container -->
+
+    <script src="../js/lib/jquery-1.10.2.min.js"></script>
+    <script src="../js/lib/bootstrap.min.js"></script>
+  </body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/AbstractFusekiTest.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/AbstractFusekiTest.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/AbstractFusekiTest.java
new file mode 100644
index 0000000..3f1aa17
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/AbstractFusekiTest.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import org.apache.jena.atlas.junit.BaseTest ;
+import org.junit.AfterClass ;
+import org.junit.Before ;
+import org.junit.BeforeClass ;
+
+/** Framework for tests using client-side operation onto a forked Fuseki server.
+ *  Not general - some test sets set up their own environment for 
+ *  different, additional requirements.
+ */
+
+public class AbstractFusekiTest extends BaseTest
+{
+    @BeforeClass
+    public static void allocServerForSuite() {
+        ServerTest.allocServer() ;
+    }
+
+    @AfterClass
+    public static void freeServerForSuite() {
+        ServerTest.freeServer() ;
+    }
+    
+    @Before public void resetServer() {
+        ServerTest.resetServer() ;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/FileSender.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/FileSender.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/FileSender.java
new file mode 100644
index 0000000..8381ab5
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/FileSender.java
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import java.io.IOException ;
+import java.io.PrintStream ;
+import java.net.HttpURLConnection ;
+import java.net.URL ;
+import java.util.ArrayList ;
+import java.util.List ;
+import java.util.UUID ;
+
+import org.apache.jena.atlas.io.IO ;
+
+public class FileSender {
+    // HttpClient 4.3 has MultipartEntity but the 4.2->4.3 change is less
+    // than trivial (and it seems some environment fix the HttpClient) 
+    // so here's some code for testing support.
+//    MultipartEntity entity = new MultipartEntity();
+//    entity.addPart(...)
+//    HttpPost request = new HttpPost(url);
+//    request.setEntity(entity);
+//    HttpClient client = new DefaultHttpClient();
+//    HttpResponse response = client.execute(request);
+    
+    class Entry {
+        String fileName ;
+        String content ;
+        String contentType ;
+    }
+    
+    private List<Entry> items = new ArrayList<Entry>() ;
+    
+    private String url ;  
+    
+    public FileSender(String url ) { this.url = url ; }
+    
+    public void add(String filename, String content, String type) {
+        Entry e = new Entry() ;
+        e.fileName = filename ;
+        e.content = content ;
+        e.contentType = type ;
+        items.add(e) ;
+    }
+    
+    public void send(String method) {
+        try {
+            String WNL = "\r\n" ;   // Web newline
+            String boundary = UUID.randomUUID().toString() ;
+            
+            HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection();
+            connection.setRequestMethod(method);
+            connection.setDoOutput(true) ;
+            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
+            try ( PrintStream ps = new PrintStream(connection.getOutputStream()) ; ) {
+                for ( Entry e : items ) {
+                    ps.print("--" + boundary+WNL) ;
+                    ps.print("Content-Disposition: form-data; name=\"FILE\"; filename=\""+e.fileName+"\""+WNL) ;
+                    ps.print("Content-Type: "+e.contentType+";charset=UTF-8"+WNL) ;
+                    ps.print(WNL);
+                    ps.print(e.content) ;
+                    ps.print(WNL);
+                }
+                ps.print("--" + boundary + "--"+WNL);
+            } 
+            connection.connect(); 
+            int responseCode = connection.getResponseCode();
+        } catch (IOException ex) { IO.exception(ex); }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/ServerTest.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/ServerTest.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/ServerTest.java
new file mode 100644
index 0000000..1a70869
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/ServerTest.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki ;
+
+import java.nio.file.Paths ;
+import java.util.Collection ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.fuseki.server.* ;
+import org.apache.jena.fuseki.jetty.JettyServerConfig ;
+import org.apache.jena.fuseki.jetty.JettyFuseki ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.NodeFactory ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ;
+import com.hp.hpl.jena.sparql.modify.request.Target ;
+import com.hp.hpl.jena.sparql.modify.request.UpdateDrop ;
+import com.hp.hpl.jena.sparql.sse.SSE ;
+import com.hp.hpl.jena.tdb.base.file.Location ;
+import com.hp.hpl.jena.update.Update ;
+import com.hp.hpl.jena.update.UpdateExecutionFactory ;
+import com.hp.hpl.jena.update.UpdateProcessor ;
+
+/**
+ * Manage a server for testing. Example for one server per test suite:
+ * 
+ * <pre>
+ *     \@BeforeClass public static void beforeClass() { ServerTest.allocServer() ; }
+ *     \@AfterClass  public static void afterClass()  { ServerTest.freeServer() ; }
+ *     \@Before      public void beforeTest()         { ServerTest.resetServer() ; }
+ * </pre>
+ */
+public class ServerTest {
+    // Abstraction that runs a SPARQL server for tests.
+
+    public static final int     port          = 3535 ;
+    public static final String  urlRoot       = "http://localhost:" + port + "/" ;
+    public static final String  datasetPath   = "/dataset" ;
+    public static final String  urlDataset    = "http://localhost:" + port + datasetPath ;
+    public static final String  serviceUpdate = urlDataset + "/update" ;
+    public static final String  serviceQuery  = urlDataset + "/query" ;
+    public static final String  serviceREST   = urlDataset + "/data" ;
+
+    public static final String  gn1           = "http://graph/1" ;
+    public static final String  gn2           = "http://graph/2" ;
+    public static final String  gn99          = "http://graph/99" ;
+
+    public static final Node    n1            = NodeFactory.createURI("http://graph/1") ;
+    public static final Node    n2            = NodeFactory.createURI("http://graph/2") ;
+    public static final Node    n99           = NodeFactory.createURI("http://graph/99") ;
+
+    public static final Graph   graph1        = SSE.parseGraph("(base <http://example/> (graph (<x> <p> 1)))") ;
+    public static final Graph   graph2        = SSE.parseGraph("(base <http://example/> (graph (<x> <p> 2)))") ;
+
+    public static final Model   model1        = ModelFactory.createModelForGraph(graph1) ;
+    public static final Model   model2        = ModelFactory.createModelForGraph(graph2) ;
+
+    private static JettyFuseki server        = null ;
+
+    // reference count of start/stop server
+    private static int          countServer   = 0 ;
+
+    // This will cause there to be one server over all tests.
+    // Must be after initialization of counters
+    // static { allocServer() ; }
+
+    static public void allocServer() {
+        if ( countServer == 0 )
+            setupServer() ;
+        countServer++ ;
+    }
+
+    static public void freeServer() {
+        if ( countServer >= 0 ) {
+            countServer-- ;
+            if ( countServer == 0 )
+                teardownServer() ;
+        }
+    }
+
+    protected static void setupServer() {
+        FusekiEnv.FUSEKI_HOME = Paths.get(TS_Fuseki.FusekiTestHome).toAbsolutePath() ;
+        FileOps.ensureDir("target");
+        FileOps.ensureDir(TS_Fuseki.FusekiTestHome);
+        FileOps.ensureDir(TS_Fuseki.FusekiTestBase) ;
+        FusekiEnv.FUSEKI_BASE = Paths.get(TS_Fuseki.FusekiTestBase).toAbsolutePath() ;
+        setupServer(null) ;
+    }
+    
+    protected static void setupServer(String authConfigFile) {
+        SystemState.location = Location.mem() ;
+        SystemState.init$() ;
+        
+        ServerInitialConfig params = new ServerInitialConfig() ;
+        DatasetGraph dsg = DatasetGraphFactory.createMem() ;
+        params.dsg = dsg ;
+        params.datasetPath = ServerTest.datasetPath ;
+        params.allowUpdate = true ;
+        FusekiServerListener.initialSetup = params ;
+        
+        JettyServerConfig config = make(true, true) ;
+        config.authConfigFile = authConfigFile ;
+        JettyFuseki.initializeServer(config);
+        JettyFuseki.instance.start() ;
+        server = JettyFuseki.instance ;
+    }
+
+    public static JettyServerConfig make(boolean allowUpdate, boolean listenLocal) {
+        JettyServerConfig config = new JettyServerConfig() ;
+        // Avoid any persistent record.
+        config.port = ServerTest.port ;
+        config.contextPath = "/" ;
+        config.loopback = listenLocal ;
+        config.jettyConfigFile = null ;
+        config.pages = Fuseki.PagesStatic ;
+        config.enableCompression = true ;
+        config.verboseLogging = false ;
+        return config ;
+    }
+
+    protected static void teardownServer() {
+        if ( server != null )
+            server.stop() ;
+        server = null ;
+        // Clear out the registry.
+        Collection<String> keys = Iter.toList(DataAccessPointRegistry.get().keys()) ;
+        for (String k : keys)
+            DataAccessPointRegistry.get().remove(k) ;
+    }
+
+    public static void resetServer() {
+        Update clearRequest = new UpdateDrop(Target.ALL) ;
+        UpdateProcessor proc = UpdateExecutionFactory.createRemote(clearRequest, ServerTest.serviceUpdate) ;
+        proc.execute() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
new file mode 100644
index 0000000..db8a4aa
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TS_Fuseki.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.atlas.logging.LogCtl ;
+import org.apache.jena.fuseki.http.TestDatasetAccessorHTTP ;
+import org.apache.jena.fuseki.http.TestDatasetGraphAccessorHTTP ;
+import org.apache.jena.fuseki.http.TestHttpOp ;
+import org.apache.jena.fuseki.server.FusekiEnv ;
+import org.junit.BeforeClass ;
+import org.junit.runner.RunWith ;
+import org.junit.runners.Suite ;
+
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses( {
+    TestHttpOp.class
+    , TestSPARQLProtocol.class
+    , TestDatasetGraphAccessorHTTP.class
+    , TestDatasetAccessorHTTP.class
+    , TestQuery.class
+    , TestAuth.class
+    , TestDatasetOps.class
+    , TestFileUpload.class
+    , TestAdmin.class
+})
+
+
+
+
+public class TS_Fuseki extends ServerTest
+{
+    public static final String FusekiTestHome = "target/FusekiHome" ;
+    public static final String FusekiTestBase = FusekiTestHome+"/run" ;
+    
+    @BeforeClass public static void setupForFusekiServer() {
+        FileOps.ensureDir(FusekiTestHome);
+        FileOps.clearDirectory(FusekiTestHome);
+        System.setProperty("FUSEKI_HOME", FusekiTestHome) ;
+        FusekiEnv.setEnvironment() ;
+        FusekiLogging.setLogging();
+        
+        org.apache.log4j.Level WARN1 = org.apache.log4j.Level.WARN ; 
+        java.util.logging.Level WARN2 = java.util.logging.Level.WARNING ;
+
+        // Occasionally log4j.properties gets out of step.
+        LogCtl.logLevel("org.apache.shiro",    WARN1, WARN2);
+        LogCtl.logLevel("org.eclipse.jetty",    WARN1, WARN2);
+        
+        LogCtl.logLevel(Fuseki.serverLogName,   WARN1, WARN2);
+        LogCtl.logLevel(Fuseki.configLogName,   WARN1, WARN2);
+        LogCtl.logLevel(Fuseki.adminLogName,    WARN1, WARN2);
+        LogCtl.logLevel(Fuseki.builderLogName,  WARN1, WARN2);
+        LogCtl.logLevel(Fuseki.actionLogName,   WARN1, WARN2);
+        LogCtl.logLevel(Fuseki.requestLogName,  WARN1, WARN2);
+        LogCtl.logLevel(Fuseki.servletRequestLogName,   WARN1, WARN2);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
new file mode 100644
index 0000000..d5e6ddb
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAdmin.java
@@ -0,0 +1,538 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import static org.apache.jena.fuseki.ServerTest.datasetPath ;
+import static org.apache.jena.fuseki.ServerTest.urlRoot ;
+import static org.apache.jena.fuseki.mgt.MgtConst.opDatasets ;
+import static org.apache.jena.fuseki.mgt.MgtConst.opPing ;
+import static org.apache.jena.fuseki.mgt.MgtConst.opServer ;
+import static org.apache.jena.fuseki.mgt.MgtConst.opStats ;
+import static org.apache.jena.riot.web.HttpOp.execHttpDelete ;
+import static org.apache.jena.riot.web.HttpOp.execHttpGet ;
+import static org.apache.jena.riot.web.HttpOp.execHttpPost ;
+
+import java.io.File ;
+import java.io.IOException ;
+import java.io.InputStream ;
+import java.util.ArrayList ;
+import java.util.List ;
+
+import org.apache.http.HttpEntity ;
+import org.apache.http.HttpResponse ;
+import org.apache.http.NameValuePair ;
+import org.apache.http.client.entity.UrlEncodedFormEntity ;
+import org.apache.http.entity.FileEntity ;
+import org.apache.http.message.BasicNameValuePair ;
+import org.apache.jena.atlas.json.JSON ;
+import org.apache.jena.atlas.json.JsonArray ;
+import org.apache.jena.atlas.json.JsonObject ;
+import org.apache.jena.atlas.json.JsonValue ;
+import org.apache.jena.atlas.junit.BaseTest ;
+import org.apache.jena.atlas.lib.Lib ;
+import org.apache.jena.atlas.web.HttpException ;
+import org.apache.jena.atlas.web.TypedInputStream ;
+import org.apache.jena.fuseki.mgt.JsonConst ;
+import org.apache.jena.riot.WebContent ;
+import org.apache.jena.riot.web.HttpOp ;
+import org.apache.jena.riot.web.HttpResponseHandler ;
+import org.apache.jena.web.HttpSC ;
+import org.junit.AfterClass ;
+import org.junit.Before ;
+import org.junit.BeforeClass ;
+import org.junit.Test ;
+
+/** Tests of the admin functionality */
+public class TestAdmin extends BaseTest {
+    
+    // Name of the dataset in the assembler file.
+    static String dsTest = "test-ds2" ;
+    
+    @BeforeClass
+    public static void beforeClass() {
+        ServerTest.allocServer() ;
+        ServerTest.resetServer() ;
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        ServerTest.freeServer() ;
+    }
+    
+    @Before public void beforeTest() {
+        ServerTest.resetServer() ;
+    }
+    
+    // --- Ping 
+    
+    @Test public void ping_1() {
+        execHttpGet(ServerTest.urlRoot+"$/"+opPing) ;
+    }
+    
+    @Test public void ping_2() {
+        execHttpPost(ServerTest.urlRoot+"$/"+opPing, null) ;
+    }
+    
+    // --- Server status 
+    
+    @Test public void server_1() {
+        JsonValue jv = httpGetJson(ServerTest.urlRoot+"$/"+opServer) ;
+        JsonObject obj = jv.getAsObject() ;
+        assertTrue(obj.hasKey(JsonConst.admin)) ;
+        assertTrue(obj.hasKey(JsonConst.datasets)) ;
+        assertTrue(obj.hasKey(JsonConst.uptime)) ;
+        assertTrue(obj.hasKey(JsonConst.startDT)) ;
+    }
+
+    @Test public void server_2() {
+        execHttpPost(ServerTest.urlRoot+"$/"+opServer, null) ;
+    }
+    
+    // --- List all datasets
+    
+    @Test public void list_datasets_1() {
+        try ( TypedInputStream in = execHttpGet(urlRoot+"$/"+opDatasets) ; ) { }
+    }
+    
+    @Test public void list_datasets_2() {
+        try ( TypedInputStream in = execHttpGet(urlRoot+"$/"+opDatasets) ) {
+            assertEqualsIgnoreCase(WebContent.contentTypeJSON, in.getContentType()) ;
+            JsonValue v = JSON.parseAny(in) ;
+            assertNotNull(v.getAsObject().get("datasets")) ; 
+            checkJsonDatasetsAll(v);
+        }
+    }
+    
+    // Specific dataset
+    @Test public void list_datasets_3() {
+        checkExists(datasetPath) ;
+    }
+    
+    // Specific dataset
+    @Test public void list_datasets_4() {
+        try {
+            getDatasetDescription("does-not-exist") ;
+        } catch (HttpException ex) {
+            assertEquals(HttpSC.NOT_FOUND_404, ex.getResponseCode()) ;
+        }
+    }
+    
+    // Specific dataset
+    @Test public void list_datasets_5() {
+        JsonValue v = getDatasetDescription(datasetPath) ;
+        checkJsonDatasetsOne(v.getAsObject()) ;
+    }
+
+    private static JsonValue getDatasetDescription(String dsName) {
+        try ( TypedInputStream in = execHttpGet(urlRoot+"$/"+opDatasets+"/"+dsName) ) {
+            assertEqualsIgnoreCase(WebContent.contentTypeJSON, in.getContentType()) ;
+            JsonValue v = JSON.parse(in) ;
+            return v ;
+        }
+    }
+
+    // -- Add
+    
+    private static void addTestDataset() {
+        File f = new File("testing/config-ds-1.ttl") ;
+        org.apache.http.entity.ContentType ct = org.apache.http.entity.ContentType.parse(WebContent.contentTypeTurtle+"; charset="+WebContent.charsetUTF8) ;
+        HttpEntity e = new FileEntity(f, ct) ;
+        execHttpPost(ServerTest.urlRoot+"$/"+opDatasets, e) ;
+    }
+    
+    private static void deleteDataset(String name) {
+        execHttpDelete(ServerTest.urlRoot+"$/"+opDatasets+"/"+name) ;
+    }
+
+    // Specific dataset
+    @Test public void add_delete_dataset_1() {
+        checkNotThere(dsTest) ;
+
+        addTestDataset() ;
+        
+        // Check exists.
+        checkExists(dsTest) ;
+        
+        // Remove it.
+        deleteDataset(dsTest) ;
+        checkNotThere(dsTest) ;
+    }
+
+    // Try to add twice
+    @Test public void add_delete_dataset_2() {
+        checkNotThere(dsTest) ;
+
+        File f = new File("testing/config-ds-1.ttl") ;
+        { 
+            org.apache.http.entity.ContentType ct = org.apache.http.entity.ContentType.parse(WebContent.contentTypeTurtle+"; charset="+WebContent.charsetUTF8) ;
+            HttpEntity e = new FileEntity(f, ct) ;
+            execHttpPost(ServerTest.urlRoot+"$/"+opDatasets, e) ;
+        }
+        // Check exists.
+        checkExists(dsTest) ;
+        try {
+            org.apache.http.entity.ContentType ct = org.apache.http.entity.ContentType.parse(WebContent.contentTypeTurtle+"; charset="+WebContent.charsetUTF8) ;
+            HttpEntity e = new FileEntity(f, ct) ;
+            execHttpPost(ServerTest.urlRoot+"$/"+opDatasets, e) ;
+        } catch (HttpException ex) {
+            assertEquals(HttpSC.CONFLICT_409, ex.getResponseCode()) ;
+        }
+        // Check exists.
+        checkExists(dsTest) ;
+        deleteDataset(dsTest) ;
+    }
+    
+    @Test public void add_delete_dataset_3() throws Exception {
+        String name = "MEMTEST" ;
+        //String args = "dbType=mem&dbName="+name ;
+        
+        List<NameValuePair> args = new ArrayList<NameValuePair>() ;
+        args.add(new BasicNameValuePair("dbType", "mem")) ;
+        args.add(new BasicNameValuePair("dbName", name)) ;
+        
+        HttpEntity e = new UrlEncodedFormEntity(args) ;
+        execHttpPost(ServerTest.urlRoot+"$/"+opDatasets, e) ;
+        checkExists(name) ;
+        deleteDataset(name) ;
+    }
+    
+    @Test public void delete_dataset_1() {
+        String name = "NoSuchDataset" ;
+        try {
+            execHttpDelete(ServerTest.urlRoot+"$/"+opDatasets+"/"+name) ;
+            fail("delete did not cause an Http Exception") ;
+        } catch ( HttpException ex ) {
+            assertEquals(HttpSC.NOT_FOUND_404, ex.getResponseCode()) ;
+        }
+    }
+
+    // ---- Active/Offline.
+
+    @Test public void state_1() {
+        // Add one
+        addTestDataset() ;
+        checkExists(dsTest) ;
+
+        execHttpPost(ServerTest.urlRoot+"$/"+opDatasets+"/"+dsTest+"?state=offline", null) ;
+
+        checkExistsNotActive(dsTest); 
+        
+        execHttpPost(ServerTest.urlRoot+"$/"+opDatasets+"/"+dsTest+"?state=active", null) ;
+        
+        checkExists(dsTest) ;
+        deleteDataset(dsTest) ;
+    }
+    
+    @Test public void state_2() {
+        addTestDataset() ;
+        execHttpPost(ServerTest.urlRoot+"$/"+opDatasets+"/"+dsTest+"?state=offline", null) ;
+        deleteDataset(dsTest) ;
+        checkNotThere(dsTest) ;
+    }
+
+    @Test public void state_3() {
+        addTestDataset() ;
+        try {
+            execHttpPost(ServerTest.urlRoot+"$/"+opDatasets+"/DoesNotExist?state=offline", null) ;
+        } catch (HttpException ex) { assertEquals(HttpSC.NOT_FOUND_404, ex.getResponseCode()) ; }
+        deleteDataset(dsTest) ;
+    }
+    
+    // ---- Backup
+
+    // ---- Server
+    
+    // ---- Stats
+    
+    @Test public void stats_1() {
+        JsonValue v = execGetJSON(urlRoot+"$/"+opStats) ;
+        checkJsonStatsAll(v); 
+    }
+    
+    @Test public void stats_2() {
+        addTestDataset() ;
+        JsonValue v = execGetJSON(urlRoot+"$/"+opStats+datasetPath) ;
+        checkJsonStatsAll(v); 
+        deleteDataset(dsTest) ;
+    }
+
+    @Test public void stats_3() {
+        addTestDataset() ;
+        try {
+            JsonValue v = execGetJSON(urlRoot+"$/"+opStats+"/DoesNotExist") ;
+            checkJsonStatsAll(v);
+        } catch (HttpException ex) { assertEquals(HttpSC.NOT_FOUND_404, ex.getResponseCode()); }
+        deleteDataset(dsTest) ;
+    }
+
+    // Sync task testing
+    
+    @Test public void task_1() {
+        String x = execSleepTask(null, 10) ;
+        assertNotNull(x) ;
+        Integer.parseInt(x) ;
+    }
+    
+    @Test public void task_2() {
+        String x = "NoSuchTask" ;
+        String url = urlRoot+"$/tasks/"+x ;
+        try {
+            httpGetJson(url) ;
+        } catch (HttpException ex) {
+            assertEquals(404, ex.getResponseCode()) ;
+        }
+        try { 
+            checkInTasks(x) ;
+            fail("No failure!") ;
+        } catch (AssertionError ex) {}
+    }
+
+    
+    @Test public void task_3() {
+        // Timing dependent.
+        // Create a "long" running task so we can find it.  
+        String x = execSleepTask(null, 100) ;
+        checkTask(x) ;
+        checkInTasks(x) ;
+        assertNotNull(x) ;
+        Integer.parseInt(x) ;
+    }
+
+    @Test public void task_4() {
+        // Timing dependent.
+        // Create a "short" running task  
+        String x = execSleepTask(null, 1) ;
+        // Check exists in the list of all tasks (should be "finished")
+        checkInTasks(x) ;
+        String url = urlRoot+"$/tasks/"+x ;
+        
+        boolean finished = false ; 
+        for ( int i = 0 ; i < 10 ; i++ ) {
+            if ( i != 0 )
+                Lib.sleep(25) ;
+            JsonValue v = httpGetJson(url) ;
+            checkTask(v) ;
+            if ( v.getAsObject().hasKey("finished") ) {
+                finished = true ;
+                break ;
+            }
+        }
+        if ( ! finished )
+            fail("Task has not finished") ;
+    }
+    
+    @Test public void task_5() {
+        // Short ruuning task - still in info API call.
+        String x = execSleepTask(null, 1) ;
+        checkInTasks(x) ;
+    }
+
+    private JsonValue getTask(String taskId) {
+        String url = urlRoot+"$/tasks/"+taskId ;
+        return httpGetJson(url) ;
+    }
+    
+
+    static class JsonResponseHandler implements HttpResponseHandler {
+
+        private JsonValue result = null ;
+        
+        public JsonValue getJSON() {
+            return result ;
+        }
+        
+        @Override
+        public void handle(String baseIRI, HttpResponse response) throws IOException {
+            try ( InputStream in = response.getEntity().getContent() ) {
+                result = JSON.parseAny(in) ;
+            }
+        }
+        
+    }
+    
+    
+    
+    private String execSleepTask(String name, int millis) {
+        String url = urlRoot+"$/sleep" ;
+        if ( name != null ) {
+            if ( name.startsWith("/") )
+                name = name.substring(1) ;
+            url = url + "/"+name ; 
+        }
+        
+        JsonResponseHandler x = new JsonResponseHandler() ; 
+        HttpOp.execHttpPost(url+"?interval="+millis, null, WebContent.contentTypeJSON, x) ;
+        JsonValue v = x.getJSON() ;
+        String id = v.getAsObject().get("taskId").getAsString().value() ;
+        return id ;
+    }
+
+    private JsonValue httpGetJson(String url) {
+        JsonResponseHandler x = new JsonResponseHandler() ; 
+        HttpOp.execHttpGet(url, WebContent.contentTypeJSON, x) ;
+        return x.getJSON() ;
+    }
+    
+    private void checkTask(String x) {
+        String url = urlRoot+"$/tasks/"+x ;
+        JsonValue v = httpGetJson(url) ;
+        checkTask(v) ;
+    }    
+    
+    private void checkTask(JsonValue v) {
+        assertNotNull(v) ;
+        assertTrue(v.isObject()) ;
+        //System.out.println(v) ;
+        JsonObject obj = v.getAsObject() ;
+        try {
+            assertTrue(obj.hasKey("task")) ;
+            assertTrue(obj.hasKey("taskId")) ;
+            // Not present until it runs : "started"
+        } catch (AssertionError ex) { 
+            System.out.println(obj) ;
+            throw ex ; 
+        }
+    }
+        
+   private void checkInTasks(String x) {
+       String url = urlRoot+"$/tasks" ;
+       JsonValue v = httpGetJson(url) ;
+       assertTrue(v.isArray()) ;
+       JsonArray array = v.getAsArray() ; 
+       int found = 0 ;
+       for ( int i = 0 ; i < array.size() ; i++ ) {
+           JsonValue jv = array.get(i) ;
+           assertTrue(jv.isObject()) ;
+           JsonObject obj = jv.getAsObject() ;
+           checkTask(obj) ;
+           if ( obj.get("taskId").getAsString().value().equals(x) ) {
+               found++ ;
+           }
+        }
+       assertEquals("Occurence of taskId count", 1, found) ;
+    }
+
+    // Auxilary
+    
+    private static void askPing(String name) {
+        if ( name.startsWith("/") )
+            name = name.substring(1) ;
+        try ( TypedInputStream in = execHttpGet(urlRoot+name+"/sparql?query=ASK%7B%7D") ) {}  
+    }
+    
+    private static void adminPing(String name) {
+        try ( TypedInputStream in = execHttpGet(urlRoot+"$/"+opDatasets+"/"+name) ) {} 
+    }
+
+    private static void checkExists(String name)  {
+        adminPing(name) ;
+        askPing(name) ;
+    }
+    
+    private static void checkExistsNotActive(String name)  {
+        adminPing(name) ;
+        try { askPing(name) ; 
+            fail("askPing did not cause an Http Exception") ;
+        } catch ( HttpException ex ) {}
+        JsonValue v = getDatasetDescription(name) ;
+        assertFalse(v.getAsObject().get("ds.state").getAsBoolean().value()) ;
+    }
+
+    private static void checkNotThere(String name) {
+        if ( name.startsWith("/") )
+            name = name.substring(1) ;
+        // Check gone exists.
+        try { adminPing(name) ; }
+        catch (HttpException ex) {
+            assertEquals(HttpSC.NOT_FOUND_404, ex.getResponseCode()) ;
+        }
+        
+        try { askPing(name) ; }
+        catch (HttpException ex) {
+            assertEquals(HttpSC.NOT_FOUND_404, ex.getResponseCode()) ;
+        }
+    }
+
+    private static void checkJsonDatasetsAll(JsonValue v) {
+        assertNotNull(v.getAsObject().get("datasets")) ; 
+        JsonArray a = v.getAsObject().get("datasets").getAsArray() ;
+        for ( JsonValue v2 : a )
+            checkJsonDatasetsOne(v2) ;
+    }
+    
+    private static void checkJsonDatasetsOne(JsonValue v) {
+        assertTrue(v.isObject()) ;
+        JsonObject obj = v.getAsObject() ;
+        assertNotNull(obj.get("ds.name")) ;
+        assertNotNull(obj.get("ds.services")) ;
+        assertNotNull(obj.get("ds.state")) ;
+        assertTrue(obj.get("ds.services").isArray()) ;
+    }
+    
+    private static void checkJsonStatsAll(JsonValue v) {
+        assertNotNull(v.getAsObject().get("datasets")) ; 
+        JsonObject a = v.getAsObject().get("datasets").getAsObject() ;
+        for ( String dsname : a.keys() ) {
+            JsonValue obj = a.get(dsname).getAsObject() ;
+            checkJsonStatsOne(obj);
+        }
+    }
+    
+    private static void checkJsonStatsOne(JsonValue v) {
+        checkJsonStatsCounters(v) ;
+        JsonObject obj1 = v.getAsObject().get("endpoints").getAsObject() ;
+        for ( String srvName : obj1.keys() ) {
+            JsonObject obj2 = obj1.get(srvName).getAsObject() ; 
+            assertTrue(obj2.hasKey("description"));
+            assertTrue(obj2.hasKey("operation"));
+            checkJsonStatsCounters(obj2);
+        }
+    }
+
+    private static void checkJsonStatsCounters(JsonValue v) {
+        JsonObject obj = v.getAsObject() ;
+        assertTrue(obj.hasKey("Requests")) ;
+        assertTrue(obj.hasKey("RequestsGood")) ;
+        assertTrue(obj.hasKey("RequestsBad")) ;
+    }
+    
+    private static JsonValue execGetJSON(String url) {
+        try ( TypedInputStream in = execHttpGet(url) ) {
+            assertEqualsIgnoreCase(WebContent.contentTypeJSON, in.getContentType()) ;
+            return JSON.parse(in) ; 
+        }
+    }
+    
+    /*
+        GET     /$/ping 
+        POST    /$/ping 
+        POST    /$/datasets/    
+        GET     /$/datasets/
+        DELETE  /$/datasets/*{name}*    
+        GET     /$/datasets/*{name}*    
+        POST    /$/datasets/*{name}*?state=offline  
+        POST    /$/datasets/*{name}*?state=active   
+        POST    /$/backup/*{name}*  
+        GET     /$/server   
+        POST    /$/server/shutdown  
+        GET     /$/stats/   
+        GET     /$/stats/*{name}*
+     */
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAuth.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAuth.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAuth.java
new file mode 100644
index 0000000..0deb01d
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestAuth.java
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import java.io.File ;
+import java.io.FileWriter ;
+import java.io.IOException ;
+import java.net.URI ;
+import java.net.URISyntaxException ;
+import java.util.HashMap ;
+import java.util.Map ;
+
+import org.apache.jena.atlas.logging.LogCtl ;
+import org.apache.jena.atlas.web.HttpException ;
+import org.apache.jena.atlas.web.auth.PreemptiveBasicAuthenticator ;
+import org.apache.jena.atlas.web.auth.ScopedAuthenticator ;
+import org.apache.jena.atlas.web.auth.ServiceAuthenticator ;
+import org.apache.jena.atlas.web.auth.SimpleAuthenticator ;
+import org.junit.AfterClass ;
+import org.junit.Assert ;
+import org.junit.BeforeClass ;
+import org.junit.Test ;
+
+import com.hp.hpl.jena.query.ARQ ;
+import com.hp.hpl.jena.query.DatasetAccessor ;
+import com.hp.hpl.jena.query.DatasetAccessorFactory ;
+import com.hp.hpl.jena.query.QueryExecutionFactory ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.sparql.engine.http.QueryEngineHTTP ;
+import com.hp.hpl.jena.sparql.engine.http.QueryExceptionHTTP ;
+import com.hp.hpl.jena.sparql.engine.http.Service ;
+import com.hp.hpl.jena.sparql.modify.UpdateProcessRemoteBase ;
+import com.hp.hpl.jena.sparql.util.Context ;
+import com.hp.hpl.jena.update.UpdateExecutionFactory ;
+import com.hp.hpl.jena.update.UpdateFactory ;
+import com.hp.hpl.jena.update.UpdateRequest ;
+
+/**
+ * Tests Fuseki operation with authentication enabled
+ */
+public class TestAuth extends ServerTest {
+
+    private static File realmFile;
+
+    /**
+     * Sets up the authentication for tests
+     * @throws IOException
+     */
+    @BeforeClass
+    public static void setup() throws IOException {
+        realmFile = File.createTempFile("realm", ".properties");
+
+        try ( FileWriter writer = new FileWriter(realmFile); ) {
+            writer.write("allowed: password, fuseki\n");
+            writer.write("forbidden: password, other");
+        }
+
+        LogCtl.logLevel(Fuseki.serverLog.getName(), org.apache.log4j.Level.WARN, java.util.logging.Level.WARNING);
+        LogCtl.logLevel(Fuseki.actionLog.getName(), org.apache.log4j.Level.WARN, java.util.logging.Level.WARNING);
+        LogCtl.logLevel("org.eclipse.jetty", org.apache.log4j.Level.WARN, java.util.logging.Level.WARNING);
+
+        ServerTest.setupServer(realmFile.getAbsolutePath());
+    }
+
+    /**
+     * Tears down authentication test setup
+     */
+    @AfterClass
+    public static void teardown() {
+        ServerTest.teardownServer(); 
+        realmFile.delete();
+    }
+
+    @Test(expected = QueryExceptionHTTP.class)
+    public void query_with_auth_01() {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+        // No auth credentials should result in an error
+        qe.execAsk();
+    }
+
+    @Test(expected = QueryExceptionHTTP.class)
+    public void query_with_auth_02() {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+        // Auth credentials for valid user with bad password
+        qe.setBasicAuthentication("allowed", "incorrect".toCharArray());
+        qe.execAsk();
+    }
+
+    @Test
+    public void query_with_auth_03() {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+        // Auth credentials for valid user with correct password
+        qe.setBasicAuthentication("allowed", "password".toCharArray());
+        Assert.assertTrue(qe.execAsk());
+    }
+
+    @Test(expected = QueryExceptionHTTP.class)
+    public void query_with_auth_04() {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+        // Auth credentials for valid user with correct password BUT not in
+        // correct role
+        qe.setBasicAuthentication("forbidden", "password".toCharArray());
+        qe.execAsk();
+    }
+
+    @Test
+    public void query_with_auth_05() {
+        // Uses auth and enables compression
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+        qe.setAllowDeflate(true);
+        qe.setAllowGZip(true);
+
+        // Auth credentials for valid user with correct password
+        qe.setBasicAuthentication("allowed", "password".toCharArray());
+        Assert.assertTrue(qe.execAsk());
+    }
+
+    @Test(expected = QueryExceptionHTTP.class)
+    public void query_with_auth_06() {
+        // Uses auth and enables compression
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+        qe.setAllowDeflate(true);
+        qe.setAllowGZip(true);
+
+        // Auth credentials for valid user with bad password
+        qe.setBasicAuthentication("allowed", "incorrect".toCharArray());
+        qe.execAsk();
+    }
+
+    @Test(expected = QueryExceptionHTTP.class)
+    public void query_with_auth_07() throws URISyntaxException {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+        // Auth credentials for valid user with correct password but scoped to
+        // wrong URI
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI("http://example"), "allowed",
+                "password".toCharArray());
+        qe.setAuthenticator(authenticator);
+        qe.execAsk();
+    }
+
+    @Test
+    public void query_with_auth_08() throws URISyntaxException {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+        // Auth credentials for valid user with correct password and scoped to
+        // correct URI
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI(serviceQuery), "allowed", "password".toCharArray());
+        qe.setAuthenticator(authenticator);
+        Assert.assertTrue(qe.execAsk());
+    }
+
+    @Test
+    public void query_with_auth_09() throws URISyntaxException {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+        // Auth credentials for valid user with correct password using
+        // pre-emptive auth
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI(serviceQuery), "allowed", "password".toCharArray());
+        qe.setAuthenticator(new PreemptiveBasicAuthenticator(authenticator));
+        Assert.assertTrue(qe.execAsk());
+    }
+
+    @Test
+    public void query_with_auth_10() {
+        Context ctx = ARQ.getContext();
+        try {
+            QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+            // Auth credentials for valid user with correct password and scoped
+            // to correct URI
+            // Provided via Service Context and its associated authenticator
+            Map<String, Context> serviceContext = new HashMap<String, Context>();
+            Context authContext = new Context();
+            authContext.put(Service.queryAuthUser, "allowed");
+            authContext.put(Service.queryAuthPwd, "password");
+            serviceContext.put(serviceQuery, authContext);
+            ctx.put(Service.serviceContext, serviceContext);
+
+            qe.setAuthenticator(new ServiceAuthenticator());
+            Assert.assertTrue(qe.execAsk());
+        } finally {
+            ctx.remove(Service.serviceContext);
+        }
+    }
+    
+    @Test
+    public void query_with_auth_11() {
+        Context ctx = ARQ.getContext();
+        try {
+            QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+            // Auth credentials for valid user with correct password and scoped
+            // to base URI of the actual service URL
+            // Provided via Service Context and its associated authenticator
+            Map<String, Context> serviceContext = new HashMap<String, Context>();
+            Context authContext = new Context();
+            authContext.put(Service.queryAuthUser, "allowed");
+            authContext.put(Service.queryAuthPwd, "password");
+            serviceContext.put(urlRoot, authContext);
+            ctx.put(Service.serviceContext, serviceContext);
+
+            qe.setAuthenticator(new ServiceAuthenticator());
+            Assert.assertTrue(qe.execAsk());
+        } finally {
+            ctx.remove(Service.serviceContext);
+        }
+    }
+    
+    @Test
+    public void query_with_auth_12() {
+        ARQ.getContext().remove(Service.serviceContext);
+
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+        // Auth credentials for valid user with correct password
+        // Use service authenticator with fallback credentials.
+        qe.setAuthenticator(new ServiceAuthenticator("allowed", "password".toCharArray()));
+        Assert.assertTrue(qe.execAsk());
+     }
+    
+    @Test
+    public void query_with_auth_13() throws URISyntaxException {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+        // Auth credentials for valid user with correct password and scoped to
+        // base URI of the actual service URL
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI(urlRoot), "allowed", "password".toCharArray());
+        qe.setAuthenticator(authenticator);
+        Assert.assertTrue(qe.execAsk());
+    }
+    
+    @Test
+    public void query_with_auth_14() throws URISyntaxException {
+        QueryEngineHTTP qe = (QueryEngineHTTP) QueryExecutionFactory.sparqlService(serviceQuery, "ASK { }");
+
+        // Auth credentials for valid user with correct password and scoped to
+        // base URI of the actual service URL
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI("http://localhost:" + port), "allowed", "password".toCharArray());
+        qe.setAuthenticator(authenticator);
+        Assert.assertTrue(qe.execAsk());
+    }
+
+    @Test(expected = HttpException.class)
+    public void update_with_auth_01() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemote(updates, serviceUpdate);
+        // No auth credentials should result in an error
+        ue.execute();
+    }
+
+    @Test(expected = HttpException.class)
+    public void update_with_auth_02() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemote(updates, serviceUpdate);
+        // Auth credentials for valid user with bad password
+        ue.setAuthentication("allowed", "incorrect".toCharArray());
+        ue.execute();
+    }
+
+    @Test
+    public void update_with_auth_03() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemote(updates, serviceUpdate);
+        // Auth credentials for valid user with correct password
+        ue.setAuthentication("allowed", "password".toCharArray());
+        ue.execute();
+    }
+
+    @Test(expected = HttpException.class)
+    public void update_with_auth_04() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemote(updates, serviceUpdate);
+        // Auth credentials for valid user with correct password BUT not in
+        // correct role
+        ue.setAuthentication("forbidden", "password".toCharArray());
+        ue.execute();
+    }
+
+    @Test(expected = HttpException.class)
+    public void update_with_auth_05() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemoteForm(updates, serviceUpdate);
+        // No auth credentials should result in an error
+        ue.execute();
+    }
+
+    @Test(expected = HttpException.class)
+    public void update_with_auth_06() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemoteForm(updates, serviceUpdate);
+        // Auth credentials for valid user with bad password
+        ue.setAuthentication("allowed", "incorrect".toCharArray());
+        ue.execute();
+    }
+
+    @Test
+    public void update_with_auth_07() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemoteForm(updates, serviceUpdate);
+        // Auth credentials for valid user with correct password
+        ue.setAuthentication("allowed", "password".toCharArray());
+        ue.execute();
+    }
+
+    @Test(expected = HttpException.class)
+    public void update_with_auth_08() {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemoteForm(updates, serviceUpdate);
+        // Auth credentials for valid user with correct password BUT not in
+        // correct role
+        ue.setAuthentication("forbidden", "password".toCharArray());
+        ue.execute();
+    }
+
+    @Test(expected = HttpException.class)
+    public void update_with_auth_09() throws URISyntaxException {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemote(updates, serviceUpdate);
+
+        // Auth credentials for valid user with correct password but scoped to
+        // wrong URI
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI("http://example"), "allowed",
+                "password".toCharArray());
+        ue.setAuthenticator(authenticator);
+        ue.execute();
+    }
+
+    @Test
+    public void update_with_auth_10() throws URISyntaxException {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemote(updates, serviceUpdate);
+
+        // Auth credentials for valid user with correct password scoped to
+        // correct URI
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI(serviceUpdate), "allowed", "password".toCharArray());
+        ue.setAuthenticator(authenticator);
+        ue.execute();
+    }
+
+    @Test
+    public void update_with_auth_11() throws URISyntaxException {
+        UpdateRequest updates = UpdateFactory.create("CREATE SILENT GRAPH <http://graph>");
+        UpdateProcessRemoteBase ue = (UpdateProcessRemoteBase) UpdateExecutionFactory.createRemote(updates, serviceUpdate);
+
+        // Auth credentials for valid user with correct password scoped to
+        // correct URI
+        // Also using pre-emptive auth
+        ScopedAuthenticator authenticator = new ScopedAuthenticator(new URI(serviceUpdate), "allowed", "password".toCharArray());
+        ue.setAuthenticator(new PreemptiveBasicAuthenticator(authenticator));
+        ue.execute();
+    }
+    
+    @Test(expected = HttpException.class)
+    public void graphstore_with_auth_01() {       
+        // No auth credentials
+        DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceREST);
+        accessor.getModel();
+    }
+    
+    @Test(expected = HttpException.class)
+    public void graphstore_with_auth_02() {
+        // Incorrect auth credentials
+        DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceREST, new SimpleAuthenticator("allowed", "incorrect".toCharArray()));
+        accessor.getModel();
+    }
+    
+    @Test
+    public void graphstore_with_auth_03() {
+        // Correct auth credentials
+        DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceREST, new SimpleAuthenticator("allowed", "password".toCharArray()));
+        Model m = accessor.getModel();
+        Assert.assertTrue(m.isEmpty());
+    }
+    
+    @Test(expected = HttpException.class)
+    public void graphstore_with_auth_04() throws URISyntaxException {
+        // Correct auth credentials scoped to wrong URI
+        DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceREST, new ScopedAuthenticator(new URI("http://example.org/"), "allowed", "password".toCharArray()));
+        accessor.getModel();
+    }
+    
+    @Test
+    public void graphstore_with_auth_05() throws URISyntaxException {
+        // Correct auth credentials scoped to correct URI
+        DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceREST, new ScopedAuthenticator(new URI(serviceREST), "allowed", "password".toCharArray()));
+        accessor.getModel();
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestDatasetOps.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestDatasetOps.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestDatasetOps.java
new file mode 100644
index 0000000..a5c2fc6
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestDatasetOps.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import static org.apache.jena.fuseki.ServerTest.serviceQuery ;
+import static org.apache.jena.fuseki.ServerTest.serviceREST ;
+import static org.apache.jena.fuseki.ServerTest.urlDataset ;
+
+import java.io.IOException ;
+import java.io.OutputStream ;
+
+import org.apache.http.HttpEntity ;
+import org.apache.http.entity.ContentProducer ;
+import org.apache.http.entity.EntityTemplate ;
+import org.apache.jena.atlas.lib.StrUtils ;
+import org.apache.jena.atlas.web.HttpException ;
+import org.apache.jena.atlas.web.TypedInputStream ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.riot.RDFFormat ;
+import org.apache.jena.riot.WebContent ;
+import org.apache.jena.riot.system.StreamRDF ;
+import org.apache.jena.riot.system.StreamRDFLib ;
+import org.apache.jena.riot.web.HttpOp ;
+import org.apache.jena.web.HttpSC ;
+import org.junit.Test ;
+
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ;
+import com.hp.hpl.jena.sparql.sse.SSE ;
+
+/** TestDatasetAccessorHTTP does most of the GSP testing.
+ *  This class adds the testing of Fuseki extras.
+ */
+public class TestDatasetOps extends AbstractFusekiTest 
+{
+    static DatasetGraph data = SSE.parseDatasetGraph(StrUtils.strjoinNL
+        ("(prefix ((: <http://example/>))",
+         "  (dataset",
+         "    (graph (_:x :p 1) (_:x :p 2))" ,
+         "    (graph :g (_:x :p 3))",
+         "))"
+         )) ;
+    
+    /** Create an HttpEntity for the graph */  
+    protected HttpEntity datasetToHttpEntity(final DatasetGraph dsg) {
+
+        final RDFFormat syntax = RDFFormat.NQUADS ;
+        ContentProducer producer = new ContentProducer() {
+            @Override
+            public void writeTo(OutputStream out) throws IOException {
+                RDFDataMgr.write(out, dsg, syntax) ;
+            }
+        } ;
+        EntityTemplate entity = new EntityTemplate(producer) ;
+        String ct = syntax.getLang().getContentType().getContentType() ;
+        entity.setContentType(ct) ;
+        return entity ;
+    }
+    
+    @Test public void gsp_x_01() {
+        gsp_x(urlDataset, urlDataset) ;
+    }
+
+    @Test public void gsp_x_02() {
+        gsp_x(urlDataset, serviceREST) ;
+    }
+
+    @Test public void gsp_x_03() {
+        gsp_x(serviceREST, urlDataset) ;
+    }
+
+    @Test public void gsp_x_04() {
+        gsp_x(serviceREST, urlDataset) ;
+    }
+
+    private void gsp_x(String outward, String inward) {
+        HttpEntity e = datasetToHttpEntity(data) ;
+        HttpOp.execHttpPut(outward, e);
+        DatasetGraph dsg = DatasetGraphFactory.createMem() ;
+        RDFDataMgr.read(dsg, inward) ;
+//        String x = HttpOp.execHttpGetString(inward, "application/n-quads") ;
+//        RDFDataMgr.read(dsg, new StringReader(x), null, Lang.NQUADS) ;
+        assertEquals(2, dsg.getDefaultGraph().size()) ;
+    }
+
+    // Get dataset.  Tests conneg.
+    @Test 
+    public void gsp_x_10() {
+        gsp_x_ct(urlDataset, WebContent.contentTypeNQuads, WebContent.contentTypeNQuads) ;
+    }
+
+    @Test 
+    public void gsp_x_11() {
+        gsp_x_ct(urlDataset, WebContent.contentTypeNQuadsAlt1, WebContent.contentTypeNQuads) ;
+    }
+
+    @Test 
+    public void gsp_x_12() {
+        gsp_x_ct(urlDataset, WebContent.contentTypeTriG, WebContent.contentTypeTriG) ;
+    }
+
+    @Test 
+    public void gsp_x_13() {
+        gsp_x_ct(urlDataset, WebContent.contentTypeTriGAlt1, WebContent.contentTypeTriG) ;
+    }
+
+    @Test 
+    public void gsp_x_14() {
+        gsp_x_ct(urlDataset, WebContent.defaultDatasetAcceptHeader, WebContent.contentTypeTriG) ;
+    }
+
+    @Test 
+    public void gsp_x_15() {
+        // Anything!
+        gsp_x_ct(urlDataset, WebContent.defaultRDFAcceptHeader, WebContent.contentTypeTriG) ;
+    }
+    
+    private void gsp_x_ct(String urldataset, String acceptheader, String contentTypeResponse) {
+        HttpEntity e = datasetToHttpEntity(data) ;
+        HttpOp.execHttpPut(urlDataset, e);
+        TypedInputStream in = HttpOp.execHttpGet(urlDataset, acceptheader) ;
+        assertEqualsIgnoreCase(in.getContentType(), contentTypeResponse) ;
+        DatasetGraph dsg = DatasetGraphFactory.createMem() ;
+        StreamRDF dest = StreamRDFLib.dataset(dsg) ;
+        RDFDataMgr.parse(dest, in) ;
+    }
+
+    @Test 
+    public void gsp_x_20()
+    {
+        HttpEntity e = datasetToHttpEntity(data) ;
+        try { 
+            HttpOp.execHttpPost(serviceQuery, e);
+        } catch (HttpException ex) {
+            assertTrue(HttpSC.isClientError(ex.getResponseCode())) ;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestFileUpload.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestFileUpload.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestFileUpload.java
new file mode 100644
index 0000000..4fa95d9
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestFileUpload.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import static org.apache.jena.fuseki.ServerTest.serviceREST ;
+import org.apache.jena.atlas.web.TypedInputStream ;
+import org.apache.jena.fuseki.http.TestDatasetAccessorHTTP ;
+import org.apache.jena.fuseki.http.TestHttpOp ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.riot.RDFLanguages ;
+import org.apache.jena.riot.web.HttpOp ;
+import org.junit.Test ;
+
+import com.hp.hpl.jena.query.DatasetAccessor ;
+import com.hp.hpl.jena.query.DatasetAccessorFactory ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+
+/** Additional tests for the SPARQL Graph Store protocol, 
+ * mainly for HTTP file upload. See {@linkplain TestDatasetAccessorHTTP}
+ * and {@linkplain TestHttpOp} for tests that exercise direct GSp functionality
+ *  
+ * @see TestDatasetAccessorHTTP  
+ * @see TestHttpOp  
+ */
+public class TestFileUpload extends AbstractFusekiTest  
+{
+    @Test public void upload_gsp_01()
+    {
+        FileSender x = new FileSender(ServerTest.serviceREST+"?default") ;
+        x.add("D.ttl", "<http://example/s> <http://example/p> <http://example/o> .", "text/turtle") ;
+        x.send("POST") ;
+        
+        Model m = ModelFactory.createDefaultModel() ;
+        TypedInputStream in = HttpOp.execHttpGet(serviceREST, "text/turtle") ;
+        RDFDataMgr.read(m, in, RDFLanguages.contentTypeToLang(in.getMediaType()) ) ;
+        // which is is effectively :
+//        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+//        Model m = du.getModel() ;
+        assertEquals(1, m.size()) ;
+    }
+    
+    @Test public void upload_gsp_02()
+    {
+        FileSender x = new FileSender(ServerTest.serviceREST+"?default") ;
+        x.add("D.ttl", "<http://example/s> <http://example/p> 123 .", "text/turtle") ;
+        x.add("D.nt", "<http://example/s> <http://example/p> <http://example/o-456> .", "application/n-triples") ;
+        x.send("PUT") ;
+        
+        // BUG
+        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+        Model m = du.getModel() ;
+        assertEquals(2, m.size()) ;
+    }
+    
+    // Extension of GSP - no graph selector => dataset
+    @Test public void upload_gsp_03()
+    {
+        FileSender x = new FileSender(ServerTest.serviceREST) ;
+        x.add("D.ttl", "<http://example/s> <http://example/p> <http://example/o> .", "text/turtle") ;
+        x.add("D.trig", "<http://example/g> { <http://example/s> <http://example/p> <http://example/o> }", "text/trig") ;
+        x.send("POST") ;
+        
+        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+        Model m = du.getModel() ;
+        assertEquals(1, m.size()) ;
+    }
+
+    @Test public void upload_gsp_04()
+    {
+        {
+            DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+            Model m = du.getModel() ;
+            assertEquals(0, m.size()) ;
+        }
+        FileSender x = new FileSender(ServerTest.urlDataset) ;
+        x.add("D.ttl", "<http://example/s> <http://example/p> <http://example/o> .", "text/plain") ;
+        x.add("D.trig", "<http://example/g> { <http://example/s> <http://example/p> 123,456 }", "text/plain") ;
+        x.send("POST") ;
+        
+        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+        Model m = du.getModel() ;
+        assertEquals(1, m.size()) ;
+        m = du.getModel("http://example/g") ;
+        assertEquals(2, m.size()) ;
+    }
+
+    // Via DatasetAccessor
+    
+    @Test public void dataset_accessor_01() {
+        FileSender x = new FileSender(ServerTest.urlDataset) ;
+        x.add("D.nq", "", "application/-n-quads") ;
+        x.send("PUT") ;
+        
+        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+        Model m = du.getModel() ;
+        assertEquals(0, m.size()) ;
+    }
+    
+    @Test public void dataset_accessor_02() {
+        FileSender x = new FileSender(ServerTest.urlDataset) ;
+        x.add("D.nq", "<http://example/s> <http://example/p> <http://example/o-456> <http://example/g> .", "application/n-quads") ;
+        x.send("PUT") ;
+        
+        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+        Model m = du.getModel("http://example/g") ;
+        assertEquals(1, m.size()) ;
+        m = du.getModel() ;
+        assertEquals(0, m.size()) ;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
new file mode 100644
index 0000000..7b021f4
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+import java.io.IOException ;
+import java.net.HttpURLConnection ;
+import java.net.URL ;
+
+import static org.apache.jena.fuseki.ServerTest.* ;
+
+import org.junit.AfterClass ;
+import org.junit.Assert ;
+import org.junit.BeforeClass ;
+import org.junit.Test ;
+import org.apache.jena.atlas.junit.BaseTest ;
+import com.hp.hpl.jena.query.* ;
+import com.hp.hpl.jena.sparql.core.Var ;
+import com.hp.hpl.jena.sparql.engine.binding.Binding ;
+import com.hp.hpl.jena.sparql.resultset.ResultSetCompare ;
+import com.hp.hpl.jena.sparql.sse.Item ;
+import com.hp.hpl.jena.sparql.sse.SSE ;
+import com.hp.hpl.jena.sparql.sse.builders.BuilderResultSet ;
+import com.hp.hpl.jena.sparql.util.Convert ;
+
+public class TestQuery extends BaseTest 
+{
+    protected static ResultSet rs1 = null ; 
+    static {
+        Item item = SSE.parseItem("(resultset (?s ?p ?o) (row (?s <x>)(?p <p>)(?o 1)))") ;
+        rs1 = BuilderResultSet.build(item) ;
+    }
+    
+    @BeforeClass public static void beforeClass()
+    {
+        ServerTest.allocServer() ;
+        ServerTest.resetServer() ;
+        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+        du.putModel(model1) ;
+        du.putModel(gn1, model2) ;
+    }
+    
+    @AfterClass public static void afterClass()
+    {
+        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
+        du.deleteDefault() ;
+        ServerTest.freeServer() ;
+    }
+    
+    @Test public void query_01()
+    {
+        execQuery("SELECT * {?s ?p ?o}", 1) ;
+    }
+    
+    @Test public void query_recursive_01()
+    {
+        String query = "SELECT * WHERE { SERVICE <" + serviceQuery + "> { ?s ?p ?o . BIND(?o AS ?x) } }";
+        try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, query) ) {
+            ResultSet rs = qExec.execSelect();
+            Var x = Var.alloc("x");
+            while (rs.hasNext()) {
+                Binding b = rs.nextBinding();
+                Assert.assertNotNull(b.get(x));
+            }
+        }
+    }
+    
+    @Test public void query_with_params_01()
+    {
+        String query = "ASK { }";
+        try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery + "?output=json", query) ) {
+            boolean result = qExec.execAsk();
+            Assert.assertTrue(result);
+        }
+    }
+    
+    @Test public void request_id_header_01() throws IOException
+    {
+        String qs = Convert.encWWWForm("ASK{}") ;
+        URL u = new URL(serviceQuery+"?query="+qs);
+        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
+        Assert.assertTrue(conn.getHeaderField("Fuseki-Request-ID") != null);
+    }
+
+    private void execQuery(String queryString, int exceptedRowCount)
+    {
+        QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, queryString) ;
+        ResultSet rs = qExec.execSelect() ;
+        int x = ResultSetFormatter.consume(rs) ;
+        assertEquals(exceptedRowCount, x) ;
+    }
+    
+    private void execQuery(String queryString, ResultSet expectedResultSet)
+    {
+        QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, queryString) ;
+        ResultSet rs = qExec.execSelect() ;
+        boolean b = ResultSetCompare.equalsByTerm(rs, expectedResultSet) ;
+        assertTrue("Result sets different", b) ;
+    }
+}