diff --git a/.travis.yml b/.travis.yml
index 1e4efa4be92..35338d03867 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,8 @@
language: java
jdk:
- - oraclejdk7
-env: GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/service-account.json
+ - oraclejdk8
+env:
+ - GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/service-account.json GCLOUD_PROJECT=cloud-samples-tests
before_install:
- openssl aes-256-cbc -K $encrypted_99d8b304f94b_key -iv $encrypted_99d8b304f94b_iv -in service-account.json.enc -out service-account.json -d
diff --git a/managedvms/sparkjava/README.md b/managedvms/sparkjava/README.md
new file mode 100644
index 00000000000..3f7ee8d795d
--- /dev/null
+++ b/managedvms/sparkjava/README.md
@@ -0,0 +1,49 @@
+gcloud-java example using Managed VMs & SparkJava
+=================================================
+
+This app demonstrates how to use [`gcloud-java`'s Datastore client](https://github.com/GoogleCloudPlatform/gcloud-java/tree/master/gcloud-java-datastore#google-cloud-java-client-for-datastore) from within an [App Engine Managed VM](https://cloud.google.com/appengine/docs/java/managed-vms/) project using [SparkJava](http://sparkjava.com/). The app allows you to create and modify a database of "users", which contains their ID, name, and email information.
+
+`gcloud-java` is an idiomatic Java client for [Google Cloud Platform](https://cloud.google.com/) services. Read more about the library [here](https://github.com/GoogleCloudPlatform/gcloud-java#google-cloud-java-client).
+
+Setup
+-----
+
+1. Create a Google Developers Console project with the Datastore API enabled. [Follow these instructions](https://cloud.google.com/docs/authentication#preparation) to get your project set up. If you wish to deploy this application, you will also need to [enable billing](https://support.google.com/cloud/?rd=2#topic=6288636).
+
+2. Set up the local development environment by [installing the Google Cloud SDK](https://cloud.google.com/sdk/) and running the following commands in command line: `gcloud auth login` and `gcloud config set project [YOUR PROJECT ID]`.
+
+3. Ensure that you have Maven installed. See installation instructions [here](https://maven.apache.org/install.html).
+
+Running locally
+---------------
+
+Run the application on your local machine by typing the following into your command line from the `sparkjava` directory: `mvn clean package exec:java`. Navigate to `localhost:8080` to view and interact with the application.
+
+Deploying
+---------
+
+If you've enabled billing (step 1 in [Setup](#Setup)), you can deploy the application to the web by running `mvn gcloud:deploy` from your command line (from the `sparkjava` directory).
+
+How does it work?
+-----------------
+
+You'll notice that the source code is split into three folders: `appengine`, `java/com/google/appengine/sparkdemo`, and `resource/public`. The `appengine` folder contains a `Dockerfile` and an `app.yaml`, necessary files to [configure the VM environment](https://cloud.google.com/appengine/docs/managed-vms/config). The `java/com/google/appengine/sparkdemo` folder contains the controller code, which uses the `gcloud-java` library to modify the records in the Google Cloud Datastore. Finally, the `resource/public` folder contains the home webpage, which uses jQuery to send HTTP requests to create, remove, and update records.
+
+Spark runs the [`main` method](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/java/com/google/appengine/sparkdemo/Main.java) upon server startup. The `main` method creates the controller, [`UserController`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/java/com/google/appengine/sparkdemo/UserController.java). The URIs used to send HTTP requests in the [home page](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/resources/public/index.html) correspond to methods in the `UserController` class. For example, the `index.html` code for `create` makes a `POST` request to the path `/api/users` with a body containing the name and email of a user to add. `UserController` contains the following code to process that request:
+
+```java
+post("/api/users", (req, res) -> userService.createUser(
+ req.queryParams("name"),
+ req.queryParams("email),
+), json());
+```
+This code snippet gets the name and email of the user from the POST request and passes it to `createUser` (in [`UserService.java`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/managedvms/sparkjava-demo/src/main/java/com/google/appengine/sparkdemo/UserService.java)) to create a database record using `gcloud-java`. If you want a more in-depth tutorial on using `gcloud-java` Datastore client, see the [Getting Started](https://github.com/GoogleCloudPlatform/gcloud-java/tree/master/gcloud-java-datastore#getting-started) section in the `gcloud-java-datastore` documentation.
+
+Communication with the Google Cloud Datastore requires authentication and setting a project ID. When running locally, `gcloud-java` automatically detects your credentials and project ID because you logged into the Google Cloud SDK and set your project ID. There are also many other options for authenticating and setting a project ID. To read more, see the [Authentication](https://github.com/GoogleCloudPlatform/gcloud-java#authentication) and [Specifying a Project ID](https://github.com/GoogleCloudPlatform/gcloud-java#specifying-a-project-id) sections of the `gcloud-java` documentation.
+
+You built and ran this application using Maven. To read more about using Maven with Managed VMs, see the [Using Apache Maven documentation](https://cloud.google.com/appengine/docs/java/managed-vms/maven). While this particular project uses Maven, `gcloud-java` can also be accessed using Gradle and SBT. See how to obtain the dependency in the [Quickstart section](https://github.com/GoogleCloudPlatform/gcloud-java#quickstart) of the `gcloud-java` documentation.
+
+License
+-------
+
+Apache 2.0 - See [LICENSE](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/LICENSE) for more information.
diff --git a/managedvms/sparkjava/pom.xml b/managedvms/sparkjava/pom.xml
new file mode 100644
index 00000000000..49ea74e938e
--- /dev/null
+++ b/managedvms/sparkjava/pom.xml
@@ -0,0 +1,89 @@
+
+
+ 4.0.0
+ com.google.appengine.sparkdemo
+ sparkdemo
+ 1.0
+
+
+ com.sparkjava
+ spark-core
+ 2.3
+
+
+ org.slf4j
+ slf4j-simple
+ 1.7.12
+
+
+ com.google.code.gson
+ gson
+ 2.4
+
+
+ junit
+ junit
+ 4.12
+
+
+ com.google.gcloud
+ gcloud-java
+ 0.1.1
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.5.1
+
+
+ 1.8
+
+
+
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+
+
+ jar-with-dependencies
+
+
+
+ com.google.appengine.sparkdemo.Main
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.4.0
+
+ com.google.appengine.sparkdemo.Main
+
+ -jar
+ target/sparkdemo-1.0-jar-with-dependencies.jar
+
+
+
+
+ com.google.appengine
+ gcloud-maven-plugin
+ 2.0.9.88.v20151125
+
+
+
+
+
+
diff --git a/managedvms/sparkjava/src/main/appengine/Dockerfile b/managedvms/sparkjava/src/main/appengine/Dockerfile
new file mode 100644
index 00000000000..9749864ab1e
--- /dev/null
+++ b/managedvms/sparkjava/src/main/appengine/Dockerfile
@@ -0,0 +1,4 @@
+FROM gcr.io/google_appengine/openjdk8
+VOLUME /tmp
+ADD sparkdemo-1.0-jar-with-dependencies.jar app.jar
+ENTRYPOINT [ "java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
diff --git a/managedvms/sparkjava/src/main/appengine/app.yaml b/managedvms/sparkjava/src/main/appengine/app.yaml
new file mode 100644
index 00000000000..e8b73970590
--- /dev/null
+++ b/managedvms/sparkjava/src/main/appengine/app.yaml
@@ -0,0 +1,2 @@
+runtime: custom
+vm: true
diff --git a/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/Main.java b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/Main.java
new file mode 100644
index 00000000000..d24e0231871
--- /dev/null
+++ b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/Main.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.google.appengine.sparkdemo;
+
+import static spark.Spark.port;
+
+import com.google.gcloud.datastore.DatastoreOptions;
+
+public class Main {
+
+ public static void main(String[] args) {
+ port(8080);
+ UserController userController =
+ new UserController(new UserService(DatastoreOptions.defaultInstance().service()));
+ }
+}
diff --git a/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/ResponseError.java b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/ResponseError.java
new file mode 100644
index 00000000000..c225851dca4
--- /dev/null
+++ b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/ResponseError.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.google.appengine.sparkdemo;
+
+public class ResponseError {
+
+ private String message;
+
+ public ResponseError(String message, String... args) {
+ this.message = String.format(message, (Object) args);
+ }
+
+ public ResponseError(Exception e) {
+ this.message = e.getMessage();
+ }
+}
diff --git a/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/User.java b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/User.java
new file mode 100644
index 00000000000..3455f4aac8e
--- /dev/null
+++ b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/User.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.google.appengine.sparkdemo;
+
+import java.util.UUID;
+
+public class User {
+
+ private String id;
+ private String name;
+ private String email;
+
+ public User(String name, String email) {
+ this(UUID.randomUUID().toString(), name, email);
+ }
+
+ public User(String id, String name, String email) {
+ this.id = id;
+ this.email = email;
+ this.name = name;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ void setId(String id) {
+ this.id = id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+}
diff --git a/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/UserController.java b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/UserController.java
new file mode 100644
index 00000000000..75d57caf832
--- /dev/null
+++ b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/UserController.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.google.appengine.sparkdemo;
+
+import static spark.Spark.after;
+import static spark.Spark.delete;
+import static spark.Spark.exception;
+import static spark.Spark.get;
+import static spark.Spark.post;
+import static spark.Spark.put;
+
+import com.google.gson.Gson;
+
+import spark.ResponseTransformer;
+import spark.Spark;
+
+public class UserController {
+
+ public UserController(final UserService userService) {
+ Spark.staticFileLocation("/public");
+
+ get("/api/users", (req, res) -> userService.getAllUsers(), UserController::toJson);
+
+ post("/api/users",
+ (req, res) -> userService.createUser(req.queryParams("name"), req.queryParams("email")),
+ json());
+
+ put("/api/users/:id", (req, res) -> userService.updateUser(
+ req.params(":id"),
+ req.queryParams("name"),
+ req.queryParams("email")
+ ), json());
+
+ delete("/api/users/:id", (req, res) -> userService.deleteUser(req.params(":id")), json());
+
+ after((req, res) -> {
+ res.type("application/json");
+ });
+
+ exception(IllegalArgumentException.class, (e, req, res) -> {
+ res.status(400);
+ res.body(toJson(new ResponseError(e)));
+ });
+ }
+
+ private static String toJson(Object object) {
+ return new Gson().toJson(object);
+ }
+
+ private static ResponseTransformer json() {
+ return UserController::toJson;
+ }
+}
diff --git a/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/UserService.java b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/UserService.java
new file mode 100644
index 00000000000..eb183ac4710
--- /dev/null
+++ b/managedvms/sparkjava/src/main/java/com/google/appengine/sparkdemo/UserService.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.google.appengine.sparkdemo;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.Entity;
+import com.google.gcloud.datastore.FullEntity;
+import com.google.gcloud.datastore.Key;
+import com.google.gcloud.datastore.KeyFactory;
+import com.google.gcloud.datastore.Query;
+import com.google.gcloud.datastore.QueryResults;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class UserService {
+
+ private static final String KINDNAME = "DEMO_USER";
+ private Datastore datastore;
+
+ public UserService(Datastore datastore) {
+ this.datastore = datastore;
+ }
+
+ public List getAllUsers() {
+ Query query =
+ Query.gqlQueryBuilder(Query.ResultType.ENTITY, "SELECT * FROM " + KINDNAME).build();
+ QueryResults results = datastore.run(query);
+ List users = new ArrayList<>();
+ while (results.hasNext()) {
+ Entity result = results.next();
+ users.add(
+ new User(result.getString("id"), result.getString("name"), result.getString("email")));
+ }
+ return users;
+ }
+
+ public User createUser(String name, String email) {
+ failIfInvalid(name, email);
+ User user = new User(name, email);
+ KeyFactory keyFactory = datastore.newKeyFactory().kind(KINDNAME);
+ Key key = keyFactory.newKey(user.getId());
+ FullEntity entity = Entity.builder(key)
+ .set("id", user.getId())
+ .set("name", name)
+ .set("email", email)
+ .build();
+ datastore.add(entity);
+ return user;
+ }
+
+ public String deleteUser(String id) {
+ KeyFactory keyFactory = datastore.newKeyFactory().kind(KINDNAME);
+ Key key = keyFactory.newKey(id);
+ datastore.delete(key);
+ return "ok";
+ }
+
+ public User updateUser(String id, String name, String email) {
+ failIfInvalid(name, email);
+ KeyFactory keyFactory = datastore.newKeyFactory().kind(KINDNAME);
+ Key key = keyFactory.newKey(id);
+ Entity entity = datastore.get(key);
+ if (entity == null) {
+ throw new IllegalArgumentException("No user with id '" + id + "' found");
+ } else {
+ entity = Entity.builder(entity)
+ .set("id", id)
+ .set("name", name)
+ .set("email", email)
+ .build();
+ datastore.update(entity);
+ }
+ return new User(id, name, email);
+ }
+
+ private void failIfInvalid(String name, String email) {
+ checkArgument(name != null && !name.isEmpty(), "Parameter 'name' cannot be empty");
+ checkArgument(email != null && !email.isEmpty(), "Parameter 'email' cannot be empty");
+ }
+}
diff --git a/managedvms/sparkjava/src/main/resources/public/index.html b/managedvms/sparkjava/src/main/resources/public/index.html
new file mode 100644
index 00000000000..ba7adea7ee0
--- /dev/null
+++ b/managedvms/sparkjava/src/main/resources/public/index.html
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
User Database
+
Using App Engine Managed VMs, Google Cloud Datastore, and SparkJava.
+
+
+
All users
+
+
+
+
+
+
+
ID
+
Name
+
Email
+
Actions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Add a user
+
+
+
+
+
+
+
+
+
+
diff --git a/managedvms/sparkjava/src/test/java/com/google/appengine/sparkdemo/UserControllerTest.java b/managedvms/sparkjava/src/test/java/com/google/appengine/sparkdemo/UserControllerTest.java
new file mode 100644
index 00000000000..5be8925b2f8
--- /dev/null
+++ b/managedvms/sparkjava/src/test/java/com/google/appengine/sparkdemo/UserControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.google.appengine.sparkdemo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.google.gson.Gson;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import spark.Spark;
+import spark.utils.IOUtils;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class UserControllerTest {
+
+ private static final String USER_NAME = "myName";
+ private static final String USER_EMAIL = "my@email.com";
+ private static String userId;
+
+ @BeforeClass
+ public static void beforeClass() {
+ Main.main(null);
+ Spark.awaitInitialization();
+ }
+
+ @Before
+ public void setUp() throws IOException {
+ User[] allUsers = getAllUsers();
+ for (User user : allUsers) {
+ deleteUser(user.getId());
+ }
+ userId = createUser(USER_NAME, USER_EMAIL).getId();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ Spark.stop();
+ }
+
+ @Test
+ public void testGetAllUsers() throws IOException {
+ User[] users = getAllUsers();
+ assertEquals(1, users.length);
+ User user = users[0];
+ assertEquals(userId, user.getId());
+ assertEquals(USER_NAME, user.getName());
+ assertEquals(USER_EMAIL, user.getEmail());
+ }
+
+ @Test
+ public void testCreateUser() throws IOException {
+ User user = createUser(USER_NAME, USER_EMAIL);
+ assertNotNull(user.getId());
+ assertEquals(USER_NAME, user.getName());
+ assertEquals(USER_EMAIL, user.getEmail());
+ }
+
+ @Test
+ public void testCreateUserInvalidRequest() {
+ try {
+ executeRequest("POST", "/api/users?name=&email=");
+ fail("Should fail due to an invalid request.");
+ } catch (IOException e) {
+ assertTrue(e.getMessage().startsWith("Server returned HTTP response code: 400 for URL"));
+ }
+ }
+
+ @Test
+ public void testDeleteUser() throws IOException {
+ assertEquals("\"ok\"", deleteUser(userId));
+ assertEquals(0, getAllUsers().length);
+ }
+
+ @Test
+ public void updateUser() throws IOException {
+ String newName = "myNewName";
+ String newEmail = "mynew@email.com";
+ String responseStr = executeRequest(
+ "PUT",
+ "/api/users/" + userId + "?id=" + userId + "&name=" + newName + "&email=" + newEmail);
+ User updatedUser = new Gson().fromJson(responseStr, User.class);
+ assertEquals(userId, updatedUser.getId());
+ assertEquals(newName, updatedUser.getName());
+ assertEquals(newEmail, updatedUser.getEmail());
+ }
+
+ private static String executeRequest(String method, String path) throws IOException {
+ URL url = new URL("http://localhost:8080" + path);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod(method);
+ connection.setDoOutput(true);
+ connection.connect();
+ return IOUtils.toString(connection.getInputStream());
+ }
+
+ private static User createUser(String name, String email) throws IOException {
+ return new Gson().fromJson(
+ executeRequest("POST", "/api/users?name=" + name + "&email=" + email), User.class);
+ }
+
+ private static String deleteUser(String id) throws IOException {
+ return executeRequest("DELETE", "/api/users/" + id);
+ }
+
+ private static User[] getAllUsers() throws IOException {
+ return new Gson().fromJson(executeRequest("GET", "/api/users"), User[].class);
+ }
+}
diff --git a/managedvms/sparkjava/src/test/java/com/google/appengine/sparkdemo/UserServiceTest.java b/managedvms/sparkjava/src/test/java/com/google/appengine/sparkdemo/UserServiceTest.java
new file mode 100644
index 00000000000..375c2dfdf9e
--- /dev/null
+++ b/managedvms/sparkjava/src/test/java/com/google/appengine/sparkdemo/UserServiceTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed 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 com.google.appengine.sparkdemo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import com.google.common.collect.Iterators;
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.DatastoreOptions;
+import com.google.gcloud.datastore.Entity;
+import com.google.gcloud.datastore.Key;
+import com.google.gcloud.datastore.Query;
+import com.google.gcloud.datastore.QueryResults;
+import com.google.gcloud.datastore.StructuredQuery;
+import com.google.gcloud.datastore.testing.LocalGcdHelper;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.List;
+
+public class UserServiceTest {
+
+ private static final int PORT = LocalGcdHelper.findAvailablePort(LocalGcdHelper.DEFAULT_PORT);
+ private static final String PROJECT_ID = LocalGcdHelper.DEFAULT_PROJECT_ID;
+ private static final String USER_ID = "myId";
+ private static final String USER_NAME = "myName";
+ private static final String USER_EMAIL = "my@email.com";
+ private static final User USER = new User(USER_ID, USER_NAME, USER_EMAIL);
+ private static final Key USER_KEY = Key.builder(PROJECT_ID, "DEMO_USER", USER_ID).build();
+ private static final Entity USER_RECORD = Entity.builder(USER_KEY)
+ .set("id", USER_ID)
+ .set("name", USER_NAME)
+ .set("email", USER_EMAIL)
+ .build();
+ private static LocalGcdHelper gcdHelper;
+ private static Datastore datastore;
+ private static UserService userService;
+
+ @BeforeClass
+ public static void beforeClass() throws IOException, InterruptedException {
+ if (!LocalGcdHelper.isActive(PROJECT_ID, PORT)) {
+ gcdHelper = LocalGcdHelper.start(PROJECT_ID, PORT);
+ }
+ datastore = DatastoreOptions.builder()
+ .projectId(PROJECT_ID)
+ .host("http://localhost:" + PORT)
+ .build()
+ .service();
+ userService = new UserService(datastore);
+ }
+
+ @Before
+ public void setUp() {
+ StructuredQuery query = Query.keyQueryBuilder().build();
+ QueryResults result = datastore.run(query);
+ datastore.delete(Iterators.toArray(result, Key.class));
+ datastore.add(USER_RECORD);
+ }
+
+ @AfterClass
+ public static void afterClass() throws IOException, InterruptedException {
+ if (gcdHelper != null) {
+ gcdHelper.stop();
+ }
+ }
+
+ @Test
+ public void testGetAllUsers() {
+ List allUsers = userService.getAllUsers();
+ assertEquals(1, allUsers.size());
+ User actualUser = allUsers.get(0);
+ assertEquals(USER.getId(), actualUser.getId());
+ assertEquals(USER.getName(), actualUser.getName());
+ assertEquals(USER.getEmail(), actualUser.getEmail());
+ }
+
+ @Test
+ public void testCreateUser() {
+ String name = "myNewName";
+ String email = "mynew@email.com";
+ User actualUser = userService.createUser(name, email);
+ assertEquals(name, actualUser.getName());
+ assertEquals(email, actualUser.getEmail());
+ assertNotNull(actualUser.getId());
+ try {
+ userService.createUser(null, email);
+ fail("Expected to fail because name is null.");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Parameter 'name' cannot be empty", e.getMessage());
+ }
+ try {
+ userService.createUser(name, null);
+ fail("Expected to fail because email is null.");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Parameter 'email' cannot be empty", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testDeleteUser() {
+ String result = userService.deleteUser(USER_ID);
+ assertEquals("ok", result);
+ assertNull(datastore.get(USER_KEY));
+ }
+
+ @Test
+ public void testUpdateUser() {
+ String newName = "myNewName";
+ String newEmail = "mynew@email.com";
+ User updatedUser = userService.updateUser(USER_ID, newName, newEmail);
+ assertEquals(USER_ID, updatedUser.getId());
+ assertEquals(newName, updatedUser.getName());
+ assertEquals(newEmail, updatedUser.getEmail());
+ try {
+ userService.updateUser(USER_ID, null, USER_EMAIL);
+ fail("Expected to fail because name is null.");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Parameter 'name' cannot be empty", e.getMessage());
+ }
+ try {
+ userService.updateUser(USER_ID, USER_NAME, null);
+ fail("Expected to fail because email is null.");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Parameter 'email' cannot be empty", e.getMessage());
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 551c70afea7..421f19cf143 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,6 +32,7 @@
storage/storage-transfermonitoringlogging
+ managedvms/sparkjava