This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit d72dba483f54fd540fcd1a722d62b982229e8c9c Author: ducnv <[email protected]> AuthorDate: Wed Apr 1 08:59:18 2020 +0700 JAMES-2888: Remove JMAPRoutes, correct CoreEcho method and test, ordering pom, remove unused [no review] commit. Just unit test, not integration yet. --- pom.xml | 5 + server/protocols/jmap-rfc-8621/pom.xml | 42 +++--- .../org/apache/james/jmap/json/Serializer.scala | 5 + .../ResponseObject.scala => method/CoreEcho.scala} | 14 +- .../ResponseObject.scala => method/Method.scala} | 13 +- .../apache/james/jmap/model/ResponseObject.scala | 5 + .../apache/james/jmap/routes/JMAPApiRoutes.scala | 99 +++++++++----- .../scala/org/apache/james/jmap/json/Fixture.scala | 13 +- .../jmap/json/RequestObjectSerializationTest.scala | 12 +- .../json/ResponseObjectSerializationTest.scala | 8 +- .../apache/james/jmap/method/CoreEchoTest.scala | 3 +- .../james/jmap/routes/JMAPApiRoutesTest.scala | 152 +++++++++++++++++++++ 12 files changed, 299 insertions(+), 72 deletions(-) diff --git a/pom.xml b/pom.xml index a30cb9b..d39bd79 100644 --- a/pom.xml +++ b/pom.xml @@ -664,6 +664,11 @@ <scope>import</scope> </dependency> <dependency> + <groupId>io.projectreactor</groupId> + <artifactId>reactor-scala-extensions_${scala.base}</artifactId> + <version>0.5.1</version> + </dependency> + <dependency> <groupId>${james.groupId}</groupId> <artifactId>apache-james-backends-cassandra</artifactId> <version>${project.version}</version> diff --git a/server/protocols/jmap-rfc-8621/pom.xml b/server/protocols/jmap-rfc-8621/pom.xml index 79dfe41..bb6a83b 100644 --- a/server/protocols/jmap-rfc-8621/pom.xml +++ b/server/protocols/jmap-rfc-8621/pom.xml @@ -33,6 +33,28 @@ <dependencies> <dependency> + <groupId>com.typesafe.play</groupId> + <artifactId>play-json_${scala.base}</artifactId> + </dependency> + <dependency> + <groupId>eu.timepit</groupId> + <artifactId>refined_${scala.base}</artifactId> + <version>0.9.13</version> + </dependency> + <dependency> + <groupId>io.rest-assured</groupId> + <artifactId>rest-assured</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.projectreactor.netty</groupId> + <artifactId>reactor-netty</artifactId> + </dependency> + <dependency> + <groupId>io.projectreactor</groupId> + <artifactId>reactor-scala-extensions_${scala.base}</artifactId> + </dependency> + <dependency> <groupId>${james.groupId}</groupId> <artifactId>james-core</artifactId> </dependency> @@ -56,25 +78,6 @@ <scope>test</scope> </dependency> <dependency> - <groupId>com.typesafe.play</groupId> - <artifactId>play-json_${scala.base}</artifactId> - </dependency> - <dependency> - <groupId>eu.timepit</groupId> - <artifactId>refined_${scala.base}</artifactId> - <version>0.9.13</version> - </dependency> - <dependency> - <groupId>io.projectreactor</groupId> - <artifactId>reactor-scala-extensions_${scala.base}</artifactId> - <version>0.5.1</version> - </dependency> - <dependency> - <groupId>io.rest-assured</groupId> - <artifactId>rest-assured</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> @@ -94,7 +97,6 @@ <artifactId>jcl-over-slf4j</artifactId> </dependency> </dependencies> - <build> <plugins> <plugin> diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala index 2189af9..173a82d 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala @@ -19,6 +19,7 @@ package org.apache.james.jmap.json +import java.io.InputStream import java.net.URL import org.apache.james.core.Username @@ -141,6 +142,10 @@ class Serializer { Json.parse(input).validate[RequestObject] } + def deserializeRequestObject(input: InputStream): JsResult[RequestObject] = { + Json.parse(input).validate[RequestObject] + } + def deserializeResponseObject(input: String): JsResult[ResponseObject] = { Json.parse(input).validate[ResponseObject] } diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEcho.scala similarity index 71% copy from server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala copy to server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEcho.scala index a50d3a2..efeb0e7 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/CoreEcho.scala @@ -16,9 +16,17 @@ * specific language governing permissions and limitations * * under the License. * * ***************************************************************/ +package org.apache.james.jmap.method -package org.apache.james.jmap.model -import org.apache.james.jmap.model.State.State +import eu.timepit.refined.auto._ +import org.apache.james.jmap.model.Invocation +import org.apache.james.jmap.model.Invocation.MethodName +import org.reactivestreams.Publisher +import reactor.core.scala.publisher.SMono -case class ResponseObject(sessionState: State, methodResponses: Seq[Invocation]) +class CoreEcho extends Method { + override val methodName = MethodName("Core/echo") + + override def process(invocation: Invocation): Publisher[Invocation] = SMono.just(invocation) +} \ No newline at end of file diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala similarity index 78% copy from server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala copy to server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala index a50d3a2..7a89b84 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/Method.scala @@ -16,9 +16,16 @@ * specific language governing permissions and limitations * * under the License. * * ***************************************************************/ +package org.apache.james.jmap.method -package org.apache.james.jmap.model -import org.apache.james.jmap.model.State.State +import org.apache.james.jmap.model.Invocation +import org.apache.james.jmap.model.Invocation.MethodName +import org.reactivestreams.Publisher + +trait Method { + val methodName: MethodName + + def process(invocation: Invocation): Publisher[Invocation] +} -case class ResponseObject(sessionState: State, methodResponses: Seq[Invocation]) diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala index a50d3a2..783801b 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/ResponseObject.scala @@ -19,6 +19,11 @@ package org.apache.james.jmap.model +import eu.timepit.refined.auto._ import org.apache.james.jmap.model.State.State case class ResponseObject(sessionState: State, methodResponses: Seq[Invocation]) + +object ResponseObject { + val SESSION_STATE: State = "75128aab4b1b" +} diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala index ddfe2fe..8336487 100644 --- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala +++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/routes/JMAPApiRoutes.scala @@ -18,52 +18,87 @@ * ***************************************************************/ package org.apache.james.jmap.routes +import java.io.InputStream +import java.nio.charset.StandardCharsets +import java.util.stream +import java.util.stream.Stream + import eu.timepit.refined.auto._ +import io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE +import io.netty.handler.codec.http.HttpMethod +import io.netty.handler.codec.http.HttpResponseStatus.OK +import org.apache.james.jmap.HttpConstants.JSON_CONTENT_TYPE +import org.apache.james.jmap.JMAPUrls.JMAP import org.apache.james.jmap.json.Serializer import org.apache.james.jmap.method.CoreEcho import org.apache.james.jmap.model.Invocation.{Arguments, MethodName} import org.apache.james.jmap.model.{Invocation, RequestObject, ResponseObject} -import org.reactivestreams.Publisher +import org.apache.james.jmap.{Endpoint, JMAPRoute, JMAPRoutes} +import org.slf4j.{Logger, LoggerFactory} import play.api.libs.json.{JsError, JsSuccess, Json} -import reactor.core.scala.publisher.SMono +import reactor.core.publisher.Mono +import reactor.core.scala.publisher.{SFlux, SMono} +import reactor.core.scheduler.Schedulers import reactor.netty.http.server.{HttpServerRequest, HttpServerResponse} -object JMAPApiRoutes { - private val ECHO_METHOD = new CoreEcho() -} +class JMAPApiRoutes extends JMAPRoutes { + override def logger(): Logger = LoggerFactory.getLogger(getClass) + + private val coreEcho = new CoreEcho -class JMAPApiRoutes { - private val echoMethod = JMAPApiRoutes.ECHO_METHOD + override def routes(): stream.Stream[JMAPRoute] = Stream.of( + JMAPRoute.builder + .endpoint(new Endpoint(HttpMethod.POST, JMAP)) + .action(this.post) + .corsHeaders, + JMAPRoute.builder + .endpoint(new Endpoint(HttpMethod.OPTIONS, JMAP)) + .action(JMAPRoutes.CORS_CONTROL) + .corsHeaders()) - def post(httpServerRequest: HttpServerRequest, httpServerResponse: HttpServerResponse): SMono[Void] = { - SMono.fromPublisher(extractRequestObject(httpServerRequest)) - .flatMap(this.process) - .doOnError(e => new RuntimeException(e.getMessage)) + private def post(httpServerRequest: HttpServerRequest, httpServerResponse: HttpServerResponse): Mono[Void] = + this.requestAsJsonStream(httpServerRequest) + .flatMap(requestObject => this.process(requestObject, httpServerResponse)) + .onErrorResume(throwable => SMono.fromPublisher(handleInternalError(httpServerResponse, throwable))) + .subscribeOn(Schedulers.elastic) + .asJava() .`then`() + + private def requestAsJsonStream(httpServerRequest: HttpServerRequest): SMono[RequestObject] = { + SMono.fromPublisher(httpServerRequest + .receive() + .aggregate() + .asInputStream()) + .flatMap(this.parseRequestObject) } - private def process(requestObject: RequestObject): SMono[ResponseObject] = { - SMono.just( - requestObject.methodCalls.map((invocation: Invocation) => - invocation.methodName match { - case echoMethod.methodName => echoMethod.process(invocation) - case _ => SMono.just(new Invocation( - MethodName("error"), - Arguments(Json.obj("type" -> "Not implemented")), - invocation.methodCallId)) - } + private def parseRequestObject(inputStream: InputStream): SMono[RequestObject] = + new Serializer().deserializeRequestObject(inputStream) match { + case JsSuccess(requestObject, _) => SMono.just(requestObject) + case JsError(errors) => SMono.raiseError(new RuntimeException(errors.toString())) + } + + private def process(requestObject: RequestObject, httpServerResponse: HttpServerResponse): SMono[Void] = + requestObject + .methodCalls + .map(this.processMethodWithMatchName) + .foldLeft(SFlux.empty[Invocation]) { (flux: SFlux[Invocation], mono: SMono[Invocation]) => flux.mergeWith(mono) } + .collectSeq() + .flatMap((invocations: Seq[Invocation]) => + SMono.fromPublisher(httpServerResponse.status(OK) + .header(CONTENT_TYPE, JSON_CONTENT_TYPE) + .sendString( + SMono.fromCallable(() => + new Serializer().serialize(ResponseObject(ResponseObject.SESSION_STATE, invocations)).toString()), + StandardCharsets.UTF_8 + ).`then`()) ) - ).flatMap((invocations: Seq[Invocation]) => SMono.just(ResponseObject(ResponseObject.SESSION_STATE, invocations))) - } - private def extractRequestObject(httpServerRequest: HttpServerRequest): Publisher[RequestObject] = { - httpServerRequest - .receive() - .asInputStream() - .flatMap(inputStream => new Serializer().deserializeRequestObject(inputStream) match { - case JsSuccess(requestObject, _) => SMono.just(new ResponseObject(ResponseObject.SESSION_STATE, requestObject.methodCalls)) - case JsError(errors) => SMono.raiseError(new RuntimeException(errors.toString())) - }) + private def processMethodWithMatchName(invocation: Invocation): SMono[Invocation] = invocation.methodName match { + case coreEcho.methodName => SMono.fromPublisher(coreEcho.process(invocation)) + case _ => SMono.just(new Invocation( + MethodName("error"), + Arguments(Json.obj("type" -> "Not implemented")), + invocation.methodCallId)) } } - diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/Fixture.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/Fixture.scala index bba26fa..e249535 100644 --- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/Fixture.scala +++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/Fixture.scala @@ -23,7 +23,7 @@ import eu.timepit.refined.auto._ import org.apache.james.jmap.model.CapabilityIdentifier.CapabilityIdentifier import org.apache.james.jmap.model.Id.Id import org.apache.james.jmap.model.Invocation.{Arguments, MethodCallId, MethodName} -import org.apache.james.jmap.model.{ClientId, CreatedIds, Invocation, ServerId} +import org.apache.james.jmap.model.{ClientId, CreatedIds, Invocation, ResponseObject, ServerId} import play.api.libs.json.Json object Fixture { @@ -32,12 +32,19 @@ object Fixture { val coreIdentifier: CapabilityIdentifier = "urn:ietf:params:jmap:core" val mailIdentifier: CapabilityIdentifier = "urn:ietf:params:jmap:mail" val invocation1: Invocation = Invocation( - methodName = MethodName("Core/echo1"), + methodName = MethodName("Core/echo"), arguments = Arguments(Json.obj("arg1" -> "arg1data", "arg2" -> "arg2data")), methodCallId = MethodCallId("c1")) val invocation2: Invocation = Invocation( - methodName = MethodName("Core/echo2"), + methodName = MethodName("Core/echo"), arguments = Arguments(Json.obj("arg3" -> "arg3data", "arg4" -> "arg4data")), methodCallId = MethodCallId("c2") ) + val unsupportedInvocation: Invocation = Invocation( + methodName = MethodName("error"), + arguments = Arguments(Json.obj("type" -> "Not implemented")), + methodCallId = MethodCallId("notsupport")) + val responseObject1: ResponseObject = ResponseObject(ResponseObject.SESSION_STATE, Seq(invocation1)) + val responseObject2: ResponseObject = ResponseObject(ResponseObject.SESSION_STATE, Seq(invocation2)) + val responseObjectWithUnsupportedMethod: ResponseObject = ResponseObject(ResponseObject.SESSION_STATE, Seq(invocation1, unsupportedInvocation)) } diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/RequestObjectSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/RequestObjectSerializationTest.scala index 173c026..4d1c5bd 100644 --- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/RequestObjectSerializationTest.scala +++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/RequestObjectSerializationTest.scala @@ -39,7 +39,7 @@ class RequestObjectSerializationTest extends AnyWordSpec with Matchers { |{ | "using": [ "urn:ietf:params:jmap:core"], | "methodCalls": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ] @@ -60,7 +60,7 @@ class RequestObjectSerializationTest extends AnyWordSpec with Matchers { |{ | "using": [ "urn:ietf:params:jmap:core"], | "methodCalls": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ] @@ -82,11 +82,11 @@ class RequestObjectSerializationTest extends AnyWordSpec with Matchers { |{ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ], - | [ "Core/echo2", { + | [ "Core/echo", { | "arg3": "arg3data", | "arg4": "arg4data" | }, "c2" ] @@ -109,7 +109,7 @@ class RequestObjectSerializationTest extends AnyWordSpec with Matchers { |{ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ] @@ -132,7 +132,7 @@ class RequestObjectSerializationTest extends AnyWordSpec with Matchers { |{ | "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ] diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala index 6dbbd8e..11c2504 100644 --- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala +++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/ResponseObjectSerializationTest.scala @@ -37,7 +37,7 @@ class ResponseObjectSerializationTest extends AnyWordSpec with Matchers { """ |{ | "methodResponses": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ] @@ -57,11 +57,11 @@ class ResponseObjectSerializationTest extends AnyWordSpec with Matchers { |{ | "sessionState": "75128aab4b1b", | "methodResponses": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ], - | [ "Core/echo2", { + | [ "Core/echo", { | "arg3": "arg3data", | "arg4": "arg4data" | }, "c2" ] @@ -82,7 +82,7 @@ class ResponseObjectSerializationTest extends AnyWordSpec with Matchers { |{ | "sessionState": "75128aab4b1b", | "methodResponses": [ - | [ "Core/echo1", { + | [ "Core/echo", { | "arg1": "arg1data", | "arg2": "arg2data" | }, "c1" ] diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoTest.scala index b723321..2d78e5f 100644 --- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoTest.scala +++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/method/CoreEchoTest.scala @@ -22,6 +22,7 @@ import org.apache.james.jmap.json.Fixture.{invocation1, invocation2} import org.apache.james.jmap.model.Invocation import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import reactor.core.scala.publisher.SMono class CoreEchoTest extends AnyWordSpec with Matchers { private val echoMethod: CoreEcho = new CoreEcho() @@ -38,7 +39,7 @@ class CoreEchoTest extends AnyWordSpec with Matchers { "success and not return anything else different than the original invocation" in { val wrongExpected: Invocation = invocation2 val dataResponse = SMono.fromPublisher(echoMethod.process(invocation1)).block() - + dataResponse should not be(wrongExpected) } } diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala new file mode 100644 index 0000000..55bf125 --- /dev/null +++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/routes/JMAPApiRoutesTest.scala @@ -0,0 +1,152 @@ +/** ************************************************************** + * 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.jmap.routes + +import java.nio.charset.StandardCharsets + +import com.google.common.collect.ImmutableSet +import io.netty.handler.codec.http.HttpHeaderNames.ACCEPT +import io.restassured.RestAssured +import io.restassured.builder.RequestSpecBuilder +import io.restassured.config.EncoderConfig.encoderConfig +import io.restassured.config.RestAssuredConfig.newConfig +import io.restassured.http.ContentType +import org.apache.http.HttpStatus +import org.apache.james.jmap.JMAPUrls.JMAP +import org.apache.james.jmap.json.Fixture._ +import org.apache.james.jmap.json.Serializer +import org.apache.james.jmap.model.RequestObject +import org.apache.james.jmap.{JMAPConfiguration, JMAPRoutesHandler, JMAPServer, Version} +import org.scalatest.BeforeAndAfter +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.matchers.should.Matchers + +class JMAPApiRoutesTest extends AnyFlatSpec with BeforeAndAfter with Matchers { + + private val TEST_CONFIGURATION: JMAPConfiguration = JMAPConfiguration.builder().enable().randomPort().build() + private val ACCEPT_JMAP_VERSION_HEADER = "application/json; jmapVersion=" + private val ACCEPT_DRAFT_VERSION_HEADER = ACCEPT_JMAP_VERSION_HEADER + Version.DRAFT.getVersion + private val ACCEPT_RFC8621_VERSION_HEADER = ACCEPT_JMAP_VERSION_HEADER + Version.RFC8621.getVersion + + private val JMAP_API_ROUTE: JMAPApiRoutes = new JMAPApiRoutes() + private val ROUTES_HANDLER: ImmutableSet[JMAPRoutesHandler] = ImmutableSet.of(new JMAPRoutesHandler(Version.RFC8621, JMAP_API_ROUTE)) + + private val REQUEST_OBJECT: String = + new Serializer().serialize(RequestObject(Seq(coreIdentifier), Seq(invocation1))).toString() + + private val REQUEST_OBJECT_WITH_UNSUPPORTED_METHOD: String = + new Serializer().serialize(RequestObject(Seq(coreIdentifier), Seq(invocation1, unsupportedInvocation))).toString() + + private val RESPONSE_OBJECT: String = new Serializer().serialize(responseObject1).toString() + private val RESPONSE_OBJECT_WITH_UNSUPPORTED_METHOD: String = new Serializer().serialize(responseObjectWithUnsupportedMethod).toString() + + var jmapServer: JMAPServer = _ + + before { + jmapServer = new JMAPServer(TEST_CONFIGURATION, ROUTES_HANDLER) + jmapServer.start() + + RestAssured.requestSpecification = new RequestSpecBuilder() + .setContentType(ContentType.JSON) + .setAccept(ContentType.JSON) + .setConfig(newConfig.encoderConfig(encoderConfig.defaultContentCharset(StandardCharsets.UTF_8))) + .setPort(jmapServer.getPort.getValue) + .setBasePath(JMAP) + .build + } + + after { + jmapServer.stop() + } + + "RFC-8621 version, GET" should "not supported and return 404 status" in { + RestAssured + .`given`() + .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) + .when() + .get + .then + .statusCode(HttpStatus.SC_NOT_FOUND) + } + + "RFC-8621 version, POST, without body" should "return 200 status" in { + RestAssured + .`given`() + .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) + .when() + .post + .then + .statusCode(HttpStatus.SC_OK) + } + + "RFC-8621 version, POST, methods include supported" should "return OK status" in { + val response = RestAssured + .`given`() + .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) + .body(REQUEST_OBJECT) + .when() + .post() + .then + .statusCode(HttpStatus.SC_OK) + .contentType(ContentType.JSON) + .extract() + .body() + .asString() + + response shouldBe (RESPONSE_OBJECT) + } + + "RFC-8621 version, POST, with methods" should "return OK status, ResponseObject depend on method" in { + + val response = RestAssured + .`given`() + .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER) + .body(REQUEST_OBJECT_WITH_UNSUPPORTED_METHOD) + .when() + .post() + .then + .statusCode(HttpStatus.SC_OK) + .contentType(ContentType.JSON) + .extract() + .body() + .asString() + + response shouldBe (RESPONSE_OBJECT_WITH_UNSUPPORTED_METHOD) + } + + "Draft version, GET" should "return 404 status" in { + RestAssured + .`given`() + .header(ACCEPT.toString, ACCEPT_DRAFT_VERSION_HEADER) + .when() + .get + .then + .statusCode(HttpStatus.SC_NOT_FOUND) + } + + "Draft version, POST, without body" should "return 400 status" in { + RestAssured + .`given`() + .header(ACCEPT.toString, ACCEPT_DRAFT_VERSION_HEADER) + .when() + .post + .then + .statusCode(HttpStatus.SC_NOT_FOUND) + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
