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

Change-Id: I578592045d0e64c2daf4cdfdb2df1d4659629820
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")