Added delete setting controller & handled no resource found (issue #37)

Change-Id: Ib24692a204b6ef1f329522aac2b8c4abc823014e
diff --git a/core/Changes b/core/Changes
index 4aaa3b2..edb5954 100644
--- a/core/Changes
+++ b/core/Changes
@@ -20,6 +20,8 @@
    - Added default setting key validation & fixed UserdataTest (margaretha)   
 28/01/2019
    - Updated Rewrite handler (margaretha)
+29/01/2019
+   - Handled "no resource found" cases (margaretha, issue #37)   
 
 version 0.61.4
 14/11/2018
diff --git a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
index ec2a148..72b8cfc 100644
--- a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
+++ b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -27,6 +27,7 @@
     public static final int INVALID_ALGORITHM = 111;
     public static final int UNSUPPORTED_API_VERSION = 112;
     public static final int NON_UNIQUE_RESULT_FOUND = 113;
+    public static final int NO_RESOURCE_FOUND = 114;
     
     /**
      * 200 status codes general JSON serialization error
diff --git a/core/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java b/core/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
index 94c2498..50aa378 100644
--- a/core/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
+++ b/core/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
@@ -89,7 +89,7 @@
         }
         else {
             throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No result found.", "");
+                    "No result found", "");
         }
 
     }
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/CoreResponseHandler.java b/core/src/main/java/de/ids_mannheim/korap/web/CoreResponseHandler.java
index 2a398e7..23ff8e6 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/CoreResponseHandler.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/CoreResponseHandler.java
@@ -94,6 +94,10 @@
             case StatusCodes.STATUS_OK:
                 status = Response.Status.OK;
                 break;
+            // EM: Added 
+            case StatusCodes.NO_RESOURCE_FOUND:
+                status = Response.Status.NOT_FOUND;
+                break;
         }
         return status;
     }
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java b/core/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java
index 63e19de..fd6fd1a 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java
@@ -109,15 +109,10 @@
             throw kustvaktResponseHandler.throwit(new KustvaktException(
                     StatusCodes.INVALID_ARGUMENT, "Bad argument:", json));
         }
-        if (codes == null) {
+        if (codes == null || codes.isEmpty()) {
             throw kustvaktResponseHandler.throwit(
                     new KustvaktException(StatusCodes.MISSING_ATTRIBUTE,
-                            "Missing attribute:", "codes"));
-        }
-        else if (codes.isEmpty()) {
-            throw kustvaktResponseHandler
-                    .throwit(new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                            "No result found.", "codes:[]"));
+                            "codes is null or empty", "codes"));
         }
 
         try {
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java b/core/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
index ff21813..7082fb8 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
@@ -37,11 +37,10 @@
  */
 @Controller
 @Path("{version}/statistics/")
-@ResourceFilters({APIVersionFilter.class, PiwikFilter.class })
+@ResourceFilters({ APIVersionFilter.class, PiwikFilter.class })
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
 public class StatisticController {
 
-
     private static final boolean DEBUG = false;
     private static Logger jlog =
             LogManager.getLogger(StatisticController.class);
@@ -50,7 +49,6 @@
     @Autowired
     private SearchKrill searchKrill;
 
-
     /**
      * Returns statistics of the virtual corpus defined by the given
      * corpusQuery parameter.
@@ -71,26 +69,26 @@
 
         KoralCollectionQueryBuilder builder = new KoralCollectionQueryBuilder();
 
-		String stats;
-		if (corpusQuery != null && !corpusQuery.isEmpty()) {
-			builder.with(corpusQuery);
-			String json = null;
-			try {
-				json = builder.toJSON();
-			}
-			catch (KustvaktException e) {
-				throw kustvaktResponseHandler.throwit(e);
-			}
-			stats = searchKrill.getStatistics(json);
-		}
-		else {
-			stats = searchKrill.getStatistics(null);
-		};
+        String stats;
+        if (corpusQuery != null && !corpusQuery.isEmpty()) {
+            builder.with(corpusQuery);
+            String json = null;
+            try {
+                json = builder.toJSON();
+            }
+            catch (KustvaktException e) {
+                throw kustvaktResponseHandler.throwit(e);
+            }
+            stats = searchKrill.getStatistics(json);
+        }
+        else {
+            stats = searchKrill.getStatistics(null);
+        };
 
-        if (stats.contains("-1")){
+        if (stats.contains("-1")) {
             throw kustvaktResponseHandler.throwit(StatusCodes.NO_RESULT_FOUND);
         }
-        if (DEBUG){
+        if (DEBUG) {
             jlog.debug("Stats: " + stats);
         }
         return Response.ok(stats).build();
diff --git a/full/Changes b/full/Changes
index 78a7e5e..f9a2efc 100644
--- a/full/Changes
+++ b/full/Changes
@@ -37,6 +37,9 @@
    - Added default foundry for morphology layer (margaretha)
 29/01/2019
    - Fixed share VC type (margaretha)
+   - Added delete setting controller (margaretha)
+   - Handled "no resource found" cases (margaretha, issue #37)
+   
 
 # version 0.61.4
 14/11/2018
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java
index e1239cf..813fb72 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java
@@ -55,14 +55,13 @@
         entityManager.merge(defaultSetting);
     }
 
-    public void deleteDefaultSetting (DefaultSetting defaultSetting)
+    public void deleteDefaultSetting (String username)
             throws KustvaktException {
-        ParameterChecker.checkObjectValue(defaultSetting, "defaultSetting");
-        if (!entityManager.contains(defaultSetting)) {
-            defaultSetting = entityManager.merge(defaultSetting);
+        ParameterChecker.checkObjectValue(username, "defaultSetting");
+        DefaultSetting defaultSetting = retrieveDefautlSetting(username);
+        if (defaultSetting != null){
+            entityManager.remove(defaultSetting);
         }
-        entityManager.remove(defaultSetting);
-
     }
 
     public DefaultSetting retrieveDefautlSetting (String username)
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
index 691eaca..358ba99 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
@@ -94,7 +94,8 @@
             group = retrieveGroupById(groupId);
         }
         catch (NoResultException e) {
-            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
+            throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                    "Group " + groupId + " is not found.",
                     "groupId: " + groupId);
         }
 
@@ -202,9 +203,8 @@
         }
         catch (NoResultException e) {
             throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No result found for query: retrieve group by used id "
-                            + userId,
-                    userId, e);
+                    "No group for username: " + userId + " is found", userId,
+                    e);
         }
     }
 
@@ -226,10 +226,8 @@
             return (UserGroup) q.getSingleResult();
         }
         catch (NoResultException e) {
-            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No result found for query: retrieve group by name "
-                            + groupName,
-                    groupName, e);
+            throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                    "Group " + groupName + " is not found", groupName, e);
         }
     }
 
@@ -261,7 +259,8 @@
         }
         catch (NoResultException e) {
             throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No hidden group found for virtual corpus with id " + vcId,
+                    "No hidden group for virtual corpus with id " + vcId
+                            + " is found",
                     String.valueOf(vcId), e);
         }
 
@@ -318,7 +317,8 @@
         }
         catch (NoResultException e) {
             throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No group found for status " + status, status.toString());
+                    "No group with status " + status + " is found",
+                    status.toString());
         }
 
     }
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
index cbfabd7..1b2c15b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
@@ -169,7 +169,7 @@
         }
         catch (NoResultException e) {
             throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No member is found in group " + groupId,
+                    "No member in group " + groupId+" is found",
                     String.valueOf(groupId));
         }
     }
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
index 0e64821..f367571 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
@@ -175,9 +175,8 @@
             vc = (VirtualCorpus) q.getSingleResult();
         }
         catch (NoResultException e) {
-            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No result found for query: retrieve virtual corpus by id "
-                            + id,
+            throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                    "Virtual corpus with id: "+ id+" is not found",
                     String.valueOf(id), e);
         }
         return vc;
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java b/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java
index d5f0b1e..fc924db 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java
@@ -95,15 +95,16 @@
         username = verifiyUsername(username, contextUsername);
         return retrieveDefaultSettings(username);
     }
-    
-    public String retrieveDefaultSettings (String username) throws KustvaktException {
+
+    public String retrieveDefaultSettings (String username)
+            throws KustvaktException {
         DefaultSetting defaultSetting =
                 settingDao.retrieveDefautlSetting(username);
         if (defaultSetting == null) {
             return null;
         }
         return defaultSetting.getSettings();
-    }    
+    }
 
     public void deleteKey (String username, String contextUsername, String key)
             throws KustvaktException {
@@ -120,4 +121,10 @@
         settingDao.updateDefaultSetting(defaultSetting);
     }
 
+    public void deleteSetting (String username, String contextUsername)
+            throws KustvaktException {
+        username = verifiyUsername(username, contextUsername);
+        settingDao.deleteDefaultSetting(username);
+    }
+
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
index d1e16df..8628328 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
@@ -188,9 +188,8 @@
 
         if (vc == null) {
             String vcCode = createdBy + "/" + vcName;
-            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No result found for query: retrieve virtual corpus by name "
-                            + vcCode,
+            throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                    "Virtual corpus "+ vcCode+" is not found.",
                     String.valueOf(vcCode));
         }
         else if (vc.getCreatedBy().equals(username)
@@ -575,9 +574,8 @@
         VirtualCorpus vc = vcDao.retrieveVCByName(vcName, createdBy);
         if (vc == null) {
             String vcCode = createdBy + "/" + vcName;
-            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                    "No result found for query: retrieve virtual corpus by name "
-                            + vcCode,
+            throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                    "Virtual corpus "+ vcCode+" is not found.",
                     String.valueOf(vcCode));
         }
         checkVCAccess(vc, username);
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserSettingController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserSettingController.java
index 4cb0cc9..71f0bff 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserSettingController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserSettingController.java
@@ -112,10 +112,11 @@
                     OAuth2Scope.READ_DEFAULT_SETTING);
             String settings = settingService.retrieveDefaultSettings(username,
                     tokenContext.getUsername());
-            if (settings == null){
+            if (settings == null) {
                 username = tokenContext.getUsername();
-                throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
-                        "No setting is found for " + username, username);
+                throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
+                        "No default setting for username: " + username+" is found",
+                        username);
             }
             return Response.ok(settings).build();
         }
@@ -125,11 +126,15 @@
     }
 
     /**
-     * Deletes an entry of a default setting of a user by the given key.
+     * Deletes an entry of a default setting of a user by the given
+     * key.
      * 
-     * @param context a security context
-     * @param username a username
-     * @param key the key of the default setting entry to be deleted
+     * @param context
+     *            a security context
+     * @param username
+     *            a username
+     * @param key
+     *            the key of the default setting entry to be deleted
      * @return
      */
     @DELETE
@@ -152,4 +157,33 @@
             throw kustvaktResponseHandler.throwit(e);
         }
     }
+
+    /**
+     * Deletes the default setting of the given username. If such a
+     * setting does not exists, no error will be thrown and response
+     * status 200 will be returned since the purpose of the request
+     * has been achieved.
+     * 
+     * @param context
+     * @param username
+     *            a username
+     * @return 200 if the request is successful
+     */
+    @DELETE
+    @ResourceFilters({ AuthenticationFilter.class, PiwikFilter.class,
+            BlockingFilter.class })
+    public Response deleteDefaultSetting (@Context SecurityContext context,
+            @PathParam("username") String username) {
+
+        TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
+        try {
+            scopeService.verifyScope(tokenContext,
+                    OAuth2Scope.DELETE_DEFAULT_SETTING);
+            settingService.deleteSetting(username, tokenContext.getUsername());
+            return Response.ok().build();
+        }
+        catch (KustvaktException e) {
+            throw kustvaktResponseHandler.throwit(e);
+        }
+    }
 }
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/ShibbolethUserControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/ShibbolethUserControllerTest.java
index fb2af03..cc25d21 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/ShibbolethUserControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/ShibbolethUserControllerTest.java
@@ -201,7 +201,7 @@
 		String entity = response.getEntity(String.class);
 		JsonNode node = JsonUtils.readTree(entity);
 		assertNotNull(node);
