Skip to content

Commit e402342

Browse files
authored
[Cloud Run] Hello Broken sample (GoogleCloudPlatform#1623)
* draft * Broken debugging sample * pom formatting
1 parent 5894655 commit e402342

File tree

5 files changed

+325
-0
lines changed

5 files changed

+325
-0
lines changed

run/hello-broken/Dockerfile

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright 2019 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# [START run_broken_dockerfile]
16+
# Use the official maven/Java 11 image to create a build artifact.
17+
# https://hub.docker.com/_/maven
18+
FROM maven:3.6.2-jdk-11-slim as builder
19+
20+
# Copy local code to the container image.
21+
WORKDIR /app
22+
COPY pom.xml .
23+
COPY src ./src
24+
25+
# Build a release artifact.
26+
RUN mvn compile assembly:single
27+
28+
# Use the Official OpenJDK image for a lean production stage of our multi-stage build.
29+
# https://hub.docker.com/r/adoptopenjdk/openjdk11/
30+
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
31+
FROM adoptopenjdk/openjdk11:alpine
32+
33+
# [START run_system_package_alpine]
34+
RUN apk --no-cache add graphviz ttf-ubuntu-font-family
35+
# [END run_system_package_alpine]
36+
37+
# Copy the jar to the production image from the builder stage.
38+
COPY --from=builder /app/target/hello-broken-*dependencies.jar /hello-broken.jar
39+
40+
# Run the web service on container startup.
41+
CMD ["java","-jar","/hello-broken.jar"]
42+
# [END run_broken_dockerfile]

run/hello-broken/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Cloud Run Broken Sample
2+
3+
This sample presents broken code in need of troubleshooting. An alternate
4+
resource at `/improved` shows a more stable implementation with more informative
5+
errors and default values.
6+
7+
Use it with the [Local Container Troubleshooting tutorial](http://cloud.google.com/run/docs/tutorials/local-troubleshooting).
8+
9+
For more details on how to work with this sample read the [Google Cloud Run Java Samples README](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/run).
10+
11+
[![Run in Google Cloud][run_img]][run_link]
12+
13+
[run_img]: https://storage.googleapis.com/cloudrun/button.svg
14+
[run_link]: https://deploy.cloud.run/?git_repo=https://github.com/GoogleCloudPlatform/java-docs-samples&dir=run/hello-broken
15+
16+
## Dependencies
17+
18+
* **Spark**: Web server framework.
19+
* **Junit**: [development] Test running framework.

run/hello-broken/pom.xml

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
15+
<modelVersion>4.0.0</modelVersion>
16+
<groupId>com.example.cloudrun</groupId>
17+
<artifactId>hello-broken</artifactId>
18+
<version>0.0.1-SNAPSHOT</version>
19+
<!-- The parent pom defines common style checks and testing strategies for our samples. Removing or replacing it should not affect the execution of the samples in anyway. -->
20+
<parent>
21+
<groupId>com.google.cloud.samples</groupId>
22+
<artifactId>shared-configuration</artifactId>
23+
<version>1.0.11</version>
24+
</parent>
25+
<properties>
26+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
27+
<maven.compiler.source>11</maven.compiler.source>
28+
<maven.compiler.target>11</maven.compiler.target>
29+
</properties>
30+
<dependencies>
31+
<dependency>
32+
<groupId>com.sparkjava</groupId>
33+
<artifactId>spark-core</artifactId>
34+
<version>2.8.0</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>ch.qos.logback</groupId>
38+
<artifactId>logback-classic</artifactId>
39+
<version>1.3.0-alpha4</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.slf4j</groupId>
43+
<artifactId>slf4j-api</artifactId>
44+
<version>1.7.5</version>
45+
</dependency>
46+
<dependency>
47+
<groupId>org.slf4j</groupId>
48+
<artifactId>slf4j-simple</artifactId>
49+
<version>1.6.4</version>
50+
</dependency>
51+
<dependency>
52+
<groupId>ch.qos.logback.contrib</groupId>
53+
<artifactId>logback-json-classic</artifactId>
54+
<version>0.1.5</version>
55+
</dependency>
56+
<dependency>
57+
<groupId>junit</groupId>
58+
<artifactId>junit</artifactId>
59+
<version>4.11</version>
60+
<scope>test</scope>
61+
</dependency>
62+
<dependency>
63+
<groupId>com.github.stefanbirkner</groupId>
64+
<artifactId>system-rules</artifactId>
65+
<version>1.16.0</version>
66+
<scope>test</scope>
67+
</dependency>
68+
</dependencies>
69+
<build>
70+
<plugins>
71+
<plugin>
72+
<artifactId>maven-compiler-plugin</artifactId>
73+
<version>3.8.0</version>
74+
</plugin>
75+
<plugin>
76+
<artifactId>maven-assembly-plugin</artifactId>
77+
<configuration>
78+
<archive>
79+
<manifest>
80+
<mainClass>com.example.cloudrun.App</mainClass>
81+
</manifest>
82+
</archive>
83+
<descriptorRefs>
84+
<descriptorRef>jar-with-dependencies</descriptorRef>
85+
</descriptorRefs>
86+
</configuration>
87+
</plugin>
88+
</plugins>
89+
</build>
90+
</project>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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.cloudrun;
18+
19+
// [START run_broken_service]
20+
import static spark.Spark.get;
21+
import static spark.Spark.port;
22+
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
public class App {
27+
28+
private static final Logger logger = LoggerFactory.getLogger(App.class);
29+
30+
public static void main(String[] args) {
31+
int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
32+
port(port);
33+
34+
get(
35+
"/",
36+
(req, res) -> {
37+
logger.info("Hello: received request.");
38+
// [START run_broken_service_problem]
39+
String name = System.getenv("NAME");
40+
if (name == null) {
41+
// Standard error logs do not appear in Stackdriver Error Reporting.
42+
System.err.println("Environment validation failed.");
43+
String msg = "Missing required server parameter";
44+
logger.error(msg, new Exception(msg));
45+
res.status(500);
46+
return "Internal Server Error";
47+
}
48+
// [END run_broken_service_problem]
49+
res.status(200);
50+
return String.format("Hello %s!", name);
51+
});
52+
53+
get(
54+
"/improved",
55+
(req, res) -> {
56+
logger.info("Hello: received request.");
57+
// [START run_broken_service_upgrade]
58+
String name = System.getenv().getOrDefault("NAME", "World");
59+
if (System.getenv("NAME") == null) {
60+
logger.warn(String.format("NAME not set, default to %s", name));
61+
}
62+
// [END run_broken_service_upgrade]
63+
res.status(200);
64+
return String.format("Hello %s!", name);
65+
});
66+
}
67+
}
68+
// [END run_broken_service]
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
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.cloudrun;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertTrue;
21+
import static spark.Spark.awaitInitialization;
22+
import static spark.Spark.stop;
23+
24+
import java.io.IOException;
25+
import java.net.HttpURLConnection;
26+
import java.net.URL;
27+
import org.junit.AfterClass;
28+
import org.junit.BeforeClass;
29+
import org.junit.Rule;
30+
import org.junit.Test;
31+
import org.junit.contrib.java.lang.system.EnvironmentVariables;
32+
import spark.utils.IOUtils;
33+
34+
public class AppTest {
35+
36+
private static final String brokenUrl = "/";
37+
private static final String fixedUrl = "/improved";
38+
39+
@Rule public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
40+
41+
@BeforeClass
42+
public static void beforeClass() {
43+
App app = new App();
44+
app.main(new String[] {});
45+
awaitInitialization();
46+
}
47+
48+
@AfterClass
49+
public static void afterClass() {
50+
stop();
51+
}
52+
53+
@Test
54+
public void brokenShouldFailOnAnyRequest() {
55+
try {
56+
TestResponse response = executeRequest("GET", brokenUrl);
57+
assertEquals(true, response);
58+
} catch (IOException e) {
59+
assertTrue(e.getMessage().startsWith("Server returned HTTP response code: 500"));
60+
}
61+
}
62+
63+
@Test
64+
public void fixShouldSucceedWithDefault() throws IOException {
65+
TestResponse response = executeRequest("GET", fixedUrl);
66+
assertEquals(200, response.status);
67+
assertEquals("Hello World!", response.body);
68+
}
69+
70+
@Test
71+
public void brokenShouldSucceedWithName() throws IOException {
72+
environmentVariables.set("NAME", "test");
73+
TestResponse response = executeRequest("GET", brokenUrl);
74+
assertEquals(200, response.status);
75+
assertEquals("Hello test!", response.body);
76+
}
77+
78+
@Test
79+
public void fixShouldSucceedWithName() throws IOException {
80+
environmentVariables.set("NAME", "test");
81+
TestResponse response = executeRequest("GET", fixedUrl);
82+
assertEquals(200, response.status);
83+
assertEquals("Hello test!", response.body);
84+
}
85+
86+
private static TestResponse executeRequest(String method, String path) throws IOException {
87+
URL url = new URL("http://localhost:8080" + path);
88+
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
89+
connection.setRequestMethod(method);
90+
connection.setDoOutput(true);
91+
connection.connect();
92+
String body = IOUtils.toString(connection.getInputStream());
93+
return new TestResponse(connection.getResponseCode(), body);
94+
}
95+
96+
public static class TestResponse {
97+
98+
public final String body;
99+
public final int status;
100+
101+
public TestResponse(int status, String body) {
102+
this.status = status;
103+
this.body = body;
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)