Skip to content

Commit 5a53097

Browse files
authored
Add PubSub Tutorial for Cloud Run (#1521)
* Add draft * Checkstyle and parent updatess * Remvoe maven plugin
1 parent a15074f commit 5a53097

File tree

7 files changed

+381
-0
lines changed

7 files changed

+381
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Use the official maven/Java 11 image to create a build artifact.
2+
# https://hub.docker.com/_/maven
3+
FROM maven:3.6.1-jdk-11 as builder
4+
5+
# Copy local code to the container image.
6+
WORKDIR /app
7+
COPY pom.xml .
8+
COPY src ./src
9+
10+
# Build a release artifact.
11+
RUN mvn package -DskipTests
12+
13+
# Use AdoptOpenJDK for base image.
14+
# It's important to use OpenJDK 8u191 or above that has container support enabled.
15+
# https://hub.docker.com/r/adoptopenjdk/openjdk11
16+
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
17+
FROM adoptopenjdk/openjdk11:x86_64-alpine-jdk-11.0.3_7-slim
18+
19+
# Copy the jar to the production image from the builder stage.
20+
COPY --from=builder /app/target/cloudrun-pubsub-*.jar /cloudrun-pubsub.jar
21+
22+
# Run the web service on container startup.
23+
CMD ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/cloudrun-pubsub.jar"]
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Cloud Run Pub/Sub Tutorial Sample
2+
3+
This sample shows how to create a service that processes Pub/Sub messages.
4+
5+
Use it with the [Cloud Pub/Sub with Cloud Run tutorial](http://cloud.google.com/run/docs/tutorials/pubsub).
6+
7+
## Build
8+
9+
```
10+
docker build --tag pubsub-tutorial:java .
11+
```
12+
13+
## Run
14+
15+
```
16+
docker run --rm -p 9090:8080 pubsub-tutorial:java
17+
```
18+
19+
## Test
20+
21+
```
22+
mvn clean verify
23+
```
24+
25+
## Deploy
26+
27+
```
28+
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/pubsub-tutorial
29+
gcloud alpha run deploy pubsub-tutorial --image gcr.io/${GOOGLE_CLOUD_PROJECT}/pubsub-tutorial
30+
```
+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright 2019 Google LLC
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+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
-->
14+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
15+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
16+
<modelVersion>4.0.0</modelVersion>
17+
<groupId>com.example.appengine</groupId>
18+
<artifactId>cloudrun-pubsub</artifactId>
19+
<version>0.0.1-SNAPSHOT</version>
20+
21+
<!--
22+
The parent pom defines common style checks and testing strategies for our samples.
23+
Removing or replacing it should not affect the execution of the samples in anyway.
24+
-->
25+
<parent>
26+
<groupId>com.google.cloud.samples</groupId>
27+
<artifactId>shared-configuration</artifactId>
28+
<version>1.0.11</version>
29+
</parent>
30+
31+
<properties>
32+
<maven.compiler.target>11</maven.compiler.target>
33+
<maven.compiler.source>11</maven.compiler.source>
34+
</properties>
35+
36+
<dependencyManagement>
37+
<dependencies>
38+
<dependency>
39+
<!-- Import dependency management from Spring Boot -->
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot-dependencies</artifactId>
42+
<version>2.1.4.RELEASE</version>
43+
<type>pom</type>
44+
<scope>import</scope>
45+
</dependency>
46+
47+
<dependency>
48+
<groupId>org.springframework.cloud</groupId>
49+
<artifactId>spring-cloud-dependencies</artifactId>
50+
<version>Greenwich.SR1</version>
51+
<type>pom</type>
52+
<scope>import</scope>
53+
</dependency>
54+
</dependencies>
55+
</dependencyManagement>
56+
57+
<dependencies>
58+
<dependency>
59+
<groupId>org.springframework.boot</groupId>
60+
<artifactId>spring-boot-starter-web</artifactId>
61+
</dependency>
62+
63+
<dependency>
64+
<groupId>org.apache.commons</groupId>
65+
<artifactId>commons-lang3</artifactId>
66+
<version>3.9</version>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>org.springframework.boot</groupId>
71+
<artifactId>spring-boot-starter-test</artifactId>
72+
<scope>test</scope>
73+
</dependency>
74+
</dependencies>
75+
76+
<build>
77+
<plugins>
78+
<plugin>
79+
<groupId>org.springframework.boot</groupId>
80+
<artifactId>spring-boot-maven-plugin</artifactId>
81+
<version>2.1.4.RELEASE</version>
82+
<executions>
83+
<execution>
84+
<goals>
85+
<goal>repackage</goal>
86+
</goals>
87+
</execution>
88+
</executions>
89+
</plugin>
90+
</plugins>
91+
</build>
92+
93+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright 2019 Google LLC
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.cloudrunpubsub;
18+
19+
// Body.Message is the payload of a Pub/Sub event. Please refer to the docs for
20+
// additional information regarding Pub/Sub events.
21+
public class Body {
22+
23+
private Message message;
24+
25+
public Body() {}
26+
27+
public Message getMessage() {
28+
return message;
29+
}
30+
31+
public void setMessage(Message message) {
32+
this.message = message;
33+
}
34+
35+
public class Message {
36+
37+
private String messageId;
38+
private String publishTime;
39+
private String data;
40+
41+
public Message() {}
42+
43+
public Message(String messageId, String publishTime, String data) {
44+
this.messageId = messageId;
45+
this.publishTime = publishTime;
46+
this.data = data;
47+
}
48+
49+
public String getMessageId() {
50+
return messageId;
51+
}
52+
53+
public void setMessageId(String messageId) {
54+
this.messageId = messageId;
55+
}
56+
57+
public String getPublishTime() {
58+
return publishTime;
59+
}
60+
61+
public void setPublishTime(String publishTime) {
62+
this.publishTime = publishTime;
63+
}
64+
65+
public String getData() {
66+
return data;
67+
}
68+
69+
public void setData(String data) {
70+
this.data = data;
71+
}
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2019 Google LLC
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+
// [START run_pubsub_server_setup]
18+
19+
package com.example.appengine.cloudrunpubsub;
20+
21+
import org.springframework.boot.SpringApplication;
22+
import org.springframework.boot.autoconfigure.SpringBootApplication;
23+
24+
@SpringBootApplication
25+
public class CloudrunPubsubApplication {
26+
public static void main(String[] args) {
27+
SpringApplication.run(CloudrunPubsubApplication.class, args);
28+
}
29+
}
30+
// [END run_pubsub_server_setup]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2019 Google LLC
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.cloudrunpubsub;
18+
19+
import java.util.Base64;
20+
import org.apache.commons.lang3.StringUtils;
21+
import org.springframework.http.HttpStatus;
22+
import org.springframework.http.ResponseEntity;
23+
import org.springframework.web.bind.annotation.RequestBody;
24+
import org.springframework.web.bind.annotation.RequestMapping;
25+
import org.springframework.web.bind.annotation.RequestMethod;
26+
import org.springframework.web.bind.annotation.RestController;
27+
28+
// [START run_pubsub_handler]
29+
// PubsubController consumes a Pub/Sub message.
30+
@RestController
31+
public class PubsubController {
32+
@RequestMapping(value = "/", method = RequestMethod.POST)
33+
public ResponseEntity receiveMessage(@RequestBody Body body) {
34+
// Get PubSub message from request body.
35+
Body.Message message = body.getMessage();
36+
if (message == null) {
37+
String msg = "Bad Request: invalid Pub/Sub message format";
38+
System.out.println(msg);
39+
return new ResponseEntity(msg, HttpStatus.BAD_REQUEST);
40+
}
41+
42+
String data = message.getData();
43+
String target =
44+
!StringUtils.isEmpty(data) ? new String(Base64.getDecoder().decode(data)) : "World";
45+
String msg = "Hello " + target + "!";
46+
47+
System.out.println(msg);
48+
return new ResponseEntity(msg, HttpStatus.OK);
49+
}
50+
}
51+
// [END run_pubsub_handler]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2019 Google LLC
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.cloudrunpubsub;
18+
19+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
20+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
21+
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
26+
import org.springframework.boot.test.context.SpringBootTest;
27+
import org.springframework.http.MediaType;
28+
import org.springframework.test.context.junit4.SpringRunner;
29+
import org.springframework.test.web.servlet.MockMvc;
30+
31+
@RunWith(SpringRunner.class)
32+
@SpringBootTest
33+
@AutoConfigureMockMvc
34+
public class PubsubControllerTests {
35+
36+
@Autowired private MockMvc mockMvc;
37+
38+
@Test
39+
public void addEmptyBody() throws Exception {
40+
mockMvc.perform(post("/")).andExpect(status().isBadRequest());
41+
}
42+
43+
@Test
44+
public void addNoMessage() throws Exception {
45+
String mockBody = "{}";
46+
47+
mockMvc
48+
.perform(post("/").contentType(MediaType.APPLICATION_JSON).content(mockBody))
49+
.andExpect(status().isBadRequest());
50+
}
51+
52+
@Test
53+
public void addInvalidMimetype() throws Exception {
54+
String mockBody = "{\"message\":{\"data\":\"dGVzdA==\","
55+
+ "\"attributes\":{},\"messageId\":\"91010751788941\""
56+
+ ",\"publishTime\":\"2017-09-25T23:16:42.302Z\"}}";
57+
58+
mockMvc
59+
.perform(post("/").contentType(MediaType.TEXT_HTML).content(mockBody))
60+
.andExpect(status().isUnsupportedMediaType());
61+
}
62+
63+
@Test
64+
public void addMinimalBody() throws Exception {
65+
String mockBody = "{\"message\":{}}";
66+
67+
mockMvc
68+
.perform(post("/").contentType(MediaType.APPLICATION_JSON).content(mockBody))
69+
.andExpect(status().isOk());
70+
}
71+
72+
@Test
73+
public void addFullBody() throws Exception {
74+
String mockBody = "{\"message\":{\"data\":\"dGVzdA==\","
75+
+ "\"attributes\":{},\"messageId\":\"91010751788941\""
76+
+ ",\"publishTime\":\"2017-09-25T23:16:42.302Z\"}}";
77+
mockMvc
78+
.perform(post("/").contentType(MediaType.APPLICATION_JSON).content(mockBody))
79+
.andExpect(status().isOk());
80+
}
81+
}

0 commit comments

Comments
 (0)