You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by zh...@apache.org on 2019/11/22 07:01:21 UTC

[submarine] branch master updated: SUBMARINE-293. Refactoring submarine server rest test framework

This is an automated email from the ASF dual-hosted git repository.

zhouquan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 4374f20  SUBMARINE-293. Refactoring submarine server rest test framework
4374f20 is described below

commit 4374f2034ed0dadb7755a942eec522fc322cf569
Author: Xun Liu <li...@apache.org>
AuthorDate: Thu Nov 21 21:08:38 2019 +0800

    SUBMARINE-293. Refactoring submarine server rest test framework
    
    ### What is this PR for?
    Provides a way to actually run the submarin server REST service and test the rest interface in the test case.
    This provides a realistic runtime environment to test whether each REST interface is working correctly.
    
    ### What type of PR is it?
    [Refactoring]
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/SUBMARINE-293
    
    ### How should this be tested?
    * [CI Pass](https://travis-ci.org/liuxunorg/submarine/builds/615024635)
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Xun Liu <li...@apache.org>
    
    Closes #98 from liuxunorg/SUBMARINE-293 and squashes the following commits:
    
    399be2b [Xun Liu] Change to GitHttpRequest
    fc10476 [Xun Liu] SUBMARINE-293. Refactoring submarine server rest test framework
---
 .../server/jobserver/rest/api/JobApi.java          |   2 +-
 .../jobserver/rest/dao/JsonExclusionStrategy.java  |  33 ----
 .../server/jobserver/rest/dao/JsonResponse.java    | 205 ---------------------
 .../utils => response}/DictAnnotation.java         |   4 +-
 .../server => response}/JsonExclusionStrategy.java |   2 +-
 .../server => response}/JsonResponse.java          |   7 +-
 .../GitHttpRequest.java}                           |   6 +-
 .../{workbench/database => }/utils/GitUtils.java   |   2 +-
 ...tisGeneratorMain.java => MybatisGenerator.java} |   4 +-
 .../server/workbench/rest/LoginRestApi.java        |   2 +-
 .../server/workbench/rest/ProjectRestApi.java      |   4 +-
 .../server/workbench/rest/SysDeptRestApi.java      |   4 +-
 .../server/workbench/rest/SysDictItemRestApi.java  |   4 +-
 .../server/workbench/rest/SysDictRestApi.java      |   4 +-
 .../server/workbench/rest/SysUserRestApi.java      |   4 +-
 .../server/workbench/rest/SystemRestApi.java       |   4 +-
 .../server/workbench/rest/TeamRestApi.java         |   4 +-
 .../submarine/jobserver/rest/api/JobApiTest.java   | 139 --------------
 ...rTest.java => AbstractSubmarineServerTest.java} | 141 ++++++++++++--
 ...erTest.java => SubmarineServerClusterTest.java} |  28 +--
 .../server/jobserver/rest/api/JobApiTest.java      | 167 +++++++++++++++++
 .../server => response}/JsonResponseTest.java      |   6 +-
 .../{workbench/server => utils}/GitUtilsTest.java  |   5 +-
 .../apache/submarine/server}/utils/TestUtils.java  |   2 +-
 .../database/utils/DictAnnotationTest.java         |   3 +-
 .../server/workbench/rest/CommonDataTest.java      |   4 +-
 .../server/workbench/rest/SysDeptRestApiTest.java  |   4 +-
 .../workbench/rest/SysDictItemRestApiTest.java     |   4 +-
 .../server/workbench/rest/SysDictRestApiTest.java  |   4 +-
 .../workbench/websocket/NotebookServerTest.java    |   8 +-
 30 files changed, 353 insertions(+), 457 deletions(-)

diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/api/JobApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/api/JobApi.java
index 039d196..f9776d1 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/api/JobApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/api/JobApi.java
@@ -18,9 +18,9 @@
 
 package org.apache.submarine.server.jobserver.rest.api;
 
-import org.apache.submarine.server.jobserver.rest.dao.JsonResponse;
 import org.apache.submarine.server.jobserver.rest.dao.MLJobSpec;
 import org.apache.submarine.server.jobserver.rest.dao.RestConstants;
