Skip to content

Commit 063f365

Browse files
tswastlesv
authored andcommitted
Add Datastore indexes samples. (#214)
Samples are moved from: https://cloud.google.com/appengine/docs/java/datastore/indexes Note: I add a new script `test-devserver.sh` to the testing config. This script runs the `mvn appengine:devserver` plugin, waits for it to start, then verifies that it gets a non-error response from the `/` path. I use this to verify that the `datastore-indexes.xml` files are correct (by disabling autoGenerate, the local devserver throws an error when a query is used without the correct index defined, just as production does). We should probably add any "hello world" or other projects to this check, as well. Anywhere we say to run `mvn appengine:devserver`, it would be good to test that it is correct.
1 parent 641ab4d commit 063f365

File tree

23 files changed

+1195
-0
lines changed

23 files changed

+1195
-0
lines changed

.travis.yml

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
language: java
1616
jdk:
1717
- oraclejdk8
18+
addons:
19+
apt:
20+
packages:
21+
- expect
1822
before_install:
1923
- openssl aes-256-cbc -K $encrypted_37a4f399de75_key -iv $encrypted_37a4f399de75_iv -in service-account.json.enc -out service-account.json -d
2024
&& export GOOGLE_APPLICATION_CREDENTIALS=$TRAVIS_BUILD_DIR/service-account.json GCLOUD_PROJECT=cloud-samples-tests
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<!--
2+
Copyright 2016 Google Inc. All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
<project>
17+
<modelVersion>4.0.0</modelVersion>
18+
<packaging>war</packaging>
19+
<version>1.0-SNAPSHOT</version>
20+
<groupId>com.example.appengine</groupId>
21+
<artifactId>appengine-datastore-indexes-exploding</artifactId>
22+
<parent>
23+
<groupId>com.google.cloud</groupId>
24+
<artifactId>doc-samples</artifactId>
25+
<version>1.0.0</version>
26+
<relativePath>../../..</relativePath>
27+
</parent>
28+
<dependencies>
29+
<dependency>
30+
<groupId>com.google.appengine</groupId>
31+
<artifactId>appengine-api-1.0-sdk</artifactId>
32+
<version>${appengine.sdk.version}</version>
33+
</dependency>
34+
<dependency>
35+
<groupId>javax.servlet</groupId>
36+
<artifactId>servlet-api</artifactId>
37+
<type>jar</type>
38+
<scope>provided</scope>
39+
</dependency>
40+
41+
<!-- Test Dependencies -->
42+
<dependency>
43+
<groupId>junit</groupId>
44+
<artifactId>junit</artifactId>
45+
<version>4.10</version>
46+
<scope>test</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>org.mockito</groupId>
50+
<artifactId>mockito-all</artifactId>
51+
<version>1.10.19</version>
52+
<scope>test</scope>
53+
</dependency>
54+
<dependency>
55+
<groupId>com.google.appengine</groupId>
56+
<artifactId>appengine-testing</artifactId>
57+
<version>${appengine.sdk.version}</version>
58+
<scope>test</scope>
59+
</dependency>
60+
<dependency>
61+
<groupId>com.google.appengine</groupId>
62+
<artifactId>appengine-api-stubs</artifactId>
63+
<version>${appengine.sdk.version}</version>
64+
<scope>test</scope>
65+
</dependency>
66+
<dependency>
67+
<groupId>com.google.appengine</groupId>
68+
<artifactId>appengine-tools-sdk</artifactId>
69+
<version>${appengine.sdk.version}</version>
70+
<scope>test</scope>
71+
</dependency>
72+
<dependency>
73+
<groupId>com.google.truth</groupId>
74+
<artifactId>truth</artifactId>
75+
<version>0.28</version>
76+
<scope>test</scope>
77+
</dependency>
78+
</dependencies>
79+
<build>
80+
<!-- for hot reload of the web application -->
81+
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
82+
<plugins>
83+
<!-- Parent POM defines ${appengine.sdk.version} (updates frequently). -->
84+
<plugin>
85+
<groupId>com.google.appengine</groupId>
86+
<artifactId>appengine-maven-plugin</artifactId>
87+
<version>${appengine.sdk.version}</version>
88+
</plugin>
89+
</plugins>
90+
</build>
91+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine;
18+
19+
import com.google.appengine.api.datastore.DatastoreService;
20+
import com.google.appengine.api.datastore.DatastoreServiceFactory;
21+
import com.google.appengine.api.datastore.Entity;
22+
import com.google.appengine.api.datastore.FetchOptions;
23+
import com.google.appengine.api.datastore.Query;
24+
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
25+
import com.google.appengine.api.datastore.Query.FilterOperator;
26+
import com.google.appengine.api.datastore.Query.FilterPredicate;
27+
28+
import java.io.IOException;
29+
import java.io.PrintWriter;
30+
import java.util.List;
31+
32+
import javax.servlet.ServletException;
33+
import javax.servlet.http.HttpServlet;
34+
import javax.servlet.http.HttpServletRequest;
35+
import javax.servlet.http.HttpServletResponse;
36+
37+
/**
38+
* A servlet to demonstrate the use of Cloud Datastore indexes.
39+
*/
40+
public class IndexesServlet extends HttpServlet {
41+
private final DatastoreService datastore;
42+
43+
public IndexesServlet() {
44+
datastore = DatastoreServiceFactory.getDatastoreService();
45+
}
46+
47+
@Override
48+
public void doGet(HttpServletRequest req, HttpServletResponse resp)
49+
throws IOException, ServletException {
50+
Query q =
51+
new Query("Widget")
52+
.setFilter(
53+
CompositeFilterOperator.and(
54+
new FilterPredicate("x", FilterOperator.EQUAL, 1),
55+
new FilterPredicate("y", FilterOperator.EQUAL, "red")))
56+
.addSort("date", Query.SortDirection.ASCENDING);
57+
List<Entity> results = datastore.prepare(q).asList(FetchOptions.Builder.withDefaults());
58+
59+
PrintWriter out = resp.getWriter();
60+
out.printf("Got %d widgets.\n", results.size());
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2016 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
18+
<application>YOUR-PROJECT-ID</application>
19+
<version>YOUR-VERSION-ID</version>
20+
<threadsafe>true</threadsafe>
21+
</appengine-web-app>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- [START_EXCLUDE silent] -->
3+
<!--
4+
Copyright 2016 Google Inc. All Rights Reserved.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
-->
18+
<!-- [END_EXCLUDE] -->
19+
<datastore-indexes autoGenerate="false">
20+
<datastore-index kind="Widget">
21+
<property name="x" direction="asc" />
22+
<property name="date" direction="asc" />
23+
</datastore-index>
24+
<datastore-index kind="Widget">
25+
<property name="y" direction="asc" />
26+
<property name="date" direction="asc" />
27+
</datastore-index>
28+
</datastore-indexes>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2016 Google Inc. All Rights Reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
18+
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
19+
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
20+
version="2.5">
21+
<servlet>
22+
<servlet-name>indexes-servlet</servlet-name>
23+
<servlet-class>com.example.appengine.IndexesServlet</servlet-class>
24+
</servlet>
25+
<servlet-mapping>
26+
<servlet-name>indexes-servlet</servlet-name>
27+
<url-pattern>/</url-pattern>
28+
</servlet-mapping>
29+
30+
<security-constraint>
31+
<web-resource-collection>
32+
<web-resource-name>profile</web-resource-name>
33+
<url-pattern>/*</url-pattern>
34+
</web-resource-collection>
35+
<user-data-constraint>
36+
<transport-guarantee>CONFIDENTIAL</transport-guarantee> <!-- Require HTTPS. -->
37+
</user-data-constraint>
38+
</security-constraint>
39+
</web-app>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2016 Google Inc. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.appengine;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static org.mockito.Mockito.when;
21+
22+
import com.google.appengine.api.datastore.DatastoreService;
23+
import com.google.appengine.api.datastore.DatastoreServiceFactory;
24+
import com.google.appengine.api.datastore.Entity;
25+
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
26+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
27+
import org.junit.After;
28+
import org.junit.Before;
29+
import org.junit.Test;
30+
import org.junit.runner.RunWith;
31+
import org.junit.runners.JUnit4;
32+
import org.mockito.Mock;
33+
import org.mockito.MockitoAnnotations;
34+
35+
import java.io.PrintWriter;
36+
import java.io.StringWriter;
37+
import java.util.Arrays;
38+
import java.util.Date;
39+
40+
import javax.servlet.http.HttpServletRequest;
41+
import javax.servlet.http.HttpServletResponse;
42+
43+
/**
44+
* Unit tests for {@link IndexesServlet}.
45+
*/
46+
@RunWith(JUnit4.class)
47+
public class IndexesServletTest {
48+
49+
private final LocalServiceTestHelper helper =
50+
new LocalServiceTestHelper(
51+
// Set no eventual consistency, that way queries return all results.
52+
// https://cloud.google.com/appengine/docs/java/tools/localunittesting#Java_Writing_High_Replication_Datastore_tests
53+
new LocalDatastoreServiceTestConfig()
54+
.setDefaultHighRepJobPolicyUnappliedJobPercentage(0));
55+
56+
@Mock private HttpServletRequest mockRequest;
57+
@Mock private HttpServletResponse mockResponse;
58+
private StringWriter responseWriter;
59+
private IndexesServlet servletUnderTest;
60+
61+
@Before
62+
public void setUp() throws Exception {
63+
MockitoAnnotations.initMocks(this);
64+
helper.setUp();
65+
66+
// Set up a fake HTTP response.
67+
responseWriter = new StringWriter();
68+
when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));
69+
70+
servletUnderTest = new IndexesServlet();
71+
}
72+
73+
@After
74+
public void tearDown() {
75+
helper.tearDown();
76+
}
77+
78+
@Test
79+
public void doGet_emptyDatastore_writesNoWidgets() throws Exception {
80+
servletUnderTest.doGet(mockRequest, mockResponse);
81+
82+
assertThat(responseWriter.toString())
83+
.named("IndexesServlet response")
84+
.isEqualTo("Got 0 widgets.\n");
85+
}
86+
87+
@Test
88+
public void doGet_repeatedPropertyEntities_writesWidgets() throws Exception {
89+
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
90+
// [START exploding_index_example_3]
91+
Entity widget = new Entity("Widget");
92+
widget.setProperty("x", Arrays.asList(1, 2, 3, 4));
93+
widget.setProperty("y", Arrays.asList("red", "green", "blue"));
94+
widget.setProperty("date", new Date());
95+
datastore.put(widget);
96+
// [END exploding_index_example_3]
97+
98+
servletUnderTest.doGet(mockRequest, mockResponse);
99+
100+
assertThat(responseWriter.toString())
101+
.named("IndexesServlet response")
102+
.isEqualTo("Got 1 widgets.\n");
103+
}
104+
}

0 commit comments

Comments
 (0)