-		assertEquals(StatusCodes.NO_RESULT_FOUND, node.at("/errors/0/0").asInt());
+		assertEquals(StatusCodes.NO_RESOURCE_FOUND, node.at("/errors/0/0").asInt());
 		assertEquals("UserDetails", node.at("/errors/0/2").asText());
 		helper().dropUser("userservicetest");
 	}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserSettingControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserSettingControllerTest.java
index 880cc14..7ac81d2 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserSettingControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserSettingControllerTest.java
@@ -33,8 +33,8 @@
 
     public ClientResponse sendPutRequest (String username,
             Map<String, Object> map) throws KustvaktException {
-        ClientResponse response = resource().path(API_VERSION).path("~"+username)
-                .path("setting")
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .type(MediaType.APPLICATION_JSON).entity(map)
@@ -45,11 +45,12 @@
 
     @Test
     public void testCreateSettingWithJson () throws KustvaktException {
-        String json = "{\"pos-foundry\":\"opennlp\",\"metadata\":\"author title "
-                + "textSigle availability\",\"resultPerPage\":25}";
+        String json =
+                "{\"pos-foundry\":\"opennlp\",\"metadata\":\"author title "
+                        + "textSigle availability\",\"resultPerPage\":25}";
 
-        ClientResponse response = resource().path(API_VERSION).path("~"+username)
-                .path("setting")
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .type(MediaType.APPLICATION_JSON).entity(json)
@@ -62,7 +63,9 @@
 
         testRetrieveSettings(username, "opennlp", numOfResult, metadata);
 
+        testDeleteKeyNotExist(username);
         testDeleteKey(username, numOfResult, metadata);
+        testDeleteSetting(username);
     }
 
     @Test
@@ -99,11 +102,12 @@
 
     @Test
     public void testPutDifferentUsername () throws KustvaktException {
-        String json = "{\"pos-foundry\":\"opennlp\",\"metadata\":\"author title "
-                + "textSigle availability\",\"resultPerPage\":25}";
+        String json =
+                "{\"pos-foundry\":\"opennlp\",\"metadata\":\"author title "
+                        + "textSigle availability\",\"resultPerPage\":25}";
 
-        ClientResponse response = resource().path(API_VERSION).path("~"+username)
-                .path("setting")
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username2, "pass"))
                 .type(MediaType.APPLICATION_JSON).entity(json)