+import org.apache.submarine.server.response.JsonResponse;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/dao/JsonExclusionStrategy.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/dao/JsonExclusionStrategy.java
deleted file mode 100644
index 9218ac4..0000000
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/dao/JsonExclusionStrategy.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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.submarine.server.jobserver.rest.dao;
-
-import com.google.gson.ExclusionStrategy;
-import com.google.gson.FieldAttributes;
-
-public class JsonExclusionStrategy implements ExclusionStrategy {
-  public boolean shouldSkipClass(Class<?> arg0) {
-    return false;
-  }
-
-  public boolean shouldSkipField(FieldAttributes f) {
-    return false;
-  }
-}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/dao/JsonResponse.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/dao/JsonResponse.java
deleted file mode 100644
index e6dcccc..0000000
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/jobserver/rest/dao/JsonResponse.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * 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.submarine.server.jobserver.rest.dao;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.TypeAdapter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.ws.rs.core.NewCookie;
-import javax.ws.rs.core.Response;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Json response builder.
- *
- * @param <T> can be an object or a ListResult
- */
-public class JsonResponse<T> {
-  private static final Logger LOG = LoggerFactory.getLogger(JsonResponse.class);
-
-  private final javax.ws.rs.core.Response.Status status;
-  private final int code;
-  private final Boolean success;
-  private final String message;
-  private final T result;
-  private final transient ArrayList<NewCookie> cookies;
-  private final transient boolean pretty = false;
-  private final Map<String, Object> attributes;
-
-  private static Gson safeGson = null;
-
-  private static final String CGLIB_PROPERTY_PREFIX = "\\$cglib_prop_";
-
-  private JsonResponse(Builder builder) {
-    this.status = builder.status;
-    this.code = builder.code;
-    this.success = builder.success;
-    this.message = builder.message;
-    this.attributes = builder.attributes;
-    this.result = (T) builder.result;
-    this.cookies = builder.cookies;
-  }
-
-  public T getResult() {
-    return result;
-  }
-
-  public Boolean getSuccess() {
-    return success;
-  }
-
-  @VisibleForTesting
-  public Map<String, Object> getAttributes() {
-    return attributes;
-  }
-
-  public static class Builder<T> {
-    private javax.ws.rs.core.Response.Status status;
-    private int code;
-    private Boolean success;
-    private String message;
-    private T result;
-    private Map<String, Object> attributes = new HashMap<>();
-    private transient ArrayList<NewCookie> cookies;
-    private transient boolean pretty = false;
-
-    public Builder(javax.ws.rs.core.Response.Status status) {
-      this.status = status;
-      this.code = status.getStatusCode();
-    }
-
-    public Builder(int code) {
-      this.code = code;
-    }
-
-    public Builder attribute(String key, Object value) {
-      this.attributes.put(key, value);
-      return this;
-    }
-
-    public Builder success(Boolean success) {
-      this.success = success;
-      return this;
-    }
-
-    public Builder message(String message) {
-      this.message = message;
-      return this;
-    }
-
-    public Builder result(T result) {
-      this.result = result;
-      return this;
-    }
-
-    public Builder code(int code) {
-      this.code = code;
-      return this;
-    }
-
-    public Builder cookies(ArrayList<NewCookie> newCookies) {
-      if (cookies == null) {
-        cookies = new ArrayList<>();
-      }
-      cookies.addAll(newCookies);
-      return this;
-    }
-
-    public javax.ws.rs.core.Response build() {
-      JsonResponse jsonResponse = new JsonResponse(this);
-      return jsonResponse.build();
-    }
-  }
-
-  @Override
-  public String toString() {
-    if (safeGson == null) {
-      GsonBuilder gsonBuilder = new GsonBuilder();
-      if (pretty) {
-        gsonBuilder.setPrettyPrinting();
-      }
-      gsonBuilder.setExclusionStrategies(new JsonExclusionStrategy());
-
-      // Trick to get the DefaultDateTypeAdatpter instance
-      // Create a first instance a Gson
-      Gson gson = gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss").create();
-
-      // Get the date adapter
-      TypeAdapter<Date> dateTypeAdapter = gson.getAdapter(Date.class);
-
-      // Ensure the DateTypeAdapter is null safe
-      TypeAdapter<Date> safeDateTypeAdapter = dateTypeAdapter.nullSafe();
-
-      safeGson = new GsonBuilder()
-          .registerTypeAdapter(Date.class, safeDateTypeAdapter)
-          .serializeNulls().create();
-    }
-
-    String json = safeGson.toJson(this);
-
-    return json;
-  }
-
-  private synchronized javax.ws.rs.core.Response build() {
-    Response.ResponseBuilder r = javax.ws.rs.core.Response.status(status).entity(this.toString());
-    if (cookies != null) {
-      for (NewCookie nc : cookies) {
-        r.cookie(nc);
-      }
-    }
-    return r.build();
-  }
-
-  // list result type response
-  // Used to return a list of records
-  public static class ListResult<T> {
-    private List<T> records;
-    private long total;
-
-    public ListResult(List<T> records, long total) {
-      this.records = records;
-      this.total = total;
-    }
-
-    public List<T> getRecords() {
-      return records;
-    }
-
-    public void setRecords(List<T> records) {
-      this.records = records;
-    }
-
-    public long getTotal() {
-      return total;
-    }
-
-    public void setTotal(long total) {
-      this.total = total;
-    }
-  }
-}
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/DictAnnotation.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/DictAnnotation.java
similarity index 97%
rename from submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/DictAnnotation.java
rename to submarine-server/server-core/src/main/java/org/apache/submarine/server/response/DictAnnotation.java
index 025185c..fae3575 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/DictAnnotation.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/DictAnnotation.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.submarine.server.workbench.database.utils;
+package org.apache.submarine.server.response;
 
 import net.sf.cglib.beans.BeanGenerator;
 import net.sf.cglib.beans.BeanMap;
@@ -24,7 +24,7 @@ import org.apache.commons.lang.StringUtils;
 import org.apache.submarine.server.workbench.annotation.Dict;
 import org.apache.submarine.server.workbench.database.entity.SysDictItem;
 import org.apache.submarine.server.workbench.database.service.SysDictItemService;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/server/JsonExclusionStrategy.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonExclusionStrategy.java
similarity index 95%
rename from submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/server/JsonExclusionStrategy.java
rename to submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonExclusionStrategy.java
index c01966a..ba62662 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/server/JsonExclusionStrategy.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonExclusionStrategy.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.submarine.server.workbench.server;
+package org.apache.submarine.server.response;
 
 import com.google.gson.ExclusionStrategy;
 import com.google.gson.FieldAttributes;
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/server/JsonResponse.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonResponse.java
similarity index 97%
rename from submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/server/JsonResponse.java
rename to submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonResponse.java
index 4f58960..1c5a0e9 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/server/JsonResponse.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/response/JsonResponse.java
@@ -16,13 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.submarine.server.workbench.server;
+package org.apache.submarine.server.response;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.TypeAdapter;
-import org.apache.submarine.server.workbench.database.utils.DictAnnotation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -78,6 +77,10 @@ public class JsonResponse<T> {
     return attributes;
   }
 
