From f1c11281dc67e5c61a5d0c66cfdb6d6aca9c1eba Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Fri, 21 Jul 2017 09:26:37 -0600 Subject: [PATCH 01/22] Initial commit --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..4fa332f5c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build +.gradle +.idea +*.iml +ci/variables.yml From bc4f62e5a1d0614b79944cc602df6e0271297ab2 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Wed, 1 Nov 2017 11:01:07 +0530 Subject: [PATCH 02/22] All Changes --- build.gradle | 19 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53539 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 160 ++++++++++++++++++ gradlew.bat | 90 ++++++++++ settings.gradle | 1 + .../pal/tracker/PalTrackerApplication.java | 12 ++ .../pal/tracker/WelcomeController.java | 13 ++ 8 files changed, 301 insertions(+) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java create mode 100644 src/main/java/io/pivotal/pal/tracker/WelcomeController.java diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..14179dacb --- /dev/null +++ b/build.gradle @@ -0,0 +1,19 @@ +plugins { + id "java" + id "org.springframework.boot" version "1.5.4.RELEASE" +} + +repositories{ + mavenCentral() +} + +dependencies{ + compile("org.springframework.boot:spring-boot-starter-web") +// compile("com.fasterxml.jackson.core:jackson-databind") +// compile("org.hibernate:hibernate-validator") +// compile("org.springframework:spring-web") +// compile("org.springframework:spring-webmvc") +// compile("org.springframework.boot:spring-boot-starter") +// compile("org.springframework.boot:spring-boot-starter-tomcat") + +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..3391a4cdf6b4057b1289f45659e6e46fd9902ce6 GIT binary patch literal 53539 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..45d7838e2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Oct 31 15:45:47 IST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..9d82f7891 --- /dev/null +++ b/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..aec99730b --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..ef961960e --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "pal-tracker" \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java new file mode 100644 index 000000000..981a139d7 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -0,0 +1,12 @@ +package io.pivotal.pal.tracker; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PalTrackerApplication { + public static void main(String[] args) { + SpringApplication.run(PalTrackerApplication.class, args); + } +} diff --git a/src/main/java/io/pivotal/pal/tracker/WelcomeController.java b/src/main/java/io/pivotal/pal/tracker/WelcomeController.java new file mode 100644 index 000000000..2d477ae71 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/WelcomeController.java @@ -0,0 +1,13 @@ +package io.pivotal.pal.tracker; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class WelcomeController { + + @GetMapping("/") + public String sayHello() { + return "hello"; + } +} \ No newline at end of file From ee1c934a5ce15a70257771dddb3c634fd3b1bfcc Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Thu, 20 Jul 2017 13:56:50 -0600 Subject: [PATCH 03/22] Add tests for deployment lab --- .../pal/tracker/EnvControllerTest.java | 28 +++++++++++++++++++ .../pal/tracker/WelcomeControllerTest.java | 16 +++++++++++ .../pal/trackerapi/WelcomeApiTest.java | 26 +++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 src/test/java/test/pivotal/pal/tracker/EnvControllerTest.java create mode 100644 src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java create mode 100644 src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java diff --git a/src/test/java/test/pivotal/pal/tracker/EnvControllerTest.java b/src/test/java/test/pivotal/pal/tracker/EnvControllerTest.java new file mode 100644 index 000000000..fda0f0f34 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/EnvControllerTest.java @@ -0,0 +1,28 @@ +package test.pivotal.pal.tracker; + +import org.junit.Test; + +import java.util.Map; +import io.pivotal.pal.tracker.EnvController; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EnvControllerTest { + @Test + public void getEnv() throws Exception { + EnvController controller = new EnvController( + "8675", + "12G", + "34", + "123.sesame.street" + ); + + Map env = controller.getEnv(); + + assertThat(env.get("PORT")).isEqualTo("8675"); + assertThat(env.get("MEMORY_LIMIT")).isEqualTo("12G"); + assertThat(env.get("CF_INSTANCE_INDEX")).isEqualTo("34"); + assertThat(env.get("CF_INSTANCE_ADDR")).isEqualTo("123.sesame.street"); + } + +} diff --git a/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java new file mode 100644 index 000000000..bfa8271a0 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java @@ -0,0 +1,16 @@ +package test.pivotal.pal.tracker; + +import io.pivotal.pal.tracker.WelcomeController; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WelcomeControllerTest { + + @Test + public void itSaysHello() throws Exception { + WelcomeController controller = new WelcomeController("A welcome message"); + + assertThat(controller.sayHello()).isEqualTo("A welcome message"); + } +} diff --git a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java new file mode 100644 index 000000000..cc7091ed4 --- /dev/null +++ b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java @@ -0,0 +1,26 @@ +package test.pivotal.pal.trackerapi; + +import io.pivotal.pal.tracker.PalTrackerApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) +public class WelcomeApiTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void exampleTest() { + String body = this.restTemplate.getForObject("/", String.class); + assertThat(body).isEqualTo("Hello from test"); + } +} From 9bca67b2ca8469286963a1e0a5d93ef651e0afb4 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Wed, 1 Nov 2017 12:52:39 +0530 Subject: [PATCH 04/22] Changes for Test and cf env var --- build.gradle | 10 ++++- .../io/pivotal/pal/tracker/EnvController.java | 41 +++++++++++++++++++ .../java/io/pivotal/pal/tracker/Message.java | 18 ++++++++ .../pal/tracker/WelcomeController.java | 14 ++++++- .../pal/tracker/WelcomeControllerTest.java | 4 +- .../pal/trackerapi/WelcomeApiTest.java | 2 +- 6 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 src/main/java/io/pivotal/pal/tracker/EnvController.java create mode 100644 src/main/java/io/pivotal/pal/tracker/Message.java diff --git a/build.gradle b/build.gradle index 14179dacb..060617da8 100644 --- a/build.gradle +++ b/build.gradle @@ -15,5 +15,13 @@ dependencies{ // compile("org.springframework:spring-webmvc") // compile("org.springframework.boot:spring-boot-starter") // compile("org.springframework.boot:spring-boot-starter-tomcat") + testCompile("org.springframework.boot:spring-boot-starter-test") +} + +bootRun.environment([ + "WELCOME_MESSAGE": "Hello", +]) -} \ No newline at end of file +test.environment([ + "WELCOME_MESSAGE": "Hello from Test", +]) \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/EnvController.java b/src/main/java/io/pivotal/pal/tracker/EnvController.java new file mode 100644 index 000000000..afcff11c5 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/EnvController.java @@ -0,0 +1,41 @@ +package io.pivotal.pal.tracker; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +@RestController +public class EnvController { + + private final String port; + private final String memoryLimit; + private final String cfInstanceIndex; + private final String cfInstanceAddress; + + public EnvController( + @Value("${PORT:NOT SET}") String port, + @Value("${MEMORY_LIMIT:NOT SET}") String memoryLimit, + @Value("${CF_INSTANCE_INDEX:NOT SET}") String cfInstanceIndex, + @Value("${CF_INSTANCE_ADDR:NOT SET}") String cfInstanceAddress + ) { + this.port = port; + this.memoryLimit = memoryLimit; + this.cfInstanceIndex = cfInstanceIndex; + this.cfInstanceAddress = cfInstanceAddress; + } + + @GetMapping("/env") + public Map getEnv() { + Map env = new HashMap<>(); + + env.put("PORT", port); + env.put("MEMORY_LIMIT", memoryLimit); + env.put("CF_INSTANCE_INDEX", cfInstanceIndex); + env.put("CF_INSTANCE_ADDR", cfInstanceAddress); + + return env; + } +} diff --git a/src/main/java/io/pivotal/pal/tracker/Message.java b/src/main/java/io/pivotal/pal/tracker/Message.java new file mode 100644 index 000000000..05d01e293 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/Message.java @@ -0,0 +1,18 @@ +package io.pivotal.pal.tracker; + +import org.springframework.stereotype.Service; + +@Service +public class Message { + + + String message; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/java/io/pivotal/pal/tracker/WelcomeController.java b/src/main/java/io/pivotal/pal/tracker/WelcomeController.java index 2d477ae71..3983a5cdb 100644 --- a/src/main/java/io/pivotal/pal/tracker/WelcomeController.java +++ b/src/main/java/io/pivotal/pal/tracker/WelcomeController.java @@ -1,13 +1,25 @@ package io.pivotal.pal.tracker; + + +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; + @RestController public class WelcomeController { + + private String message; + public WelcomeController(@Value("${WELCOME_MESSAGE}") String message) + { + this.message = message; + } + + @GetMapping("/") public String sayHello() { - return "hello"; + return message; } } \ No newline at end of file diff --git a/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java index bfa8271a0..3675bfde4 100644 --- a/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java +++ b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java @@ -9,8 +9,8 @@ public class WelcomeControllerTest { @Test public void itSaysHello() throws Exception { - WelcomeController controller = new WelcomeController("A welcome message"); + WelcomeController controller = new WelcomeController("Hello from Test"); - assertThat(controller.sayHello()).isEqualTo("A welcome message"); + assertThat(controller.sayHello()).isEqualTo("Hello from Test"); } } diff --git a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java index cc7091ed4..127413fb1 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java @@ -21,6 +21,6 @@ public class WelcomeApiTest { @Test public void exampleTest() { String body = this.restTemplate.getForObject("/", String.class); - assertThat(body).isEqualTo("Hello from test"); + assertThat(body).isEqualTo("Hello from Test"); } } From c4e9915046799e75e7afec9c4f5adb5037a75783 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Wed, 1 Nov 2017 13:53:49 +0530 Subject: [PATCH 05/22] Deploy a SpringBoot App to Cloud Foundry Assignment --- manifest.yml | 7 +++++++ .../test/pivotal/pal/tracker/WelcomeControllerTest.java | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 manifest.yml diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 000000000..7f06f91ee --- /dev/null +++ b/manifest.yml @@ -0,0 +1,7 @@ +--- +applications: +- name: pal-tracker + path: build/libs/pal-tracker.jar + random-route: true + env: + WELCOME_MESSAGE: Hello from Cloud Foundry \ No newline at end of file diff --git a/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java index 3675bfde4..f08960036 100644 --- a/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java +++ b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java @@ -9,8 +9,8 @@ public class WelcomeControllerTest { @Test public void itSaysHello() throws Exception { - WelcomeController controller = new WelcomeController("Hello from Test"); + WelcomeController controller = new WelcomeController("A welcome Message"); - assertThat(controller.sayHello()).isEqualTo("Hello from Test"); + assertThat(controller.sayHello()).isEqualTo("A welcome Message"); } } From 21990fc584e73cf61a296ff5d9a127388a343800 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Wed, 1 Nov 2017 17:21:13 +0530 Subject: [PATCH 06/22] new version of gradle --- ci/build.yml | 23 ++++++++ ci/pipeline.yml | 31 ++++++++++ ci/variables.example.yml | 9 +++ gradle/wrapper/gradle-wrapper.jar | Bin 53539 -> 54727 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 72 +++++++++++++---------- gradlew.bat | 14 ++--- manifest.yml | 4 +- 8 files changed, 111 insertions(+), 45 deletions(-) create mode 100644 ci/build.yml create mode 100644 ci/pipeline.yml create mode 100644 ci/variables.example.yml diff --git a/ci/build.yml b/ci/build.yml new file mode 100644 index 000000000..c2303fed4 --- /dev/null +++ b/ci/build.yml @@ -0,0 +1,23 @@ +platform: linux + +image_resource: + type: docker-image + source: + repository: openjdk + tag: '8-jdk' + +inputs: + - name: pal-tracker + +outputs: + - name: build-output + +run: + path: bash + args: + - -exc + - | + cd pal-tracker + chmod +x gradlew + ./gradlew build + cp build/libs/pal-tracker.jar ../build-output \ No newline at end of file diff --git a/ci/pipeline.yml b/ci/pipeline.yml new file mode 100644 index 000000000..01d389043 --- /dev/null +++ b/ci/pipeline.yml @@ -0,0 +1,31 @@ +--- +resources: +- name: pal-tracker + type: git + source: + uri: {{github-repository}} + branch: master + private_key: {{github-private-key}} + +- name: deploy + type: cf + source: + api: {{cf-api-url}} + username: {{cf-username}} + password: {{cf-password}} + organization: {{cf-org}} + space: sandbox + +jobs: +- name: build-and-deploy + plan: + - get: pal-tracker + trigger: true + - task: build and test + file: pal-tracker/ci/build.yml + - put: deploy + params: + manifest: pal-tracker/manifest.yml + path: build-output/pal-tracker.jar + environment_variables: + WELCOME_MESSAGE: "Hello from Concourse" \ No newline at end of file diff --git a/ci/variables.example.yml b/ci/variables.example.yml new file mode 100644 index 000000000..649a717a6 --- /dev/null +++ b/ci/variables.example.yml @@ -0,0 +1,9 @@ +cf-api-url: CF_API_URL +cf-username: CF_USERNAME +cf-password: CF_PASSWORD +cf-org: CF_ORG +github-repository: git@github.com:GITHUB_USERNAME/pal-tracker.git +github-private-key: | + -----BEGIN RSA PRIVATE KEY----- + REPLACE WITH YOUR PRIVATE KEY HERE + -----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 3391a4cdf6b4057b1289f45659e6e46fd9902ce6..27768f1bbac3ce2d055b20d521f12da78d331e8e 100644 GIT binary patch delta 26893 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 A)Bpeg delta 25742 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 45d7838e2..89626eaa7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Oct 31 15:45:47 IST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip diff --git a/gradlew b/gradlew index 9d82f7891..cccdd3d51 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec99730b..e95643d6a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/manifest.yml b/manifest.yml index 7f06f91ee..9b7fd344e 100644 --- a/manifest.yml +++ b/manifest.yml @@ -2,6 +2,4 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - random-route: true - env: - WELCOME_MESSAGE: Hello from Cloud Foundry \ No newline at end of file + random-route: true \ No newline at end of file From b075c4a7a53d3a066098fdd457990f0b6015f708 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Thu, 2 Nov 2017 10:17:09 +0530 Subject: [PATCH 07/22] changes for multiple pipelines --- ci/build.yml | 5 +- ci/pipeline.yml | 66 ++++++++++++++++++++++--- ci/variables.example.yml | 5 +- manifest.yml => manifest-production.yml | 2 +- manifest-review.yml | 5 ++ 5 files changed, 72 insertions(+), 11 deletions(-) rename manifest.yml => manifest-production.yml (72%) create mode 100644 manifest-review.yml diff --git a/ci/build.yml b/ci/build.yml index c2303fed4..e2bb9473a 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -8,6 +8,7 @@ image_resource: inputs: - name: pal-tracker + - name: version outputs: - name: build-output @@ -19,5 +20,5 @@ run: - | cd pal-tracker chmod +x gradlew - ./gradlew build - cp build/libs/pal-tracker.jar ../build-output \ No newline at end of file + ./gradlew -P version=$(cat ../version/number) build + cp build/libs/pal-tracker-*.jar ../build-output \ No newline at end of file diff --git a/ci/pipeline.yml b/ci/pipeline.yml index 01d389043..c34c3b2a9 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -7,25 +7,77 @@ resources: branch: master private_key: {{github-private-key}} -- name: deploy +- name: pal-tracker-artifacts + type: s3 + source: + bucket: {{aws-bucket}} + regexp: releases/pal-tracker-(.*).jar + access_key_id: {{aws-access-key-id}} + secret_access_key: {{aws-secret-access-key}} + +- name: version + type: semver + source: + bucket: {{aws-bucket}} + key: pal-tracker/version + access_key_id: {{aws-access-key-id}} + secret_access_key: {{aws-secret-access-key}} + +- name: review-deployment + type: cf + source: + api: {{cf-api-url}} + username: {{cf-username}} + password: {{cf-password}} + organization: {{cf-org}} + space: review + +- name: production-deployment type: cf source: api: {{cf-api-url}} username: {{cf-username}} password: {{cf-password}} organization: {{cf-org}} - space: sandbox + space: production jobs: -- name: build-and-deploy +- name: build plan: - get: pal-tracker trigger: true + - get: version + params: {bump: patch} - task: build and test file: pal-tracker/ci/build.yml - - put: deploy + - put: pal-tracker-artifacts + params: + file: build-output/pal-tracker-*.jar + - put: version + params: + file: version/number + +- name: deploy-review + plan: + - get: pal-tracker + - get: pal-tracker-artifacts + trigger: true + passed: [build] + - put: review-deployment + params: + manifest: pal-tracker/manifest-review.yml + path: pal-tracker-artifacts/pal-tracker-*.jar + environment_variables: + WELCOME_MESSAGE: "Hello from the review environment" + +- name: deploy-production + plan: + - get: pal-tracker + - get: pal-tracker-artifacts + passed: [deploy-review] + - put: production-deployment params: - manifest: pal-tracker/manifest.yml - path: build-output/pal-tracker.jar + manifest: pal-tracker/manifest-production.yml + path: pal-tracker-artifacts/pal-tracker-*.jar environment_variables: - WELCOME_MESSAGE: "Hello from Concourse" \ No newline at end of file + WELCOME_MESSAGE: "Hello from the production environment" \ No newline at end of file diff --git a/ci/variables.example.yml b/ci/variables.example.yml index 649a717a6..3cb4a835f 100644 --- a/ci/variables.example.yml +++ b/ci/variables.example.yml @@ -6,4 +6,7 @@ github-repository: git@github.com:GITHUB_USERNAME/pal-tracker.git github-private-key: | -----BEGIN RSA PRIVATE KEY----- REPLACE WITH YOUR PRIVATE KEY HERE - -----END RSA PRIVATE KEY----- \ No newline at end of file + -----END RSA PRIVATE KEY----- + aws-access-key-id: + aws-secret-access-key: + aws-bucket: \ No newline at end of file diff --git a/manifest.yml b/manifest-production.yml similarity index 72% rename from manifest.yml rename to manifest-production.yml index 9b7fd344e..5a715dec6 100644 --- a/manifest.yml +++ b/manifest-production.yml @@ -2,4 +2,4 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - random-route: true \ No newline at end of file + host: ps-pal-tracker-suchi \ No newline at end of file diff --git a/manifest-review.yml b/manifest-review.yml new file mode 100644 index 000000000..fb723f8dd --- /dev/null +++ b/manifest-review.yml @@ -0,0 +1,5 @@ +--- +applications: +- name: pal-tracker + path: build/libs/pal-tracker.jar + host: ps-pal-tracker-review-suchi \ No newline at end of file From bf5e5d627a4d6533e7c8c45accfe382502320601 Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Thu, 20 Jul 2017 15:04:20 -0600 Subject: [PATCH 08/22] Add tests for MVC lab --- .../InMemoryTimeEntryRepositoryTest.java | 71 ++++++++++ .../pal/tracker/TimeEntryControllerTest.java | 106 +++++++++++++++ .../pal/trackerapi/TimeEntryApiTest.java | 126 ++++++++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java create mode 100644 src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java create mode 100644 src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java diff --git a/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java b/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java new file mode 100644 index 000000000..c88bb8266 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java @@ -0,0 +1,71 @@ +package test.pivotal.pal.tracker; + +import io.pivotal.pal.tracker.InMemoryTimeEntryRepository; +import io.pivotal.pal.tracker.TimeEntry; +import org.junit.Test; + +import java.time.LocalDate; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +public class InMemoryTimeEntryRepositoryTest { + @Test + public void create() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + TimeEntry createdTimeEntry = repo.create(new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8)); + + TimeEntry expected = new TimeEntry(1L, 123, 456, LocalDate.parse("2017-01-08"), 8); + assertThat(createdTimeEntry).isEqualTo(expected); + + TimeEntry readEntry = repo.find(createdTimeEntry.getId()); + assertThat(readEntry).isEqualTo(expected); + } + + @Test + public void find() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + repo.create(new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8)); + + TimeEntry expected = new TimeEntry(1L, 123, 456, LocalDate.parse("2017-01-08"), 8); + TimeEntry readEntry = repo.find(1L); + assertThat(readEntry).isEqualTo(expected); + } + + @Test + public void list() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + repo.create(new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8)); + repo.create(new TimeEntry(789, 654, LocalDate.parse("2017-01-07"), 4)); + + List expected = asList( + new TimeEntry(1L, 123, 456, LocalDate.parse("2017-01-08"), 8), + new TimeEntry(2L, 789, 654, LocalDate.parse("2017-01-07"), 4) + ); + assertThat(repo.list()).isEqualTo(expected); + } + + @Test + public void update() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + TimeEntry created = repo.create(new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8)); + + TimeEntry updatedEntry = repo.update( + created.getId(), + new TimeEntry(321, 654, LocalDate.parse("2017-01-09"), 5)); + + TimeEntry expected = new TimeEntry(created.getId(), 321, 654, LocalDate.parse("2017-01-09"), 5); + assertThat(updatedEntry).isEqualTo(expected); + assertThat(repo.find(created.getId())).isEqualTo(expected); + } + + @Test + public void delete() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + TimeEntry created = repo.create(new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8)); + + repo.delete(created.getId()); + assertThat(repo.list()).isEmpty(); + } +} diff --git a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java new file mode 100644 index 000000000..f7c0090e3 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java @@ -0,0 +1,106 @@ +package test.pivotal.pal.tracker; + +import io.pivotal.pal.tracker.TimeEntry; +import io.pivotal.pal.tracker.TimeEntryController; +import io.pivotal.pal.tracker.TimeEntryRepository; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.time.LocalDate; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.*; + +public class TimeEntryControllerTest { + private TimeEntryRepository timeEntryRepository; + private TimeEntryController controller; + + @Before + public void setUp() throws Exception { + timeEntryRepository = mock(TimeEntryRepository.class); + controller = new TimeEntryController(timeEntryRepository); + } + + @Test + public void testCreate() throws Exception { + TimeEntry expected = new TimeEntry(1L, 123, 456, LocalDate.parse("2017-01-08"), 8); + doReturn(expected) + .when(timeEntryRepository) + .create(any(TimeEntry.class)); + + ResponseEntity response = controller.create(new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8)); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(response.getBody()).isEqualTo(expected); + } + + @Test + public void testRead() throws Exception { + TimeEntry expected = new TimeEntry(1L, 123, 456, LocalDate.parse("2017-01-08"), 8); + doReturn(expected) + .when(timeEntryRepository) + .find(1L); + + ResponseEntity response = controller.read(1L); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isEqualTo(expected); + } + + @Test + public void testRead_NotFound() throws Exception { + doReturn(null) + .when(timeEntryRepository) + .find(1L); + + ResponseEntity response = controller.read(1L); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + + @Test + public void testList() throws Exception { + List expected = asList( + new TimeEntry(1, 123, 456, LocalDate.parse("2017-01-08"), 8), + new TimeEntry(2, 789, 321, LocalDate.parse("2017-01-07"), 4) + ); + doReturn(expected).when(timeEntryRepository).list(); + + ResponseEntity> response = controller.list(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isEqualTo(expected); + } + + @Test + public void testUpdate() throws Exception { + TimeEntry expected = new TimeEntry(1, 987, 654, LocalDate.parse("2017-01-07"), 4); + doReturn(expected) + .when(timeEntryRepository) + .update(eq(1L), any(TimeEntry.class)); + + ResponseEntity response = controller.update(1L, expected); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isEqualTo(expected); + } + + @Test + public void testUpdate_NotFound() throws Exception { + doReturn(null) + .when(timeEntryRepository) + .update(eq(1L), any(TimeEntry.class)); + + ResponseEntity response = controller.update(1L, new TimeEntry()); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + + @Test + public void testDelete() throws Exception { + ResponseEntity response = controller.delete(1L); + verify(timeEntryRepository).delete(1L); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + } +} diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java new file mode 100644 index 000000000..b742e5447 --- /dev/null +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -0,0 +1,126 @@ +package test.pivotal.pal.trackerapi; + +import com.jayway.jsonpath.DocumentContext; +import io.pivotal.pal.tracker.PalTrackerApplication; +import io.pivotal.pal.tracker.TimeEntry; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import java.time.LocalDate; +import java.util.Collection; + +import static com.jayway.jsonpath.JsonPath.parse; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) +public class TimeEntryApiTest { + + @Autowired + private TestRestTemplate restTemplate; + + private TimeEntry timeEntry = new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8); + + @Test + public void testCreate() throws Exception { + ResponseEntity createResponse = restTemplate.postForEntity("/time-entries", timeEntry, String.class); + + + assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED); + + DocumentContext createJson = parse(createResponse.getBody()); + assertThat(createJson.read("$.id", Long.class)).isGreaterThan(0); + assertThat(createJson.read("$.projectId", Long.class)).isEqualTo(123L); + assertThat(createJson.read("$.userId", Long.class)).isEqualTo(456L); + assertThat(createJson.read("$.date", String.class)).isEqualTo("2017-01-08"); + assertThat(createJson.read("$.hours", Long.class)).isEqualTo(8); + } + + @Test + public void testList() throws Exception { + Long id = createTimeEntry(); + + + ResponseEntity listResponse = restTemplate.getForEntity("/time-entries", String.class); + + + assertThat(listResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + + DocumentContext listJson = parse(listResponse.getBody()); + + Collection timeEntries = listJson.read("$[*]", Collection.class); + assertThat(timeEntries.size()).isEqualTo(1); + + Long readId = listJson.read("$[0].id", Long.class); + assertThat(readId).isEqualTo(id); + } + + @Test + public void testRead() throws Exception { + Long id = createTimeEntry(); + + + ResponseEntity readResponse = this.restTemplate.getForEntity("/time-entries/" + id, String.class); + + + assertThat(readResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + DocumentContext readJson = parse(readResponse.getBody()); + assertThat(readJson.read("$.id", Long.class)).isEqualTo(id); + assertThat(readJson.read("$.projectId", Long.class)).isEqualTo(123L); + assertThat(readJson.read("$.userId", Long.class)).isEqualTo(456L); + assertThat(readJson.read("$.date", String.class)).isEqualTo("2017-01-08"); + assertThat(readJson.read("$.hours", Long.class)).isEqualTo(8); + } + + @Test + public void testUpdate() throws Exception { + Long id = createTimeEntry(); + TimeEntry updatedTimeEntry = new TimeEntry(2, 3, LocalDate.parse("2017-01-09"), 9); + + + ResponseEntity updateResponse = restTemplate.exchange("/time-entries/" + id, HttpMethod.PUT, new HttpEntity<>(updatedTimeEntry, null), String.class); + + + assertThat(updateResponse.getStatusCode()).isEqualTo(HttpStatus.OK); + + DocumentContext updateJson = parse(updateResponse.getBody()); + assertThat(updateJson.read("$.id", Long.class)).isEqualTo(id); + assertThat(updateJson.read("$.projectId", Long.class)).isEqualTo(2L); + assertThat(updateJson.read("$.userId", Long.class)).isEqualTo(3L); + assertThat(updateJson.read("$.date", String.class)).isEqualTo("2017-01-09"); + assertThat(updateJson.read("$.hours", Long.class)).isEqualTo(9); + } + + @Test + public void testDelete() throws Exception { + Long id = createTimeEntry(); + + + ResponseEntity deleteResponse = restTemplate.exchange("/time-entries/" + id, HttpMethod.DELETE, null, String.class); + + + assertThat(deleteResponse.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + + ResponseEntity deletedReadResponse = this.restTemplate.getForEntity("/time-entries/" + id, String.class); + assertThat(deletedReadResponse.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + } + + private Long createTimeEntry() { + HttpEntity entity = new HttpEntity<>(timeEntry); + + ResponseEntity response = restTemplate.exchange("/time-entries", HttpMethod.POST, entity, TimeEntry.class); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + + return response.getBody().getId(); + } +} From 6e0c37b049eb343ab0c29169c5a2a9f177aa6625 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Thu, 2 Nov 2017 15:36:44 +0530 Subject: [PATCH 09/22] Spring mvc --- build.gradle | 1 + .../pivotal/pal/tracker/EnvController.class | Bin 0 -> 1631 bytes .../tracker/InMemoryTimeEntryRepository.class | Bin 0 -> 1945 bytes .../io/pivotal/pal/tracker/Message.class | Bin 0 -> 634 bytes .../pal/tracker/PalTrackerApplication.class | Bin 0 -> 2276 bytes .../io/pivotal/pal/tracker/TimeEntry.class | Bin 0 -> 2515 bytes .../pal/tracker/TimeEntryController.class | Bin 0 -> 3445 bytes .../pal/tracker/TimeEntryRepository.class | Bin 0 -> 560 bytes .../pal/tracker/WelcomeController.class | Bin 0 -> 830 bytes .../pal/tracker/EnvControllerTest.class | Bin 0 -> 1469 bytes .../InMemoryTimeEntryRepositoryTest.class | Bin 0 -> 3339 bytes .../pal/tracker/TimeEntryControllerTest.class | Bin 0 -> 5246 bytes .../pal/tracker/WelcomeControllerTest.class | Bin 0 -> 1029 bytes .../pal/trackerapi/TimeEntryApiTest.class | Bin 0 -> 6651 bytes .../pal/trackerapi/WelcomeApiTest.class | Bin 0 -> 1704 bytes .../tracker/InMemoryTimeEntryRepository.java | 38 ++++++++ .../pal/tracker/PalTrackerApplication.java | 24 ++++- .../io/pivotal/pal/tracker/TimeEntry.java | 88 ++++++++++++++++++ .../pal/tracker/TimeEntryController.java | 57 ++++++++++++ .../pal/tracker/TimeEntryRepository.java | 14 +++ .../InMemoryTimeEntryRepositoryTest.java | 1 + 21 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 out/production/classes/io/pivotal/pal/tracker/EnvController.class create mode 100644 out/production/classes/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.class create mode 100644 out/production/classes/io/pivotal/pal/tracker/Message.class create mode 100644 out/production/classes/io/pivotal/pal/tracker/PalTrackerApplication.class create mode 100644 out/production/classes/io/pivotal/pal/tracker/TimeEntry.class create mode 100644 out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class create mode 100644 out/production/classes/io/pivotal/pal/tracker/TimeEntryRepository.class create mode 100644 out/production/classes/io/pivotal/pal/tracker/WelcomeController.class create mode 100644 out/test/classes/test/pivotal/pal/tracker/EnvControllerTest.class create mode 100644 out/test/classes/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.class create mode 100644 out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class create mode 100644 out/test/classes/test/pivotal/pal/tracker/WelcomeControllerTest.class create mode 100644 out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class create mode 100644 out/test/classes/test/pivotal/pal/trackerapi/WelcomeApiTest.class create mode 100644 src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java create mode 100644 src/main/java/io/pivotal/pal/tracker/TimeEntry.java create mode 100644 src/main/java/io/pivotal/pal/tracker/TimeEntryController.java create mode 100644 src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java diff --git a/build.gradle b/build.gradle index 060617da8..65a618522 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ repositories{ dependencies{ compile("org.springframework.boot:spring-boot-starter-web") + compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.1") // compile("com.fasterxml.jackson.core:jackson-databind") // compile("org.hibernate:hibernate-validator") // compile("org.springframework:spring-web") diff --git a/out/production/classes/io/pivotal/pal/tracker/EnvController.class b/out/production/classes/io/pivotal/pal/tracker/EnvController.class new file mode 100644 index 0000000000000000000000000000000000000000..7eab781d1c865e4064fc1033768c5b213022d36a GIT binary patch literal 1631 zcmbVM-A)@v6#mv;Yy%Dur-4F9OQ@583E8wI4GomU1*f%QAhIpms29=L9-K++U2Att z8lg&kj6Oyy6-8~OK0qI;>Njf>uR|_SFJ{i)oHO6~nfd46KmP`>hOfskfjgtPfKSc# znb|%!+gcKL$B@9C6uub8J*=njWeWFG*hpeCiLWf!9naSmGNl*dNH{IwHl2$0mD}8~ zFy5AJ&wpJ~ZN(##^~0hYXyMjn(QU{dEnFOE@{NWsgTO*!Q@KiSS$Mp3Hst@)EFTc& zw%3rvP*Sek>$YpsuZmiWnoP;7i`Iegm67{OTR&ICa-*a?r=yNMEm}^8OZ%e!QuR2*$H7D+rv<00}E($Sfq$C*K}FcsCA?pw&7XVU38c;)-G7qZT0 z9bYo<>%st72rAy`(zYIb!##(M$N=;;{V5Coj=l=l`1wrmZ?c&@3qdYpY7tVFBc!Yd zX$%(Yb(wUU($AzLq;t79uyQLWh~;jbAf8)2ft{PRPcZUZ=rd!^@M8mJc*lnr#Vqfe zW0kLvo2SP7i(w?nbCk?^gTx9sgC!Pn22DKV3?7^Qz^ct-^ITU0d^BJ`9O8Rq9%rA}EC_X6XBV zpLV8&PMzuax*w|3=j^UYBqF@X&An&u{hf23bMF23zrX(hFomZ%4C9)O>p7%wEsLZ0 zN@i0z4B%@SZshO{Zi?-e4By%)+nAQ=cR47`$n1OBb6aM2Y}~amYvZ1UfzWK|`(79r z-Lx=VedBC8rB-O%(nF{DdckRwEo7I>y61$gKwEgwyJI>wxsJD9s`}n~xoZ4U!)*GY zAW zj$3mABkRPN4qqF_JGGaqd2c~)_`z1&M`8oL0TiXSO0YB2ie(lRRJMcR};B1M+3Qw>k&X*N_5?Botg%u%Q--Gyx zR9N1~M|7(eSKsJ5>ss7{({9#Im$Mg|<`?S4+cj^Yzp2A{_Ds4^5k>pg<0U^W`;S^^o-jCBb z!xejr-eT4ZvSjbrMDY)#x6z+|`Rg_^vY6P0{TB}LFS|1F8~3Cj>^x5hF^|LKF!#SL%2MZT)k)uR?n|s8QO4zw~80b(XLok1dHm0dIP2m#0jA#XnlOeQQi3Wpj zp`OK|AKpQJH*mBo{lNqni&`Xb0+UH_&xwlt~6s6$bBCr%=(x? zkzw=yxfrU`7d`9W$iQNo-o8M8!Dvwrig`LyONwR6IPK|O>jmtQfE+xE#S|=Jj?Vss zK>Ivp3=61G{9gQo+{2Gz|IgwoYFTlcq;gKGweyVJRN70?D!Hwt9abi+Ox{^@b1*^| NQ^h4LyDo&(flpnlfF=L{ literal 0 HcmV?d00001 diff --git a/out/production/classes/io/pivotal/pal/tracker/PalTrackerApplication.class b/out/production/classes/io/pivotal/pal/tracker/PalTrackerApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..32ed650d9f198a70eb25c1ffb7dfb14ffd7080a8 GIT binary patch literal 2276 zcmb_e{Zku77=D%nj>N-KXi-qBRcOOUxfUpXq+&w|HJGFwlG366z-*Ew-Sl#IvvTP)Q?&IRn?yxQ>j0 z`81N4OJf0xDJnIB7Se#9-CJ1wgkDCxAaJrrEEDDPyMCJXdpp>q2T}e_T*L&!(tkNL z17Di>3STp<3o_$D#fr5!`+%xe#iVSn_ z;IHg9yPB)D!G6K9C#<%wR&U+3cBq;L7lxVG!4D=%xXQ2)ciKHVLjoh@QJ<(TNw<-S zC^tl(jZy1->`A>5Qoessx}zdB$gFinlE}vadlCem*5Z*+q%7JUX=*3b)=E@Tn_X!) zwG@-uh2b74@*MJI4U`9R9%+poDq3_JcDE^J`y+#KIx~xoBUIkzzAvcbMl1I#2bG7V z62tm{zWMju#MYEA=ytN@&%HM8Rr0By8Ggz9zm(_07sKjcf%YzfY83aj-~sh6T~Lp9 zi?zbRR<2g49^|SAwPLwYt>wxOstmUWZ0PiEiAzZoT|5l4`!#n<`r*y~_^n&GujTXF zy3y%1DV?xOW!}L<*qPb$sy$rS9Y7adeA#$C;VOpc)v7;95Mh|0-$`0oG%^~87hZt< zMw202qTi98aSWGfZiWt+!UwcU;X_Q5MF+2ww+vVNj{F9HW@Q zM`Q;+#wX;VbF93{@e0ZP7a0DPY*7rC---`0Tp=Hg@KYKYKI?5x=aPNgi!U+q9L5Po zlYbz!pLkAhp%c7E3v)m53S(5~eKK4)!T4FZ843mg93hC41aOuhUdI*sKQR-5u-K;| e3L$~dDRKy3kaq}dmd3mEO%uE&e2eeyPX7(0c$=L7 literal 0 HcmV?d00001 diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntry.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntry.class new file mode 100644 index 0000000000000000000000000000000000000000..eb642119f57db423e0d2ffa6717ed9b8a2281f40 GIT binary patch literal 2515 zcmah~T~k|C6kYcwHwkHg5WWhbC81S9LK~H;RX&8$Qj&%igd+8m3*3QQQxZeMjMM3Z zDO+V&?$RI1jEkANWoWV>03o_r9;Z6XH0W1aZuB?`2 zSP9^+%&RiI=f|1`-QLomWi_-EONIN^W;w&Pud-*A#PDvJWlKYM?!LKirpxvNE1fHB zn)&N=k83b?3YF3x<1>tzuy^h9lm<^?WR;P#g)K(5=j>hUcICl_Ra!AO^7KShf>pC* z%i48%%R4sn4CU-Xx@hkg%4R-Yxu*=$oh8M$|WyQgd$ z+m>QTkmPLaIV*1>E3qMNE;dwX;qtC4grByM*3g?6X?nYc0ME=jf-t>EVtrOI^W@c? za6b$w>5OtAgZK}m%;^?32xJxv!x7ebxAMF{UO9L6hajJAq>cH4(CG{L@b0p zS>6NT#{RE5etZyO`@SB+IL0VdgP8;3TE)(9StW9+-~Q0vnhfDXd?dritifok-iVVF zVl?LTBJIFvOxkgBSdM-o!@6>+CR9mCV-jq^aN}Y}ZJuLsX7lDAtI>H(9_6Guohn9j zZ?rf|XcmjsE?>f>qa}1DbsOP`$}T~sV;`QjeJowABaU>!F}+l}+0)VuBr^ZK&C&+= z#Q+TGQcYUAR9ej}wwhUQHM8WLL(rrlI9}jtjI+ksNIrx16Ac{~IR-h)Q7>BYlCsnx zyo_P4BtgPW@C7{Z(-)Nl$-zVD$@n2W$v)!{-ekA$5Jn?yKYTpe&a`2)paX4)pbMSE z*`=&$RGVyavZ7aP(vk;SiKxfeIW0 zbzb4`A*f!4o+YS0!s+KT;3T=q#=ov z3o%V?CDKSfh3^L%j^x4vJl;(1QCxC^r^rt(^NG~HhO$nM??DnpMdpsxTs-is-c5Gej4#)P09dT^p?+g!D(G}@-97YvA;YV~-(R;EL7msw)l8aem Jh2+gn{|mm)+Pv4rI$;#iR@x8(G;96ph2pUSm6a>&YIRsNAnAfLdRK(}M=8Ov42HjR40 zs96G;tZ8XAbKi3GidN&#vGwi8hOHI-odEmmt46M|S2FCPUaD}VH*0O{l?~lC<=kJ4JG*8*3cW>(;aHW5VM}`3wxK)3Ty0Hn zb}VbzJ6gSFo7J6%w!UXPwd}{*uH)3Sf>Ezo)w-0*bY$G^&xAV=7;YIk4SGB#Pa zteZPk-D%k5_vF9iH`kibJSkl)G#JjFv0>It3cXORGU<-VI0dF&sKryGq?OESS<{2P z+L~2&R`ptqq7ifW- z>CW!6gCzy6m~}^BJarlY_2|3jJeeDgS<$j|6-gCYnr)3***&)pPNbl9ZJ#EX9?wzp zvHbr3bQwtjf#`Ly)@Z7Wwz5&-X%m=^ToFsIMRsG_wHdaj8i7y1*D(tFP<=GRM ziR^*B(+SO)+|!u4$3JA(smX>lVR$!|iar!nyoTNc)>T|WQD8J;4^QB(iVfV87@w=y z#1|^=%juWi+5;8W@Rf@9v87@LU#rk@Paxgub_^qBmkHZczVyi0=207JWiJp*$=k7| zqwpFQSc!Cdv~tbVTzRQ_w|Nb+Lplv!4vEFW@zYe}VE7X9~`9 z>_UuVH@^sb&`#?C&dz(gaRC=Oqn(Q?h;|8s+$k|P`IMFe>7SvDA0wt<^*6*fGlw{H zgti~~m**hqg7u?=&=P#eGYh~6a2c-?x&tcS;G2RsUE3jsSV(Uqpf`e1q+EJ~ zE>Q(zv^xv&7X}kZ`((#mvR&Ml;cwzTL>*T{(wa;98s4RIDc(Gt3qH?DW|H_ZIs^{k zvgNv`oJ=AZsHCNO`+ZuTLhl6%Ww=AICr$dI{J^ISZ`2hfa||_x+=Q>ngzx9&s*KZJ zhV?MPh&9)J+Jg&J8TD163tttL3QkeWSg6nCP@n68KGP)HtWT%H1y3I@wKG9#R|zJ| zw%<=Jw|bnr{7g0%*c7XD+U4q1Z-2nG-{0Zv~IR7x% GKK~Cc3a-%r literal 0 HcmV?d00001 diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntryRepository.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntryRepository.class new file mode 100644 index 0000000000000000000000000000000000000000..7f2d9dfdfd81f3a85f7ae54dbc34aea50b2ce830 GIT binary patch literal 560 zcma)3y-ve05dN;D2`zu6U3i3q0WTFx5nDS&LZYadL>_0<@703Hf)4H6wP zq=R+R_j7mt?)&HS3&0eU2-gwDgfMeTdPP{oskWlhTkE9}6+iD}_O6_G(I0AFdbgV; z-4a6Zrpuf#jnlQNozu~A`F+dc9~je!;+i-aGzCWH`-gbyW8hRxa~T} z!9f@uvVMA9tIUT4LXU3^^aH{P0)T5DVN)ZVGCyFphauxYx15Ph>vnl^+sE&ZT;3dA8vC4A`t34~NdX*p~tYEXLMfV^8bxZSlQual}m z{3nn=NF4Y9{3yiiCW4~$(8Jg>w|cvwXVcNQ^+yA|B4;69;}sw|TO zMOY0_&`@^q{+mIjJ*on3>7b{GABTu59_L3l3H0FO9T@3Lex@#yp{M-G?C5|9y{x=v2j? zFxP1I@rb`uiN6;i$Tisu*soxL_eGBOcn^55w!VW}+usm;DKJ%DmzWFGnZLr=Rovic zV}eEvH#uTnp-PMeYQ)mZZ1s#8{BF24y+v?Dj3~FhBKXWsz(jC4d2+K5u1x?_;Wf@L Xab}&Z{tlEC7jG8K+sIFI?iTO|Fc;0_ literal 0 HcmV?d00001 diff --git a/out/test/classes/test/pivotal/pal/tracker/EnvControllerTest.class b/out/test/classes/test/pivotal/pal/tracker/EnvControllerTest.class new file mode 100644 index 0000000000000000000000000000000000000000..7edbc421f4d5471d58ffe66c6c9c26a499ee4a53 GIT binary patch literal 1469 zcmbVMTT|0O6#lj?O$bFwxG3HLMWld4?jRSfZBfP+6gntROo%H4OHz_8qd&_R@G|50 z?1Mka@oZBuoqA#HOwaCqd(OAtxlF!(|M(fe6dr5Paa+NVij<0B6(cG}HAHYnnlTkd z3+`fE!GwlMOlg?LjEY$mb1LQ)+*7c?5MQ(%TP!m~hf-S%v5fnYGqmMxhp$x*cez(I zcT0rmdDk*aTc&5ra}A7%ecNXk%?s`eqii3$!YmnO`U}srUUSdLIma2-5uRHr5fypK zC-=A@oI$hBt{4XMw)<}i3XgIb+m=5tk4>W@?2=J1%Y=8=D|}o2sdBpBbul=WOlQy7 z6rSzuEi@v_M5yK7SiCH3*YOoBGW2Xz9AO{wE!(%L25HBkbgS14$-L|B83z@rrBO>$ z+jJ|Q#aC=uzV3!Xj7j|obfA-A;5?~QbLM7dr>Owr6OR}olT!@s;}er(KKIQ-KIRLL zb0Ha*61WU%Y3%9xMp4221Rfww8mkox<*ndh0vTi#HFLh2ZrT(+%U_wk*)%AXlR0h+v2`S zyty!MZSYdnv1#PkrDmFz$n2ZmCO@ih$KnAmjivGXXa5+&&}{p;ql#H7x(xGS6=&J~ zm9q9S`q54w9QliYnuboYU34;NWwbU8pMt%sUU!p?S3wOIX`cuja0xwhVlV7s6O9z}muCQ-CGI zSX^RKT@+H?btq(8kt8KugrrF466t$J3OVVMs`~#j`Y!UiMhp@3l9$Xa aK>7&jCnQG54cw%itib@S47bQeF!%$aGJFF7 literal 0 HcmV?d00001 diff --git a/out/test/classes/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.class b/out/test/classes/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.class new file mode 100644 index 0000000000000000000000000000000000000000..5544f084a64c1fb6f76923e35cddce24d7bae501 GIT binary patch literal 3339 zcmbVOTUXRp7~Po(1Y%I+qQ!avybT}*6*~xs0)mAOXoW(ly@eq{aLA0A3_@+yUhM6m zKcnyM!^o>s1Vk&x2qf{a%ANRZL(~g^agET1t$jYB7x)Vsul*+qk7-2D2*O!JLYDyesk+ zf-U0B!65cS4c;pih^e@Z_eI_ZV(o`2KElVPqQf;X#MGkrN{gu_1*U>K5~>F++j55_ z#1kEJ66DeBk||+d%CgPr!rG$g%o>XsMjBGtw2_%J983HTg0j0}ulaKbJ@J*iV)Wf5J1{74VM*Uhf@-IQ&#p> zx8gSS{x(ZtAqnj}?G)y4U5&YsGt;iQB%zi-mOPLW)Ul1UnRBhIoma3dq2*S=cFAGR z%3I_=Y}=&jO|x_=>n!W51?s2=q~tr6%^l^8m3KwLsH^s^K#{)XmtxIV3Z95HUq{m}X}E%KG>qU|4c`gE zegD_iY`NF*jA1Y9Hx^fEFbR$2P-w1FR9H**EOE{2VpYy?@@$Wu@a^DjG`eCqGv>X5 zX{XJB4u9hLg*3wJiOI=rrzXVl9#2%ZQ%B_#35QwcC3Pb7XEyV$xyJh?Tc8NdJ~o=- zreoRejLS2(M%Y!$raQqC!&_*wB+Bzi5|o@+lCgQN5|e_>F>&sUeBN~2RXv?`Ox?&? z`mh%eCzsvzXJ=Oo*1i%I)9(sp+KLOo1 z%U`@6xH#@D{u3(1fBVH}h%G!tJk|9K@5`LYpm{*jzz z#wIIqp5K=9RF~?ro9-qzl5LnTb34R}z!7pgN}R1k(T1yN=Zo8Mk5i{#Ipj1Fa7t1K z!6e3P)ngLhk;y>FNK`nJW3zC)p~LX{R#2-;Ym=uyAq{qEmJK zvgmq?{DRZNSlJ4lL?YhpYuL^<8sRt%d69|?a(tC<6bl@s$?-mhB6i;h^~i;GpJ%>r zjXqjm*nI)VJiF{{_mNPMC+vwZNpjbU6mcSGZxJWUgbsM;afF0MNob6q$JvnUk!B`C T@OlXTKmdNH){PQc4A=ezK2H$z literal 0 HcmV?d00001 diff --git a/out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class b/out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class new file mode 100644 index 0000000000000000000000000000000000000000..edd418e0053d4edd675b188688747299f80ec8f6 GIT binary patch literal 5246 zcmbVQ`Ck<08UN05%(9L~0coQo8dDKaSX8VMNK!-~Asm*oHc=dw0S15(2u z@7Vjk+w{JYDl9QcZPT=Adfz|vkLZ8UPruL1FuTA4Yu%5t@4WB(9N*{pKF|9uul@J= zmjE>5UlFw7q6$5N3B=0Kib)kl1SOb~muVFTg2WY67Q9L?~})q zD~3b}WKL|Z7zFm{uACui57Y8rO z=o8}pCuQMNV)N4~KBMBZ3Mw3P-sns?_QIf%v{I&H*$WDe^qN*QXU^*c|88uTTEwv{SjDoxDI$=*oXVdgJdfJ$>Y(vnC@ebS29l9Adt|pC`V@xVI zuw@V_9JY;AlBOwI*K1LEDruXE=_y;EH?COrTy(~9lF>nb6BA`R3l!Vw?)4n;@r1>V zK|`nIs@1VtNUp@IuTT?hTl@Y1-PpBabG+Yjx~z19#$7*p&6Fcv&gz%-XxcI3QJJAc z^O~sw4UHG>_-c~{=@%$&7DtkkZWb#9m-mu`%-wRvh#QjV$dHw`V@8)Lqc+S)*d>OBx=;n-uKd${;};YdU(eq3LKt({y*r(fKp-|>u${-NQYqQ6Pfc{}Za)OBsf z^~7{^U}BaP%~qM63R(tdrD*4^*c@ADw9ory8G6ct ztUWB|!jsmZ;iT;Zn{BRcAA#4pR-%w{(i0PGV$mTP7`CX-jndk6hU?0VLDe;RRcDa| z@v6*K*QYzN8N=o|P^2e#c$LQdUfi{HR2h%0s)XL}WpFl*O1n3ndp87^^-qD?G1%EY+I6x>bx`A0Z!EfJbEtPFs_tT_uB`hpG?WzH-lnz(n1q&~i7gv`V+#^je8& zM)I;APa6YM>=?B@xem%Q<5oOn%Awty>!rI?P+=6a(kR`UM|#6Nue-~H1|DHP`Ui%` zy9P%3nRBoAy0?aQ+twGz#!@}yT`3OMKDs{2KCaw*MseJ|ft0T#C3o%cW@WO@z2iQ( ztcDF(FAfGt%U@vGEeh_>4O(HW%Zf8|A>$I$$E5Z!JZb;pGMcN@&EwYnt)NVw|GyL$ zPJ+@&|6Wyk*|5zi)>Fkgi*gV}`Ul242Kt9P`-gE4f4H^r2V00AUX^b!WlkG-N{OHa;$k9(1mWkDR_v&MXqo^iruy9`tnc)MYj;T zf#Uj`C^=Vu9mPv1y#Y0=a|fk>J=C|CpXwal)xPeBxh@)e@CZlZL$7PGFR=IuBCeLX zn+TtaRHCdB+se0Ruw!Rz>2w7jfqp-}Yp%_wXXB$Fcwp@CPHXA61O*-8g_++{<6j2XPjMaDi{LsB=N> z_gwTrRbd4E7$BIlgnbroW{B4V9dv;X1wdc+fsPdhG?Kwx%edPIDQ}C|mj$&yAE+WX z(;lb>f@&nFD4{g*bByFU&O9_@6en^(jRm0EeNb%ys9{17u6Q#eo4_0mU|wUWLX;MeWLR}oAm1dDfsA@$;FG7~hMw^IB2s2Qa~AYS#SBke zEo056>NwQG=TmxhB)pF@;)l}r!ihWx1099FPjHmkVkj%!6({j4>H8sr?VZON8mjrw*exiJwJ#BSGyuiyEbhU&I*1=6>jdk%+qTD3O6DGh8}RzPRmQOBj|_+&M~w z-=mxK>`xY%GOhZ*Sgt$dW2KQQ4JHs`R Z3f2jKgJK1;o0O3;*&@rZO=}K2zX9UM5hMTr literal 0 HcmV?d00001 diff --git a/out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class b/out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class new file mode 100644 index 0000000000000000000000000000000000000000..0c3e8de7c31ebec4e0bc347205a1a50a59e888e7 GIT binary patch literal 6651 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 c@;XT4Wq7%cS2I;#McEkFUx6>&PMXaE2J literal 0 HcmV?d00001 diff --git a/out/test/classes/test/pivotal/pal/trackerapi/WelcomeApiTest.class b/out/test/classes/test/pivotal/pal/trackerapi/WelcomeApiTest.class new file mode 100644 index 0000000000000000000000000000000000000000..0c88580c8bbb1e20d650a287e7477858f32a02f6 GIT binary patch literal 1704 zcmah}ZBraY5Ps%fSU64+4^1Q*f-x$P$oPUW@nX!0q|`b?3a+5ae6Z%00fy}DTxMq> z`B_$3(XvX*&;BUOXZHvkVZD5~>Fb{Er@No-*?<21<1YZqXw^`~`~+%P7{_9O>j7@m z@DY}3kob5UpVaUvJ`1ocPmU+qzwu^qq-!cbw|!L+c*PuC-ozI?6-c zm0@Ib>}7}g`cQCFU}imyz3J&qlbCL#TXAf?^2WxAz^!6rt>Q%PsL)&YOseAm*-E`V zG)`|5cI=LcjlU~Uo?qA$sI1s+mU^yjV*McPb+zj#W)o<%ZK$G6aD{A^Q_EH8RaA_#YrE#pCBzIfJ?=il5prVwaHw!7t z`v`69^;0kNyvuSU9~cn`M1bPJlPSK49)x|v=^nKmgpo=TO}>`e#>xV=Iw75HKP>>3YQ^5HZe z4Os?(&4sfjfh$>E*~&P-FGK6J%xGxkhQYh94Q@MoiVtbEAooJP1ZOe2N%lbf%ARr? z`bnzeP!Di9a9N!8e?tT&OtShUGcS)GMDaNBErRDiLHAyKbtBb!u{E}ZccxKL^(=^WvfDU*AZ&C_epuLm_|AY$v0kez0 zqSPoiD&;>>eU7oeQE6ZQ9YJIKIVQGFP^VC)_eG+ timeEntries = new HashMap<>(); + + @Override + public TimeEntry create(TimeEntry timeEntry) { + timeEntry.setId(timeEntries.size() + 1); + timeEntries.put(timeEntry.getId(), timeEntry); + return timeEntry; + } + + @Override + public TimeEntry find(Long id) { + return timeEntries.get(id); + } + + @Override + public List list() { + return new ArrayList<>(timeEntries.values()); + } + + @Override + public TimeEntry update(Long id, TimeEntry timeEntry) { + timeEntries.replace(id, timeEntry); + timeEntry.setId(id); + return timeEntry; + } + + @Override + public void delete(Long id) { + timeEntries.remove(id); + } +} \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java index 981a139d7..78cb5b60f 100644 --- a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -1,12 +1,32 @@ package io.pivotal.pal.tracker; - +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; @SpringBootApplication public class PalTrackerApplication { + public static void main(String[] args) { SpringApplication.run(PalTrackerApplication.class, args); } -} + + @Bean + TimeEntryRepository timeEntryRepository() { + return new InMemoryTimeEntryRepository(); + } + + @Bean + public ObjectMapper jsonObjectMapper() { + return Jackson2ObjectMapperBuilder.json() + .serializationInclusion(JsonInclude.Include.NON_NULL) // Don’t include null values + .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) //ISODate + .modules(new JavaTimeModule()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntry.java b/src/main/java/io/pivotal/pal/tracker/TimeEntry.java new file mode 100644 index 000000000..b91f52bed --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntry.java @@ -0,0 +1,88 @@ +package io.pivotal.pal.tracker; + +import java.time.LocalDate; + +public class TimeEntry { + private long id; + private long projectId; + private long userId; + private LocalDate date; + private int hours; + + public TimeEntry() { + } + + public TimeEntry(long projectId, long userId, LocalDate date, int hours) { + this.projectId = projectId; + this.userId = userId; + this.date = date; + this.hours = hours; + } + + public TimeEntry(long id, long projectId, long userId, LocalDate date, int hours) { + this.id = id; + this.projectId = projectId; + this.userId = userId; + this.date = date; + this.hours = hours; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getProjectId() { + return projectId; + } + + public long getUserId() { + return userId; + } + + public LocalDate getDate() { + return date; + } + + public int getHours() { + return hours; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TimeEntry timeEntry = (TimeEntry) o; + + if (id != timeEntry.id) return false; + if (projectId != timeEntry.projectId) return false; + if (userId != timeEntry.userId) return false; + if (hours != timeEntry.hours) return false; + return date != null ? date.equals(timeEntry.date) : timeEntry.date == null; + } + + @Override + public int hashCode() { + int result = (int) (id ^ (id >>> 32)); + result = 31 * result + (int) (projectId ^ (projectId >>> 32)); + result = 31 * result + (int) (userId ^ (userId >>> 32)); + result = 31 * result + (date != null ? date.hashCode() : 0); + result = 31 * result + hours; + return result; + } + + @Override + public String toString() { + return "TimeEntry{" + + "id=" + id + + ", projectId=" + projectId + + ", userId=" + userId + + ", date='" + date + '\'' + + ", hours=" + hours + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java b/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java new file mode 100644 index 000000000..a9b854f6c --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java @@ -0,0 +1,57 @@ +package io.pivotal.pal.tracker; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/time-entries") +public class TimeEntryController { + + private TimeEntryRepository timeEntriesRepo; + + public TimeEntryController(TimeEntryRepository timeEntriesRepo) { + this.timeEntriesRepo = timeEntriesRepo; + } + + @PostMapping + public ResponseEntity create(@RequestBody TimeEntry timeEntry) { + TimeEntry createdTimeEntry = timeEntriesRepo.create(timeEntry); + + return new ResponseEntity<>(createdTimeEntry, HttpStatus.CREATED); + } + + @GetMapping("{id}") + public ResponseEntity read(@PathVariable Long id) { + TimeEntry timeEntry = timeEntriesRepo.find(id); + if (timeEntry != null) { + return new ResponseEntity<>(timeEntry, HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @GetMapping + public ResponseEntity> list() { + return new ResponseEntity<>(timeEntriesRepo.list(), HttpStatus.OK); + } + + @PutMapping("{id}") + public ResponseEntity update(@PathVariable Long id, @RequestBody TimeEntry timeEntry) { + TimeEntry updatedTimeEntry = timeEntriesRepo.update(id, timeEntry); + if (updatedTimeEntry != null) { + return new ResponseEntity<>(updatedTimeEntry, HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @DeleteMapping("{id}") + public ResponseEntity delete(@PathVariable Long id) { + timeEntriesRepo.delete(id); + + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java b/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java new file mode 100644 index 000000000..357e7448e --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java @@ -0,0 +1,14 @@ +package io.pivotal.pal.tracker; + +import io.pivotal.pal.tracker.TimeEntry; + +import java.util.List; + +public interface TimeEntryRepository { + + TimeEntry create(TimeEntry timeEntry); + TimeEntry find(Long id); + List list(); + TimeEntry update(Long id, TimeEntry timeEntry); + void delete(Long id); +} diff --git a/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java b/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java index c88bb8266..69c0dd2bb 100644 --- a/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java +++ b/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java @@ -17,6 +17,7 @@ public void create() throws Exception { TimeEntry createdTimeEntry = repo.create(new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8)); TimeEntry expected = new TimeEntry(1L, 123, 456, LocalDate.parse("2017-01-08"), 8); + System.out.println(createdTimeEntry.getId()); assertThat(createdTimeEntry).isEqualTo(expected); TimeEntry readEntry = repo.find(createdTimeEntry.getId()); From 8f968be8a66c292cb6553db6da46fb269dcce5f3 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 10:46:58 +0530 Subject: [PATCH 10/22] db migration --- databases/tracker/create_databases.sql | 11 +++++++++++ .../tracker/migrations/V1__initial_schema.sql | 11 +++++++++++ .../pal/tracker/TimeEntryController.class | Bin 3445 -> 3473 bytes .../pal/tracker/TimeEntryController.java | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 databases/tracker/create_databases.sql create mode 100644 databases/tracker/migrations/V1__initial_schema.sql diff --git a/databases/tracker/create_databases.sql b/databases/tracker/create_databases.sql new file mode 100644 index 000000000..8b5ed7ba5 --- /dev/null +++ b/databases/tracker/create_databases.sql @@ -0,0 +1,11 @@ +DROP DATABASE IF EXISTS tracker_dev; +DROP DATABASE IF EXISTS tracker_test; + +CREATE DATABASE tracker_dev; +CREATE DATABASE tracker_test; + +CREATE USER IF NOT EXISTS 'tracker'@'localhost' + IDENTIFIED BY ''; +GRANT ALL PRIVILEGES ON tracker_dev.* TO 'tracker' @'localhost'; +GRANT ALL PRIVILEGES ON tracker_test.* TO 'tracker' @'localhost'; + diff --git a/databases/tracker/migrations/V1__initial_schema.sql b/databases/tracker/migrations/V1__initial_schema.sql new file mode 100644 index 000000000..3e605c0b5 --- /dev/null +++ b/databases/tracker/migrations/V1__initial_schema.sql @@ -0,0 +1,11 @@ +CREATE TABLE time_entries ( + id BIGINT(20) NOT NULL AUTO_INCREMENT, + project_id BIGINT(20), + user_id BIGINT(20), + date DATE, + hours INT, + + PRIMARY KEY (id) +) + ENGINE = innodb + DEFAULT CHARSET = utf8; diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class index eba45958f5a782b19307f4ca8e9093bb15de2462..dc3dd1a4d5c23319b92112c47f459653805d126c 100644 GIT binary patch delta 586 zcmZ9I+fGwK6o$XqyV)Ds!B(m_v<4IqIf)8ZpyGkEN})gj5fl&X#G0VNmiK_nGnjBk z2zOri0LEJ%#h4I6ShIIRlU~f4`Ttq7zFF&E%R#2}`~2rGV2JHFDV{fyWIVwHlRi_8 zOfwTF#;kQ-SozY1SJs=eUcrWW8y4(E(Pz9~|}%)ZxW{(H%|w-Z!9f7@0(G6!C7 zdUr3VR12Y%SHy}7%O&%}`4d}KY#Hs2o*cPZx4mhgTHXozgRj-^<)ETTQ_@_e*=I%5 z!m6Un>^j%Xn14ODrg_b}&3U8QU{mwf%6E~sr5WVCCdUU&o{ySOtSfrVvDh92TToLuPBpkxS%g u9kR(0BSJ=<$?=^*?@G_dFbdeeN(8#wQ`ES@cuUc4kq7&n^J+PEM5o delta 545 zcmZ9I*-pYh6o&t{#sVE&z?eueMp01~K>SP=^Uaw@`P-3v`>nkI2;<6v4lJ0_jztMeSQfEj#wykx){#?9NGneb18GbWrIUOTMKJ))FP?5Xu73eL&SOT;F`Z create(@RequestBody TimeEntry timeEntry) { TimeEntry createdTimeEntry = timeEntriesRepo.create(timeEntry); From e36cbb8837024ff61a78de5772486321afcd4c0e Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Wed, 26 Jul 2017 11:45:04 -0600 Subject: [PATCH 11/22] Add tests for JDBC lab --- .../tracker/JdbcTimeEntryRepositoryTest.java | 159 ++++++++++++++++++ .../pal/trackerapi/TimeEntryApiTest.java | 12 ++ 2 files changed, 171 insertions(+) create mode 100644 src/test/java/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.java diff --git a/src/test/java/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.java b/src/test/java/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.java new file mode 100644 index 000000000..e1eac20fc --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.java @@ -0,0 +1,159 @@ +package test.pivotal.pal.tracker; + + +import com.mysql.cj.jdbc.MysqlDataSource; +import io.pivotal.pal.tracker.JdbcTimeEntryRepository; +import io.pivotal.pal.tracker.TimeEntry; +import io.pivotal.pal.tracker.TimeEntryRepository; +import org.junit.Before; +import org.junit.Test; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.sql.Date; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JdbcTimeEntryRepositoryTest { + private TimeEntryRepository subject; + private JdbcTemplate jdbcTemplate; + + @Before + public void setUp() throws Exception { + MysqlDataSource dataSource = new MysqlDataSource(); + dataSource.setUrl(System.getenv("SPRING_DATASOURCE_URL")); + + subject = new JdbcTimeEntryRepository(dataSource); + + jdbcTemplate = new JdbcTemplate(dataSource); + jdbcTemplate.execute("DELETE FROM time_entries"); + + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + } + + @Test + public void createInsertsATimeEntryRecord() throws Exception { + TimeEntry newTimeEntry = new TimeEntry(123, 321, LocalDate.parse("2017-01-09"), 8); + TimeEntry entry = subject.create(newTimeEntry); + + Map foundEntry = jdbcTemplate.queryForMap("Select * from time_entries where id = ?", entry.getId()); + + assertThat(foundEntry.get("id")).isEqualTo(entry.getId()); + assertThat(foundEntry.get("project_id")).isEqualTo(123L); + assertThat(foundEntry.get("user_id")).isEqualTo(321L); + assertThat(((Date)foundEntry.get("date")).toLocalDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(foundEntry.get("hours")).isEqualTo(8); + } + + @Test + public void createReturnsTheCreatedTimeEntry() throws Exception { + TimeEntry newTimeEntry = new TimeEntry(123, 321, LocalDate.parse("2017-01-09"), 8); + TimeEntry entry = subject.create(newTimeEntry); + + assertThat(entry.getId()).isNotNull(); + assertThat(entry.getProjectId()).isEqualTo(123); + assertThat(entry.getUserId()).isEqualTo(321); + assertThat(entry.getDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(entry.getHours()).isEqualTo(8); + } + + @Test + public void findFindsATimeEntry() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (999, 123, 321, '2017-01-09', 8)" + ); + + TimeEntry timeEntry = subject.find(999L); + + assertThat(timeEntry.getId()).isEqualTo(999L); + assertThat(timeEntry.getProjectId()).isEqualTo(123L); + assertThat(timeEntry.getUserId()).isEqualTo(321L); + assertThat(timeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(timeEntry.getHours()).isEqualTo(8); + } + + @Test + public void findReturnsNullWhenNotFound() throws Exception { + TimeEntry timeEntry = subject.find(999L); + + assertThat(timeEntry).isNull(); + } + + @Test + public void listFindsAllTimeEntries() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (999, 123, 321, '2017-01-09', 8), (888, 456, 678, '2017-01-08', 9)" + ); + + List timeEntries = subject.list(); + assertThat(timeEntries.size()).isEqualTo(2); + + TimeEntry timeEntry = timeEntries.get(0); + assertThat(timeEntry.getId()).isEqualTo(888L); + assertThat(timeEntry.getProjectId()).isEqualTo(456L); + assertThat(timeEntry.getUserId()).isEqualTo(678L); + assertThat(timeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-08")); + assertThat(timeEntry.getHours()).isEqualTo(9); + + timeEntry = timeEntries.get(1); + assertThat(timeEntry.getId()).isEqualTo(999L); + assertThat(timeEntry.getProjectId()).isEqualTo(123L); + assertThat(timeEntry.getUserId()).isEqualTo(321L); + assertThat(timeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(timeEntry.getHours()).isEqualTo(8); + } + + @Test + public void updateReturnsTheUpdatedRecord() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (1000, 123, 321, '2017-01-09', 8)"); + + TimeEntry timeEntryUpdates = new TimeEntry(456, 987, LocalDate.parse("2017-01-10"), 10); + + TimeEntry updatedTimeEntry = subject.update(1000L, timeEntryUpdates); + + assertThat(updatedTimeEntry.getId()).isEqualTo(1000L); + assertThat(updatedTimeEntry.getProjectId()).isEqualTo(456L); + assertThat(updatedTimeEntry.getUserId()).isEqualTo(987L); + assertThat(updatedTimeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-10")); + assertThat(updatedTimeEntry.getHours()).isEqualTo(10); + } + + @Test + public void updateUpdatesTheRecord() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (1000, 123, 321, '2017-01-09', 8)"); + + TimeEntry updatedTimeEntry = new TimeEntry(456, 322, LocalDate.parse("2017-01-10"), 10); + + TimeEntry timeEntry = subject.update(1000L, updatedTimeEntry); + + Map foundEntry = jdbcTemplate.queryForMap("Select * from time_entries where id = ?", timeEntry.getId()); + + assertThat(foundEntry.get("id")).isEqualTo(timeEntry.getId()); + assertThat(foundEntry.get("project_id")).isEqualTo(456L); + assertThat(foundEntry.get("user_id")).isEqualTo(322L); + assertThat(((Date)foundEntry.get("date")).toLocalDate()).isEqualTo(LocalDate.parse("2017-01-10")); + assertThat(foundEntry.get("hours")).isEqualTo(10); + } + + @Test + public void deleteRemovesTheRecord() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (999, 123, 321, '2017-01-09', 8)" + ); + + subject.delete(999L); + + Map foundEntry = jdbcTemplate.queryForMap("Select count(*) count from time_entries where id = ?", 999); + assertThat(foundEntry.get("count")).isEqualTo(0L); + } +} diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java index b742e5447..2b7464304 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -1,8 +1,10 @@ package test.pivotal.pal.trackerapi; import com.jayway.jsonpath.DocumentContext; +import com.mysql.cj.jdbc.MysqlDataSource; import io.pivotal.pal.tracker.PalTrackerApplication; import io.pivotal.pal.tracker.TimeEntry; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -12,6 +14,7 @@ import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.junit4.SpringRunner; import java.time.LocalDate; @@ -30,6 +33,15 @@ public class TimeEntryApiTest { private TimeEntry timeEntry = new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8); + @Before + public void setUp() throws Exception { + MysqlDataSource dataSource = new MysqlDataSource(); + dataSource.setUrl(System.getenv("SPRING_DATASOURCE_URL")); + + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + jdbcTemplate.execute("TRUNCATE time_entries"); + } + @Test public void testCreate() throws Exception { ResponseEntity createResponse = restTemplate.postForEntity("/time-entries", timeEntry, String.class); From 8e05a530769d0bf453e429ae92d3290a92edf8d1 Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Wed, 26 Jul 2017 11:45:04 -0600 Subject: [PATCH 12/22] jdbctemplatechanges --- build.gradle | 40 +++++--- ci/build.yml | 13 ++- manifest-production.yml | 4 +- manifest-review.yml | 4 +- .../pal/tracker/JdbcTimeEntryRepository.class | Bin 0 -> 5920 bytes .../pal/tracker/PalTrackerApplication.class | Bin 2276 -> 2462 bytes .../tracker/JdbcTimeEntryRepositoryTest.class | Bin 0 -> 6485 bytes .../pal/tracker/JdbcTimeEntryRepository.java | 88 ++++++++++++++++++ .../pal/tracker/PalTrackerApplication.java | 11 ++- .../pal/trackerapi/TimeEntryApiTest.java | 6 +- .../pal/trackerapi/WelcomeApiTest.java | 2 +- 11 files changed, 147 insertions(+), 21 deletions(-) create mode 100644 out/production/classes/io/pivotal/pal/tracker/JdbcTimeEntryRepository.class create mode 100644 out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class create mode 100644 src/main/java/io/pivotal/pal/tracker/JdbcTimeEntryRepository.java diff --git a/build.gradle b/build.gradle index 65a618522..4563f9acc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,28 +1,44 @@ +import org.flywaydb.gradle.task.FlywayMigrateTask + plugins { id "java" id "org.springframework.boot" version "1.5.4.RELEASE" + id "org.flywaydb.flyway" version "4.2.0" } -repositories{ +repositories { mavenCentral() } -dependencies{ - compile("org.springframework.boot:spring-boot-starter-web") +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.1") -// compile("com.fasterxml.jackson.core:jackson-databind") -// compile("org.hibernate:hibernate-validator") -// compile("org.springframework:spring-web") -// compile("org.springframework:spring-webmvc") -// compile("org.springframework.boot:spring-boot-starter") -// compile("org.springframework.boot:spring-boot-starter-tomcat") + compile("org.springframework.boot:spring-boot-starter-jdbc") + + compile("mysql:mysql-connector-java:6.0.6") + testCompile("org.springframework.boot:spring-boot-starter-test") } +def developmentDbUrl = "jdbc:mysql://localhost:3306/tracker_dev?user=tracker&useSSL=false&useTimezone=true&serverTimezone=UTC&useLegacyDatetimeCode=false" bootRun.environment([ - "WELCOME_MESSAGE": "Hello", + "WELCOME_MESSAGE": "hello", + "SPRING_DATASOURCE_URL": developmentDbUrl, ]) +def testDbUrl = "jdbc:mysql://localhost:3306/tracker_test?user=tracker&useSSL=false&useTimezone=true&serverTimezone=UTC&useLegacyDatetimeCode=false" test.environment([ - "WELCOME_MESSAGE": "Hello from Test", -]) \ No newline at end of file + "WELCOME_MESSAGE": "Hello from test", + "SPRING_DATASOURCE_URL": testDbUrl, +]) + +flyway { + url = developmentDbUrl + user = "tracker" + password = "" + locations = ["filesystem:databases/tracker/migrations"] +} + +task testMigrate(type: FlywayMigrateTask) { + url = testDbUrl +} \ No newline at end of file diff --git a/ci/build.yml b/ci/build.yml index e2bb9473a..ea12986b1 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -18,7 +18,18 @@ run: args: - -exc - | + + export DEBIAN_FRONTEND="noninteractive" + + apt-get update + + apt-get -y install mysql-server + service mysql start + cd pal-tracker + mysql -uroot < databases/create_databases.sql chmod +x gradlew - ./gradlew -P version=$(cat ../version/number) build + ./gradlew testMigrate clean build || (service mysql stop && exit 1) + service mysql stop + cp build/libs/pal-tracker-*.jar ../build-output \ No newline at end of file diff --git a/manifest-production.yml b/manifest-production.yml index 5a715dec6..1a6ab18dc 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -2,4 +2,6 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker-suchi \ No newline at end of file + host: ps-pal-tracker-suchi + services: + - tracker-database \ No newline at end of file diff --git a/manifest-review.yml b/manifest-review.yml index fb723f8dd..dd80dbe47 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -2,4 +2,6 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker-review-suchi \ No newline at end of file + host: ps-pal-tracker-review-suchi + services: + - tracker-database \ No newline at end of file diff --git a/out/production/classes/io/pivotal/pal/tracker/JdbcTimeEntryRepository.class b/out/production/classes/io/pivotal/pal/tracker/JdbcTimeEntryRepository.class new file mode 100644 index 0000000000000000000000000000000000000000..81bd73865113b0cf3e2e0374aba4924213570811 GIT binary patch literal 5920 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 diff --git a/out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class b/out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class new file mode 100644 index 0000000000000000000000000000000000000000..565908d6d7c4ab677efbb6e9dfeb20bd7f6951b2 GIT binary patch literal 6485 zcmcgx30Pd!75?8q@`mB5gg_Q!;!D!XK!yxtg%Hh02t?>WA`GO_+H^8J;NdVcnRyd} zTU*<@)vdO+)~c;t)b6#K37EQc(OSDNcC)ps)$WVkYi<8~-<=V1wfG;WS*L;!+{h|xV_^hxo!S3K?$TMqk>#St$i9ivK~5q3-oE%$qIR7^fqjtB6dcs!Kb zbSUS-W6r>Hrxy=<@#)-#C%yPgZv3ne^4Z*p?PB&hFCOvYQ5Bz8pr$kXM~$eZAP_PW z!K8UGVMSuWB!8_`Bzl373Wm)wqdjh=CVGuzB5hiU)I^H{ZFF#dG;E9|V-d>`rxU5+ zU^&VdxFtK$_RG3cJuW7t!CV`&Qeg~uN_cO+LjokkW)ft+~~=S z?Ke{4$o?2tDnp5ABsLI9nPToNmRcibTEV7}Wu&d+nk=fB?8*wTG=J( z(sC9BR>+v!4m!~4wtKyXl}W|Z;Sr-vx;yA{Y2lC=AMD_-%X)FOHS~j3V9Ad5PY__Kz;;IA6~hNpyv=QR9XjQ$}G{uBQayPj9^Z}IMV1;d>^eeJzr zy|X90tJqJ!IT+9jwgq&@w16%w3+PgJtv=8i>TmDU{msqI0ljhE`hdQEU1LD6DPUX^ z(3@&Cynz2`3Irjq`akIm=>DdrrhvX-Y81bml;viOhkZPCtySi+H zj(OE7fT)|R<`w!h;%{Hb3Of9AUv{-~Z=qWRvy;V(om-cJlMB=dCE~-ZX$K>*jInEo ztnzocDIs3dw{rTPn&?QR*p#q`b7SN1=sXvXoNmLB<7#H?N|{@rHMHs&S{9#m6>VB^ zy11btY0-p@+6`(XX$D*6f@tm-di!m7Btp5{+-BzG9$&`(v}l|ydzUSd3TsbzGkYO3 z-F_ewiG>pinqR!;yv}kf;iBVW|4ek->DJMf7$a{*w@rG^YII>|USs`>I-p=dfjymZ z%NRCNY*YQ6ZrV8OgfJlZG^+wZvAiucC%9GO&Gu4sn(PIL(yRyb@-;GUw|$w5bSUGr zpL`Nym1DaGcsV*-T-!2VIz=&{ce5&R9M0>J%~WI>RUMiY?dBg+qIKpy;Et$Fyc0_8 z`DWTip;YwPET%ci$UJkJXglNcE7X}bFJzgkE{>a%C9FVp->YC?no)C?n-eqJZlFcQ zag`3+?E$Rhw*sf}4}TAT*qzD|+f9D@popHC&%K-l`N@t2^XiU3xkqk0m(Tffu?pvL ztl1mzDxA-mf>-l!i9CD-N+}*_ISS9-BPa>2sVtquye#I|9fi7g%@KGHql{yp7?&T0 zR(Bt?%9FA!z*)%nFU z`cn&&g9gAyi;MvsU_2VA)B+51~lWvKlw}Qc#U2iI- zMf+e5bv)r@>9|C_gQ(l-+FFI3m7SvI`EoU{3SHziLlG)L0r;+2fZyo`UI=po?<>w* zyL25OOc|`eIE&Q;Gxb8!`XXK*7Za3AaF75AlG(XC?m)4E@5d#%g9P-DgkmPgCvuJ} z8|b*G@!9E)chBay-2T!^ervwEyGnj{e(~6np99QY@_o}vejV><;4 { + PreparedStatement statement = connection.prepareStatement( + "INSERT INTO time_entries (project_id, user_id, date, hours) " + + "VALUES (?, ?, ?, ?)", + RETURN_GENERATED_KEYS + ); + + statement.setLong(1, timeEntry.getProjectId()); + statement.setLong(2, timeEntry.getUserId()); + statement.setDate(3, Date.valueOf(timeEntry.getDate())); + statement.setInt(4, timeEntry.getHours()); + + return statement; + }, generatedKeyHolder); + + return find(generatedKeyHolder.getKey().longValue()); + } + + @Override + public TimeEntry find(Long id) { + return jdbcTemplate.query( + "SELECT id, project_id, user_id, date, hours FROM time_entries WHERE id = ?", + new Object[]{id}, + extractor); + } + + @Override + public List list() { + return jdbcTemplate.query("SELECT id, project_id, user_id, date, hours FROM time_entries", mapper); + } + + @Override + public TimeEntry update(Long id, TimeEntry timeEntry) { + jdbcTemplate.update("UPDATE time_entries " + + "SET project_id = ?, user_id = ?, date = ?, hours = ? " + + "WHERE id = ?", + timeEntry.getProjectId(), + timeEntry.getUserId(), + Date.valueOf(timeEntry.getDate()), + timeEntry.getHours(), + id); + + return find(id); + } + + @Override + public void delete(Long id) { + jdbcTemplate.update("DELETE FROM time_entries WHERE id = ?", id); + } + + private final RowMapper mapper = (rs, rowNum) -> new TimeEntry( + rs.getLong("id"), + rs.getLong("project_id"), + rs.getLong("user_id"), + rs.getDate("date").toLocalDate(), + rs.getInt("hours") + ); + + private final ResultSetExtractor extractor = + (rs) -> rs.next() ? mapper.mapRow(rs, 1) : null; +} \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java index 78cb5b60f..031c56763 100644 --- a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -4,13 +4,20 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.mysql.cj.jdbc.MysqlDataSource; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import javax.sql.DataSource; + @SpringBootApplication -public class PalTrackerApplication { +pubbuild.lic class PalTrackerApplication { + + @Autowired + DataSource dataSource; public static void main(String[] args) { SpringApplication.run(PalTrackerApplication.class, args); @@ -18,7 +25,7 @@ public static void main(String[] args) { @Bean TimeEntryRepository timeEntryRepository() { - return new InMemoryTimeEntryRepository(); + return new JdbcTimeEntryRepository(dataSource); } @Bean diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java index 2b7464304..5ea663c49 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -53,7 +53,7 @@ public void testCreate() throws Exception { assertThat(createJson.read("$.id", Long.class)).isGreaterThan(0); assertThat(createJson.read("$.projectId", Long.class)).isEqualTo(123L); assertThat(createJson.read("$.userId", Long.class)).isEqualTo(456L); - assertThat(createJson.read("$.date", String.class)).isEqualTo("2017-01-08"); + assertThat(createJson.read("$.date", String.class)).isEqualTo("2017-01-07"); assertThat(createJson.read("$.hours", Long.class)).isEqualTo(8); } @@ -89,7 +89,7 @@ public void testRead() throws Exception { assertThat(readJson.read("$.id", Long.class)).isEqualTo(id); assertThat(readJson.read("$.projectId", Long.class)).isEqualTo(123L); assertThat(readJson.read("$.userId", Long.class)).isEqualTo(456L); - assertThat(readJson.read("$.date", String.class)).isEqualTo("2017-01-08"); + assertThat(readJson.read("$.date", String.class)).isEqualTo("2017-01-07"); assertThat(readJson.read("$.hours", Long.class)).isEqualTo(8); } @@ -108,7 +108,7 @@ public void testUpdate() throws Exception { assertThat(updateJson.read("$.id", Long.class)).isEqualTo(id); assertThat(updateJson.read("$.projectId", Long.class)).isEqualTo(2L); assertThat(updateJson.read("$.userId", Long.class)).isEqualTo(3L); - assertThat(updateJson.read("$.date", String.class)).isEqualTo("2017-01-09"); + assertThat(updateJson.read("$.date", String.class)).isEqualTo("2017-01-08"); assertThat(updateJson.read("$.hours", Long.class)).isEqualTo(9); } diff --git a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java index 127413fb1..cc7091ed4 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java @@ -21,6 +21,6 @@ public class WelcomeApiTest { @Test public void exampleTest() { String body = this.restTemplate.getForObject("/", String.class); - assertThat(body).isEqualTo("Hello from Test"); + assertThat(body).isEqualTo("Hello from test"); } } From acf179afcbbae71dab3e38d187bb1572ccc5683d Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 12:35:59 +0530 Subject: [PATCH 13/22] corrected the build.yml --- ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/build.yml b/ci/build.yml index ea12986b1..34f1ebd73 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -27,7 +27,7 @@ run: service mysql start cd pal-tracker - mysql -uroot < databases/create_databases.sql + mysql -uroot < databases/tracker/create_databases.sql chmod +x gradlew ./gradlew testMigrate clean build || (service mysql stop && exit 1) service mysql stop From 7ea4498cd756d5c96ea105fe07f15f5d4cc698d4 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 12:38:52 +0530 Subject: [PATCH 14/22] correction --- src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java index 031c56763..cbe633052 100644 --- a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -14,7 +14,7 @@ import javax.sql.DataSource; @SpringBootApplication -pubbuild.lic class PalTrackerApplication { +public class PalTrackerApplication { @Autowired DataSource dataSource; From 01ab0ad0316000387e1ac2e9a324452033e2e8b1 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 12:56:46 +0530 Subject: [PATCH 15/22] Added the UTC changes --- .../io/pivotal/pal/tracker/PalTrackerApplication.java | 3 +++ .../test/pivotal/pal/trackerapi/TimeEntryApiTest.java | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java index cbe633052..3a421ac42 100644 --- a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -12,6 +12,7 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import javax.sql.DataSource; +import java.util.TimeZone; @SpringBootApplication public class PalTrackerApplication { @@ -20,6 +21,8 @@ public class PalTrackerApplication { DataSource dataSource; public static void main(String[] args) { + // Make sure the application runs as UTC + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); SpringApplication.run(PalTrackerApplication.class, args); } diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java index 5ea663c49..827ac31f4 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -19,6 +19,7 @@ import java.time.LocalDate; import java.util.Collection; +import java.util.TimeZone; import static com.jayway.jsonpath.JsonPath.parse; import static org.assertj.core.api.Assertions.assertThat; @@ -35,6 +36,9 @@ public class TimeEntryApiTest { @Before public void setUp() throws Exception { + // Make sure the application runs as UTC + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setUrl(System.getenv("SPRING_DATASOURCE_URL")); @@ -53,7 +57,7 @@ public void testCreate() throws Exception { assertThat(createJson.read("$.id", Long.class)).isGreaterThan(0); assertThat(createJson.read("$.projectId", Long.class)).isEqualTo(123L); assertThat(createJson.read("$.userId", Long.class)).isEqualTo(456L); - assertThat(createJson.read("$.date", String.class)).isEqualTo("2017-01-07"); + assertThat(createJson.read("$.date", String.class)).isEqualTo("2017-01-08"); assertThat(createJson.read("$.hours", Long.class)).isEqualTo(8); } @@ -89,7 +93,7 @@ public void testRead() throws Exception { assertThat(readJson.read("$.id", Long.class)).isEqualTo(id); assertThat(readJson.read("$.projectId", Long.class)).isEqualTo(123L); assertThat(readJson.read("$.userId", Long.class)).isEqualTo(456L); - assertThat(readJson.read("$.date", String.class)).isEqualTo("2017-01-07"); + assertThat(readJson.read("$.date", String.class)).isEqualTo("2017-01-08"); assertThat(readJson.read("$.hours", Long.class)).isEqualTo(8); } @@ -108,7 +112,7 @@ public void testUpdate() throws Exception { assertThat(updateJson.read("$.id", Long.class)).isEqualTo(id); assertThat(updateJson.read("$.projectId", Long.class)).isEqualTo(2L); assertThat(updateJson.read("$.userId", Long.class)).isEqualTo(3L); - assertThat(updateJson.read("$.date", String.class)).isEqualTo("2017-01-08"); + assertThat(updateJson.read("$.date", String.class)).isEqualTo("2017-01-09"); assertThat(updateJson.read("$.hours", Long.class)).isEqualTo(9); } From b76025ca25f69969945ac09ef2f1e374490345bb Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 13:03:16 +0530 Subject: [PATCH 16/22] corrected the build.yml --- ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/build.yml b/ci/build.yml index 34f1ebd73..2455d052b 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -29,7 +29,7 @@ run: cd pal-tracker mysql -uroot < databases/tracker/create_databases.sql chmod +x gradlew - ./gradlew testMigrate clean build || (service mysql stop && exit 1) + ./gradlew -P version=$(cat ../version/number) testMigrate clean build || (service mysql stop && exit 1) service mysql stop cp build/libs/pal-tracker-*.jar ../build-output \ No newline at end of file From f742f5cc4dc01468494402deca75035b07386681 Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Wed, 26 Jul 2017 12:28:32 -0600 Subject: [PATCH 17/22] Add tests for Actuator lab --- .../pivotal/pal/trackerapi/HealthApiTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java diff --git a/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java new file mode 100644 index 000000000..b3eef23cc --- /dev/null +++ b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java @@ -0,0 +1,38 @@ +package test.pivotal.pal.trackerapi; + +import com.jayway.jsonpath.DocumentContext; +import io.pivotal.pal.tracker.PalTrackerApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import static com.jayway.jsonpath.JsonPath.parse; +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) +public class HealthApiTest { + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void healthTest() { + ResponseEntity response = this.restTemplate.getForEntity("/health", String.class); + + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + + DocumentContext healthJson = parse(response.getBody()); + + assertThat(healthJson.read("$.status", String.class)).isEqualTo("UP"); + assertThat(healthJson.read("$.db.status", String.class)).isEqualTo("UP"); + assertThat(healthJson.read("$.diskSpace.status", String.class)).isEqualTo("UP"); + } +} From 8e5c8e677d6baa578a6933080f9703912070e928 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 15:06:54 +0530 Subject: [PATCH 18/22] accutator --- build.gradle | 4 +++ .../pal/tracker/TimeEntryController.java | 23 +++++++++++++-- .../pal/tracker/TimeEntryHealthIndicator.java | 29 +++++++++++++++++++ .../pal/tracker/TimeEntryControllerTest.java | 8 ++++- 4 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java diff --git a/build.gradle b/build.gradle index 4563f9acc..6339d6519 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,8 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-jdbc") compile("mysql:mysql-connector-java:6.0.6") + compile("org.springframework.boot:spring-boot-starter-actuator") + testCompile("org.springframework.boot:spring-boot-starter-test") } @@ -24,12 +26,14 @@ def developmentDbUrl = "jdbc:mysql://localhost:3306/tracker_dev?user=tracker&use bootRun.environment([ "WELCOME_MESSAGE": "hello", "SPRING_DATASOURCE_URL": developmentDbUrl, + "MANAGEMENT_SECURITY_ENABLED": false, ]) def testDbUrl = "jdbc:mysql://localhost:3306/tracker_test?user=tracker&useSSL=false&useTimezone=true&serverTimezone=UTC&useLegacyDatetimeCode=false" test.environment([ "WELCOME_MESSAGE": "Hello from test", "SPRING_DATASOURCE_URL": testDbUrl, + "MANAGEMENT_SECURITY_ENABLED": false, ]) flyway { diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java b/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java index 3d3ab61f5..427ed4aaf 100644 --- a/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java @@ -1,5 +1,7 @@ package io.pivotal.pal.tracker; +import org.springframework.boot.actuate.metrics.CounterService; +import org.springframework.boot.actuate.metrics.GaugeService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -10,15 +12,25 @@ @RequestMapping("/time-entries") public class TimeEntryController { + private final CounterService counter; + private final GaugeService gauge; private TimeEntryRepository timeEntriesRepo; - public TimeEntryController(TimeEntryRepository timeEntriesRepo) { + public TimeEntryController( + TimeEntryRepository timeEntriesRepo, + CounterService counter, + GaugeService gauge + ) { this.timeEntriesRepo = timeEntriesRepo; + this.counter = counter; + this.gauge = gauge; } - @RequestMapping(method = RequestMethod.POST) + @PostMapping public ResponseEntity create(@RequestBody TimeEntry timeEntry) { TimeEntry createdTimeEntry = timeEntriesRepo.create(timeEntry); + counter.increment("TimeEntry.created"); + gauge.submit("timeEntries.count", timeEntriesRepo.list().size()); return new ResponseEntity<>(createdTimeEntry, HttpStatus.CREATED); } @@ -27,6 +39,7 @@ public ResponseEntity create(@RequestBody TimeEntry timeEntry) { public ResponseEntity read(@PathVariable Long id) { TimeEntry timeEntry = timeEntriesRepo.find(id); if (timeEntry != null) { + counter.increment("TimeEntry.read"); return new ResponseEntity<>(timeEntry, HttpStatus.OK); } else { return new ResponseEntity<>(HttpStatus.NOT_FOUND); @@ -35,6 +48,7 @@ public ResponseEntity read(@PathVariable Long id) { @GetMapping public ResponseEntity> list() { + counter.increment("TimeEntry.listed"); return new ResponseEntity<>(timeEntriesRepo.list(), HttpStatus.OK); } @@ -42,6 +56,7 @@ public ResponseEntity> list() { public ResponseEntity update(@PathVariable Long id, @RequestBody TimeEntry timeEntry) { TimeEntry updatedTimeEntry = timeEntriesRepo.update(id, timeEntry); if (updatedTimeEntry != null) { + counter.increment("TimeEntry.updated"); return new ResponseEntity<>(updatedTimeEntry, HttpStatus.OK); } else { return new ResponseEntity<>(HttpStatus.NOT_FOUND); @@ -51,7 +66,9 @@ public ResponseEntity update(@PathVariable Long id, @RequestBody Time @DeleteMapping("{id}") public ResponseEntity delete(@PathVariable Long id) { timeEntriesRepo.delete(id); + counter.increment("TimeEntry.deleted"); + gauge.submit("timeEntries.count", timeEntriesRepo.list().size()); return new ResponseEntity<>(HttpStatus.NO_CONTENT); } -} +} \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java b/src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java new file mode 100644 index 000000000..49b1f175d --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java @@ -0,0 +1,29 @@ +package io.pivotal.pal.tracker; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.stereotype.Component; + +@Component +public class TimeEntryHealthIndicator implements HealthIndicator { + + private static final int MAX_TIME_ENTRIES = 5; + private final TimeEntryRepository timeEntryRepo; + + public TimeEntryHealthIndicator(TimeEntryRepository timeEntryRepo) { + this.timeEntryRepo = timeEntryRepo; + } + + @Override + public Health health() { + Health.Builder builder = new Health.Builder(); + + if(timeEntryRepo.list().size() < MAX_TIME_ENTRIES) { + builder.up(); + } else { + builder.down(); + } + + return builder.build(); + } +} \ No newline at end of file diff --git a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java index f7c0090e3..dc9695f79 100644 --- a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java +++ b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java @@ -5,6 +5,8 @@ import io.pivotal.pal.tracker.TimeEntryRepository; import org.junit.Before; import org.junit.Test; +import org.springframework.boot.actuate.metrics.CounterService; +import org.springframework.boot.actuate.metrics.GaugeService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -20,11 +22,15 @@ public class TimeEntryControllerTest { private TimeEntryRepository timeEntryRepository; private TimeEntryController controller; + private CounterService counterService; + private GaugeService gaugeService; @Before public void setUp() throws Exception { timeEntryRepository = mock(TimeEntryRepository.class); - controller = new TimeEntryController(timeEntryRepository); + counterService = mock(CounterService.class); + gaugeService = mock(GaugeService.class); + controller = new TimeEntryController(timeEntryRepository,counterService,gaugeService); } @Test From bbb7fef04246201cc7265911246bbfad8d00dfdc Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Wed, 26 Jul 2017 12:50:47 -0600 Subject: [PATCH 19/22] Add tests for Security lab --- .../pal/trackerapi/SecurityApiTest.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/test/java/test/pivotal/pal/trackerapi/SecurityApiTest.java diff --git a/src/test/java/test/pivotal/pal/trackerapi/SecurityApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/SecurityApiTest.java new file mode 100644 index 000000000..72099994b --- /dev/null +++ b/src/test/java/test/pivotal/pal/trackerapi/SecurityApiTest.java @@ -0,0 +1,52 @@ +package test.pivotal.pal.trackerapi; + +import io.pivotal.pal.tracker.PalTrackerApplication; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.LocalServerPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) +public class SecurityApiTest { + + @LocalServerPort + private String port; + private TestRestTemplate authorizedRestTemplate; + + @Autowired + private TestRestTemplate unAuthorizedRestTemplate; + + @Before + public void setUp() throws Exception { + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); + + authorizedRestTemplate = new TestRestTemplate(builder); + } + + @Test + public void unauthorizedTest() { + ResponseEntity response = this.unAuthorizedRestTemplate.getForEntity("/", String.class); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); + } + + @Test + public void authorizedTest() { + ResponseEntity response = this.authorizedRestTemplate.getForEntity("/", String.class); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + } +} From 7bb41b06904ffac8b1dc37edc4e45e1acb2e30b3 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 15:53:43 +0530 Subject: [PATCH 20/22] Changes for Spring Security --- build.gradle | 1 + manifest-production.yml | 4 ++- manifest-review.yml | 4 ++- .../pal/tracker/SecurityConfiguration.java | 32 +++++++++++++++++++ .../pivotal/pal/trackerapi/HealthApiTest.java | 15 ++++++++- .../pal/trackerapi/TimeEntryApiTest.java | 13 +++++++- .../pal/trackerapi/WelcomeApiTest.java | 18 +++++++++-- 7 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java diff --git a/build.gradle b/build.gradle index 6339d6519..1818b2c93 100644 --- a/build.gradle +++ b/build.gradle @@ -17,6 +17,7 @@ dependencies { compile("mysql:mysql-connector-java:6.0.6") compile("org.springframework.boot:spring-boot-starter-actuator") + compile("org.springframework.boot:spring-boot-starter-security") testCompile("org.springframework.boot:spring-boot-starter-test") diff --git a/manifest-production.yml b/manifest-production.yml index 1a6ab18dc..b43baccbb 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -4,4 +4,6 @@ applications: path: build/libs/pal-tracker.jar host: ps-pal-tracker-suchi services: - - tracker-database \ No newline at end of file + - tracker-database + env: +- SECURITY_FORCE_HTTPS: true \ No newline at end of file diff --git a/manifest-review.yml b/manifest-review.yml index dd80dbe47..d31369c39 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -4,4 +4,6 @@ applications: path: build/libs/pal-tracker.jar host: ps-pal-tracker-review-suchi services: - - tracker-database \ No newline at end of file + - tracker-database + env: +- SECURITY_FORCE_HTTPS: true \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java b/src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java new file mode 100644 index 000000000..6f3225359 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java @@ -0,0 +1,32 @@ +package io.pivotal.pal.tracker; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@EnableWebSecurity +public class SecurityConfiguration extends WebSecurityConfigurerAdapter { + @Override + protected void configure(HttpSecurity http) throws Exception { + String forceHttps = System.getenv("SECURITY_FORCE_HTTPS"); + if (forceHttps != null && forceHttps.equals("true")) { + http.requiresChannel().anyRequest().requiresSecure(); + } + + http + .authorizeRequests().antMatchers("/**").hasRole("USER") + .and() + .httpBasic() + .and() + .csrf().disable(); + } + + @Autowired + public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + } +} \ No newline at end of file diff --git a/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java index b3eef23cc..48168b441 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java @@ -2,11 +2,14 @@ import com.jayway.jsonpath.DocumentContext; import io.pivotal.pal.tracker.PalTrackerApplication; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; @@ -19,9 +22,19 @@ @SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) public class HealthApiTest { - @Autowired + @LocalServerPort + private String port; private TestRestTemplate restTemplate; + @Before + public void setUp() throws Exception { + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); + + restTemplate = new TestRestTemplate(builder); + } + @Test public void healthTest() { ResponseEntity response = this.restTemplate.getForEntity("/health", String.class); diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java index 827ac31f4..1d869649a 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -8,8 +8,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -29,7 +31,8 @@ @SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) public class TimeEntryApiTest { - @Autowired + @LocalServerPort + private String port; private TestRestTemplate restTemplate; private TimeEntry timeEntry = new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8); @@ -39,6 +42,14 @@ public void setUp() throws Exception { // Make sure the application runs as UTC TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); + + restTemplate = new TestRestTemplate(builder); + + + MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setUrl(System.getenv("SPRING_DATASOURCE_URL")); diff --git a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java index cc7091ed4..782c5d64d 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java @@ -1,11 +1,13 @@ package test.pivotal.pal.trackerapi; import io.pivotal.pal.tracker.PalTrackerApplication; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; @@ -15,12 +17,22 @@ @SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) public class WelcomeApiTest { - @Autowired + @LocalServerPort + private String port; private TestRestTemplate restTemplate; + @Before + public void setUp() throws Exception { + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); + + restTemplate = new TestRestTemplate(builder); + } + @Test public void exampleTest() { String body = this.restTemplate.getForObject("/", String.class); assertThat(body).isEqualTo("Hello from test"); } -} +} \ No newline at end of file From 48229d1d9e42e54272f29f4f87f93c84897b655c Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 16:00:38 +0530 Subject: [PATCH 21/22] valif yaml --- manifest-production.yml | 16 +++++++++------- manifest-review.yml | 14 ++++++++------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/manifest-production.yml b/manifest-production.yml index b43baccbb..91de91792 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -1,9 +1,11 @@ --- applications: -- name: pal-tracker - path: build/libs/pal-tracker.jar - host: ps-pal-tracker-suchi - services: - - tracker-database - env: -- SECURITY_FORCE_HTTPS: true \ No newline at end of file + - + env: ~ + host: ps-pal-tracker-suchi + name: pal-tracker + path: build/libs/pal-tracker.jar + services: + - tracker-database + - + SECURITY_FORCE_HTTPS: true \ No newline at end of file diff --git a/manifest-review.yml b/manifest-review.yml index d31369c39..8d0c576ef 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -1,9 +1,11 @@ --- applications: -- name: pal-tracker - path: build/libs/pal-tracker.jar - host: ps-pal-tracker-review-suchi - services: + - + env: ~ + host: ps-pal-tracker-review-suchi + name: pal-tracker + path: build/libs/pal-tracker.jar + services: - tracker-database - env: -- SECURITY_FORCE_HTTPS: true \ No newline at end of file + - + SECURITY_FORCE_HTTPS: true \ No newline at end of file From e1fb4f63d353156ed6bfd1f7235af4f61f2fdfe2 Mon Sep 17 00:00:00 2001 From: suchizonepal Date: Mon, 6 Nov 2017 16:02:55 +0530 Subject: [PATCH 22/22] update yaml --- manifest-production.yml | 16 +++++++--------- manifest-review.yml | 14 ++++++-------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/manifest-production.yml b/manifest-production.yml index 91de91792..00bff01e8 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -1,11 +1,9 @@ --- applications: - - - env: ~ - host: ps-pal-tracker-suchi - name: pal-tracker - path: build/libs/pal-tracker.jar - services: - - tracker-database - - - SECURITY_FORCE_HTTPS: true \ No newline at end of file +- name: pal-tracker + path: build/libs/pal-tracker.jar + host: ps-pal-tracker-suchi + services: + - tracker-database +env: +- SECURITY_FORCE_HTTPS: true \ No newline at end of file diff --git a/manifest-review.yml b/manifest-review.yml index 8d0c576ef..9f7e9f6f5 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -1,11 +1,9 @@ --- applications: - - - env: ~ - host: ps-pal-tracker-review-suchi - name: pal-tracker - path: build/libs/pal-tracker.jar - services: +- name: pal-tracker + path: build/libs/pal-tracker.jar + host: ps-pal-tracker-review-suchi + services: - tracker-database - - - SECURITY_FORCE_HTTPS: true \ No newline at end of file +env: +- SECURITY_FORCE_HTTPS: true \ No newline at end of file