james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From btell...@apache.org
Subject [2/9] james-project git commit: JAMES-1759 WebAdminServer should allow CRUD operations on domains
Date Wed, 22 Jun 2016 08:36:42 GMT
JAMES-1759 WebAdminServer should allow CRUD operations on domains


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/6053d805
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/6053d805
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/6053d805

Branch: refs/heads/master
Commit: 6053d8056b91322988d8e70d57c79c9a2d6baa90
Parents: ff64e6d
Author: Benoit Tellier <btellier@linagora.com>
Authored: Thu Jun 16 19:13:13 2016 +0700
Committer: Benoit Tellier <btellier@linagora.com>
Committed: Wed Jun 22 15:32:24 2016 +0700

----------------------------------------------------------------------
 .../james/webadmin/routes/DomainRoutes.java     | 118 +++++++
 .../james/webadmin/utils/JsonTransformer.java   |  40 +++
 .../james/webadmin/routes/DomainRoutesTest.java | 318 +++++++++++++++++++
 3 files changed, 476 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/6053d805/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
new file mode 100644
index 0000000..bbfa522
--- /dev/null
+++ b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/routes/DomainRoutes.java
@@ -0,0 +1,118 @@
+/****************************************************************
+ * 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.james.webadmin.routes;
+
+import static org.apache.james.webadmin.Constants.SEPARATOR;
+
+import javax.inject.Inject;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+import spark.Request;
+import spark.Response;
+import spark.Service;
+
+public class DomainRoutes implements Routes {
+
+    private static final String DOMAIN_NAME = ":domainName";
+    private static final String EMPTY_BODY = "";
+    private static final Logger LOGGER = LoggerFactory.getLogger(DomainRoutes.class);
+
+    public static final String DOMAINS = "/domains";
+    public static final String SPECIFIC_DOMAIN = DOMAINS + SEPARATOR + DOMAIN_NAME;
+    public static final int MAXIMUM_DOMAIN_SIZE = 256;
+
+
+    private final DomainList domainList;
+    private final JsonTransformer jsonTransformer;
+
+    @Inject
+    public DomainRoutes(DomainList domainList, JsonTransformer jsonTransformer) {
+        this.domainList = domainList;
+        this.jsonTransformer = jsonTransformer;
+    }
+
+    @Override
+    public void define(Service service) {
+        service.get(DOMAINS,
+            (request, response) -> domainList.getDomains(),
+            jsonTransformer);
+
+        service.get(SPECIFIC_DOMAIN, this::exists);
+
+        service.put(SPECIFIC_DOMAIN, this::addDomain);
+
+        service.delete(SPECIFIC_DOMAIN, this::removeDomain);
+    }
+
+    private String removeDomain(Request request, Response response) {
+        try {
+            String domain = request.params(DOMAIN_NAME);
+            removeDomain(domain);
+        } catch (DomainListException e) {
+            LOGGER.info("{} did not exists", request.params(DOMAIN_NAME));
+        }
+        response.status(204);
+        return EMPTY_BODY;
+    }
+
+    private void removeDomain(String domain) throws DomainListException {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(domain));
+        domainList.removeDomain(domain);
+    }
+
+    private String addDomain(Request request, Response response) {
+        try {
+            addDomain(request.params(DOMAIN_NAME));
+            response.status(204);
+        } catch (DomainListException e) {
+            LOGGER.info("{} already exists", request.params(DOMAIN_NAME));
+            response.status(204);
+        } catch (IllegalArgumentException e) {
+            LOGGER.info("Invalid request for domain creation");
+            response.status(400);
+        }
+        return EMPTY_BODY;
+    }
+
+    private void addDomain(String domain) throws DomainListException {
+        Preconditions.checkArgument(!Strings.isNullOrEmpty(domain));
+        Preconditions.checkArgument(!domain.contains("@"));
+        Preconditions.checkArgument(domain.length() < MAXIMUM_DOMAIN_SIZE);
+        domainList.addDomain(domain);
+    }
+
+    private String exists(Request request, Response response) throws DomainListException
{
+        if (!domainList.containsDomain(request.params(DOMAIN_NAME))) {
+            response.status(404);
+        } else {
+            response.status(204);
+        }
+        return EMPTY_BODY;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/6053d805/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
new file mode 100644
index 0000000..c1a17f9
--- /dev/null
+++ b/server/protocols/webadmin/src/main/java/org/apache/james/webadmin/utils/JsonTransformer.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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.james.webadmin.utils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+import spark.ResponseTransformer;
+
+public class JsonTransformer implements ResponseTransformer {
+
+    private final ObjectMapper objectMapper;
+
+    public JsonTransformer() {
+        objectMapper = new ObjectMapper();
+        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+    }
+
+    @Override
+    public String render(Object o) throws Exception {
+        return objectMapper.writeValueAsString(o);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/6053d805/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
new file mode 100644
index 0000000..c401933
--- /dev/null
+++ b/server/protocols/webadmin/src/test/java/org/apache/james/webadmin/routes/DomainRoutesTest.java
@@ -0,0 +1,318 @@
+/****************************************************************
+ * 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.james.webadmin.routes;
+
+import static com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.when;
+import static com.jayway.restassured.RestAssured.with;
+import static com.jayway.restassured.config.EncoderConfig.encoderConfig;
+import static com.jayway.restassured.config.RestAssuredConfig.newConfig;
+import static org.apache.james.webadmin.Constants.SEPARATOR;
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Charsets;
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.parsing.Parser;
+
+import de.bechte.junit.runners.context.HierarchicalContextRunner;
+
+@RunWith(HierarchicalContextRunner.class)
+public class DomainRoutesTest {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DomainRoutesTest.class);
+    public static final String DOMAIN = "domain";
+
+    private WebAdminServer webAdminServer;
+
+    private void createServer(DomainList domainList) throws Exception {
+        webAdminServer = new WebAdminServer(new DomainRoutes(domainList, new JsonTransformer()));
+        webAdminServer.configure(NO_CONFIGURATION);
+        webAdminServer.await();
+
+        RestAssured.port = webAdminServer.getPort().toInt();
+        RestAssured.config = newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8));
+        RestAssured.defaultParser = Parser.JSON;
+        RestAssured.basePath = DomainRoutes.DOMAINS;
+    }
+
+    @After
+    public void stop() {
+        webAdminServer.destroy();
+    }
+
+    public class NormalBehaviour {
+
+        @Before
+        public void setUp() throws Exception {
+            DNSService dnsService = mock(DNSService.class);
+            when(dnsService.getHostName(any())).thenReturn("localhost");
+            when(dnsService.getLocalHost()).thenReturn(InetAddress.getByName("localhost"));
+
+            MemoryDomainList domainList = new MemoryDomainList();
+            domainList.setDNSService(dnsService);
+            domainList.setLog(LOGGER);
+            domainList.setAutoDetectIP(false);
+            createServer(domainList);
+        }
+
+        @Test
+        public void getDomainsShouldBeEmptyByDefault() {
+            given()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void putShouldReturnErrorWhenUsedWithEmptyDomain() {
+            given()
+                .put(SEPARATOR)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void deleteShouldReturnErrorWhenUsedWithEmptyDomain() {
+            given()
+                .delete(SEPARATOR)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldBeOk() {
+            given()
+                .put(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainsShouldDisplayAddedDomains() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(containsString(DOMAIN));
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWhenNameContainsAT() {
+            when()
+                .put(DOMAIN + "@" + DOMAIN)
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWhenNameContainsUrlSeparator() {
+            when()
+                .put(DOMAIN + "/" + DOMAIN)
+            .then()
+                .statusCode(404);
+        }
+
+        @Test
+        public void putShouldReturnUserErrorWhenNameIsTooLong() {
+            when()
+                .put(DOMAIN + "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789."
+
+                    "0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789.0123456789."
+
+                    "0123456789.0123456789.0123456789.")
+            .then()
+                .statusCode(400);
+        }
+
+        @Test
+        public void putShouldWorkOnTheSecondTimeForAGivenValue() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .put(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void deleteShouldRemoveTheGivenDomain() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(204);
+
+            when()
+                .get()
+            .then()
+                .statusCode(200)
+                .body(is("[]"));
+        }
+
+        @Test
+        public void deleteShouldBeOkWhenTheDomainIsNotPresent() {
+            given()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainShouldReturnOkWhenTheDomainIsPresent() {
+            with()
+                .put(DOMAIN);
+
+            when()
+                .get(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainShouldReturnNotFoundWhenTheDomainIsAbsent() {
+            given()
+                .get(DOMAIN)
+            .then()
+                .statusCode(404);
+        }
+
+    }
+
+    public class ExceptionHandling {
+
+        private DomainList domainList;
+        private String domain;
+
+        @Before
+        public void setUp() throws Exception {
+            domainList = mock(DomainList.class);
+            createServer(domainList);
+            domain = "domain";
+        }
+
+        @Test
+        public void deleteShouldReturnErrorOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(domainList).removeDomain(domain);
+
+            when()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void putShouldReturnErrorOnUnknownException() throws Exception {
+            doThrow(new RuntimeException()).when(domainList).addDomain(domain);
+
+            when()
+                .put(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getDomainShouldReturnErrorOnUnknownException() throws Exception {
+            when(domainList.containsDomain(domain)).thenThrow(new RuntimeException());
+
+            when()
+                .get(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getDomainsShouldReturnErrorOnUnknownException() throws Exception {
+            when(domainList.getDomains()).thenThrow(new RuntimeException());
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void deleteShouldReturnOkWhenDomainListException() throws Exception {
+            doThrow(new DomainListException("message")).when(domainList).removeDomain(domain);
+
+            when()
+                .delete(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void putShouldReturnOkWhenDomainListException() throws Exception {
+            doThrow(new DomainListException("message")).when(domainList).addDomain(domain);
+
+            when()
+                .put(DOMAIN)
+            .then()
+                .statusCode(204);
+        }
+
+        @Test
+        public void getDomainShouldReturnErrorOnDomainListException() throws Exception {
+            when(domainList.containsDomain(domain)).thenThrow(new DomainListException("message"));
+
+            when()
+                .get(DOMAIN)
+            .then()
+                .statusCode(500);
+        }
+
+        @Test
+        public void getDomainsShouldReturnErrorOnDomainListException() throws Exception {
+            when(domainList.getDomains()).thenThrow(new DomainListException("message"));
+
+            when()
+                .get()
+            .then()
+                .statusCode(500);
+        }
+
+    }
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Mime
View raw message