+  public int getCode() {
+    return code;
+  }
+
   public static class Builder<T> {
     private javax.ws.rs.core.Response.Status status;
     private int code;
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/HttpRequestUtil.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/utils/GitHttpRequest.java
similarity index 95%
rename from submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/HttpRequestUtil.java
rename to submarine-server/server-core/src/main/java/org/apache/submarine/server/utils/GitHttpRequest.java
index f374146..50d301f 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/HttpRequestUtil.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/utils/GitHttpRequest.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.submarine.server.workbench.database.utils;
+package org.apache.submarine.server.utils;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,8 +32,8 @@ import java.net.URLConnection;
 import java.util.Date;
 import java.util.Map;
 
-public class HttpRequestUtil {
-  private static final Logger LOG = LoggerFactory.getLogger(HttpRequestUtil.class);
+public class GitHttpRequest {
+  private static final Logger LOG = LoggerFactory.getLogger(GitHttpRequest.class);
 
   /**
    * Sends an HTTP request to the specified URL
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/GitUtils.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/utils/GitUtils.java
similarity index 99%
rename from submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/GitUtils.java
rename to submarine-server/server-core/src/main/java/org/apache/submarine/server/utils/GitUtils.java
index 666648b..7c0dca0 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/GitUtils.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/utils/GitUtils.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.submarine.server.workbench.database.utils;
+package org.apache.submarine.server.utils;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.ListBranchCommand;
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGeneratorMain.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGenerator.java
similarity index 95%
rename from submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGeneratorMain.java
rename to submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGenerator.java
index 68eb63a..f0f28e0 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGeneratorMain.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/database/utils/MybatisGenerator.java
@@ -34,7 +34,7 @@ import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 
-public class MybatisGeneratorMain {
+public class MybatisGenerator {
   private static final Logger LOG = LoggerFactory.getLogger(TeamService.class);
 
   public static void main(String[] args) {
@@ -42,7 +42,7 @@ public class MybatisGeneratorMain {
     boolean overwrite = true;
     // If a null pointer here, write directly absolute path.
     String genCfg = "/mbgConfiguration.xml";
-    File configFile = new File(MybatisGeneratorMain.class.getResource(genCfg).getFile());
+    File configFile = new File(MybatisGenerator.class.getResource(genCfg).getFile());
     ConfigurationParser cp = new ConfigurationParser(warnings);
     Configuration config = null;
     try {
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/LoginRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/LoginRestApi.java
index 3149735..0394115 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/LoginRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/LoginRestApi.java
@@ -25,7 +25,7 @@ import org.apache.submarine.server.workbench.annotation.SubmarineApi;
 import org.apache.submarine.server.workbench.database.MyBatisUtil;
 import org.apache.submarine.server.workbench.database.entity.SysUser;
 import org.apache.submarine.server.workbench.database.mappers.SysUserMapper;
-import org.apache.submarine.server.workbench.server.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/ProjectRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/ProjectRestApi.java
index 28ea7f0..8741c0c 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/ProjectRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/ProjectRestApi.java
@@ -22,8 +22,8 @@ import com.github.pagehelper.PageInfo;
 import org.apache.submarine.server.workbench.annotation.SubmarineApi;
 import org.apache.submarine.server.workbench.database.entity.Project;
 import org.apache.submarine.server.workbench.database.service.ProjectService;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDeptRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDeptRestApi.java
index 891d9f2..0db262a 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDeptRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDeptRestApi.java
@@ -28,8 +28,8 @@ import org.apache.submarine.server.workbench.database.entity.SysDeptTree;
 import org.apache.submarine.server.workbench.database.entity.SysDept;
 import org.apache.submarine.server.workbench.database.mappers.SysDeptMapper;
 import org.apache.submarine.server.workbench.database.utils.DepartmentUtil;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApi.java
index 79d0f9f..29f5dbc 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApi.java
@@ -27,8 +27,8 @@ import org.apache.submarine.server.workbench.database.MyBatisUtil;
 import org.apache.submarine.server.workbench.database.entity.SysDictItem;
 import org.apache.submarine.server.workbench.database.mappers.SysDictItemMapper;
 import org.apache.submarine.server.workbench.database.service.SysDictItemService;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictRestApi.java
index 0dfcbf7..b5d4fff 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysDictRestApi.java
@@ -26,8 +26,8 @@ import org.apache.submarine.server.workbench.annotation.SubmarineApi;
 import org.apache.submarine.server.workbench.database.MyBatisUtil;
 import org.apache.submarine.server.workbench.database.entity.SysDict;
 import org.apache.submarine.server.workbench.database.mappers.SysDictMapper;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysUserRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysUserRestApi.java
index 6107831..8728897 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysUserRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SysUserRestApi.java
@@ -28,8 +28,8 @@ import org.apache.submarine.server.workbench.entity.Action;
 import org.apache.submarine.server.workbench.entity.Permission;
 import org.apache.submarine.server.workbench.entity.Role;
 import org.apache.submarine.server.workbench.entity.UserInfo;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SystemRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SystemRestApi.java
index 3e26689..83ab0b3 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SystemRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/SystemRestApi.java
@@ -26,8 +26,8 @@ import org.apache.submarine.server.workbench.database.MyBatisUtil;
 import org.apache.submarine.server.workbench.database.entity.SysUser;
 import org.apache.submarine.server.workbench.database.mappers.SystemMapper;
 import org.apache.submarine.server.workbench.database.service.SysUserService;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/TeamRestApi.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/TeamRestApi.java
index 6eae8af..6149e9c 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/TeamRestApi.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/rest/TeamRestApi.java
@@ -22,8 +22,8 @@ import com.github.pagehelper.PageInfo;
 import org.apache.submarine.server.workbench.annotation.SubmarineApi;
 import org.apache.submarine.server.workbench.database.entity.Team;
 import org.apache.submarine.server.workbench.database.service.TeamService;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/jobserver/rest/api/JobApiTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/jobserver/rest/api/JobApiTest.java
deleted file mode 100644
index 3dad526..0000000
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/jobserver/rest/api/JobApiTest.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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.submarine.jobserver.rest.api;
-
-import org.junit.Test;
-
-public class JobApiTest { //extends JerseyTest {
-  /*
-  @Override
-  protected Application configure() {
-    return new ResourceConfig(JobApi.class);
-  }*/
-
-  @Test
-  public void testJobServerPing() {
-    /*
-    String str = "Pong";
-    Response response = target(RestConstants.V1 + "/"
-        + RestConstants.JOBS + "/" + RestConstants.PING)
-        .request()
-        .get();
-    Gson gson = new Gson();
-    JsonResponse r = gson.fromJson(response.getEntity().toString(),
-        JsonResponse.class);
-    assertEquals("Response code should be 200 ",
-        Response.Status.OK.getStatusCode(), response.getStatus());
-    assertEquals("Response message should be " + str,
-        str, r.getResult().toString());*/
-  }
-
-  // Test job created with correct JSON input
-  @Test
-  public void testCreateJobWhenJsonInputIsCorrectThenResponseCodeAccepted() {
-    /*
-    String jobSpec = "{\"type\": \"tensorflow\", \"version\":\"v1.13\"}";
-    Response response = target(RestConstants.V1 + "/" + RestConstants.JOBS)
-        .request()
-        .post(Entity.entity(jobSpec, MediaType.APPLICATION_JSON));
-
-    assertEquals("Http Response should be 202 ",
-        Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
-     */
-  }
-
-  // Test job created with incorrect JSON input
-  @Test
-  public void testCreateJobWhenJsonInputIsWrongThenResponseCodeBadRequest() {
-    /*
-    String jobSpec = "{\"ttype\": \"tensorflow\", \"version\":\"v1.13\"}";
-    Response response = target(RestConstants.V1 + "/" + RestConstants.JOBS)
-        .request()
-        .post(Entity.entity(jobSpec, MediaType.APPLICATION_JSON));
-
-    assertEquals("Http Response should be 400 ",
-        Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus());*/
-  }
-
-  // Test get job list
-  @Test
-  public void testGetJobList() {/*
-    Response response = target(RestConstants.V1 + "/" + RestConstants.JOBS)
-        .request()
-        .get();
-
-    assertEquals("Http Response should be 200 ",
-        Response.Status.OK.getStatusCode(), response.getStatus());*/
-  }
-
-  // Test get job by id
-  @Test
-  public void testGetJobById() {/*
-    String jobId = "job1";
-    Response response = target(RestConstants.V1 + "/"
-        + RestConstants.JOBS + "/" + jobId)
-        .request()
-        .get();
-    Gson gson = new Gson();
-    JsonResponse r = gson.fromJson(response.getEntity().toString(),
-        JsonResponse.class);
-    assertEquals("Http Response should be 200 ",
-        Response.Status.OK.getStatusCode(), response.getStatus());
-    assertEquals("Job id should be " + jobId,
-        jobId, r.getResult().toString());*/
-  }
-
-  // Test delete job by id
-  @Test
-  public void testDeleteJobById() {/*
-    String jobId = "job1";
-    Response response = target(RestConstants.V1 + "/"
-        + RestConstants.JOBS + "/" + jobId)
-        .request()
-        .delete();
-    Gson gson = new Gson();
-    JsonResponse r = gson.fromJson(response.getEntity().toString(),
-        JsonResponse.class);
-    assertEquals("Http Response should be 200 ",
-        Response.Status.OK.getStatusCode(), response.getStatus());
-    assertEquals("Deleted job id should be " + jobId,
-        jobId, r.getResult().toString());*/
-  }
-
-  /**
-   * FiXME. The manual YAML test with postman works but failed here.
-   * We need to figure out why the YAML entity provider not work in this test.
-   * */
-  @Test
-  public void testCreateJobWhenYamlInputIsCorrectThenResponseCodeAccepted() {
-//    Client client = ClientBuilder.newBuilder()
-//        .register(new YamlEntityProvider<>()).build();
-//    this.setClient(client);
-//    String jobSpec = "type: tf";
-//    Response response = target(RestConstants.V1 + "/"
-//        + RestConstants.JOBS + "/" + "test")
-//        .request()
-//        .put(Entity.entity(jobSpec, "application/yaml"));
-//
-//    assertEquals("Http Response should be 202 ",
-//        Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
-  }
-
-}
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/AbstractWorkbenchServerTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/AbstractSubmarineServerTest.java
similarity index 59%
rename from submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/AbstractWorkbenchServerTest.java
rename to submarine-server/server-core/src/test/java/org/apache/submarine/server/AbstractSubmarineServerTest.java
index 2ff3b8a..fbc550c 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/AbstractWorkbenchServerTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/AbstractSubmarineServerTest.java
@@ -14,38 +14,47 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.submarine.server.workbench.server;
+package org.apache.submarine.server;
 
 import com.google.gson.JsonElement;
 import com.google.gson.JsonParseException;
 import com.google.gson.JsonParser;
+import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.cookie.CookiePolicy;
+import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
+import org.apache.commons.httpclient.methods.DeleteMethod;
 import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.commons.httpclient.methods.RequestEntity;
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.submarine.commons.utils.SubmarineConfiguration;
-import org.apache.submarine.server.SubmarineServer;
-import org.apache.submarine.server.workbench.utils.TestUtils;
+import org.apache.submarine.server.utils.TestUtils;
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.ws.rs.core.MediaType;
 import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.regex.Pattern;
 
-public abstract class AbstractWorkbenchServerTest {
+public abstract class AbstractSubmarineServerTest {
   protected static final Logger LOG =
-      LoggerFactory.getLogger(AbstractWorkbenchServerTest.class);
+      LoggerFactory.getLogger(AbstractSubmarineServerTest.class);
 
   static final String WEBSOCKET_API_URL = "/ws";
   static final String URL = getUrlToTest();
   protected static final boolean WAS_RUNNING = checkIfServerIsRunning();
 
-  protected static File workbenchServerHome;
+  protected static File submarineServerHome;
   protected static File confDir;
 
   public static String getWebsocketApiUrlToTest() {
@@ -79,14 +88,14 @@ public abstract class AbstractWorkbenchServerTest {
   };
 
   public static void startUp(String testClassName) throws Exception {
-    LOG.info("Starting WorkbenchServer testClassName: {}", testClassName);
+    LOG.info("Starting SubmarineServer testClassName: {}", testClassName);
 
     if (!WAS_RUNNING) {
       // copy the resources files to a temp folder
-      workbenchServerHome = new File("..");
-      LOG.info("SUBMARINE_WORKBENCH_SERVER_HOME: "
-          + workbenchServerHome.getAbsolutePath());
-      confDir = new File(workbenchServerHome, "conf_" + testClassName);
+      submarineServerHome = new File("..");
+      LOG.info("SUBMARINE_SERVER_HOME: "
+          + submarineServerHome.getAbsolutePath());
+      confDir = new File(submarineServerHome, "conf_" + testClassName);
       confDir.mkdirs();
 
       System.setProperty(SubmarineConfiguration.ConfVars.WORKBENCH_WEB_WAR.getVarName(),
@@ -95,11 +104,11 @@ public abstract class AbstractWorkbenchServerTest {
           confDir.getAbsolutePath());
 
       // some test profile does not build workbench-web.
-      // to prevent submarine workbench server starting up fail,
+      // to prevent submarine server starting up fail,
       // create workbench-web/dist directory
       new File("../workbench-web/dist").mkdirs();
 
-      LOG.info("Staring test workbench server up...");
+      LOG.info("Staring test Submarine server up...");
 
       executor = Executors.newSingleThreadExecutor();
       executor.submit(SERVER);
@@ -113,9 +122,9 @@ public abstract class AbstractWorkbenchServerTest {
         }
       }
       if (started == false) {
-        throw new RuntimeException("Can not start workbench server.");
+        throw new RuntimeException("Can not start Submarine server.");
       }
-      LOG.info("Test workbench server stared.");
+      LOG.info("Test Submarine server stared.");
     }
   }
 
@@ -134,7 +143,7 @@ public abstract class AbstractWorkbenchServerTest {
 
   protected static void shutDown(final boolean deleteConfDir) throws Exception {
     if (!WAS_RUNNING) {
-      LOG.info("Terminating test workbench server...");
+      LOG.info("Terminating test Submarine server...");
       SubmarineServer.jettyWebServer.stop();
       executor.shutdown();
 
@@ -149,10 +158,10 @@ public abstract class AbstractWorkbenchServerTest {
         }
       }
       if (started == true) {
-        throw new RuntimeException("Can not stop Submarine workbench server");
+        throw new RuntimeException("Can not stop Submarine server");
       }
 
-      LOG.info("Test Submarine workbench server terminated.");
+      LOG.info("Test Submarine server terminated.");
 
       if (deleteConfDir) {
         FileUtils.deleteDirectory(confDir);
@@ -160,6 +169,68 @@ public abstract class AbstractWorkbenchServerTest {
     }
   }
 
+  protected static PostMethod httpPost(String path, String body) throws IOException {
+    return httpPost(path, body, StringUtils.EMPTY, StringUtils.EMPTY);
+  }
+
+  protected static PostMethod httpPost(String path, String request, String user, String pwd)
+      throws IOException {
+    LOG.info("Connecting to {}", URL + path);
+
+    HttpClient httpClient = new HttpClient();
+    PostMethod postMethod = new PostMethod(URL + path);
+    postMethod.setRequestBody(request);
+    postMethod.setRequestHeader("Content-type", MediaType.APPLICATION_JSON);
+    postMethod.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
+
+    if (userAndPasswordAreNotBlank(user, pwd)) {
+      postMethod.setRequestHeader("Cookie", "JSESSIONID=" + getCookie(user, pwd));
+    }
+
+    httpClient.executeMethod(postMethod);
+
+    LOG.info("{} - {}", postMethod.getStatusCode(), postMethod.getStatusText());
+
+    return postMethod;
+  }
+
+  protected static PutMethod httpPut(String path, String body) throws IOException {
+    return httpPut(path, body, StringUtils.EMPTY, StringUtils.EMPTY);
+  }
+
+  protected static PutMethod httpPut(String path, String body, String user, String pwd) throws IOException {
+    LOG.info("Connecting to {}", URL + path);
+    HttpClient httpClient = new HttpClient();
+    PutMethod putMethod = new PutMethod(URL + path);
+    putMethod.addRequestHeader("Origin", URL);
+    putMethod.setRequestHeader("Content-type", "application/yaml");
+    RequestEntity entity = new ByteArrayRequestEntity(body.getBytes("UTF-8"));
+    putMethod.setRequestEntity(entity);
+    if (userAndPasswordAreNotBlank(user, pwd)) {
+      putMethod.setRequestHeader("Cookie", "JSESSIONID=" + getCookie(user, pwd));
+    }
+    httpClient.executeMethod(putMethod);
+    LOG.info("{} - {}", putMethod.getStatusCode(), putMethod.getStatusText());
+    return putMethod;
+  }
+
+  protected static DeleteMethod httpDelete(String path) throws IOException {
+    return httpDelete(path, StringUtils.EMPTY, StringUtils.EMPTY);
+  }
+
+  protected static DeleteMethod httpDelete(String path, String user, String pwd) throws IOException {
+    LOG.info("Connecting to {}", URL + path);
+    HttpClient httpClient = new HttpClient();
+    DeleteMethod deleteMethod = new DeleteMethod(URL + path);
+    deleteMethod.addRequestHeader("Origin", URL);
+    if (userAndPasswordAreNotBlank(user, pwd)) {
+      deleteMethod.setRequestHeader("Cookie", "JSESSIONID=" + getCookie(user, pwd));
+    }
+    httpClient.executeMethod(deleteMethod);
+    LOG.info("{} - {}", deleteMethod.getStatusCode(), deleteMethod.getStatusText());
+    return deleteMethod;
+  }
+
   protected static GetMethod httpGet(String path) throws IOException {
     return httpGet(path, "", "");
   }
@@ -187,7 +258,7 @@ public abstract class AbstractWorkbenchServerTest {
       isRunning = request.getStatusCode() == 200;
     } catch (IOException e) {
       LOG.warn("AbstractTestRestApi.checkIfServerIsRunning() fails .. " +
-          "Submarine workbench server is not running");
+          "Submarine server is not running");
       isRunning = false;
     } finally {
       if (request != null) {
@@ -262,4 +333,36 @@ public abstract class AbstractWorkbenchServerTest {
       }
     };
   }
+
+  protected static boolean userAndPasswordAreNotBlank(String user, String pwd) {
+    if (StringUtils.isBlank(user) && StringUtils.isBlank(pwd)) {
+      return false;
+    }
+    return true;
+  }
+
+  private static String getCookie(String user, String password) throws IOException {
+    HttpClient httpClient = new HttpClient();
+    PostMethod postMethod = new PostMethod(URL + "/login");
+    postMethod.addRequestHeader("Origin", URL);
+    postMethod.setParameter("password", password);
+    postMethod.setParameter("userName", user);
+    httpClient.executeMethod(postMethod);
+    LOG.info("{} - {}", postMethod.getStatusCode(), postMethod.getStatusText());
+    Pattern pattern = Pattern.compile("JSESSIONID=([a-zA-Z0-9-]*)");
+    Header[] setCookieHeaders = postMethod.getResponseHeaders("Set-Cookie");
+    String jsessionId = null;
+    for (Header setCookie : setCookieHeaders) {
+      java.util.regex.Matcher matcher = pattern.matcher(setCookie.toString());
+      if (matcher.find()) {
+        jsessionId = matcher.group(1);
+      }
+    }
+
+    if (jsessionId != null) {
+      return jsessionId;
+    } else {
+      return StringUtils.EMPTY;
+    }
+  }
 }
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/WorkbenchClusterServerTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/SubmarineServerClusterTest.java
similarity index 76%
rename from submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/WorkbenchClusterServerTest.java
rename to submarine-server/server-core/src/test/java/org/apache/submarine/server/SubmarineServerClusterTest.java
index fca467e..d0475cd 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/WorkbenchClusterServerTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/SubmarineServerClusterTest.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.submarine.server.workbench.server;
+package org.apache.submarine.server;
 
 import org.apache.submarine.commons.cluster.ClusterClient;
 import org.apache.submarine.commons.cluster.meta.ClusterMetaType;
@@ -36,14 +36,14 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-public class WorkbenchClusterServerTest {
-  private static final Logger LOG = LoggerFactory.getLogger(WorkbenchClusterServerTest.class);
+public class SubmarineServerClusterTest extends AbstractSubmarineServerTest {
+  private static final Logger LOG = LoggerFactory.getLogger(SubmarineServerClusterTest.class);
 
   private static ClusterClient clusterClient = null;
 
   @BeforeClass
   public static void start() throws Exception {
-    LOG.info("WorkbenchClusterServerTest:start()");
+    LOG.info("SubmarineServerClusterTest:start()");
 
     SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
     String serverHost = NetworkUtils.findAvailableHostAddress();
@@ -52,7 +52,7 @@ public class WorkbenchClusterServerTest {
     conf.setClusterAddress(clusterAdd);
 
     // Run the workbench service in a thread
-    AbstractWorkbenchServerTest.startUp(WorkbenchClusterServerTest.class.getSimpleName());
+    startUp(SubmarineServerClusterTest.class.getSimpleName());
 
     // Mock Cluster client
     Class clazz = ClusterClient.class;
@@ -60,20 +60,20 @@ public class WorkbenchClusterServerTest {
     constructor = clazz.getDeclaredConstructor();
     constructor.setAccessible(true);
     clusterClient = (ClusterClient) constructor.newInstance();
-    clusterClient.start("TestWorkbenchClusterServer");
+    clusterClient.start("SubmarineServerClusterTest");
 
     // Waiting for cluster startup
     int wait = 0;
     while (wait++ < 100) {
       if (clusterClient.raftInitialized()) {
-        LOG.info("TestWorkbenchClusterServer::start {}(ms) found cluster leader", wait * 3000);
+        LOG.info("SubmarineServerClusterTest::start {}(ms) found cluster leader", wait * 3000);
         break;
       }
 
       sleep(3000);
     }
 
-    assertTrue("Can not start Submarine workbench server!", clusterClient.raftInitialized());
+    assertTrue("Can not start Submarine server!", clusterClient.raftInitialized());
 
     // Waiting for the workbench server to register in the cluster
     sleep(5000);
@@ -81,18 +81,18 @@ public class WorkbenchClusterServerTest {
 
   @AfterClass
   public static void stop() throws Exception {
-    LOG.info("WorkbenchClusterServerTest::stop >>>");
-    AbstractWorkbenchServerTest.shutDown();
+    LOG.info("SubmarineServerClusterTest::stop >>>");
+    shutDown();
 
     if (null != clusterClient) {
       clusterClient.shutdown();
     }
-    LOG.info("WorkbenchClusterServerTest::stop <<<");
+    LOG.info("SubmarineServerClusterTest::stop <<<");
   }
 
   @Test
-  public void testGetWorkbenchClusterMeta() {
-    LOG.info("TestWorkbenchClusterServer::testGetWorkbenchClusterMeta >>>");
+  public void testGetServerClusterMeta() {
+    LOG.info("SubmarineServerClusterTest::testGetServerClusterMeta >>>");
     // Get metadata for workbench server
     Object srvMeta = clusterClient.getClusterMeta(ClusterMetaType.SERVER_META, "");
     LOG.info("testGetWorkbenchClusterMeta = {}", srvMeta.toString());
@@ -102,6 +102,6 @@ public class WorkbenchClusterServerTest {
     HashMap hashMap = (HashMap) srvMeta;
 
     assertEquals(hashMap.size(), 1);
-    LOG.info("TestWorkbenchClusterServer::testGetWorkbenchClusterMeta <<<");
+    LOG.info("SubmarineServerClusterTest::testGetServerClusterMeta <<<");
   }
 }
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/jobserver/rest/api/JobApiTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/jobserver/rest/api/JobApiTest.java
new file mode 100644
index 0000000..dfefca2
--- /dev/null
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/jobserver/rest/api/JobApiTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.submarine.server.jobserver.rest.api;
+
+import com.google.gson.Gson;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.submarine.server.AbstractSubmarineServerTest;
+import org.apache.submarine.server.jobserver.rest.dao.RestConstants;
+import org.apache.submarine.server.response.JsonResponse;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+public class JobApiTest extends AbstractSubmarineServerTest {
+  private static final Logger LOG = LoggerFactory.getLogger(JobApiTest.class);
+
+  @BeforeClass
+  public static void init() throws Exception {
+    AbstractSubmarineServerTest.startUp(JobApiTest.class.getSimpleName());
+  }
+
+  @AfterClass
+  public static void destroy() throws Exception {
+    AbstractSubmarineServerTest.shutDown();
+  }
+
+  @Test
+  public void testJobServerPing() throws IOException {
+    GetMethod response = httpGet("/api/" + RestConstants.V1 + "/"
+        + RestConstants.JOBS + "/" + RestConstants.PING);
+    LOG.info(response.toString());
+
+    String requestBody = response.getResponseBodyAsString();
+    LOG.info(requestBody);
+
+    Gson gson = new Gson();
+    JsonResponse jsonResponse = gson.fromJson(requestBody, JsonResponse.class);
+    assertEquals("Response code should be 200 ",
+        Response.Status.OK.getStatusCode(), jsonResponse.getCode());
+    assertEquals("Response result should be Pong", "Pong",
+        jsonResponse.getResult().toString());
+  }
+
+  // Test job created with correct JSON input
+  @Test
+  public void testCreateJobWhenJsonInputIsCorrectThenResponseCodeAccepted() throws IOException {
+    String jobSpec = "{\"type\": \"tensorflow\", \"version\":\"v1.13\"}";
+
+    PostMethod response = httpPost("/api/" + RestConstants.V1 + "/" + RestConstants.JOBS, jobSpec);
+    LOG.info(response.toString());
+
+    String requestBody = response.getResponseBodyAsString();
+    LOG.info(requestBody);
+
+    Gson gson = new Gson();
+    JsonResponse jsonResponse = gson.fromJson(requestBody, JsonResponse.class);
+    assertEquals("Response code should be 202 ",
+        Response.Status.ACCEPTED.getStatusCode(), jsonResponse.getCode());
+  }
+
+  // Test job created with incorrect JSON input
+  @Test
+  public void testCreateJobWhenJsonInputIsWrongThenResponseCodeBadRequest() throws IOException {
+    String jobSpec = "{\"ttype\": \"tensorflow\", \"version\":\"v1.13\"}";
+
+    PostMethod response = httpPost("/api/" + RestConstants.V1 + "/" + RestConstants.JOBS, jobSpec);
+
+    assertEquals("Http Response should be 400 ",
+        Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusCode());
+  }
+
+  // Test get job list
+  @Test
+  public void testGetJobList() throws IOException {
+    GetMethod response = httpGet("/api/" + RestConstants.V1 + "/" + RestConstants.JOBS);
+    LOG.info(response.toString());
+
+    String requestBody = response.getResponseBodyAsString();
+    LOG.info(requestBody);
+
+    Gson gson = new Gson();
+    JsonResponse jsonResponse = gson.fromJson(requestBody, JsonResponse.class);
+    assertEquals("Response code should be 200 ",
+        Response.Status.OK.getStatusCode(), jsonResponse.getCode());
+  }
+
+  // Test get job by id
+  @Test
+  public void testGetJobById() throws IOException {
+    String jobId = "job1";
+    GetMethod response = httpGet("/api/" + RestConstants.V1 + "/"
+        + RestConstants.JOBS + "/" + jobId);
+    LOG.info(response.toString());
+
+    String requestBody = response.getResponseBodyAsString();
+    LOG.info(requestBody);
+
+    Gson gson = new Gson();
+    JsonResponse jsonResponse = gson.fromJson(requestBody, JsonResponse.class);
+    assertEquals("Response code should be 200 ",
+        Response.Status.OK.getStatusCode(), jsonResponse.getCode());
+    assertEquals("Job id should be " + jobId, jobId,
+        jsonResponse.getResult().toString());
+  }
+
+  // Test delete job by id
+  @Test
+  public void testDeleteJobById() throws IOException {
+    String jobId = "job1";
+    DeleteMethod response = httpDelete("/api/" + RestConstants.V1 + "/"
+        + RestConstants.JOBS + "/" + jobId);
+    LOG.info(response.toString());
+
+    String requestBody = response.getResponseBodyAsString();
+    LOG.info(requestBody);
+
+    Gson gson = new Gson();
+    JsonResponse jsonResponse = gson.fromJson(requestBody, JsonResponse.class);
+    assertEquals("Response code should be 200 ",
+        Response.Status.OK.getStatusCode(), jsonResponse.getCode());
+  }
+
+  /**
+   * FiXME. The manual YAML test with postman works but failed here.
+   * We need to figure out why the YAML entity provider not work in this test.
+   * */
+  @Test
+  public void testCreateJobWhenYamlInputIsCorrectThenResponseCodeAccepted() throws IOException {
+//    Client client = ClientBuilder.newBuilder()
+//        .register(new YamlEntityProvider<>()).build();
+//    this.setClient(client);
+//    String jobSpec = "type: tf";
+//    Response response = target(RestConstants.V1 + "/"
+//        + RestConstants.JOBS + "/" + "test")
+//        .request()
+//        .put(Entity.entity(jobSpec, "application/yaml"));
+//
+//    assertEquals("Http Response should be 202 ",
+//        Response.Status.ACCEPTED.getStatusCode(), response.getStatus());
+  }
+}
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/JsonResponseTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/response/JsonResponseTest.java
similarity index 94%
rename from submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/JsonResponseTest.java
rename to submarine-server/server-core/src/test/java/org/apache/submarine/server/response/JsonResponseTest.java
index 6cfee5e..32a9aa4 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/JsonResponseTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/response/JsonResponseTest.java
@@ -15,13 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.submarine.server.workbench.server;
+package org.apache.submarine.server.response;
 
+import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
-import com.google.gson.reflect.TypeToken;
 import org.apache.submarine.server.workbench.database.entity.SysDict;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.junit.Test;
 
 import javax.ws.rs.core.Response;
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/GitUtilsTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/utils/GitUtilsTest.java
similarity index 97%
rename from submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/GitUtilsTest.java
rename to submarine-server/server-core/src/test/java/org/apache/submarine/server/utils/GitUtilsTest.java
index a0a2669..f2fbd69 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/server/GitUtilsTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/utils/GitUtilsTest.java
@@ -16,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.submarine.server.workbench.server;
+package org.apache.submarine.server.utils;
 
 import com.google.common.collect.Lists;
 import com.google.gson.Gson;
-import org.apache.submarine.server.workbench.database.utils.GitUtils;
 import org.eclipse.jgit.api.PullResult;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.lib.Ref;
@@ -38,7 +37,7 @@ import java.util.List;
 import java.util.Map;
 
 import static junit.framework.TestCase.assertEquals;
-import static org.apache.submarine.server.workbench.database.utils.HttpRequestUtil.sendHttpRequest;
+import static org.apache.submarine.server.utils.GitHttpRequest.sendHttpRequest;
 
 public class GitUtilsTest {
   private static final Logger LOG = LoggerFactory.getLogger(GitUtilsTest.class);
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/utils/TestUtils.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/utils/TestUtils.java
similarity index 97%
rename from submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/utils/TestUtils.java
rename to submarine-server/server-core/src/test/java/org/apache/submarine/server/utils/TestUtils.java
index b821908..5135cfb 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/workbench/utils/TestUtils.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/utils/TestUtils.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.submarine.server.workbench.utils;
+package org.apache.submarine.server.utils;
 
 import org.apache.submarine.server.SubmarineServer;
 import org.glassfish.hk2.api.ServiceLocator;
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/utils/DictAnnotationTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/utils/DictAnnotationTest.java
index bfc4e94..9f24213 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/utils/DictAnnotationTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/database/utils/DictAnnotationTest.java
@@ -22,9 +22,10 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.internal.LinkedTreeMap;
 import com.google.gson.reflect.TypeToken;
+import org.apache.submarine.server.response.DictAnnotation;
 import org.apache.submarine.server.workbench.rest.CommonDataTest;
 import org.apache.submarine.server.workbench.rest.SysUserRestApi;
-import org.apache.submarine.server.workbench.server.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse;
 import org.junit.Test;
 
 import javax.ws.rs.core.Response;
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/CommonDataTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/CommonDataTest.java
index aa103c8..fafe837 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/CommonDataTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/CommonDataTest.java
@@ -27,8 +27,8 @@ import org.apache.submarine.server.workbench.database.entity.SysDict;
 import org.apache.submarine.server.workbench.database.entity.SysDictItem;
 import org.apache.submarine.server.workbench.database.entity.SysUser;
 import org.apache.submarine.server.workbench.database.service.SysUserService;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDeptRestApiTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDeptRestApiTest.java
index a893e33..d657c12 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDeptRestApiTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDeptRestApiTest.java
@@ -22,8 +22,8 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import org.apache.submarine.server.workbench.database.entity.SysDept;
 import org.apache.submarine.server.workbench.database.entity.SysDeptTree;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.junit.After;
 import org.junit.Test;
 
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApiTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApiTest.java
index b3c336f..7cc680f 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApiTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictItemRestApiTest.java
@@ -23,8 +23,8 @@ import com.google.gson.GsonBuilder;
 import com.google.gson.reflect.TypeToken;
 import org.apache.submarine.server.workbench.database.entity.SysDict;
 import org.apache.submarine.server.workbench.database.entity.SysDictItem;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictRestApiTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictRestApiTest.java
index df35104..767403c 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictRestApiTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/rest/SysDictRestApiTest.java
@@ -22,8 +22,8 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.reflect.TypeToken;
 import org.apache.submarine.server.workbench.database.entity.SysDict;
-import org.apache.submarine.server.workbench.server.JsonResponse;
-import org.apache.submarine.server.workbench.server.JsonResponse.ListResult;
+import org.apache.submarine.server.response.JsonResponse;
+import org.apache.submarine.server.response.JsonResponse.ListResult;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/websocket/NotebookServerTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/websocket/NotebookServerTest.java
index 83976f3..a18e0cd 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/websocket/NotebookServerTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/workbench/websocket/NotebookServerTest.java
@@ -16,7 +16,7 @@
  */
 package org.apache.submarine.server.workbench.websocket;
 
-import org.apache.submarine.server.workbench.server.AbstractWorkbenchServerTest;
+import org.apache.submarine.server.AbstractSubmarineServerTest;
 import org.eclipse.jetty.websocket.api.Session;
 import org.eclipse.jetty.websocket.api.StatusCode;
 import org.eclipse.jetty.websocket.api.WebSocketAdapter;
@@ -32,19 +32,19 @@ public class NotebookServerTest {
 
   @BeforeClass
   public static void init() throws Exception {
-    AbstractWorkbenchServerTest.startUp(
+    AbstractSubmarineServerTest.startUp(
         NotebookServerTest.class.getSimpleName());
   }
 
   @AfterClass
   public static void destroy() throws Exception {
-    AbstractWorkbenchServerTest.shutDown();
+    AbstractSubmarineServerTest.shutDown();
   }
 
   @Test
   public void testWebsocketConnection() throws Exception{
     URI uri = URI.create(
-        AbstractWorkbenchServerTest.getWebsocketApiUrlToTest());
+        AbstractSubmarineServerTest.getWebsocketApiUrlToTest());
     WebSocketClient client = new WebSocketClient();
     try {
       client.start();


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