@@ -118,8 +122,8 @@
 
     @Test
     public void testGetDifferentUsername () throws KustvaktException {
-        ClientResponse response = resource().path(API_VERSION).path("~"+username)
-                .path("setting")
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username2, "pass"))
                 .get(ClientResponse.class);
@@ -132,9 +136,42 @@
     }
 
     @Test
+    public void testGetSettingNotExist () throws KustvaktException {
+        String username = "tralala";
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .get(ClientResponse.class);
+
+        assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
+        
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+
+        assertEquals(StatusCodes.NO_RESOURCE_FOUND,
+                node.at("/errors/0/0").asInt());
+        assertEquals("No default setting for username: " + username +" is found",
+                node.at("/errors/0/1").asText());
+        assertEquals(username, node.at("/errors/0/2").asText());
+    }
+    
+    @Test
+    public void testDeleteSettingNotExist () throws KustvaktException {
+        String username = "tralala";
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .delete(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+    }
+
+    @Test
     public void testDeleteKeyDifferentUsername () throws KustvaktException {
-        ClientResponse response = resource().path(API_VERSION).path("~"+username)
-                .path("setting").path("pos-foundry")
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting").path("pos-foundry")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username2, "pass"))
                 .delete(ClientResponse.class);
@@ -146,11 +183,47 @@
                 node.at("/errors/0/0").asInt());
     }
 
