This is an automated email from the ASF dual-hosted git repository.
feiwang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-kyuubi.git
The following commit(s) were added to refs/heads/master by this push:
new fc3d282 [KYUUBI #1052] Implement api: /sessions (POST)
fc3d282 is described below
commit fc3d28295dd03f24e101068adb49337e3c1f6dbf
Author: yanghua <[email protected]>
AuthorDate: Sat Sep 11 22:52:48 2021 +0800
[KYUUBI #1052] Implement api: /sessions (POST)
<!--
Thanks for sending a pull request!
Here are some tips for you:
1. If this is your first time, please read our contributor guidelines:
https://kyuubi.readthedocs.io/en/latest/community/contributions.html
2. If the PR is related to an issue in
https://github.com/apache/incubator-kyuubi/issues, add '[KYUUBI #XXXX]' in your
PR title, e.g., '[KYUUBI #XXXX] Your PR title ...'.
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g.,
'[WIP][KYUUBI #XXXX] Your PR title ...'.
-->
### _Why are the changes needed?_
<!--
Please clarify why the changes are needed. For instance,
1. If you add a feature, you can talk about the use case of it.
2. If you fix a bug, you can clarify why it is a bug.
-->
### _How was this patch tested?_
- [ ] Add some test cases that check the changes thoroughly including
negative and positive cases if possible
- [ ] Add screenshots for manual tests if appropriate
- [ ] [Run
test](https://kyuubi.readthedocs.io/en/latest/develop_tools/testing.html#running-tests)
locally before make a pull request
Closes #1073 from yanghua/KYUUBI-1052.
Closes #1052
926a6a62 [yanghua] Addressed review suggestion
f227c042 [yanghua] [KYUUBI #1052] Implement api: /sessions (POST)
Authored-by: yanghua <[email protected]>
Signed-off-by: fwang12 <[email protected]>
---
kyuubi-server/pom.xml | 12 ++++
.../server/api/v1/dto/SessionOpenRequest.java | 72 ++++++++++++++++++++
.../server/api/v1/dto/SessionOpenedCount.java | 18 +++++
.../kyuubi/server/api/v1/SessionsResource.scala | 21 +++++-
.../kyuubi/server/RestFrontendServiceSuite.scala | 46 ++++---------
.../server/api/v1/SessionsResourceSuite.scala | 78 ++++++++++++++++++++++
pom.xml | 22 ++++++
7 files changed, 233 insertions(+), 36 deletions(-)
diff --git a/kyuubi-server/pom.xml b/kyuubi-server/pom.xml
index 8b18244..df79a6b 100644
--- a/kyuubi-server/pom.xml
+++ b/kyuubi-server/pom.xml
@@ -133,6 +133,18 @@
</dependency>
<dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-jetty</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.kyuubi</groupId>
<artifactId>kyuubi-common_${scala.binary.version}</artifactId>
<version>${project.version}</version>
diff --git
a/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenRequest.java
b/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenRequest.java
new file mode 100644
index 0000000..68f2c3a
--- /dev/null
+++
b/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenRequest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.kyuubi.server.api.v1.dto;
+
+import java.util.Map;
+
+public class SessionOpenRequest {
+
+ private int protocolVersion;
+ private String user;
+ private String password;
+ private String ipAddr;
+ private Map configs;
+
+ public SessionOpenRequest() {
+ }
+
+ public int getProtocolVersion() {
+ return protocolVersion;
+ }
+
+ public void setProtocolVersion(int protocolVersion) {
+ this.protocolVersion = protocolVersion;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getIpAddr() {
+ return ipAddr;
+ }
+
+ public void setIpAddr(String ipAddr) {
+ this.ipAddr = ipAddr;
+ }
+
+ public Map<String, String> getConfigs() {
+ return configs;
+ }
+
+ public void setConfigs(Map<String, String> configs) {
+ this.configs = configs;
+ }
+}
diff --git
a/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenedCount.java
b/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenedCount.java
index 914793b..84964b4 100644
---
a/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenedCount.java
+++
b/kyuubi-server/src/main/java/org/apache/kyuubi/server/api/v1/dto/SessionOpenedCount.java
@@ -18,6 +18,7 @@
package org.apache.kyuubi.server.api.v1.dto;
import java.io.Serializable;
+import java.util.Objects;
public class SessionOpenedCount implements Serializable {
@@ -33,4 +34,21 @@ public class SessionOpenedCount implements Serializable {
public void setOpenSessionCount(int openSessionCount) {
this.openSessionCount = openSessionCount;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SessionOpenedCount)) {
+ return false;
+ }
+ SessionOpenedCount that = (SessionOpenedCount) o;
+ return openSessionCount == that.getOpenSessionCount();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(openSessionCount);
+ }
}
diff --git
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala
index 9fcc9dd..201b2fc 100644
---
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala
+++
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/api/v1/SessionsResource.scala
@@ -17,15 +17,21 @@
package org.apache.kyuubi.server.api.v1
-import javax.ws.rs.{GET, Path, Produces}
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.scala.DefaultScalaModule
+import javax.ws.rs.{Consumes, GET, Path, POST, Produces}
import javax.ws.rs.core.MediaType
+import org.apache.hive.service.rpc.thrift.TProtocolVersion
+import scala.collection.JavaConverters.mapAsScalaMapConverter
import org.apache.kyuubi.server.api.ApiRequestContext
-import org.apache.kyuubi.server.api.v1.dto.SessionOpenedCount
+import org.apache.kyuubi.server.api.v1.dto.{SessionOpenedCount,
SessionOpenRequest}
@Produces(Array(MediaType.APPLICATION_JSON))
private[v1] class SessionsResource extends ApiRequestContext {
+ private val mapper = new ObjectMapper().registerModule(DefaultScalaModule)
+
@GET
@Path("count")
def sessionCount(): SessionOpenedCount = {
@@ -36,4 +42,15 @@ private[v1] class SessionsResource extends ApiRequestContext
{
sessionOpenedCount
}
+ @POST
+ @Consumes(Array(MediaType.APPLICATION_JSON))
+ def openSession(request : SessionOpenRequest): String = {
+ val sessionHandle = backendService.openSession(
+ TProtocolVersion.findByValue(request.getProtocolVersion),
+ request.getUser,
+ request.getPassword,
+ request.getIpAddr,
+ request.getConfigs.asScala.toMap)
+ mapper.writeValueAsString(sessionHandle)
+ }
}
diff --git
a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala
b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala
index 531bda6..4c73b7a 100644
---
a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala
+++
b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/RestFrontendServiceSuite.scala
@@ -20,20 +20,19 @@ package org.apache.kyuubi.server
import java.util.Locale
import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.module.scala.DefaultScalaModule
import org.scalatest.time.SpanSugar._
import scala.io.Source
import org.apache.kyuubi.KyuubiFunSuite
import org.apache.kyuubi.config.KyuubiConf
-import org.apache.kyuubi.server.api.v1.dto.SessionOpenedCount
-import org.apache.kyuubi.service.{NoopBackendService, NoopServer}
+import org.apache.kyuubi.service.NoopServer
import org.apache.kyuubi.service.ServiceState._
-import org.apache.kyuubi.session.{NoopSessionImpl, NoopSessionManager,
SessionManager}
class RestFrontendServiceSuite extends KyuubiFunSuite{
test("kyuubi rest frontend service basic") {
- val server = new RestNoopServer()
+ val server = new RestFrontendServiceSuite.RestNoopServer()
server.stop()
val conf = KyuubiConf()
assert(server.getServices.isEmpty)
@@ -64,7 +63,7 @@ class RestFrontendServiceSuite extends KyuubiFunSuite{
}
test("kyuubi rest frontend service http basic") {
- withKyuubiRestServer {
+ RestFrontendServiceSuite.withKyuubiRestServer {
(_, host, port) =>
eventually(timeout(10.seconds), interval(50.milliseconds)) {
val html = Source.fromURL(s"http://$host:$port/api/v1/ping").mkString
@@ -72,21 +71,17 @@ class RestFrontendServiceSuite extends KyuubiFunSuite{
}
}
}
+}
- test("kyuubi rest frontend service for sessions resource") {
- withKyuubiRestServer {
- (_, host, port) =>
- val expectedCount = new SessionOpenedCount()
- expectedCount.setOpenSessionCount(1)
- val expectedStr = new ObjectMapper().writeValueAsString(expectedCount)
+object RestFrontendServiceSuite {
- eventually(timeout(10.seconds), interval(50.milliseconds)) {
- val html =
Source.fromURL(s"http://$host:$port/api/v1/sessions/count").mkString
- assert(html.toLowerCase(Locale.ROOT).equalsIgnoreCase(expectedStr))
- }
- }
+ class RestNoopServer extends NoopServer {
+ override val frontendService = new RestFrontendService(backendService)
}
+ val OBJECT_MAPPER = new ObjectMapper().registerModule(DefaultScalaModule)
+ val TEST_SERVER_PORT = KyuubiConf().get(KyuubiConf.FRONTEND_REST_BIND_PORT)
+
def withKyuubiRestServer(f: (RestFrontendService, String, Int) => Unit):
Unit = {
val server = new RestNoopServer()
server.stop()
@@ -100,27 +95,10 @@ class RestFrontendServiceSuite extends KyuubiFunSuite{
try {
f(frontendService, conf.get(KyuubiConf.FRONTEND_REST_BIND_HOST).get,
- conf.get(KyuubiConf.FRONTEND_REST_BIND_PORT))
+ TEST_SERVER_PORT)
} finally {
server.stop()
}
}
- class RestNoopServer extends NoopServer {
- override val backendService: NoopBackendService = new RestMockedBeService
- override val frontendService = new RestFrontendService(backendService)
- }
-
- class RestMockedBeService extends NoopBackendService {
- override val sessionManager: SessionManager = new
RestMockedSessionManager()
- }
-
- class RestMockedSessionManager extends NoopSessionManager {
- // It's a ugly and temporally implementation will replace it via creation
rest API.
- var session = new NoopSessionImpl(null, null, null, null, Map(), this)
- setSession(session.handle, session)
-
- override protected def isServer: Boolean = true
- }
-
}
diff --git
a/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/SessionsResourceSuite.scala
b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/SessionsResourceSuite.scala
new file mode 100644
index 0000000..41ca013
--- /dev/null
+++
b/kyuubi-server/src/test/scala/org/apache/kyuubi/server/api/v1/SessionsResourceSuite.scala
@@ -0,0 +1,78 @@
+/*
+ * 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.kyuubi.server.api.v1
+
+import javax.ws.rs.client.Entity
+import javax.ws.rs.core.{Application, MediaType}
+
+import org.glassfish.jersey.server.ResourceConfig
+import org.glassfish.jersey.test.{JerseyTest, TestProperties}
+import org.glassfish.jersey.test.jetty.JettyTestContainerFactory
+import org.glassfish.jersey.test.spi.TestContainerFactory
+import org.junit.Test
+
+import org.apache.kyuubi.server.RestFrontendServiceSuite
+import org.apache.kyuubi.server.RestFrontendServiceSuite.{OBJECT_MAPPER,
TEST_SERVER_PORT}
+import org.apache.kyuubi.server.api.v1.dto.{SessionOpenedCount,
SessionOpenRequest}
+import org.apache.kyuubi.session.SessionHandle
+
+class SessionsResourceSuite extends JerseyTest {
+
+ override def configure: Application = {
+ forceSet(TestProperties.CONTAINER_PORT, TEST_SERVER_PORT.toString)
+ new ResourceConfig(getClass)
+ }
+
+ override def getTestContainerFactory: TestContainerFactory = new
JettyTestContainerFactory
+
+ @Test
+ def testOpenAndCountSession: Unit = {
+ val requestObj = new SessionOpenRequest
+ requestObj.setProtocolVersion(1)
+ requestObj.setUser("admin")
+ requestObj.setPassword("123456")
+ requestObj.setIpAddr("localhost")
+ val configs = new java.util.HashMap[String, String]
+ configs.put("testConfig", "testValue")
+ requestObj.setConfigs(configs)
+
+ RestFrontendServiceSuite.withKyuubiRestServer {
+ (_, _, _) =>
+ var response = target(s"api/v1/sessions")
+ .request(MediaType.APPLICATION_JSON_TYPE)
+ .post(Entity.entity(requestObj, MediaType.APPLICATION_JSON_TYPE))
+
+ assert(200 == response.getStatus)
+
+ val sessionHandle = OBJECT_MAPPER.readValue(
+ response.readEntity(classOf[String]), classOf[SessionHandle])
+
+ assert(sessionHandle.protocol.getValue == 1)
+ assert(sessionHandle.identifier != null)
+
+ // verify the open session count
+ val expectedCount = new SessionOpenedCount()
+ expectedCount.setOpenSessionCount(1)
+
+ response = target("api/v1/sessions/count").request().get()
+ val responseObj = response.readEntity(classOf[SessionOpenedCount])
+ assert(responseObj.equals(expectedCount))
+ }
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index be40371..2212752 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1292,6 +1292,28 @@
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework</groupId>
+ <artifactId>jersey-test-framework-core</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
+
+ <dependency>
+
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-jetty</artifactId>
+ <version>${jersey.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-util</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-continuation</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
</dependencies>
</dependencyManagement>