Skip to content

Commit 149a162

Browse files
author
Takashi Matsuo
committed
Extracted code snippets from the unittest docs and added travis config.
1 parent 20e5204 commit 149a162

16 files changed

+649
-0
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
language: java
2+
3+
env:
4+
- TEST_DIR=unittests
5+
6+
script: cd $TEST_DIR && mvn test

unittests/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# appengine-ndb-snippets
2+
3+
## unittests
4+
5+
This subdirectory contains code snippets for [Local Unit Testing for Java](https://cloud.google.com/appengine/docs/java/tools/localunittesting).

unittests/pom.xml

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
4+
<modelVersion>4.0.0</modelVersion>
5+
<packaging>war</packaging>
6+
<version>1.0-SNAPSHOT</version>
7+
8+
<groupId>com.google.appengine.samples.unittest</groupId>
9+
<artifactId>unittests</artifactId>
10+
11+
<properties>
12+
<appengine.app.version>1</appengine.app.version>
13+
<appengine.version>1.9.18</appengine.version>
14+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15+
</properties>
16+
17+
<prerequisites>
18+
<maven>3.1.0</maven>
19+
</prerequisites>
20+
21+
<dependencies>
22+
<!-- Compile/runtime dependencies -->
23+
<dependency>
24+
<groupId>com.google.appengine</groupId>
25+
<artifactId>appengine-api-1.0-sdk</artifactId>
26+
<version>${appengine.version}</version>
27+
</dependency>
28+
<dependency>
29+
<groupId>javax.servlet</groupId>
30+
<artifactId>servlet-api</artifactId>
31+
<version>2.5</version>
32+
<scope>provided</scope>
33+
</dependency>
34+
<dependency>
35+
<groupId>jstl</groupId>
36+
<artifactId>jstl</artifactId>
37+
<version>1.2</version>
38+
</dependency>
39+
40+
<!-- Test Dependencies -->
41+
<dependency>
42+
<groupId>junit</groupId>
43+
<artifactId>junit</artifactId>
44+
<version>4.12</version>
45+
<scope>test</scope>
46+
</dependency>
47+
<dependency>
48+
<groupId>com.google.appengine</groupId>
49+
<artifactId>appengine-testing</artifactId>
50+
<version>${appengine.version}</version>
51+
<scope>test</scope>
52+
</dependency>
53+
<dependency>
54+
<groupId>com.google.appengine</groupId>
55+
<artifactId>appengine-api-stubs</artifactId>
56+
<version>${appengine.version}</version>
57+
<scope>test</scope>
58+
</dependency>
59+
</dependencies>
60+
61+
<build>
62+
<!-- for hot reload of the web application-->
63+
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory>
64+
<plugins>
65+
<plugin>
66+
<groupId>org.codehaus.mojo</groupId>
67+
<artifactId>versions-maven-plugin</artifactId>
68+
<version>2.1</version>
69+
<executions>
70+
<execution>
71+
<phase>compile</phase>
72+
<goals>
73+
<goal>display-dependency-updates</goal>
74+
<goal>display-plugin-updates</goal>
75+
</goals>
76+
</execution>
77+
</executions>
78+
</plugin>
79+
<plugin>
80+
<groupId>org.apache.maven.plugins</groupId>
81+
<version>3.1</version>
82+
<artifactId>maven-compiler-plugin</artifactId>
83+
<configuration>
84+
<source>1.7</source>
85+
<target>1.7</target>
86+
</configuration>
87+
</plugin>
88+
<plugin>
89+
<groupId>org.apache.maven.plugins</groupId>
90+
<artifactId>maven-war-plugin</artifactId>
91+
<version>2.4</version>
92+
<configuration>
93+
<archiveClasses>true</archiveClasses>
94+
<webResources>
95+
<!-- in order to interpolate version from pom into appengine-web.xml -->
96+
<resource>
97+
<directory>${basedir}/src/main/webapp/WEB-INF</directory>
98+
<filtering>true</filtering>
99+
<targetPath>WEB-INF</targetPath>
100+
</resource>
101+
</webResources>
102+
</configuration>
103+
</plugin>
104+
105+
<plugin>
106+
<groupId>com.google.appengine</groupId>
107+
<artifactId>appengine-maven-plugin</artifactId>
108+
<version>${appengine.version}</version>
109+
<configuration>
110+
<enableJarClasses>false</enableJarClasses>
111+
<!-- Comment in the below snippet to bind to all IPs instead of just localhost -->
112+
<!-- address>0.0.0.0</address>
113+
<port>8080</port -->
114+
<!-- Comment in the below snippet to enable local debugging with a remove debugger
115+
like those included with Eclipse or IntelliJ -->
116+
<!-- jvmFlags>
117+
<jvmFlag>-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n</jvmFlag>
118+
</jvmFlags -->
119+
</configuration>
120+
</plugin>
121+
<plugin>
122+
<groupId>org.apache.maven.plugins</groupId>
123+
<artifactId>maven-checkstyle-plugin</artifactId>
124+
<version>2.15</version>
125+
<executions>
126+
<execution>
127+
<id>checkstyle</id>
128+
<phase>validate</phase>
129+
<goals>
130+
<goal>check</goal>
131+
</goals>
132+
<configuration>
133+
<failOnViolation>true</failOnViolation>
134+
</configuration>
135+
</execution>
136+
</executions>
137+
</plugin>
138+
</plugins>
139+
</build>
140+
</project>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
3+
<application>your-app-id</application>
4+
<version>${appengine.app.version}</version>
5+
<threadsafe>true</threadsafe>
6+
7+
<system-properties>
8+
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
9+
</system-properties>
10+
</appengine-web-app>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# A default java.util.logging configuration.
2+
# (All App Engine logging is through java.util.logging by default).
3+
#
4+
# To use this configuration, copy it into your application's WEB-INF
5+
# folder and add the following to your appengine-web.xml:
6+
#
7+
# <system-properties>
8+
# <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
9+
# </system-properties>
10+
#
11+
12+
# Set the default logging level for all loggers to WARNING
13+
.level = WARNING
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
3+
4+
</web-app>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.google.appengine.samples.unittest;
2+
3+
// [START auth]
4+
import com.google.appengine.api.users.UserService;
5+
import com.google.appengine.api.users.UserServiceFactory;
6+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
7+
import com.google.appengine.tools.development.testing.LocalUserServiceTestConfig;
8+
import org.junit.After;
9+
import org.junit.Before;
10+
import org.junit.Test;
11+
12+
import static org.junit.Assert.*;
13+
14+
public class AuthenticationTest {
15+
16+
private final LocalServiceTestHelper helper =
17+
new LocalServiceTestHelper(new LocalUserServiceTestConfig())
18+
.setEnvIsAdmin(true).setEnvIsLoggedIn(true);
19+
20+
@Before
21+
public void setUp() {
22+
helper.setUp();
23+
}
24+
25+
@After
26+
public void tearDown() {
27+
helper.tearDown();
28+
}
29+
30+
@Test
31+
public void testIsAdmin() {
32+
UserService userService = UserServiceFactory.getUserService();
33+
assertTrue(userService.isUserAdmin());
34+
}
35+
}
36+
// [END auth]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.google.appengine.samples.unittest;
2+
3+
// [START local_capabilities]
4+
import com.google.appengine.api.capabilities.Capability;
5+
import com.google.appengine.api.capabilities.CapabilityStatus;
6+
import com.google.appengine.api.datastore.DatastoreService;
7+
import com.google.appengine.api.datastore.DatastoreServiceFactory;
8+
import com.google.appengine.api.datastore.FetchOptions;
9+
import com.google.appengine.api.datastore.Query;
10+
import com.google.appengine.tools.development.testing.LocalCapabilitiesServiceTestConfig;
11+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
12+
import com.google.apphosting.api.ApiProxy;
13+
import org.junit.After;
14+
import org.junit.Test;
15+
16+
import static org.junit.Assert.*;
17+
18+
public class CapabilitiesTest {
19+
20+
private LocalServiceTestHelper helper;
21+
22+
@After
23+
public void tearDown() {
24+
helper.tearDown();
25+
}
26+
27+
@Test(expected = ApiProxy.CapabilityDisabledException.class)
28+
public void testDisabledDatastore() {
29+
Capability testOne = new Capability("datastore_v3");
30+
CapabilityStatus testStatus = CapabilityStatus.DISABLED;
31+
//Initialize
32+
LocalCapabilitiesServiceTestConfig config =
33+
new LocalCapabilitiesServiceTestConfig().setCapabilityStatus(testOne, testStatus);
34+
helper = new LocalServiceTestHelper(config);
35+
helper.setUp();
36+
FetchOptions fo = FetchOptions.Builder.withLimit(10);
37+
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
38+
assertEquals(0, ds.prepare(new Query("yam")).countEntities(fo));
39+
}
40+
}
41+
// [END local_capabilities]
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.google.appengine.samples.unittest;
2+
3+
// [START taskqueue_example_2]
4+
import com.google.appengine.api.taskqueue.DeferredTask;
5+
import com.google.appengine.api.taskqueue.QueueFactory;
6+
import com.google.appengine.api.taskqueue.TaskOptions;
7+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
8+
import com.google.appengine.tools.development.testing.LocalTaskQueueTestConfig;
9+
import org.junit.After;
10+
import org.junit.Before;
11+
import org.junit.Test;
12+
13+
import java.util.concurrent.TimeUnit;
14+
15+
import static org.junit.Assert.*;
16+
17+
public class DeferredTaskTest {
18+
19+
// Unlike CountDownLatch, TaskCountDownlatch lets us reset.
20+
private final LocalTaskQueueTestConfig.TaskCountDownLatch latch =
21+
new LocalTaskQueueTestConfig.TaskCountDownLatch(1);
22+
23+
private final LocalServiceTestHelper helper =
24+
new LocalServiceTestHelper(new LocalTaskQueueTestConfig()
25+
.setDisableAutoTaskExecution(false)
26+
.setCallbackClass(LocalTaskQueueTestConfig.DeferredTaskCallback.class)
27+
.setTaskExecutionLatch(latch));
28+
29+
private static class MyTask implements DeferredTask {
30+
private static boolean taskRan = false;
31+
32+
@Override
33+
public void run() {
34+
taskRan = true;
35+
}
36+
}
37+
38+
@Before
39+
public void setUp() {
40+
helper.setUp();
41+
}
42+
43+
@After
44+
public void tearDown() {
45+
MyTask.taskRan = false;
46+
latch.reset();
47+
helper.tearDown();
48+
}
49+
50+
@Test
51+
public void testTaskGetsRun() throws InterruptedException {
52+
QueueFactory.getDefaultQueue().add(
53+
TaskOptions.Builder.withPayload(new MyTask()));
54+
assertTrue(latch.await(5, TimeUnit.SECONDS));
55+
assertTrue(MyTask.taskRan);
56+
}
57+
}
58+
// [END taskqueue_example_2]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.google.appengine.samples.unittest;
2+
3+
import com.google.appengine.api.datastore.DatastoreService;
4+
import com.google.appengine.api.datastore.DatastoreServiceFactory;
5+
import com.google.appengine.api.datastore.Entity;
6+
import com.google.appengine.api.datastore.Key;
7+
import com.google.appengine.api.datastore.Query;
8+
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
9+
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
10+
import org.junit.After;
11+
import org.junit.Before;
12+
import org.junit.Test;
13+
14+
import static com.google.appengine.api.datastore.FetchOptions.Builder.withLimit;
15+
import static org.junit.Assert.*;
16+
17+
// [START HRD_example_2]
18+
// ...
19+
import com.google.appengine.api.datastore.dev.HighRepJobPolicy;
20+
21+
public class LocalCustomPolicyHighRepDatastoreTest {
22+
private static final class CustomHighRepJobPolicy implements HighRepJobPolicy {
23+
static int newJobCounter = 0;
24+
static int existingJobCounter = 0;
25+
@Override
26+
public boolean shouldApplyNewJob(Key entityGroup) {
27+
// every other new job fails to apply
28+
return newJobCounter++ % 2 == 0;
29+
}
30+
31+
@Override
32+
public boolean shouldRollForwardExistingJob(Key entityGroup) {
33+
// every other existing job fails to apply
34+
return existingJobCounter++ % 2 == 0;
35+
}
36+
}
37+
38+
private final LocalServiceTestHelper helper =
39+
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
40+
.setAlternateHighRepJobPolicyClass(CustomHighRepJobPolicy.class));
41+
42+
@Before
43+
public void setUp() {
44+
helper.setUp();
45+
}
46+
47+
@After
48+
public void tearDown() {
49+
helper.tearDown();
50+
}
51+
52+
@Test
53+
public void testEventuallyConsistentGlobalQueryResult() {
54+
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
55+
ds.put(new Entity("yam")); // applies
56+
ds.put(new Entity("yam")); // does not apply
57+
// first global query only sees the first Entity
58+
assertEquals(1, ds.prepare(new Query("yam")).countEntities(withLimit(10)));
59+
// second global query sees both Entities because we "groom" (attempt to
60+
// apply unapplied jobs) after every query
61+
assertEquals(2, ds.prepare(new Query("yam")).countEntities(withLimit(10)));
62+
}
63+
}
64+
// [END HRD_example_2]

0 commit comments

Comments
 (0)