Added user-group name pattern (issue #33).

Change-Id: I578592045d0e64c2daf4cdfdb2df1d4659629820
diff --git a/core/pom.xml b/core/pom.xml
index 4b30bac..bd89d6d 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -298,7 +298,7 @@
 		<dependency>
 			<groupId>de.ids_mannheim.korap</groupId>
 			<artifactId>Krill</artifactId>
-			<version>[0.58.7,)</version>
+			<version>[0.59.0,)</version>
 			<exclusions>
 				<exclusion>
 					<groupId>org.glassfish.jersey.containers</groupId>
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 a8cba15..bd4bf89 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
@@ -124,6 +124,7 @@
     public static final int INVITATION_EXPIRED = 1605;
     public static final int GROUP_NOT_FOUND = 1606;
     public static final int GROUP_DELETED = 1607;
+    public static final int GROUP_EXISTS = 1608;
     
     /**
      * 1800 Oauth2 and OpenID
diff --git a/full/Changes b/full/Changes
index 3ab4839..0256d49 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,6 +1,8 @@
 # version 0.62.2
 17/10/2019
-   - Handled vulnerability CVE-2019-17195.
+   - Handled vulnerability CVE-2019-17195. (margaretha)
+8/11/2019
+   - Added user-group name pattern (margaretha, issue #33)
 
 # version 0.62.1
 08/07/2019
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
index e06e9b2..8eee9a4 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
@@ -8,6 +8,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
@@ -49,6 +50,8 @@
     public static Logger jlog = LogManager.getLogger(UserGroupService.class);
     public static boolean DEBUG = false;
     
+    public static Pattern groupNamePattern = Pattern.compile("[-\\w.]+");
+    
     @Autowired
     private UserGroupDao userGroupDao;
     @Autowired
@@ -215,9 +218,28 @@
     public void createUserGroup (UserGroupJson groupJson, String createdBy)
             throws KustvaktException {
 
+        String name = groupJson.getName();
+        if (!groupNamePattern.matcher(name).matches()) {
+            throw new KustvaktException(StatusCodes.INVALID_ARGUMENT,
+                    "User-group name must only contains letters, numbers, "
+                            + "underscores, hypens and spaces",
+                    name);
+        }
+        
+        try{
+            userGroupDao.retrieveGroupByName(groupJson.getName());
+            throw new KustvaktException(StatusCodes.GROUP_EXISTS,
+                    "User-group name must be unique.");
+        }
+        catch (KustvaktException e) {
+            if (e.getStatusCode() != StatusCodes.NO_RESOURCE_FOUND){
+                throw e;
+            }
+        }
+        
         int groupId=0;
         try {
-            groupId = userGroupDao.createGroup(groupJson.getName(), createdBy,
+            groupId = userGroupDao.createGroup(name, createdBy,
                     UserGroupStatus.ACTIVE);
         }
         // handle DB exceptions, e.g. unique constraint
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
index 98298c8..4f66530 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
@@ -89,10 +89,8 @@
 
     /**
      * Lists user-groups for system-admin purposes. If username
-     * parameter
-     * is not specified, list user-groups of all users. If status is
-     * not
-     * specified, list user-groups of all statuses.
+     * parameter is not specified, list user-groups of all users. If
+     * status is not specified, list user-groups of all statuses.
      * 
      * @param securityContext
      * @param username
@@ -207,10 +205,11 @@
             throw kustvaktResponseHandler.throwit(e);
         }
     }
-    
+
     @DELETE
     @Path("{groupName}")
-    public Response deleteUserGroupByName (@Context SecurityContext securityContext,
+    public Response deleteUserGroupByName (
+            @Context SecurityContext securityContext,
             @PathParam("groupName") String groupName) {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
@@ -283,7 +282,8 @@
         }
     }
 
-    /** Very similar to addMemberRoles web-service, but allows deletion 
+    /**
+     * Very similar to addMemberRoles web-service, but allows deletion
      * as well.
      * 
      * @param securityContext
@@ -383,8 +383,7 @@
 
     /**
      * Handles requests to accept membership invitation. Only invited
-     * users
-     * can subscribe to the corresponding user-group.
+     * users can subscribe to the corresponding user-group.
      * 
      * @param securityContext
      * @param groupId
@@ -411,8 +410,7 @@
 
     /**
      * Handles requests to reject membership invitation. A member can
-     * only
-     * unsubscribe him/herself from a group.
+     * only unsubscribe him/herself from a group.
      * 
      * Implemented identical to delete group member.
      * 
diff --git a/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql b/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql
index 3a0a054..ea8f1f7 100644
--- a/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql
+++ b/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql
@@ -2,61 +2,61 @@
 
 -- user groups
 INSERT INTO user_group(name,status,created_by) 
-	VALUES ("marlin group","ACTIVE","marlin");
+	VALUES ("marlin-group","ACTIVE","marlin");
 	
 INSERT INTO user_group(name,status,created_by) 
-	VALUES ("dory group","ACTIVE","dory");
+	VALUES ("dory-group","ACTIVE","dory");
 
 INSERT INTO user_group(name,status,created_by) 
-	VALUES ("auto group","HIDDEN","system");
+	VALUES ("auto-group","HIDDEN","system");
 
 --INSERT INTO user_group(name,status,created_by) 
 --	VALUES ("all users","HIDDEN","system");
 
 INSERT INTO user_group(name,status,created_by, deleted_by) 
-	VALUES ("deleted group","DELETED","dory", "dory");
+	VALUES ("deleted-group","DELETED","dory", "dory");
 
 
 
 -- user group members
 INSERT INTO user_group_member(user_id, group_id, status, created_by)
 	SELECT "marlin",
-		(SELECT id from user_group where name = "marlin group"),
+		(SELECT id from user_group where name = "marlin-group"),
 		"ACTIVE","marlin";
 
 INSERT INTO user_group_member(user_id, group_id, status, created_by)
 	SELECT "dory",
-		(SELECT id from user_group where name = "marlin group"),
+		(SELECT id from user_group where name = "marlin-group"),
 		"ACTIVE","marlin";
 		
 INSERT INTO user_group_member(user_id, group_id, status, created_by)
 	SELECT "dory",
-		(SELECT id from user_group where name = "dory group"),
+		(SELECT id from user_group where name = "dory-group"),
 		"ACTIVE","dory";
 
 INSERT INTO user_group_member(user_id, group_id, status, created_by)
 	SELECT "nemo",
-		(SELECT id from user_group where name = "dory group"),
+		(SELECT id from user_group where name = "dory-group"),
 		"ACTIVE","dory";
 
 INSERT INTO user_group_member(user_id, group_id, status, created_by)
 	SELECT "marlin",
-		(SELECT id from user_group where name = "dory group"),
+		(SELECT id from user_group where name = "dory-group"),
 		"PENDING","dory";
 	
 INSERT INTO user_group_member(user_id, group_id, status, created_by, deleted_by)
 	SELECT "pearl",
-		(SELECT id from user_group where name = "dory group"),
+		(SELECT id from user_group where name = "dory-group"),
 		"DELETED","dory", "pearl";
 
 INSERT INTO user_group_member(user_id, group_id, status, created_by)
 	SELECT "pearl",
-		(SELECT id from user_group where name = "auto group"),
+		(SELECT id from user_group where name = "auto-group"),
 		"ACTIVE","system";
 
 INSERT INTO user_group_member(user_id, group_id, status, created_by)
 	SELECT "dory",
-		(SELECT id from user_group where name = "deleted group"),
+		(SELECT id from user_group where name = "deleted-group"),
 		"ACTIVE","dory";
 
 		
@@ -89,7 +89,7 @@
 INSERT INTO virtual_corpus_access(virtual_corpus_id, user_group_id, status, created_by) 
 	SELECT 
 		(SELECT id from virtual_corpus where name = "group-vc"), 
-		(SELECT id from user_group where name = "dory group"), 
+		(SELECT id from user_group where name = "dory-group"), 
 		"ACTIVE", "dory";
 
 --INSERT INTO virtual_corpus_access(virtual_corpus_id, user_group_id, status, created_by) 
@@ -101,13 +101,13 @@
 INSERT INTO virtual_corpus_access(virtual_corpus_id, user_group_id, status, created_by) 
 	SELECT 
 		(SELECT id from virtual_corpus where name = "published-vc"),
-		(SELECT id from user_group where name = "marlin group"),
+		(SELECT id from user_group where name = "marlin-group"),
 		"ACTIVE", "marlin";
 
 INSERT INTO virtual_corpus_access(virtual_corpus_id, user_group_id, status, created_by) 
 	SELECT 
 		(SELECT id from virtual_corpus where name = "published-vc"),
-		(SELECT id from user_group where name = "auto group"),
+		(SELECT id from user_group where name = "auto-group"),
 		"HIDDEN", "system";
 
 	
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
index 5e66b23..cabc5da 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
@@ -153,7 +153,8 @@
             ClientHandlerException, KustvaktException {
 
         UserGroupJson json = new UserGroupJson();
-        json.setName("admin test group");
+        String groupName = "admin-test-group";
+        json.setName(groupName);
         json.setMembers(new String[] { "marlin", "nemo" });
 
         ClientResponse response = resource().path(API_VERSION).path("group").path("create")
@@ -171,7 +172,7 @@
         JsonNode node = listGroup(testUsername);
         assertEquals(1, node.size());
         node = node.get(0);
-        assertEquals("admin test group", node.get("name").asText());
+        assertEquals(groupName, node.get("name").asText());
 
         String groupId = node.get("id").asText();
         testMemberRole("marlin", groupId);
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
index a0876ee..52880e7 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
@@ -70,7 +70,7 @@
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
     }
 
-    // dory is a group admin in dory group
+    // dory is a group admin in dory-group
     @Test
     public void testListDoryGroups () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
@@ -86,12 +86,12 @@
         JsonNode node = JsonUtils.readTree(entity);
         JsonNode group = node.get(1);
         assertEquals(2, group.at("/id").asInt());
-        assertEquals("dory group", group.at("/name").asText());
+        assertEquals("dory-group", group.at("/name").asText());
         assertEquals("dory", group.at("/owner").asText());
         assertEquals(3, group.at("/members").size());
     }
 
-    // nemo is a group member in dory group
+    // nemo is a group member in dory-group
     @Test
     public void testListNemoGroups () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
@@ -106,7 +106,7 @@
         JsonNode node = JsonUtils.readTree(entity);
 
         assertEquals(2, node.at("/0/id").asInt());
-        assertEquals("dory group", node.at("/0/name").asText());
+        assertEquals("dory-group", node.at("/0/name").asText());
         assertEquals("dory", node.at("/0/owner").asText());
         // group members are not allowed to see other members
         assertEquals(0, node.at("/0/members").size());
@@ -151,15 +151,7 @@
         json.setName(groupName);
         json.setMembers(new String[] {});
 
-        ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("create").type(MediaType.APPLICATION_JSON)
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
-                .post(ClientResponse.class);
-
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-     
+        testCreateUserGroup(json);
         deleteGroupByName(groupName);
     }
 
@@ -171,6 +163,12 @@
         UserGroupJson json = new UserGroupJson();
         json.setName(groupName);
 
+        testCreateUserGroup(json);
+        deleteGroupByName(groupName);
+    }
+    
+    private void testCreateUserGroup (UserGroupJson json) throws UniformInterfaceException,
+            ClientHandlerException, KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
                 .path("create").type(MediaType.APPLICATION_JSON)
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
@@ -179,16 +177,30 @@
                 .post(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
+    }
+    
+    private void testCreateSameGroupName (UserGroupJson json)
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+        ClientResponse response = resource().path(API_VERSION).path("group")
+                .path("create").type(MediaType.APPLICATION_JSON)
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
+                .post(ClientResponse.class);
+
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         
-        deleteGroupByName(groupName);
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(StatusCodes.GROUP_EXISTS, node.at("/errors/0/0").asInt());
     }
     
     @Test
-    public void testUserGroup () throws UniformInterfaceException,
+    public void testCreateGroupInvalidName () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-
         UserGroupJson json = new UserGroupJson();
-        json.setName("new user group");
+        String groupName = "invalid-group-name$"; 
+        json.setName(groupName);
         json.setMembers(new String[] { "marlin", "nemo" });
 
         ClientResponse response = resource().path(API_VERSION).path("group")
@@ -197,22 +209,33 @@
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
                 .post(ClientResponse.class);
+        
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+        
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(StatusCodes.INVALID_ARGUMENT, node.at("/errors/0/0").asInt());
+        assertEquals("User-group name must only contains letters, numbers, "
+                + "underscores, hypens and spaces", node.at("/errors/0/1").asText());
+        assertEquals("invalid-group-name$", node.at("/errors/0/2").asText());
+    }
+    
+    @Test
+    public void testUserGroup () throws UniformInterfaceException,
+            ClientHandlerException, KustvaktException {
 
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        UserGroupJson json = new UserGroupJson();
+        String groupName = "new-user-group"; 
+        json.setName(groupName);
+        json.setMembers(new String[] { "marlin", "nemo" });
+
+        testCreateUserGroup(json);
+        testCreateSameGroupName(json);
 
         // list user group
-        response = resource().path(API_VERSION).path("group").path("list")
-                .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);
-        JsonNode node = JsonUtils.readTree(entity);
+        JsonNode node = retrieveUserGroups(username);;
         assertEquals(1, node.size());
         node = node.get(0);
-        assertEquals("new user group", node.get("name").asText());
+        assertEquals("new-user-group", node.get("name").asText());
         String groupId = node.get("id").asText();
 
         assertEquals(username, node.get("owner").asText());
@@ -290,7 +313,7 @@
         // dory delete pearl
         ClientResponse response = resource().path(API_VERSION).path("group")
                 .path("member")
-                // dory group
+                // dory-group
                 .path("delete").path("2").path("pearl")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
@@ -320,9 +343,9 @@
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         assertEquals(StatusCodes.GROUP_MEMBER_DELETED,
                 node.at("/errors/0/0").asInt());
-        assertEquals("pearl has already been deleted from the group dory group",
+        assertEquals("pearl has already been deleted from the group dory-group",
                 node.at("/errors/0/1").asText());
-        assertEquals("[pearl, dory group]", node.at("/errors/0/2").asText());
+        assertEquals("[pearl, dory-group]", node.at("/errors/0/2").asText());
     }
 
     private void testDeleteGroup (String groupId)
@@ -398,9 +421,9 @@
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(StatusCodes.GROUP_DELETED, node.at("/errors/0/0").asInt());
-        assertEquals("Group deleted group has been deleted.",
+        assertEquals("Group deleted-group has been deleted.",
                 node.at("/errors/0/1").asText());
-        assertEquals("deleted group", node.at("/errors/0/2").asText());
+        assertEquals("deleted-group", node.at("/errors/0/2").asText());
     }
 
     @Test
@@ -491,7 +514,7 @@
     @Test
     public void testInviteDeletedMember2 () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        // pearl has status deleted in dory group
+        // pearl has status deleted in dory-group
         String[] members = new String[] { "pearl" };
 
         UserGroupJson userGroup = new UserGroupJson();
@@ -521,7 +544,7 @@
     @Test
     public void testInvitePendingMember () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        // marlin has status PENDING in dory group
+        // marlin has status PENDING in dory-group
         String[] members = new String[] { "marlin" };
 
         UserGroupJson userGroup = new UserGroupJson();
@@ -543,16 +566,16 @@
                 node.at("/errors/0/0").asInt());
         assertEquals(
                 "Username marlin with status PENDING exists in the user-group "
-                        + "dory group",
+                        + "dory-group",
                 node.at("/errors/0/1").asText());
-        assertEquals("[marlin, PENDING, dory group]",
+        assertEquals("[marlin, PENDING, dory-group]",
                 node.at("/errors/0/2").asText());
     }
 
     @Test
     public void testInviteActiveMember () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        // nemo has status active in dory group
+        // nemo has status active in dory-group
         String[] members = new String[] { "nemo" };
 
         UserGroupJson userGroup = new UserGroupJson();
@@ -575,9 +598,9 @@
                 node.at("/errors/0/0").asInt());
         assertEquals(
                 "Username nemo with status ACTIVE exists in the user-group "
-                        + "dory group",
+                        + "dory-group",
                 node.at("/errors/0/1").asText());
-        assertEquals("[nemo, ACTIVE, dory group]",
+        assertEquals("[nemo, ACTIVE, dory-group]",
                 node.at("/errors/0/2").asText());
     }
 
@@ -604,12 +627,12 @@
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(StatusCodes.GROUP_DELETED, node.at("/errors/0/0").asInt());
-        assertEquals("Group deleted group has been deleted.",
+        assertEquals("Group deleted-group has been deleted.",
                 node.at("/errors/0/1").asText());
-        assertEquals("deleted group", node.at("/errors/0/2").asText());
+        assertEquals("deleted-group", node.at("/errors/0/2").asText());
     }
 
-    // marlin has GroupMemberStatus.PENDING in dory group
+    // marlin has GroupMemberStatus.PENDING in dory-group
     @Test
     public void testSubscribePendingMember () throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
@@ -631,7 +654,7 @@
 
         JsonNode group = node.get(1);
         assertEquals(2, group.at("/id").asInt());
-        assertEquals("dory group", group.at("/name").asText());
+        assertEquals("dory-group", group.at("/name").asText());
         assertEquals("dory", group.at("/owner").asText());
         // group members are not allowed to see other members
         assertEquals(0, group.at("/members").size());
@@ -642,16 +665,16 @@
         assertEquals(PredefinedRole.VC_ACCESS_MEMBER.name(),
                 group.at("/userRoles/1").asText());
 
-        // unsubscribe marlin from dory group
+        // unsubscribe marlin from dory-group
         testUnsubscribeActiveMember(form);
         checkGroupMemberRole("2", "marlin");
 
-        // invite marlin to dory group to set back the
+        // invite marlin to dory-group to set back the
         // GroupMemberStatus.PENDING
         testInviteDeletedMember();
     }
 
-    // pearl has GroupMemberStatus.DELETED in dory group
+    // pearl has GroupMemberStatus.DELETED in dory-group
     @Test
     public void testSubscribeDeletedMember () throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
@@ -669,7 +692,7 @@
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         assertEquals(StatusCodes.GROUP_MEMBER_DELETED,
                 node.at("/errors/0/0").asInt());
-        assertEquals("pearl has already been deleted from the group dory group",
+        assertEquals("pearl has already been deleted from the group dory-group",
                 node.at("/errors/0/1").asText());
     }
 
@@ -753,7 +776,7 @@
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(StatusCodes.GROUP_DELETED, node.at("/errors/0/0").asInt());
-        assertEquals("Group new user group has been deleted.",
+        assertEquals("Group new-user-group has been deleted.",
                 node.at("/errors/0/1").asText());
     }
 
@@ -801,9 +824,9 @@
     public void testUnsubscribeDeletedMember ()
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        // pearl unsubscribes from dory group
+        // pearl unsubscribes from dory-group
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        // dory group
+        // dory-group
         form.add("groupId", "2");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
@@ -819,9 +842,9 @@
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         assertEquals(StatusCodes.GROUP_MEMBER_DELETED,
                 node.at("/errors/0/0").asInt());
-        assertEquals("pearl has already been deleted from the group dory group",
+        assertEquals("pearl has already been deleted from the group dory-group",
                 node.at("/errors/0/1").asText());
-        assertEquals("[pearl, dory group]", node.at("/errors/0/2").asText());
+        assertEquals("[pearl, dory-group]", node.at("/errors/0/2").asText());
     }
 
     @Test
@@ -833,7 +856,7 @@
         assertEquals(2, node.size());
 
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        // dory group
+        // dory-group
         form.add("groupId", "2");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
@@ -848,7 +871,7 @@
         node = retrieveUserGroups("marlin");
         assertEquals(1, node.size());
 
-        // invite marlin to dory group to set back the
+        // invite marlin to dory-group to set back the
         // GroupMemberStatus.PENDING
         testInviteDeletedMember();
     }
@@ -939,7 +962,7 @@
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(StatusCodes.GROUP_DELETED, node.at("/errors/0/0").asInt());
-        assertEquals("Group new user group has been deleted.",
+        assertEquals("Group new-user-group has been deleted.",
                 node.at("/errors/0/1").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 cb868d3..aa0da5d 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
@@ -258,7 +258,7 @@
             ClientHandlerException, KustvaktException {
         String vcCreator = "marlin";
         String vcName = "marlin-vc";
-        String groupName = "marlin group";
+        String groupName = "marlin-group";
 
         testCreateVCAccess(vcCreator, vcName, groupName);
         JsonNode node = testlistAccessByGroup(groupName);
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 63ba359..297d3ab 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
@@ -783,7 +783,7 @@
 
     @Test
     public void testlistAccessByNonVCAAdmin () throws KustvaktException {
-        JsonNode node = testlistAccessByGroup("nemo", "dory group");
+        JsonNode node = testlistAccessByGroup("nemo", "dory-group");
         assertEquals(StatusCodes.AUTHORIZATION_FAILED,
                 node.at("/errors/0/0").asInt());
         assertEquals("Unauthorized operation for user: nemo",
@@ -814,7 +814,7 @@
     @Test
     public void testlistAccessByGroup () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("vc")
-                .path("access").queryParam("groupName", "dory group")
+                .path("access").queryParam("groupName", "dory-group")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -827,7 +827,7 @@
         assertEquals("group-vc", node.at("/0/vcName").asText());
         assertEquals(2, node.at("/0/userGroupId").asInt());
 
-        assertEquals("dory group", node.at("/0/userGroupName").asText());
+        assertEquals("dory-group", node.at("/0/userGroupName").asText());
     }
 
     @Test
@@ -835,7 +835,7 @@
             ClientHandlerException, KustvaktException {
 
         String vcName = "marlin-vc";
-        String groupName = "marlin group";
+        String groupName = "marlin-group";
 
         // check the vc type
         JsonNode node = testSearchVC("marlin", "marlin", vcName);
@@ -954,7 +954,7 @@
 
         // nemo is not VCA in marlin group
         ClientResponse response = resource().path(API_VERSION).path("vc")
-                .path("nemo").path("nemo-vc").path("share").path("marlin group")
+                .path("nemo").path("nemo-vc").path("share").path("marlin-group")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("nemo", "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")