+    private void testDeleteSetting (String username) throws KustvaktException {
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .delete(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        response = resource().path(API_VERSION).path("~" + username)
+                .path("setting")
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .get(ClientResponse.class);
+
+        assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(StatusCodes.NO_RESOURCE_FOUND,
+                node.at("/errors/0/0").asInt());
+        assertEquals(username, node.at("/errors/0/2").asText());
+    }
+    
+    // EM: deleting a non-existing key does not throw an error, because 
+    // the purpose of the request has been achieved.
+    private void testDeleteKeyNotExist (String username) throws KustvaktException {
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting").path("lemma-foundry")
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .delete(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+    }
+
     private void testDeleteKey (String username, int numOfResult,
             String metadata) throws KustvaktException {
 
-        ClientResponse response = resource().path(API_VERSION).path("~"+username)
-                .path("setting").path("pos-foundry")
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting").path("pos-foundry")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .delete(ClientResponse.class);
@@ -173,8 +246,8 @@
 
     private void testRetrieveSettings (String username, String posFoundry,
             int numOfResult, String metadata) throws KustvaktException {
-        ClientResponse response = resource().path(API_VERSION).path("~"+username)
-                .path("setting")
+        ClientResponse response = resource().path(API_VERSION)
+                .path("~" + username).path("setting")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VCReferenceTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VCReferenceTest.java
index 59b4d9a..fc58ff8 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VCReferenceTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VCReferenceTest.java
@@ -120,7 +120,7 @@
 
         String ent = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(ent);
-        assertEquals(StatusCodes.NO_RESULT_FOUND,
+        assertEquals(StatusCodes.NO_RESOURCE_FOUND,
                 node.at("/errors/0/0").asInt());
         assertEquals("username/vc1", node.at("/errors/0/2").asText());
     }
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java
index b4f0194..84d6659 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java
@@ -27,7 +27,7 @@
  * @author margaretha
  *
  */
-public class VirtualCorpusControllerAdminTest extends SpringJerseyTest {
+public class VirtualCorpusControllerAdminTest extends VirtualCorpusTestBase {
 
     private String admin = "admin";
     private String username = "VirtualCorpusControllerAdminTest";
@@ -260,8 +260,10 @@
 
         String accessId = testlistAccessByVC(vcId);
         testDeleteVCAccess(accessId);
+        
+        testEditVCType(admin, vcId, VirtualCorpusType.PRIVATE);
     }
-
+    
     private void testCreateVCAccess (String vcId, String groupId)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
index 558a0af..f3723cc 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
@@ -29,7 +29,6 @@
 
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.SpringJerseyTest;
 import de.ids_mannheim.korap.constant.AuthenticationScheme;
 import de.ids_mannheim.korap.constant.VirtualCorpusType;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -41,7 +40,7 @@
  * @author margaretha
  *
  */
-public class VirtualCorpusControllerTest extends SpringJerseyTest {
+public class VirtualCorpusControllerTest extends VirtualCorpusTestBase {
 
     private void checkWWWAuthenticateHeader (ClientResponse response) {
         Set<Entry<String, List<String>>> headers =
@@ -61,22 +60,6 @@
         }
     }
 
-    private JsonNode testSearchVC (String username, String vcId)
-            throws UniformInterfaceException, ClientHandlerException,
-            KustvaktException {
-        ClientResponse response = resource().path(API_VERSION).path("vc")
-                .path(vcId)
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
-                .get(ClientResponse.class);
-        String entity = response.getEntity(String.class);
-        // System.out.println(entity);
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-
-        return JsonUtils.readTree(entity);
-    }
-
     private JsonNode testListVC (String username)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
@@ -821,8 +804,11 @@
         // list vc access by dory
         node = testlistAccessByVC("dory", vcId);
         assertEquals(0, node.size());
+        
+        testEditVCType("marlin", vcId, VirtualCorpusType.PRIVATE);
     }
 
+
     private ClientResponse testShareVC (String vcId)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusTestBase.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusTestBase.java
new file mode 100644
index 0000000..b773135
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusTestBase.java
@@ -0,0 +1,56 @@
+package de.ids_mannheim.korap.web.controller;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.http.entity.ContentType;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.ClientResponse.Status;
+
+import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+public abstract class VirtualCorpusTestBase extends SpringJerseyTest{
+    
+    protected JsonNode testSearchVC (String username, String vcId)
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+        ClientResponse response = resource().path(API_VERSION).path("vc")
+                .path(vcId)
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .get(ClientResponse.class);
+        String entity = response.getEntity(String.class);
+        // System.out.println(entity);
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        return JsonUtils.readTree(entity);
+    }
+    
+    protected void testEditVCType (String username, String vcId,
+            VirtualCorpusType type) throws KustvaktException {
+        String json = "{\"id\": \"" + vcId + "\", \"type\": \"" + type + "\"}";
+
+        ClientResponse response = resource().path(API_VERSION).path("vc")
+                .path("edit")
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .post(ClientResponse.class, json);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        JsonNode node = testSearchVC(username, vcId);
+        assertEquals(type.displayName(), node.at("/type").asText());
+    }
+}