From f1c11281dc67e5c61a5d0c66cfdb6d6aca9c1eba Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Fri, 21 Jul 2017 09:26:37 -0600 Subject: [PATCH 01/29] 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 137be362d1b0bcb20b92c6129d7c16a2fbd3e862 Mon Sep 17 00:00:00 2001 From: James Denman Date: Tue, 16 Jan 2018 17:21:41 -0500 Subject: [PATCH 02/29] initial commit --- .gitignore | 2 +- build.gradle | 12 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53324 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++++++++++++++++++ gradlew.bat | 90 ++++++++++ settings.gradle | 1 + .../pal/tracker/PalTrackerApplication.java | 12 ++ .../pal/tracker/WelcomeController.java | 13 ++ 9 files changed, 299 insertions(+), 1 deletion(-) 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/.gitignore b/.gitignore index 4fa332f5c..6250dc478 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ build .gradle .idea *.iml -ci/variables.yml +ci/variables.yml \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..edb330bac --- /dev/null +++ b/build.gradle @@ -0,0 +1,12 @@ +plugins { + id "java" + id "org.springframework.boot" version "1.5.4.RELEASE" +} + +repositories { + mavenCentral() +} + +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") +} \ 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..3baa851b28c65f87dd36a6748e1a85cf360c1301 GIT binary patch literal 53324 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

*Ou)7mZ_?&1& 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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..5f66027fe --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Jan 16 16:31:17 EST 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..27309d923 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# 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 ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +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" -a "$nonstop" = "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..f6d5974e7 --- /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 + +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 + +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 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. +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..80f2a72a5 --- /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); + } +} \ No newline at end of file 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 ed7a1831a8fee62b6dbeb59bb47d60cec4652e21 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Wed, 17 Jan 2018 08:26:47 -0700 Subject: [PATCH 03/29] Simple Spring Boot app --- build.gradle | 12 ++++++++++++ settings.gradle | 1 + .../pivotal/pal/tracker/PalTrackerApplication.java | 11 +++++++++++ .../io/pivotal/pal/tracker/WelcomeController.java | 13 +++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 build.gradle 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..bf82fb8f5 --- /dev/null +++ b/build.gradle @@ -0,0 +1,12 @@ +plugins { + id "java" + id "org.springframework.boot" version "1.5.4.RELEASE" +} + +repositories { + mavenCentral() +} + +dependencies { + compile("org.springframework.boot:spring-boot-starter-web") +} 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..2a76fb9f2 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -0,0 +1,11 @@ +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); + } +} \ No newline at end of file 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 2be3d7e4a73e458592d5d3021007f648dc8f626e Mon Sep 17 00:00:00 2001 From: James Denman Date: Thu, 18 Jan 2018 10:33:34 -0500 Subject: [PATCH 04/29] fresh project --- build.gradle | 1 + .../io/pivotal/pal/tracker/WelcomeController.java | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 src/main/java/io/pivotal/pal/tracker/WelcomeController.java diff --git a/build.gradle b/build.gradle index edb330bac..4ff9a3509 100644 --- a/build.gradle +++ b/build.gradle @@ -9,4 +9,5 @@ repositories { dependencies { compile("org.springframework.boot:spring-boot-starter-web") + testCompile("org.springframework.boot:spring-boot-starter-test") } \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/WelcomeController.java b/src/main/java/io/pivotal/pal/tracker/WelcomeController.java deleted file mode 100644 index 2d477ae71..000000000 --- a/src/main/java/io/pivotal/pal/tracker/WelcomeController.java +++ /dev/null @@ -1,13 +0,0 @@ -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 975872459f16aedacd3d97ff739f3cec50b7b40e Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Thu, 20 Jul 2017 15:04:20 -0600 Subject: [PATCH 05/29] Add tests for MVC lab --- .../InMemoryTimeEntryRepositoryTest.java | 72 ++++++++++ .../pal/tracker/TimeEntryControllerTest.java | 106 +++++++++++++++ .../pal/trackerapi/TimeEntryApiTest.java | 126 ++++++++++++++++++ 3 files changed, 304 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..03e804956 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java @@ -0,0 +1,72 @@ +package test.pivotal.pal.tracker; + +import io.pivotal.pal.tracker.TimeEntryRepository; +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 { + TimeEntryRepository 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 { + TimeEntryRepository 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 { + TimeEntryRepository 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 { + TimeEntryRepository 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 { + TimeEntryRepository 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 02ce59e463864b2e570162d72f96d6f6e55a949f Mon Sep 17 00:00:00 2001 From: James Denman Date: Thu, 18 Jan 2018 17:15:16 -0500 Subject: [PATCH 06/29] finished Spring MVC lab James & Becky --- build.gradle | 1 + ci/build.yml | 24 +++++ ci/pipeline.yml | 83 +++++++++++++++ manifest-production.yml | 5 + manifest-review.yml | 5 + .../tracker/InMemoryTimeEntryRepository.java | 37 +++++++ .../pal/tracker/PalTrackerApplication.java | 20 ++++ .../io/pivotal/pal/tracker/TimeEntry.java | 100 ++++++++++++++++++ .../pal/tracker/TimeEntryController.java | 64 +++++++++++ .../pal/tracker/TimeEntryRepository.java | 27 +++++ .../pal/tracker/TimeEntryControllerTest.java | 18 ++-- .../pal/trackerapi/TimeEntryApiTest.java | 2 + 12 files changed, 377 insertions(+), 9 deletions(-) create mode 100644 ci/build.yml create mode 100644 ci/pipeline.yml create mode 100644 manifest-production.yml create mode 100644 manifest-review.yml 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 4ff9a3509..04ab9e2f4 100644 --- a/build.gradle +++ b/build.gradle @@ -9,5 +9,6 @@ repositories { dependencies { compile("org.springframework.boot:spring-boot-starter-web") + compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.1") testCompile("org.springframework.boot:spring-boot-starter-test") } \ No newline at end of file diff --git a/ci/build.yml b/ci/build.yml new file mode 100644 index 000000000..4ba28db53 --- /dev/null +++ b/ci/build.yml @@ -0,0 +1,24 @@ +platform: linux + +image_resource: + type: docker-image + source: + repository: openjdk + tag: '8-jdk' + +inputs: + - name: pal-tracker + - name: version + +outputs: + - name: build-output + +run: + path: bash + args: + - -exc + - | + cd pal-tracker + chmod +x gradlew + ./gradlew -P version=$(cat ../version/number) build + cp build/libs/pal-tracker-*.jar ../build-output diff --git a/ci/pipeline.yml b/ci/pipeline.yml new file mode 100644 index 000000000..928173bf6 --- /dev/null +++ b/ci/pipeline.yml @@ -0,0 +1,83 @@ +--- +resources: +- name: pal-tracker + type: git + source: + uri: {{github-repository}} + branch: master + private_key: {{github-private-key}} + +- 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: production + +jobs: +- name: build + plan: + - get: pal-tracker + trigger: true + - get: version + params: {bump: patch} + - task: build and test + file: pal-tracker/ci/build.yml + - 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-production.yml + path: pal-tracker-artifacts/pal-tracker-*.jar + environment_variables: + WELCOME_MESSAGE: "Hello from the production environment" diff --git a/manifest-production.yml b/manifest-production.yml new file mode 100644 index 000000000..193682320 --- /dev/null +++ b/manifest-production.yml @@ -0,0 +1,5 @@ +--- +applications: +- name: pal-tracker + path: build/libs/pal-tracker.jar + host: ps-pal-tracker diff --git a/manifest-review.yml b/manifest-review.yml new file mode 100644 index 000000000..65369e833 --- /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 diff --git a/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java b/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java new file mode 100644 index 000000000..b4406f8f3 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java @@ -0,0 +1,37 @@ +package io.pivotal.pal.tracker; + +import java.util.*; + +public class InMemoryTimeEntryRepository extends TimeEntryRepository { + private Map timeEntryMap = new HashMap<>(); + private long highestId = 0L; + + @Override + public TimeEntry create(TimeEntry timeEntry) { + timeEntry.setId(++highestId); + timeEntryMap.put(timeEntry.getId(), timeEntry); + return timeEntry; + } + + @Override + public TimeEntry find(long id){ + return timeEntryMap.get(id); + } + + @Override + public void delete(long id) { + timeEntryMap.remove(id); + } + + @Override + public List list() { + return new ArrayList<>(timeEntryMap.values()); + } + + @Override + public TimeEntry update(long id, TimeEntry timeEntry) { + timeEntry.setId(id); + timeEntryMap.put(id, timeEntry); + return timeEntry; + } +} diff --git a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java index 80f2a72a5..78cb5b60f 100644 --- a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -1,7 +1,13 @@ 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 { @@ -9,4 +15,18 @@ 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..377e177b5 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntry.java @@ -0,0 +1,100 @@ +package io.pivotal.pal.tracker; + +import java.time.LocalDate; +import java.util.Objects; + +public class TimeEntry { + private long id; + private long projectId; + private long userId; + private LocalDate date; + private int hours; + + + public TimeEntry(int projectId, int userId, LocalDate date, int hours) { + this.projectId = projectId; + this.userId = userId; + this.date = date; + this.hours = hours; + } + + public TimeEntry(long id, int projectId, int userId, LocalDate date, int hours) { + this.id = id; + this.projectId = projectId; + this.userId = userId; + this.date = date; + this.hours = hours; + } + + public TimeEntry() { + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getProjectId() { + return projectId; + } + + public void setProjectId(long projectId) { + this.projectId = projectId; + } + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public LocalDate getDate() { + return date; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public int getHours() { + return hours; + } + + public void setHours(int hours) { + this.hours = hours; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TimeEntry timeEntry = (TimeEntry) o; + return id == timeEntry.id && + projectId == timeEntry.projectId && + userId == timeEntry.userId && + hours == timeEntry.hours && + Objects.equals(date, timeEntry.date); + } + + @Override + public int hashCode() { + + return Objects.hash(id, projectId, userId, date, hours); + } + + @Override + public String toString() { + return "TimeEntry{" + + "id=" + id + + ", projectId=" + projectId + + ", userId=" + userId + + ", date=" + date + + ", hours=" + hours + + '}'; + } +} 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..1cca9424b --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java @@ -0,0 +1,64 @@ +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 +public class TimeEntryController { + private TimeEntryRepository timeEntryRepository; + + public TimeEntryController(TimeEntryRepository timeEntryRepository) { + this.timeEntryRepository = timeEntryRepository; + } + + @PostMapping("/time-entries") + @ResponseBody + public ResponseEntity create(@RequestBody TimeEntry timeEntry) { + System.out.println("TIME ENTRY Controller: " + timeEntry); + ResponseEntity response = new ResponseEntity(timeEntryRepository.create(timeEntry), HttpStatus.CREATED); + return response; + } + + @GetMapping("/time-entries/{id}") + @ResponseBody + public ResponseEntity read(@PathVariable long id) { + TimeEntry existingTimeEntry = timeEntryRepository.find(id); + ResponseEntity response; + if (existingTimeEntry != null) { + response = new ResponseEntity(existingTimeEntry, HttpStatus.OK); + } else { + response = new ResponseEntity(HttpStatus.NOT_FOUND); + } + return response; + } + + @GetMapping("/time-entries") + @ResponseBody + public ResponseEntity> list() { + ResponseEntity> responseEntity = new ResponseEntity(timeEntryRepository.list(), HttpStatus.OK); + return responseEntity; + } + + @PutMapping("/time-entries/{id}") + @ResponseBody + public ResponseEntity update(@PathVariable long id, @RequestBody TimeEntry timeEntry) { + TimeEntry existingTimeEntry = timeEntryRepository.update(id, timeEntry); + ResponseEntity response; + if (existingTimeEntry != null) { + response = new ResponseEntity(existingTimeEntry, HttpStatus.OK); + } else { + response = new ResponseEntity(HttpStatus.NOT_FOUND); + } + return response; + } + + @DeleteMapping("/time-entries/{id}") + @ResponseBody + public ResponseEntity delete(@PathVariable long id) { + timeEntryRepository.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..d1e891360 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java @@ -0,0 +1,27 @@ +package io.pivotal.pal.tracker; + +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class TimeEntryRepository { + public TimeEntry create(TimeEntry timeEntry) { + return null; + } + + public TimeEntry find(long id) { + return null; + } + + public List list() { + return null; + } + + public TimeEntry update(long id, TimeEntry timeEntry) { + return null; + } + + public void delete(long id) { + } +} diff --git a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java index f7c0090e3..8ef3d46f7 100644 --- a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java +++ b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java @@ -29,15 +29,15 @@ public void setUp() throws Exception { @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); +// 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 diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java index b742e5447..a784b96b9 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -34,10 +34,12 @@ public class TimeEntryApiTest { public void testCreate() throws Exception { ResponseEntity createResponse = restTemplate.postForEntity("/time-entries", timeEntry, String.class); + System.out.println("TIME ENTRY TEST: " + timeEntry); assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED); DocumentContext createJson = parse(createResponse.getBody()); + System.out.println("create JSON: " + createJson); assertThat(createJson.read("$.id", Long.class)).isGreaterThan(0); assertThat(createJson.read("$.projectId", Long.class)).isEqualTo(123L); assertThat(createJson.read("$.userId", Long.class)).isEqualTo(456L); From ce7df664fac225e567d757ed3ced454b961440ba Mon Sep 17 00:00:00 2001 From: James Denman Date: Thu, 18 Jan 2018 17:21:54 -0500 Subject: [PATCH 07/29] finished Spring MVC lab James & Becky --- ci/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/build.yml b/ci/build.yml index 4ba28db53..88cc555d1 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -18,6 +18,7 @@ run: args: - -exc - | + export TERM=${TERM:-dumb} cd pal-tracker chmod +x gradlew ./gradlew -P version=$(cat ../version/number) build From 4211df2c379790faf1eba5965d07375f0661db80 Mon Sep 17 00:00:00 2001 From: James Denman Date: Thu, 18 Jan 2018 17:26:29 -0500 Subject: [PATCH 08/29] finished Spring MVC lab James & Becky --- .../pal/tracker/TimeEntryControllerTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java index 8ef3d46f7..f7c0090e3 100644 --- a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java +++ b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java @@ -29,15 +29,15 @@ public void setUp() throws Exception { @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); + 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 From 3121e6f4600d7571e268a528c8a081626095e52e Mon Sep 17 00:00:00 2001 From: James Denman Date: Thu, 18 Jan 2018 17:32:22 -0500 Subject: [PATCH 09/29] finished Spring MVC lab James & Becky --- manifest-production.yml | 2 +- manifest-review.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest-production.yml b/manifest-production.yml index 193682320..06bfdeb15 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -2,4 +2,4 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker + host: ps-pal-tracker-james-becky diff --git a/manifest-review.yml b/manifest-review.yml index 65369e833..2b6670025 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -2,4 +2,4 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker-review + host: ps-pal-tracker-review-james-backy From f32b284145b2fdc2c573d392c68a59f9fd2b40f2 Mon Sep 17 00:00:00 2001 From: James Denman Date: Thu, 18 Jan 2018 17:43:38 -0500 Subject: [PATCH 10/29] finished Spring MVC lab James & Becky --- build.gradle | 10 ++++- .../io/pivotal/pal/tracker/EnvController.java | 41 +++++++++++++++++++ .../pal/tracker/WelcomeController.java | 13 ++++++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/pivotal/pal/tracker/EnvController.java create mode 100644 src/main/java/io/pivotal/pal/tracker/WelcomeController.java diff --git a/build.gradle b/build.gradle index 04ab9e2f4..bde7f2f19 100644 --- a/build.gradle +++ b/build.gradle @@ -11,4 +11,12 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.1") testCompile("org.springframework.boot:spring-boot-starter-test") -} \ No newline at end of file +} + +bootRun.environment([ + "WELCOME_MESSAGE": "hello", +]) + +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..b8c0167d2 --- /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; + } +} \ No newline at end of file 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 50ad725febd3b0f515749b42f71f71d4400b7275 Mon Sep 17 00:00:00 2001 From: James Denman Date: Thu, 18 Jan 2018 17:46:40 -0500 Subject: [PATCH 11/29] finished Spring MVC lab James & Becky --- build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bde7f2f19..dc380127c 100644 --- a/build.gradle +++ b/build.gradle @@ -19,4 +19,10 @@ bootRun.environment([ test.environment([ "WELCOME_MESSAGE": "Hello from test", -]) \ No newline at end of file +]) + +assignments { + apiUrl = "https://caddy.pal.pivotal.io" + email = ["james.denman@dell.com","rmcinerney@pivotal.io"] + cohortIdentifier = "349802131" +} \ No newline at end of file From d526f85c0243d518228fcd82d3966caad8a1242a Mon Sep 17 00:00:00 2001 From: Mike Gehard Date: Tue, 9 Jan 2018 09:47:21 -0700 Subject: [PATCH 12/29] Add task for migrating databases --- ci/migrateDatabase.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 ci/migrateDatabase.yml diff --git a/ci/migrateDatabase.yml b/ci/migrateDatabase.yml new file mode 100644 index 000000000..b2af8c5ef --- /dev/null +++ b/ci/migrateDatabase.yml @@ -0,0 +1,29 @@ +platform: linux + +image_resource: + type: docker-image + source: + repository: openjdk + tag: '8-jdk' + +inputs: + - name: pal-tracker +# - name: version + +#outputs: +# - name: build-output + +run: + path: bash + args: + - -exc + - | + cd pal-tracker + curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx + chmod +x cf + curl -L "https://repo1.maven.org/maven2/org/flywaydb/flyway-commandline/5.0.5/flyway-commandline-5.0.5-linux-x64.tar.gz" | tar -zx + chmod +x flyway-5.0.5/flyway + ./cf login -a $CF_API_URL -u $CF_USERNAME -p $CF_PASSWORD -o $CF_ORG -s $CF_SPACE + ./cf ssh -N -L 63306:$MYSQL_IP:3306 pal-tracker & + sleep 2 + ./flyway-5.0.5/flyway -url="jdbc:mysql://127.0.0.1:63306/$DATABASE_NAME" -locations=filesystem:databases/tracker -user=$DATABASE_USERNAME -password=$DATABASE_PASSWORD clean migrate From adea743a943c86512aae94ee58a5a2087f6f688a Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 09:22:13 -0700 Subject: [PATCH 13/29] Adding Migrations --- build.gradle | 6 ------ databases/tracker/create_databases.sql | 10 ++++++++++ databases/tracker/migrations/V1__initial_schema.sql | 11 +++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 databases/tracker/create_databases.sql create mode 100644 databases/tracker/migrations/V1__initial_schema.sql diff --git a/build.gradle b/build.gradle index 3260db2f0..7b5faa8d0 100644 --- a/build.gradle +++ b/build.gradle @@ -20,9 +20,3 @@ bootRun.environment([ test.environment([ "WELCOME_MESSAGE": "Hello from test", ]) - -assignments { - apiUrl = "https://caddy.pal.pivotal.io" - email = ["james.denman@dell.com","rmcinerney@pivotal.io"] - cohortIdentifier = "349802131" -} diff --git a/databases/tracker/create_databases.sql b/databases/tracker/create_databases.sql new file mode 100644 index 000000000..a0674bdda --- /dev/null +++ b/databases/tracker/create_databases.sql @@ -0,0 +1,10 @@ +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..daca8c4e3 --- /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; \ No newline at end of file From 5c6a827a66acd5a02b95f6375a0c9d3f81ed3927 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 09:31:19 -0700 Subject: [PATCH 14/29] Updated hosts --- manifest-production.yml | 2 +- manifest-review.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest-production.yml b/manifest-production.yml index 06bfdeb15..b89f7cb93 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -2,4 +2,4 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker-james-becky + host: ps-pal-tracker-becky-allen diff --git a/manifest-review.yml b/manifest-review.yml index 2b6670025..860ddba40 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -2,4 +2,4 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker-review-james-backy + host: ps-pal-tracker-review-becky-allen From 72db368807624dbee47f10e0969d35daf82f7343 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 09:55:15 -0700 Subject: [PATCH 15/29] Updated pipeline to connect to db --- ci/pipeline.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ci/pipeline.yml b/ci/pipeline.yml index 928173bf6..2f795a159 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -60,9 +60,22 @@ jobs: - name: deploy-review plan: - get: pal-tracker + passed: [build] - get: pal-tracker-artifacts trigger: true passed: [build] + - task: migrate database + file: pal-tracker/ci/migrateDatabase.yml + params: + CF_API_URL: https://api.sys.pikes.pal.pivotal.io + CF_USERNAME: rmcinerney@pivotal.io + CF_PASSWORD: e858bdfa + CF_ORG: rebecca-mcinerney-pal + CF_SPACE: review + MYSQL_IP: 192.168.16.87 + DATABASE_NAME: cf_37740baf_3b05_4485_adb2_65500a4f3539 + DATABASE_USERNAME: wjTZzLvL9B29CRsY + DATABASE_PASSWORD: WwqEEczDuSGWbfGy - put: review-deployment params: manifest: pal-tracker/manifest-review.yml @@ -73,8 +86,21 @@ jobs: - name: deploy-production plan: - get: pal-tracker + passed: [deploy-review] - get: pal-tracker-artifacts passed: [deploy-review] + - task: migrate database + file: pal-tracker/ci/migrateDatabase.yml + params: + CF_API_URL: https://api.sys.pikes.pal.pivotal.io + CF_USERNAME: rmcinerney@pivotal.io + CF_PASSWORD: e858bdfa + CF_ORG: rebecca-mcinerney-pal + CF_SPACE: production + MYSQL_IP: {{mysql-ip}} + DATABASE_NAME: cf_f51d41e7_ada2_42c6_85ca_9d254cb9be46 + DATABASE_USERNAME: mkRXClES4I4NpF5D + DATABASE_PASSWORD: IPoX5zr60CFDmSpe - put: production-deployment params: manifest: pal-tracker/manifest-production.yml From efb1a5c5c1799cc8e5393f0e1500ab9802091ba6 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 09:59:14 -0700 Subject: [PATCH 16/29] Added production ip address. --- ci/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/pipeline.yml b/ci/pipeline.yml index 2f795a159..b077666b1 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -97,7 +97,7 @@ jobs: CF_PASSWORD: e858bdfa CF_ORG: rebecca-mcinerney-pal CF_SPACE: production - MYSQL_IP: {{mysql-ip}} + MYSQL_IP: 192.168.16.87 DATABASE_NAME: cf_f51d41e7_ada2_42c6_85ca_9d254cb9be46 DATABASE_USERNAME: mkRXClES4I4NpF5D DATABASE_PASSWORD: IPoX5zr60CFDmSpe From b95b6c24f7420c52ece18dd2d6f897fc29c1b256 Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Wed, 26 Jul 2017 11:45:04 -0600 Subject: [PATCH 17/29] Add tests for JDBC lab --- .../tracker/JdbcTimeEntryRepositoryTest.java | 159 ++++++++++++++++++ 1 file changed, 159 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); + } +} From fed71704bb2a2007ddc879d2ef04737bbb520685 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 11:58:16 -0700 Subject: [PATCH 18/29] jdbc lab: *added config files *updated dependencies *Changed TimeEntryRepository to an interface *Added jdbc connection and updated application bean to return JdbcTimeEntryRepository --- build.gradle | 22 +++++ ci/build.yml | 16 +++- manifest-production.yml | 2 + manifest-review.yml | 4 +- .../pivotal/pal/tracker/EnvController.class | Bin 0 -> 1631 bytes .../tracker/InMemoryTimeEntryRepository.class | Bin 0 -> 1881 bytes .../pal/tracker/JdbcTimeEntryRepository.class | Bin 0 -> 1956 bytes .../pal/tracker/PalTrackerApplication.class | Bin 0 -> 2276 bytes .../io/pivotal/pal/tracker/TimeEntry.class | Bin 0 -> 2950 bytes .../pal/tracker/TimeEntryController.class | Bin 0 -> 3801 bytes .../pal/tracker/TimeEntryRepository.class | Bin 0 -> 515 bytes .../pal/tracker/WelcomeController.class | Bin 0 -> 612 bytes .../InMemoryTimeEntryRepositoryTest.class | Bin 0 -> 3102 bytes .../tracker/JdbcTimeEntryRepositoryTest.class | Bin 0 -> 6377 bytes .../pal/tracker/TimeEntryControllerTest.class | Bin 0 -> 5021 bytes .../pal/trackerapi/TimeEntryApiTest.class | Bin 0 -> 6880 bytes .../tracker/InMemoryTimeEntryRepository.java | 2 +- .../pal/tracker/JdbcTimeEntryRepository.java | 85 ++++++++++++++++++ .../pal/tracker/PalTrackerApplication.java | 6 +- .../io/pivotal/pal/tracker/TimeEntry.java | 8 ++ .../pal/tracker/TimeEntryRepository.java | 24 ++--- .../pal/trackerapi/TimeEntryApiTest.java | 17 +++- 22 files changed, 159 insertions(+), 27 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/JdbcTimeEntryRepository.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/InMemoryTimeEntryRepositoryTest.class create mode 100644 out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class create mode 100644 out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class create mode 100644 out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class create mode 100644 src/main/java/io/pivotal/pal/tracker/JdbcTimeEntryRepository.java diff --git a/build.gradle b/build.gradle index 7b5faa8d0..4563f9acc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,9 @@ +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 { @@ -10,13 +13,32 @@ repositories { dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.1") + 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", + "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", + "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 88cc555d1..2455d052b 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -18,8 +18,18 @@ run: args: - -exc - | - export TERM=${TERM:-dumb} + + export DEBIAN_FRONTEND="noninteractive" + + apt-get update + + apt-get -y install mysql-server + service mysql start + cd pal-tracker + mysql -uroot < databases/tracker/create_databases.sql chmod +x gradlew - ./gradlew -P version=$(cat ../version/number) build - cp build/libs/pal-tracker-*.jar ../build-output + ./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 diff --git a/manifest-production.yml b/manifest-production.yml index b89f7cb93..8e752b077 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -3,3 +3,5 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar host: ps-pal-tracker-becky-allen + services: + - tracker-database diff --git a/manifest-review.yml b/manifest-review.yml index 860ddba40..897eba97d 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-becky-allen + host: ps-pal-tracker-review + services: + - tracker-database \ No newline at end of file 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%rAr>QL7{;HIy`(IGb+w|lwkTe@7jdnn)^;gg5D;9XRR@Qeb~<5+%dsKZ$!3}1 zziMYxN}cKSbN{H0&zr=}q9T0A*_@O2{NCrhm$U!<|Mx!trtqkM60Vu}x&Q;$hHwnm zW%#CmVNA*JZ2>p%-7s$Adl`N((U9M16F=DaZ2S++Y0 z#pZK++phOQ?bf-_P#Aiw+nycv0!LwX|JUhw>e^nr-t@h8qpAIRM{oO~?bbVd!oY6* z?gaHGZ+$dogt)2On@%@e+)z+U3i)a6>2O9NQ?9HkWM};i`YJZH=RE9ftvkUJd)?*A z@uuIh-Bml#GEWw>;im2?OdaHU(OY)5{9vaq;gQqvyE^0&rQ}4Nc?xhT}RSJIh@XGFNv)2B=&aNKlh&JmQV_7N-xF zC27j{IvY`J7RpP9?>Lh9!ehS|w48Y@={)z5)LfM+v~UKWDU{NRyl;0mS(O$};8P2y zaN5Ew$`85WXkiHtEHtr9Cx=y}g@pD@BQT7-0l){%^8q_>n;FkXLfNgS_toUA z@45_*_C1O{lTf1@Xy8j_73X=;mB2FR)n`Zv@ckrjMFV4eSPgv7bB$HQ@pH}=kl`C} zvbqaZeGOx67nzsHR)=09_h+>AEXPrr0Xby3y$BOuaAw6D@g>GNVE(2G=gs zs%tNhE7-ph_6qsx3uJ4rVE%=275%Yq5uE@ literal 0 HcmV?d00001 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..6dc5b313c99d50e0e7cfa5bffc9e7f7abb1f972c GIT binary patch literal 1956 zcmb7FZBrXn6n^d|&4zWMlqy(7*0PbQ}LkgCPMGXo*9l|I+ zOXG7DcQxF@l7=tvC0qA-`AS0$%WSP^Sj7WQ`C6lthbq2Nkr&Vp8~gRDJZiaiCcaHXDP__46+8HbRb=%#u1Bdxn0K~x zY~wo>JM2_+WKh*{6Vn0<|4-vY#yJUn#SSDew_K?m{ooH$yAp7hWSQz8qA@07L0xD42pl=Yo|* zE0@O@eEXXi6X#%jf?E;B3})$0#+Z-%w_!|17&@JEeQ__hBip3C46?K`!p~5tdmx|v z4au=9>A#SwCGMO+Jw>`wOOiDdSy#x?PVr8qmLf|(#c-vjPVvzRMxJD+PH=TV#Wd0c zd6P)JMbylYHH$giraw9p_sLtK>zO7aA|T(VDUY~CDkmZ=K}F6*O>(LC=);7G!Te&* V7tioTe|Fuui7uGH9ZFKL@E@jm%8vj5 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..3fde1ef57116bfbaa1990eba11f4940b7ed7c49b GIT binary patch literal 2950 zcmai#+jCP@6vn@E%SmGhrI2#zg-8U_Bqbtup%o}aQc^CqfCZGEwukmWNJ5%)#&LXc z#{a+>N1l99UvNfeZ0P9d_@WQ~O^)NY_Bl<{G{xy;@3n7h{r0!kKK=XOUw#L067>io zxYmU*^3qI5b6uK(G?TJ=!^X`BZsE3#43ywin$7ZwW>4!)UD>GNi<%nRX-t2e`?}& zfsK@ew-#M>LymZ7YuO)}sR>z(a`D!N3Q?}M47<2`C(xyfOY64HdC^0|-qcXXi)*mC z-`}$@)p3i257W^#Ur^#v(lAd26J|=O7jmE1ogx*92X2Z^X)$+mP7-&1=sq)179~}- zT9=q!NuH8Q!;YyM<(qUWN@bQ5LoGSWOMYs?wenQ0>XjBX>{-8%^5xG`>Btl*=iRHG z>v9T0|hbK0k zN?(lP8A{ZCW1r7?x$YGg+$wL|1pL%n7>S~ciZsue?`)!3^dpogoAB$Nww+B#>8tJZ z5zZ!5sjKm_9Ir)j1>=6w#){4|bFzDrT56JF?NVU%npX_+#GOYwWN&NIB%iU3YZc0p z5_`od*4>+rCEP?%ZYn#n+zh8?@}-))C<^qlcv{>C^W1Do)@A)c%kp|P$(wd66}QCi zz;G*YPzS9pH%U&%e2cGJ-sEmQUJJrjcbhJ-b$M+2Xso?3znp*tT}qIaF6F6uR;cP( zq^f6~vhRk*Dt?RYVU9kB!LvYr`W3Wv-xsUU)BS9X^zbUoblhBp^^-b%gzW)@*v4RD zC!==rZx`a|VdUL7%9WG8FQhQU5xtV-5F?2-NK03i@EFPxB2)3C1D>zAVskC2cn+>2 zlpat}aZ^$4w-i=r6V{+Q5~r(PbYU;y_R-qUpa&SBPoa$}^kfq)spJy0q=FQnq=Gb+ zC6FRaQl2-@ifEYt@&tQ1X$j3zIN+h(Qw8+yQ{xGSJC=a~~C)B)gD7dkPw>yI9?I1%PL5_C@(c3|W z336;35UEg+@STnzMmxyyjvyyGgBa}~rwDR-8xVOS0&)_k*vf+tmDf{a{>X{e)ST-G zavEoX!=v0SH6BW5Sf=eDBLo@U21LqD0-wdXz*j4X^|B4*Qb&+?aefO(-=>%1m*_Y_ zu5JS&)h-|xFcSFslLamHHk;0T2g`h!`3tdh19pbLZ($iPGk+jFnPw$t`TOz(&eGOt z>$J194cZ3n1Z|79^$p@QO`7H!y1s^Oeh<@-I~wX8_@9{xzUu3I$pya8NlfE59Ge=0LE~UpB^2TxN8S2JEr}EaT}K}%9X~N+By_Kl6)ro8zM6XVM1$o zV`|2vr7O##Whg5os8cgGJ8KQmsWt3q&&Iu$Y@BI6cm4-u5UHsZ-b=z2eno8N6?XP? zH?WKTLJjov?DlP4>^;71h#mKBvw_~8y}oTVu&?{G2KF~_puIF7wlEZ$3|ARd$NT>Q Db`}9^ literal 0 HcmV?d00001 diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class new file mode 100644 index 0000000000000000000000000000000000000000..a24ea613c0e312c3e20f90a22abc71dbd9b22f38 GIT binary patch literal 3801 zcmbVOYf}?f7=BI?vJe(fZc4R6wbpQ5ig+m?tswJk1Wh1Db*Hye~%d-*S& z>DQKNVW>0x=!gC$r_<-`=4#U>n3uTv@HLQt#3XyY%TF`>1l!B zjF~Z=SphA46ve?+fxw)VGz2;#X2yu-(;J4J&^J5N#LdTLd-O*txuw8hF)^eo=2k{`@;0f7 zA7Qtd`r)4?Ns|q;d&{T@R%ca^wC85>#Ze*^*PZQRB@sj*MKT12!$;w=y_mXQ_6zh@ z7wB%bSfuMUeXLPIGm%I7j;`e$Go?icsUZ#}i+bb8-+GT=KAUu#Ml`%wKek6P?l3LF)A>_}KoRXoG4if`ofxwrPMiW$66aRc9}n8)`j ze!z~vP`$&i3|8P+*}d4tBV&_=HBe7qz#o=}Uxn_ucJU5+G zhAz}XNT2JHTX_#zXz0MMM>o-)`_Ig|&6Axcfs^Oir_3$SUr)^66gXeA0^A-}R-oOf zN-qn%Hl*s_eID|J=3ercX}||x>@LrzXe_b55W5#8$Z)vftvZWAEHzt#ztvc0YXDk+ zE-<#CXl#8h7EQ3E@gDE6CwZq8@X3C_w;J08f8Qw?p zK3et>dWqJxq2J&eK7{JS9@-AjzBKX+bt-r6rtKb#aZkDPfM>I`^ElqedG0$#oeyw< zW0+E%d=7GT=srXa!x-V(DF2FtIK~&=jxkPv66jBSHt{(ovGgCJ!;k3bD|AVCqkA|; zR8xVU(IMx1IDUZ6sX$*q!t}cY^}5=pdAUF1($h~;hDn2jJIQaSDJP)?eN=L9s@lD23JSK;Ycwa_d%%rl zYyAl^R4hhALv*TL9e6ud{SQ;A7fS`Seyk;hP8TdJSkE^MXBn zu7GBbXo9pb;gUUii0%L+ov+X>@%04?gf~?a-qhDrM(Pnh&YYZJq%V@dOAO}~7xgTy z%N&t}%b-q_2%jhrF4ttv_^E&1r9MFIqDG1Ob7ks_8FiDsdKp!wyv@f&k8&@s=1Y0C zM5D3*dJ1{fbQ8iJ5`bqHBF+^1%=eh>pwIXL4kLbqW5x(4ks15|b6b^I literal 0 HcmV?d00001 diff --git a/out/production/classes/io/pivotal/pal/tracker/WelcomeController.class b/out/production/classes/io/pivotal/pal/tracker/WelcomeController.class new file mode 100644 index 0000000000000000000000000000000000000000..7f43ca61cec144e2406134f5138b176151dc875f GIT binary patch literal 612 zcma)3O-lnY5Pj*lRa>oE_2{h@G#3woB1l0!tO_di;3>PtHf@?L*|f!fr6<9IKfoU) z&f1~{FAZddH}l?1X7c&<{sG_s+hydiQ9`|l%_6oK3dhPQf5MP$?6w(lE&C`Ls(~`{ zYB&g`yAz?NNG-6D&~4#Vil@Px@2Z5M87RwRHL_l49@F(sM1AS_z0{E%$d)zUS*@iz zVkjlz`9f-K8P*%SK~IbX*TQu8t#`_Fh_QV$G+qs4TP2Emof<=hy|RW{9R${OcoL`7 zCnpASY+av^WynKi9=Z7C@^k4gMI28`=0`#gX$r;}%C~mtB6+6LvFiVxxSzg=;c)Io zH!|@v6D}c-0z* J%%tr)@C}4ylKcPw 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..3a1dad15e06346696eee18d6c90c083e10c99142 GIT binary patch literal 3102 zcmbVOTUQfT6#ga|m@rJ`;uW<@DQdVmfLH_+K?Dp9*a||ay$#6-gCU8NiOTY=edt^N zg+HJ#0(G@(^{uP_rB8kD>bGaYBvfLsS&PicK4!(xGC!5w|fRqe&fiFs0)zrse01Ow7h`uZ~6J6VZ{toJ2pBl}R1*Scu`i zL_U+R&n5Ce!=i>I1@$+btmBO16GN;?|n&E?H|CMp~1(l$BYw zTt|MFf~vRS6cmgmJ-gtUdFNTqvodC$f1Yclp4hIL$j;kaId^->*|Mjzp1b|P&gTk_ zCn4sHv4NCpTOM~%T}~CHiUI-FI|QL_T`V)l!?o$~Cof(AB__M20n zPrpdndC$pZ3mP6OXnRo1dhC7KDLBMEnavWSKh3R^Id|RMERsL71V(-AWLZ(oI0a7@ zY+BDOv*mU97)*J@I(?amCHs93}VZ` zbz}|X1lx`O>s+eqi<_~s>*oEnO?pYe@p35i(SB51Wcupg^#!ZTTW*0M%y^)@UubH> zau@BVMLV0a$GU=vgNfAqTs)CDbSfbyxVskd zR%wlwyi$49Tq{8-$Er{$dxanlSE{^3!L9eFsGLq|X5(|U9d#t?R8maGYt(Nm?``8F zwDA=xpL+0^;5@%S%xOrPLi8I)e!JIk36}|Mm~&S+ ziZZVeagJ1UF;nHLZuD>@-1PFP@Dkkz`HH)$j3sJs=HPoU{wV#DGtTIPH9(5he;$4S8npMt1ww99B< zOIJuioWQ&IKV1(NsKEvm$aCz`q2Ht5r=vY+KcwSji4G4H*`}=v2l#= z;0}7B6E|=TBN*j)0%KSuIVs%2GmKXl{&`48E;Rf@=7~Edm^tJdewAd4W2zhedPvBR zJZ$2Vks}hahtpAn`o6}QGNe;Jvv&w-ijbzM>kL87R;W1=wm%TIf4bCuHSIoOb3D!e E0%d^Kd;kCd literal 0 HcmV?d00001 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..799398ac1dd0d9d465a050c4a045638e6334d42a GIT binary patch literal 6377 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 I?ZIXL1$g>$c>n+a 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..d82cebcf24f10d817c12bc742a9114397c59d8bd GIT binary patch literal 5021 zcmb7I3tJTD6@F*A%(6~Y5KUE5i56WD95k_-VoY#Fge;4J1!5&3!!p3=va`<4sw8dG zduuQ0J-y#+@3*88*O;WXX`iQ0|3d#me?p(WXJ(vT^I+czH`od&U?=HE&u-C zTkisR9RG|#$Eb>Q3}YB?z#&YicrJ!IoR^mmtGE!wWDL*ag&3lk60sLI!N7D38O&@# z1g0#^%9gnp=3&Kf5tkZ}#X<}@*fN)wxyvy)uw_R6Oww3St?X8tiP=bgJ2#2&K8V{)CmY z+>;7w;_c%KY7_R1sbEXe%9*L+!nEn6jp;0Bnv!2jYyqR&$83lVc3?es29kY<9X>M&#+EiZ1J63LP)-e{$tG07V zpLgB7J`xBqQI@;NZCgEA-;n@MRNNRb4O-r@JXVYOd+{2o*2Ia8eLqPz8t>VhO4;ri zyO^VK&yS>4aK+1u#uY;^x>i<~8SZ%ezNsn=O;zvsa+6i*7bsp9$MQ2?7Pkp5|D^(% zCvw`%nv&?)s9kh2<{3-K*%H>pa+)0yXEgSZqY65zFDVsY(C|fkNkcadSFy8fRBU}& z!x22DpmigI1aYMM@UgD$!(H9SRlKU&l+CG z4GnMLMy2^R z#=K{K`9^xs5+58G@HgGJHX!DrGxmt-7M&cMY^Cl1f#0(3MWNspr>EJx^idg@j;ODU z(*5fU*VTEGs`sy|x{M@@S97JhA;Zngn-2SbjgjM_Ri6oZ@R^OH%6M#49rS*8e7)EV zRb{67o_?T8Q3VgpneHeLrDDN9Ef2)kIXlks0P%&1Xph(+9Zko*sAqV7=|!)kcD_urr?x4L)tYn_^VL$sRvi?yAYaa zUl&@XFbiqclC!rhK3Em8Ygs82?-cPh6SLyd5gC4l0Za|2r_KzIrI;kYS$fBNuj3et zq))w3@X!9X_=S~W2_jW_A*juISB0i~QLJ1$xE`-pxc68P@v??BXethdQC__w$|4G$ zeDF+`x09j~^D+~}P!BRZ#o&g~A0OPf167sFRCSuFPjmfDaK)*=Vmj6=DK5_QFo>mw zrxL@dbYCisNBPZ1m+vF|(i0vMvR^Pz@(srcLi&KP>BIpE8GaoBq_IWVR zgfQO@V4kZAX6!b0*7*2hOW0LLvwJl(HIM}RXu62z5Ygz^PnLA@UV4<666D7)N0NLW z&AAXwPk`oVh^C)XLJ@!F>^k@cLVVX5qX_ru%6%ET4@#0b@DtM_P$U_?`@6^v(5Wan z*+@n{OwP2DHHXL;aeIfaK5)AgTfEToz~q`Z>(89!Xsu)nhR*&Mo4k~|b?=ZpHLIm$ z^n9&MH{+4Un(d8BZ_^%fQY9rvOK4p|%iDNV@zb@0y{lyFF7}o10YY!9K)j!Y3!-Qu zg*ws46eWnXpR^jlI0i9;XHY=0B57`b{x~uAa#f++`@J|syf{dV{Iz7bHndLqQei}v z0(wq*v1qLMPh;fO5b_GRu@d%|EAc>Wz*ORkuL6Fp!aGN*K1-^OkgB7k@E9?Tlcp26 zfafYuPli1ur)qED_K}dPYdL!^boQm7isI7QSos}EX?`UfWb0!gb=Dv(pRVQQ o)5JCl%#u=b*vZay09J)B@xYe`?D6PQE*pPly|Q_hdLtP5KN>_1t^fc4 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..8c5344b65e3692a8afd6d3aa8596368fa4fb0880 GIT binary patch literal 6880 zcmb_g349!775{&^X0w^5>9z^96bKMXn z|Gn?+KK!4%?**_)tPCQEYZSaLfY%4{23#9N3Eo(VOYtW8cyj=6QE;7tw+8VxTwjT| z;~fg#8N?D?6TrLV-*?N$d*tK2LA(#|58?y(U=TOpLzTD@9}eOpxJjfuf z;NuEDq2QBMxD~fa$=icCicbY_M>&0x{~eJFcLp$%T@Viia7;?h25}c|3gGUXWFSZ{ zk4xu1Eswh=fO{3(SA~tZU&?77rSO-eDYSZH5zeYFgmzZqw3|=0O^cYf1iZ zr}WrEX9zA8s z_v~VsJz>({mTo6tpQH4oSvajdX-Xh?Xi&;`qznhg>X`F^_#_!Uk6Py&{)BBOwVV(m zH0^0=$yM%3TM2=4yJOarHmOe^(x;(B6S8?+?@TDMDY!iQr<(#fKNZwS;l_9in#*x>+00y6Y&Gi?i$m}63; zV5!@p9r7&B?OdePkgsllRk`e%24SyrRWr63*E+0t+=$7OX`q6DjzwtPIc$J04te!4 zk5MV&8g-JfJ2~bgqbB2g7|T;cpxRw3=my;dk9MaKH)Kgvk2xO-qRZU{9_&4Qshc#< z8KJf7o{d8Vlg2E|y!us|Lx@YriaZ$tsXT`wi&1G?xIko9d*-&4i_~>tk@kXvRwflQ zcAB!TYV#;$%cDi|L12}KI;l(|!Lnt?7&7e%dQ^T;k7uZSfv;yyF~(fBYYzD~X@gFi zq6HeF0e{6p@5*VrYCG7|vX!gE;(9tQ+1D}`c>Q`j>NcA8WHN5XoUX<*tJx64iGya! zO2~3l@GY(l6|Iq`5$Rz^?vSu=fD8HAP;8ZFR}HlHcJ}p*^!E)!RSaNIpnjp|$a3De z;rt7mH=N(RVY7m7tN0GSE0w>eq94yw(TyH~C7P_sW(JgUin69q&TeC1i5HgoMkiUN z3cj!62l%0aAF22;9v3*JAmVE6$e8glBPFmb8tDnwhkK&~!}ZbdV03G}il5*K`S_`d zpW){Uo>cJ^excx(Dt?7uEBK9y-{N-)ey`#Wcv`_9Rs0EmR`D17Rl(n67=NeVZVlFV z4fgeJt!LwJXp!xxy5NZHMgph%wbXuIHZrk>f`6#^C;lZ*d`7{)Rs0A4CEN`y$&@8S zjf}~|xfEz<$)t^x>`E04Ewb5AM?evRkA{{BmPA@b1_xD9B1%b@iqkV%_j*>cGAA=mcuI9}I&B+MoQtds@9J9DE_+5l zZ+n{#8Tu3fsnC;2BSBI(`}pg<(~8QPibe8yPYY}~Q9fW>?h?zP=(2QIY0;%pv4<=P z+4$`^r=waw51F;|{IcdVZ81mV1|!$)Oxm3i&!Z!AD$ASM6{c@zN-=qHr0hv8W~B^G zPKNEyf;;mD-QDPfPPBJY%<%E}$bS?AX`77M@k05mngxjOx z&ILz}d_c`7AVmZYsu*naIg+?2k#UFu! z{N1R8|2TO=pqFnI{M+ZOawO+ph3_2i`Hb?d%XtS@Hy(p%JdTp#nj_1^L!r`Hl+^@| zq5Mu%-0o=a=2QOM1FS+B&cq&mQfY;{7{X=zD=OKnfIF<|_Lv?8B3~J=&43^CxG=t^qXRu-xwMS7mgHwk1cIy48oW;r>kJ2hC zHRUy$LZ^jR)AZ?g;fylekJYm{vvLOYLrtNxp0%+8XV0L4Tj%<0t#P;3I-cgt@$hw_ z(it>TX}ymU9cdVn5S2ng)PgEL&%p|uiw!sr+p!K2G-4F%aRg1c9?iI&Qjb8xla!D! z*1J$;VO)X7@OuDB&a+nx{!Dwnp zseQzvgqjy)oLH1nvl$bVD5HfcOj52qkB=)qLisCrwjVzGbNGlI+%KclgL!;%q})t? zF&N3nMFI9~{y9)I&&|K)x%t-|nu~wUi{W3R(*kx8lP;`b6WBz4T*L-&88J_@0bI-C zznK_3z%rHGYjiQlBY$5O`8DKT+(G^#T+KX5o#(K_5Dj-f4=f^EIcMV#eZma~$fK25+$0(bnnz;;=+-1BP# z7iaf;@~}nr0jl{mf*pR1;4%h3j5?Na2Sy0LP9R5dh}6A~K;KI8K1_l?Novbv$YLQ> z`D8qiO-3Cag+=WWTDcKPrlpj2uE7C5%kpV)_eQvP1+DmzKb1=h9%sQx@=wf1{-fv= zdGre%BP=_{9Er<`YlUR(l;VX3xymW^{fsn0@*Tit(sCF!5y*H5Ig!U8mc^ivtt0Ia zau`b~FENmWtRpJ!o+PBZH#Y_)@&^<)7J2vGKu_cy)h4MXFQH@DmF<&9amo5niF;pd zD@5+xNp7z!nL%V0UAIx+ZTukz&%W}y*cf~ zlZ(RLyE4Cbgz=QplDyGh?6mna_~|O{za)m2;$?h!Ij@NrUV&E{cnw~QS5r2~{j2d! Jyz1hW{{t6nguMU& literal 0 HcmV?d00001 diff --git a/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java b/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java index b4406f8f3..b136416c1 100644 --- a/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java +++ b/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java @@ -2,7 +2,7 @@ import java.util.*; -public class InMemoryTimeEntryRepository extends TimeEntryRepository { +public class InMemoryTimeEntryRepository implements TimeEntryRepository { private Map timeEntryMap = new HashMap<>(); private long highestId = 0L; diff --git a/src/main/java/io/pivotal/pal/tracker/JdbcTimeEntryRepository.java b/src/main/java/io/pivotal/pal/tracker/JdbcTimeEntryRepository.java new file mode 100644 index 000000000..b0655af1a --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/JdbcTimeEntryRepository.java @@ -0,0 +1,85 @@ +package io.pivotal.pal.tracker; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; + +import javax.sql.DataSource; +import java.sql.Date; +import java.sql.PreparedStatement; +import java.util.List; + +import static java.sql.Statement.RETURN_GENERATED_KEYS; + +public class JdbcTimeEntryRepository implements TimeEntryRepository { + private JdbcTemplate jdbcTemplate; + + public JdbcTimeEntryRepository(DataSource dataSource) { + jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public TimeEntry create(TimeEntry timeEntry) { + KeyHolder generatedKeyHolder = new GeneratedKeyHolder(); + + jdbcTemplate.update(connection -> { + 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; +} diff --git a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java index 78cb5b60f..5e691b048 100644 --- a/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -9,6 +9,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import javax.sql.DataSource; + @SpringBootApplication public class PalTrackerApplication { @@ -17,8 +19,8 @@ public static void main(String[] args) { } @Bean - TimeEntryRepository timeEntryRepository() { - return new InMemoryTimeEntryRepository(); + TimeEntryRepository timeEntryRepository(DataSource dataSource) { + return new JdbcTimeEntryRepository(dataSource); } @Bean diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntry.java b/src/main/java/io/pivotal/pal/tracker/TimeEntry.java index 377e177b5..2320db8e0 100644 --- a/src/main/java/io/pivotal/pal/tracker/TimeEntry.java +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntry.java @@ -26,6 +26,14 @@ public TimeEntry(long id, int projectId, int userId, LocalDate date, int hours) 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 TimeEntry() { } diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java b/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java index d1e891360..9fce7c1f9 100644 --- a/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java @@ -1,27 +1,15 @@ package io.pivotal.pal.tracker; -import org.springframework.stereotype.Component; - import java.util.List; -@Component -public class TimeEntryRepository { - public TimeEntry create(TimeEntry timeEntry) { - return null; - } +public interface TimeEntryRepository { + TimeEntry create(TimeEntry timeEntry); - public TimeEntry find(long id) { - return null; - } + TimeEntry find(long id); - public List list() { - return null; - } + List list(); - public TimeEntry update(long id, TimeEntry timeEntry) { - return null; - } + TimeEntry update(long id, TimeEntry timeEntry); - public void delete(long id) { - } + void delete(long id); } diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java index a784b96b9..8fd373785 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,10 +14,12 @@ 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; import java.util.Collection; +import java.util.TimeZone; import static com.jayway.jsonpath.JsonPath.parse; import static org.assertj.core.api.Assertions.assertThat; @@ -25,6 +29,17 @@ @SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) public class TimeEntryApiTest { + @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"); + + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + } + @Autowired private TestRestTemplate restTemplate; @@ -34,8 +49,6 @@ public class TimeEntryApiTest { public void testCreate() throws Exception { ResponseEntity createResponse = restTemplate.postForEntity("/time-entries", timeEntry, String.class); - System.out.println("TIME ENTRY TEST: " + timeEntry); - assertThat(createResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED); DocumentContext createJson = parse(createResponse.getBody()); From 42d1817935b4b17050f81b72b084bef793ff2c9a Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 12:02:36 -0700 Subject: [PATCH 19/29] Removing out directory --- .gitignore | 1 + .../io/pivotal/pal/tracker/EnvController.class | Bin 1631 -> 0 bytes .../tracker/InMemoryTimeEntryRepository.class | Bin 1881 -> 0 bytes .../pal/tracker/JdbcTimeEntryRepository.class | Bin 1956 -> 0 bytes .../pal/tracker/PalTrackerApplication.class | Bin 2276 -> 0 bytes .../io/pivotal/pal/tracker/TimeEntry.class | Bin 2950 -> 0 bytes .../pal/tracker/TimeEntryController.class | Bin 3801 -> 0 bytes .../pal/tracker/TimeEntryRepository.class | Bin 515 -> 0 bytes .../pivotal/pal/tracker/WelcomeController.class | Bin 612 -> 0 bytes .../InMemoryTimeEntryRepositoryTest.class | Bin 3102 -> 0 bytes .../tracker/JdbcTimeEntryRepositoryTest.class | Bin 6377 -> 0 bytes .../pal/tracker/TimeEntryControllerTest.class | Bin 5021 -> 0 bytes .../pal/trackerapi/TimeEntryApiTest.class | Bin 6880 -> 0 bytes 13 files changed, 1 insertion(+) delete mode 100644 out/production/classes/io/pivotal/pal/tracker/EnvController.class delete mode 100644 out/production/classes/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.class delete mode 100644 out/production/classes/io/pivotal/pal/tracker/JdbcTimeEntryRepository.class delete mode 100644 out/production/classes/io/pivotal/pal/tracker/PalTrackerApplication.class delete mode 100644 out/production/classes/io/pivotal/pal/tracker/TimeEntry.class delete mode 100644 out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class delete mode 100644 out/production/classes/io/pivotal/pal/tracker/TimeEntryRepository.class delete mode 100644 out/production/classes/io/pivotal/pal/tracker/WelcomeController.class delete mode 100644 out/test/classes/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.class delete mode 100644 out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class delete mode 100644 out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class delete mode 100644 out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class diff --git a/.gitignore b/.gitignore index 6250dc478..a33515788 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ build .gradle .idea +out *.iml ci/variables.yml \ No newline at end of file diff --git a/out/production/classes/io/pivotal/pal/tracker/EnvController.class b/out/production/classes/io/pivotal/pal/tracker/EnvController.class deleted file mode 100644 index 7eab781d1c865e4064fc1033768c5b213022d36a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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%rAr>QL7{;HIy`(IGb+w|lwkTe@7jdnn)^;gg5D;9XRR@Qeb~<5+%dsKZ$!3}1 zziMYxN}cKSbN{H0&zr=}q9T0A*_@O2{NCrhm$U!<|Mx!trtqkM60Vu}x&Q;$hHwnm zW%#CmVNA*JZ2>p%-7s$Adl`N((U9M16F=DaZ2S++Y0 z#pZK++phOQ?bf-_P#Aiw+nycv0!LwX|JUhw>e^nr-t@h8qpAIRM{oO~?bbVd!oY6* z?gaHGZ+$dogt)2On@%@e+)z+U3i)a6>2O9NQ?9HkWM};i`YJZH=RE9ftvkUJd)?*A z@uuIh-Bml#GEWw>;im2?OdaHU(OY)5{9vaq;gQqvyE^0&rQ}4Nc?xhT}RSJIh@XGFNv)2B=&aNKlh&JmQV_7N-xF zC27j{IvY`J7RpP9?>Lh9!ehS|w48Y@={)z5)LfM+v~UKWDU{NRyl;0mS(O$};8P2y zaN5Ew$`85WXkiHtEHtr9Cx=y}g@pD@BQT7-0l){%^8q_>n;FkXLfNgS_toUA z@45_*_C1O{lTf1@Xy8j_73X=;mB2FR)n`Zv@ckrjMFV4eSPgv7bB$HQ@pH}=kl`C} zvbqaZeGOx67nzsHR)=09_h+>AEXPrr0Xby3y$BOuaAw6D@g>GNVE(2G=gs zs%tNhE7-ph_6qsx3uJ4rVE%=275%Yq5uE@ diff --git a/out/production/classes/io/pivotal/pal/tracker/JdbcTimeEntryRepository.class b/out/production/classes/io/pivotal/pal/tracker/JdbcTimeEntryRepository.class deleted file mode 100644 index 6dc5b313c99d50e0e7cfa5bffc9e7f7abb1f972c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1956 zcmb7FZBrXn6n^d|&4zWMlqy(7*0PbQ}LkgCPMGXo*9l|I+ zOXG7DcQxF@l7=tvC0qA-`AS0$%WSP^Sj7WQ`C6lthbq2Nkr&Vp8~gRDJZiaiCcaHXDP__46+8HbRb=%#u1Bdxn0K~x zY~wo>JM2_+WKh*{6Vn0<|4-vY#yJUn#SSDew_K?m{ooH$yAp7hWSQz8qA@07L0xD42pl=Yo|* zE0@O@eEXXi6X#%jf?E;B3})$0#+Z-%w_!|17&@JEeQ__hBip3C46?K`!p~5tdmx|v z4au=9>A#SwCGMO+Jw>`wOOiDdSy#x?PVr8qmLf|(#c-vjPVvzRMxJD+PH=TV#Wd0c zd6P)JMbylYHH$giraw9p_sLtK>zO7aA|T(VDUY~CDkmZ=K}F6*O>(LC=);7G!Te&* V7tioTe|Fuui7uGH9ZFKL@E@jm%8vj5 diff --git a/out/production/classes/io/pivotal/pal/tracker/PalTrackerApplication.class b/out/production/classes/io/pivotal/pal/tracker/PalTrackerApplication.class deleted file mode 100644 index 32ed650d9f198a70eb25c1ffb7dfb14ffd7080a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntry.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntry.class deleted file mode 100644 index 3fde1ef57116bfbaa1990eba11f4940b7ed7c49b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2950 zcmai#+jCP@6vn@E%SmGhrI2#zg-8U_Bqbtup%o}aQc^CqfCZGEwukmWNJ5%)#&LXc z#{a+>N1l99UvNfeZ0P9d_@WQ~O^)NY_Bl<{G{xy;@3n7h{r0!kKK=XOUw#L067>io zxYmU*^3qI5b6uK(G?TJ=!^X`BZsE3#43ywin$7ZwW>4!)UD>GNi<%nRX-t2e`?}& zfsK@ew-#M>LymZ7YuO)}sR>z(a`D!N3Q?}M47<2`C(xyfOY64HdC^0|-qcXXi)*mC z-`}$@)p3i257W^#Ur^#v(lAd26J|=O7jmE1ogx*92X2Z^X)$+mP7-&1=sq)179~}- zT9=q!NuH8Q!;YyM<(qUWN@bQ5LoGSWOMYs?wenQ0>XjBX>{-8%^5xG`>Btl*=iRHG z>v9T0|hbK0k zN?(lP8A{ZCW1r7?x$YGg+$wL|1pL%n7>S~ciZsue?`)!3^dpogoAB$Nww+B#>8tJZ z5zZ!5sjKm_9Ir)j1>=6w#){4|bFzDrT56JF?NVU%npX_+#GOYwWN&NIB%iU3YZc0p z5_`od*4>+rCEP?%ZYn#n+zh8?@}-))C<^qlcv{>C^W1Do)@A)c%kp|P$(wd66}QCi zz;G*YPzS9pH%U&%e2cGJ-sEmQUJJrjcbhJ-b$M+2Xso?3znp*tT}qIaF6F6uR;cP( zq^f6~vhRk*Dt?RYVU9kB!LvYr`W3Wv-xsUU)BS9X^zbUoblhBp^^-b%gzW)@*v4RD zC!==rZx`a|VdUL7%9WG8FQhQU5xtV-5F?2-NK03i@EFPxB2)3C1D>zAVskC2cn+>2 zlpat}aZ^$4w-i=r6V{+Q5~r(PbYU;y_R-qUpa&SBPoa$}^kfq)spJy0q=FQnq=Gb+ zC6FRaQl2-@ifEYt@&tQ1X$j3zIN+h(Qw8+yQ{xGSJC=a~~C)B)gD7dkPw>yI9?I1%PL5_C@(c3|W z336;35UEg+@STnzMmxyyjvyyGgBa}~rwDR-8xVOS0&)_k*vf+tmDf{a{>X{e)ST-G zavEoX!=v0SH6BW5Sf=eDBLo@U21LqD0-wdXz*j4X^|B4*Qb&+?aefO(-=>%1m*_Y_ zu5JS&)h-|xFcSFslLamHHk;0T2g`h!`3tdh19pbLZ($iPGk+jFnPw$t`TOz(&eGOt z>$J194cZ3n1Z|79^$p@QO`7H!y1s^Oeh<@-I~wX8_@9{xzUu3I$pya8NlfE59Ge=0LE~UpB^2TxN8S2JEr}EaT}K}%9X~N+By_Kl6)ro8zM6XVM1$o zV`|2vr7O##Whg5os8cgGJ8KQmsWt3q&&Iu$Y@BI6cm4-u5UHsZ-b=z2eno8N6?XP? zH?WKTLJjov?DlP4>^;71h#mKBvw_~8y}oTVu&?{G2KF~_puIF7wlEZ$3|ARd$NT>Q Db`}9^ diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class deleted file mode 100644 index a24ea613c0e312c3e20f90a22abc71dbd9b22f38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3801 zcmbVOYf}?f7=BI?vJe(fZc4R6wbpQ5ig+m?tswJk1Wh1Db*Hye~%d-*S& z>DQKNVW>0x=!gC$r_<-`=4#U>n3uTv@HLQt#3XyY%TF`>1l!B zjF~Z=SphA46ve?+fxw)VGz2;#X2yu-(;J4J&^J5N#LdTLd-O*txuw8hF)^eo=2k{`@;0f7 zA7Qtd`r)4?Ns|q;d&{T@R%ca^wC85>#Ze*^*PZQRB@sj*MKT12!$;w=y_mXQ_6zh@ z7wB%bSfuMUeXLPIGm%I7j;`e$Go?icsUZ#}i+bb8-+GT=KAUu#Ml`%wKek6P?l3LF)A>_}KoRXoG4if`ofxwrPMiW$66aRc9}n8)`j ze!z~vP`$&i3|8P+*}d4tBV&_=HBe7qz#o=}Uxn_ucJU5+G zhAz}XNT2JHTX_#zXz0MMM>o-)`_Ig|&6Axcfs^Oir_3$SUr)^66gXeA0^A-}R-oOf zN-qn%Hl*s_eID|J=3ercX}||x>@LrzXe_b55W5#8$Z)vftvZWAEHzt#ztvc0YXDk+ zE-<#CXl#8h7EQ3E@gDE6CwZq8@X3C_w;J08f8Qw?p zK3et>dWqJxq2J&eK7{JS9@-AjzBKX+bt-r6rtKb#aZkDPfM>I`^ElqedG0$#oeyw< zW0+E%d=7GT=srXa!x-V(DF2FtIK~&=jxkPv66jBSHt{(ovGgCJ!;k3bD|AVCqkA|; zR8xVU(IMx1IDUZ6sX$*q!t}cY^}5=pdAUF1($h~;hDn2jJIQaSDJP)?eN=L9s@lD23JSK;Ycwa_d%%rl zYyAl^R4hhALv*TL9e6ud{SQ;A7fS`Seyk;hP8TdJSkE^MXBn zu7GBbXo9pb;gUUii0%L+ov+X>@%04?gf~?a-qhDrM(Pnh&YYZJq%V@dOAO}~7xgTy z%N&t}%b-q_2%jhrF4ttv_^E&1r9MFIqDG1Ob7ks_8FiDsdKp!wyv@f&k8&@s=1Y0C zM5D3*dJ1{fbQ8iJ5`bqHBF+^1%=eh>pwIXL4kLbqW5x(4ks15|b6b^I diff --git a/out/production/classes/io/pivotal/pal/tracker/WelcomeController.class b/out/production/classes/io/pivotal/pal/tracker/WelcomeController.class deleted file mode 100644 index 7f43ca61cec144e2406134f5138b176151dc875f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 612 zcma)3O-lnY5Pj*lRa>oE_2{h@G#3woB1l0!tO_di;3>PtHf@?L*|f!fr6<9IKfoU) z&f1~{FAZddH}l?1X7c&<{sG_s+hydiQ9`|l%_6oK3dhPQf5MP$?6w(lE&C`Ls(~`{ zYB&g`yAz?NNG-6D&~4#Vil@Px@2Z5M87RwRHL_l49@F(sM1AS_z0{E%$d)zUS*@iz zVkjlz`9f-K8P*%SK~IbX*TQu8t#`_Fh_QV$G+qs4TP2Emof<=hy|RW{9R${OcoL`7 zCnpASY+av^WynKi9=Z7C@^k4gMI28`=0`#gX$r;}%C~mtB6+6LvFiVxxSzg=;c)Io zH!|@v6D}c-0z* J%%tr)@C}4ylKcPw diff --git a/out/test/classes/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.class b/out/test/classes/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.class deleted file mode 100644 index 3a1dad15e06346696eee18d6c90c083e10c99142..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3102 zcmbVOTUQfT6#ga|m@rJ`;uW<@DQdVmfLH_+K?Dp9*a||ay$#6-gCU8NiOTY=edt^N zg+HJ#0(G@(^{uP_rB8kD>bGaYBvfLsS&PicK4!(xGC!5w|fRqe&fiFs0)zrse01Ow7h`uZ~6J6VZ{toJ2pBl}R1*Scu`i zL_U+R&n5Ce!=i>I1@$+btmBO16GN;?|n&E?H|CMp~1(l$BYw zTt|MFf~vRS6cmgmJ-gtUdFNTqvodC$f1Yclp4hIL$j;kaId^->*|Mjzp1b|P&gTk_ zCn4sHv4NCpTOM~%T}~CHiUI-FI|QL_T`V)l!?o$~Cof(AB__M20n zPrpdndC$pZ3mP6OXnRo1dhC7KDLBMEnavWSKh3R^Id|RMERsL71V(-AWLZ(oI0a7@ zY+BDOv*mU97)*J@I(?amCHs93}VZ` zbz}|X1lx`O>s+eqi<_~s>*oEnO?pYe@p35i(SB51Wcupg^#!ZTTW*0M%y^)@UubH> zau@BVMLV0a$GU=vgNfAqTs)CDbSfbyxVskd zR%wlwyi$49Tq{8-$Er{$dxanlSE{^3!L9eFsGLq|X5(|U9d#t?R8maGYt(Nm?``8F zwDA=xpL+0^;5@%S%xOrPLi8I)e!JIk36}|Mm~&S+ ziZZVeagJ1UF;nHLZuD>@-1PFP@Dkkz`HH)$j3sJs=HPoU{wV#DGtTIPH9(5he;$4S8npMt1ww99B< zOIJuioWQ&IKV1(NsKEvm$aCz`q2Ht5r=vY+KcwSji4G4H*`}=v2l#= z;0}7B6E|=TBN*j)0%KSuIVs%2GmKXl{&`48E;Rf@=7~Edm^tJdewAd4W2zhedPvBR zJZ$2Vks}hahtpAn`o6}QGNe;Jvv&w-ijbzM>kL87R;W1=wm%TIf4bCuHSIoOb3D!e E0%d^Kd;kCd diff --git a/out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class b/out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class deleted file mode 100644 index 799398ac1dd0d9d465a050c4a045638e6334d42a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6377 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 I?ZIXL1$g>$c>n+a diff --git a/out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class b/out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class deleted file mode 100644 index d82cebcf24f10d817c12bc742a9114397c59d8bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5021 zcmb7I3tJTD6@F*A%(6~Y5KUE5i56WD95k_-VoY#Fge;4J1!5&3!!p3=va`<4sw8dG zduuQ0J-y#+@3*88*O;WXX`iQ0|3d#me?p(WXJ(vT^I+czH`od&U?=HE&u-C zTkisR9RG|#$Eb>Q3}YB?z#&YicrJ!IoR^mmtGE!wWDL*ag&3lk60sLI!N7D38O&@# z1g0#^%9gnp=3&Kf5tkZ}#X<}@*fN)wxyvy)uw_R6Oww3St?X8tiP=bgJ2#2&K8V{)CmY z+>;7w;_c%KY7_R1sbEXe%9*L+!nEn6jp;0Bnv!2jYyqR&$83lVc3?es29kY<9X>M&#+EiZ1J63LP)-e{$tG07V zpLgB7J`xBqQI@;NZCgEA-;n@MRNNRb4O-r@JXVYOd+{2o*2Ia8eLqPz8t>VhO4;ri zyO^VK&yS>4aK+1u#uY;^x>i<~8SZ%ezNsn=O;zvsa+6i*7bsp9$MQ2?7Pkp5|D^(% zCvw`%nv&?)s9kh2<{3-K*%H>pa+)0yXEgSZqY65zFDVsY(C|fkNkcadSFy8fRBU}& z!x22DpmigI1aYMM@UgD$!(H9SRlKU&l+CG z4GnMLMy2^R z#=K{K`9^xs5+58G@HgGJHX!DrGxmt-7M&cMY^Cl1f#0(3MWNspr>EJx^idg@j;ODU z(*5fU*VTEGs`sy|x{M@@S97JhA;Zngn-2SbjgjM_Ri6oZ@R^OH%6M#49rS*8e7)EV zRb{67o_?T8Q3VgpneHeLrDDN9Ef2)kIXlks0P%&1Xph(+9Zko*sAqV7=|!)kcD_urr?x4L)tYn_^VL$sRvi?yAYaa zUl&@XFbiqclC!rhK3Em8Ygs82?-cPh6SLyd5gC4l0Za|2r_KzIrI;kYS$fBNuj3et zq))w3@X!9X_=S~W2_jW_A*juISB0i~QLJ1$xE`-pxc68P@v??BXethdQC__w$|4G$ zeDF+`x09j~^D+~}P!BRZ#o&g~A0OPf167sFRCSuFPjmfDaK)*=Vmj6=DK5_QFo>mw zrxL@dbYCisNBPZ1m+vF|(i0vMvR^Pz@(srcLi&KP>BIpE8GaoBq_IWVR zgfQO@V4kZAX6!b0*7*2hOW0LLvwJl(HIM}RXu62z5Ygz^PnLA@UV4<666D7)N0NLW z&AAXwPk`oVh^C)XLJ@!F>^k@cLVVX5qX_ru%6%ET4@#0b@DtM_P$U_?`@6^v(5Wan z*+@n{OwP2DHHXL;aeIfaK5)AgTfEToz~q`Z>(89!Xsu)nhR*&Mo4k~|b?=ZpHLIm$ z^n9&MH{+4Un(d8BZ_^%fQY9rvOK4p|%iDNV@zb@0y{lyFF7}o10YY!9K)j!Y3!-Qu zg*ws46eWnXpR^jlI0i9;XHY=0B57`b{x~uAa#f++`@J|syf{dV{Iz7bHndLqQei}v z0(wq*v1qLMPh;fO5b_GRu@d%|EAc>Wz*ORkuL6Fp!aGN*K1-^OkgB7k@E9?Tlcp26 zfafYuPli1ur)qED_K}dPYdL!^boQm7isI7QSos}EX?`UfWb0!gb=Dv(pRVQQ o)5JCl%#u=b*vZay09J)B@xYe`?D6PQE*pPly|Q_hdLtP5KN>_1t^fc4 diff --git a/out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class b/out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class deleted file mode 100644 index 8c5344b65e3692a8afd6d3aa8596368fa4fb0880..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6880 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 Jyz1hW{{t6nguMU& From d7b96d568f9025b657ef58e6df2ec928d4f214e8 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 14:08:11 -0700 Subject: [PATCH 20/29] Updating name of jar --- ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/build.yml b/ci/build.yml index 2455d052b..f30e32bd7 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -32,4 +32,4 @@ run: ./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 + cp build/libs/pal-tracker.jar ../build-output \ No newline at end of file From 113f4c29d172d886ddb1dbbd968e225e67b671ce Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 14:11:26 -0700 Subject: [PATCH 21/29] Updating name of jar in pipeline.yml --- ci/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/pipeline.yml b/ci/pipeline.yml index b077666b1..3b7696f21 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -52,7 +52,7 @@ jobs: file: pal-tracker/ci/build.yml - put: pal-tracker-artifacts params: - file: build-output/pal-tracker-*.jar + file: build-output/pal-tracker.jar - put: version params: file: version/number From 89d03f97246079cf1ccb0ce85aa56a815580364e Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 14:24:16 -0700 Subject: [PATCH 22/29] Added debug flag to build.yml --- ci/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/build.yml b/ci/build.yml index f30e32bd7..ca4cf08ea 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 -P version=$(cat ../version/number) testMigrate clean build || (service mysql stop && exit 1) + ./gradlew --debug -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 54defff692bdae03eb8ed7c00950aba221de7f8a Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 14:40:03 -0700 Subject: [PATCH 23/29] Updated gradle version in wrapper. --- gradle/wrapper/gradle-wrapper.jar | Bin 53324 -> 54333 bytes gradle/wrapper/gradle-wrapper.properties | 3 +-- gradlew | 26 +++++++++++++++-------- gradlew.bat | 6 ------ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 3baa851b28c65f87dd36a6748e1a85cf360c1301..99340b4ad18d3c7e764794d300ffd35017036793 100644 GIT binary patch delta 38555 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 U+d*tnN8>QU5;)~;9re@y0h&&8E&u=k delta 37643 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 LoWQZ#;a`6P0ok^Q diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5f66027fe..57c7d2d22 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Jan 16 16:31:17 EST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip diff --git a/gradlew b/gradlew index 27309d923..cccdd3d51 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -33,11 +33,11 @@ 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 @@ -154,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 "$@") -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +# 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" "$@" diff --git a/gradlew.bat b/gradlew.bat index f6d5974e7..e95643d6a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -49,7 +49,6 @@ goto fail @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 From 0770ca53b0a9af6cde1bf711b4bafef12dee1c94 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 14:47:05 -0700 Subject: [PATCH 24/29] Changing jar names back to original --- ci/build.yml | 4 ++-- ci/pipeline.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/build.yml b/ci/build.yml index ca4cf08ea..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 --debug -P version=$(cat ../version/number) 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 + 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 3b7696f21..b077666b1 100644 --- a/ci/pipeline.yml +++ b/ci/pipeline.yml @@ -52,7 +52,7 @@ jobs: file: pal-tracker/ci/build.yml - put: pal-tracker-artifacts params: - file: build-output/pal-tracker.jar + file: build-output/pal-tracker-*.jar - put: version params: file: version/number From c765cccadd7f93108da5eef7094257e749f5c106 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Fri, 19 Jan 2018 14:58:41 -0700 Subject: [PATCH 25/29] Updated hosts --- manifest-production.yml | 2 +- manifest-review.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manifest-production.yml b/manifest-production.yml index 8e752b077..8e2b4a8f1 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -2,6 +2,6 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker-becky-allen + host: becky-allen-pal-tracker services: - tracker-database diff --git a/manifest-review.yml b/manifest-review.yml index 897eba97d..f9b77bb5d 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -2,6 +2,6 @@ applications: - name: pal-tracker path: build/libs/pal-tracker.jar - host: ps-pal-tracker-review + host: becky-allen-pal-tracker-review services: - tracker-database \ No newline at end of file From ffe98ba3d11f4d8ce58ee9abd6ab8c44b58e3ea3 Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Wed, 26 Jul 2017 12:28:32 -0600 Subject: [PATCH 26/29] 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 d4511e7c8ed674cdaa4fc00e6b0e124990ac5a78 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Mon, 22 Jan 2018 09:58:26 -0700 Subject: [PATCH 27/29] *Added in boot actuator. *Added some metrics to the time entries controller --- build.gradle | 8 +++++- .../pal/tracker/TimeEntryController.java | 19 ++++++++++++-- .../pal/tracker/TimeEntryHealthIndicator.java | 26 +++++++++++++++++++ .../pal/tracker/TimeEntryControllerTest.java | 8 +++++- 4 files changed, 57 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..78ed474b7 100644 --- a/build.gradle +++ b/build.gradle @@ -14,22 +14,28 @@ dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.1") compile("org.springframework.boot:spring-boot-starter-jdbc") - + compile("org.springframework.boot:spring-boot-starter-actuator") compile("mysql:mysql-connector-java:6.0.6") testCompile("org.springframework.boot:spring-boot-starter-test") } +springBoot { + buildInfo() +} + def developmentDbUrl = "jdbc:mysql://localhost:3306/tracker_dev?user=tracker&useSSL=false&useTimezone=true&serverTimezone=UTC&useLegacyDatetimeCode=false" 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 1cca9424b..6ac6b7fa4 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.*; @@ -9,15 +11,23 @@ @RestController public class TimeEntryController { private TimeEntryRepository timeEntryRepository; + private final CounterService counter; + private final GaugeService gauge; - public TimeEntryController(TimeEntryRepository timeEntryRepository) { + public TimeEntryController( + CounterService counter, + GaugeService gauge, + TimeEntryRepository timeEntryRepository) { this.timeEntryRepository = timeEntryRepository; + this.counter = counter; + this.gauge = gauge; } @PostMapping("/time-entries") @ResponseBody public ResponseEntity create(@RequestBody TimeEntry timeEntry) { - System.out.println("TIME ENTRY Controller: " + timeEntry); + counter.increment("TimeEntry.created"); + gauge.submit("timeEntries.count", timeEntryRepository.list().size()); ResponseEntity response = new ResponseEntity(timeEntryRepository.create(timeEntry), HttpStatus.CREATED); return response; } @@ -28,6 +38,7 @@ public ResponseEntity read(@PathVariable long id) { TimeEntry existingTimeEntry = timeEntryRepository.find(id); ResponseEntity response; if (existingTimeEntry != null) { + counter.increment("TimeEntry.read"); response = new ResponseEntity(existingTimeEntry, HttpStatus.OK); } else { response = new ResponseEntity(HttpStatus.NOT_FOUND); @@ -38,6 +49,7 @@ public ResponseEntity read(@PathVariable long id) { @GetMapping("/time-entries") @ResponseBody public ResponseEntity> list() { + counter.increment("TimeEntry.listed"); ResponseEntity> responseEntity = new ResponseEntity(timeEntryRepository.list(), HttpStatus.OK); return responseEntity; } @@ -48,6 +60,7 @@ public ResponseEntity update(@PathVariable long id, @RequestBody TimeEntry timeE TimeEntry existingTimeEntry = timeEntryRepository.update(id, timeEntry); ResponseEntity response; if (existingTimeEntry != null) { + counter.increment("TimeEntry.updated"); response = new ResponseEntity(existingTimeEntry, HttpStatus.OK); } else { response = new ResponseEntity(HttpStatus.NOT_FOUND); @@ -58,6 +71,8 @@ public ResponseEntity update(@PathVariable long id, @RequestBody TimeEntry timeE @DeleteMapping("/time-entries/{id}") @ResponseBody public ResponseEntity delete(@PathVariable long id) { + counter.increment("TimeEntry.deleted"); + gauge.submit("timeEntries.count", timeEntryRepository.list().size()); timeEntryRepository.delete(id); return new ResponseEntity(HttpStatus.NO_CONTENT); } 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..ff635c19c --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java @@ -0,0 +1,26 @@ +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 TimeEntryRepository timeEntryRepository; + + public TimeEntryHealthIndicator(TimeEntryRepository timeEntryRepository) { + this.timeEntryRepository = timeEntryRepository; + } + + @Override + public Health health() { + int currentTimeEntries = timeEntryRepository.list().size(); + Health.Builder builder = new Health.Builder(); + if (currentTimeEntries < 5) { + builder.up(); + } else { + builder.down(); + } + return builder.build(); + } +} diff --git a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java index f7c0090e3..83065eb99 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(counterService, gaugeService, timeEntryRepository); } @Test From 0a019744535d7c59f4d1f1b0c81c05b91ef885f5 Mon Sep 17 00:00:00 2001 From: Tyson Gern Date: Wed, 26 Jul 2017 12:50:47 -0600 Subject: [PATCH 28/29] 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 5e21b80175006c159757a91d33dabd73730134c5 Mon Sep 17 00:00:00 2001 From: Becky McInerney Date: Mon, 22 Jan 2018 11:12:00 -0700 Subject: [PATCH 29/29] *Added Spring Security dependency *Added basic http authorization *Fixed the tests to do authorization in setup *Added SECURITY_FORCE_HTTPS environment variable --- build.gradle | 1 + manifest-production.yml | 2 ++ manifest-review.yml | 4 ++- .../pal/tracker/SecurityConfiguration.java | 36 +++++++++++++++++++ .../pivotal/pal/trackerapi/HealthApiTest.java | 17 +++++++-- .../pal/trackerapi/TimeEntryApiTest.java | 18 ++++++---- 6 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java diff --git a/build.gradle b/build.gradle index 78ed474b7..069589093 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ dependencies { compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.1") compile("org.springframework.boot:spring-boot-starter-jdbc") compile("org.springframework.boot:spring-boot-starter-actuator") + compile("org.springframework.boot:spring-boot-starter-security") compile("mysql:mysql-connector-java:6.0.6") testCompile("org.springframework.boot:spring-boot-starter-test") diff --git a/manifest-production.yml b/manifest-production.yml index 8e2b4a8f1..60474d18a 100644 --- a/manifest-production.yml +++ b/manifest-production.yml @@ -5,3 +5,5 @@ applications: host: becky-allen-pal-tracker services: - tracker-database +env: + SECURITY_FORCE_HTTPS: true diff --git a/manifest-review.yml b/manifest-review.yml index f9b77bb5d..bf4f9e429 100644 --- a/manifest-review.yml +++ b/manifest-review.yml @@ -4,4 +4,6 @@ applications: path: build/libs/pal-tracker.jar host: becky-allen-pal-tracker-review 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..d9500113c --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java @@ -0,0 +1,36 @@ +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 authenticationManagerBuilder) { + try { + authenticationManagerBuilder + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java index b3eef23cc..505815830 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java @@ -2,11 +2,13 @@ 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,14 +21,23 @@ @SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) public class HealthApiTest { - @Autowired private TestRestTemplate restTemplate; + @LocalServerPort + private String port; + + @Before + public void setUp() { + 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); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); DocumentContext healthJson = parse(response.getBody()); diff --git a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java index 8fd373785..a77b83a17 100644 --- a/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -7,9 +7,10 @@ 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.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; @@ -29,6 +30,11 @@ @SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) public class TimeEntryApiTest { + private TestRestTemplate restTemplate; + private TimeEntry timeEntry = new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8); + @LocalServerPort + private String port; + @Before public void setUp() throws Exception { MysqlDataSource dataSource = new MysqlDataSource(); @@ -38,12 +44,12 @@ public void setUp() throws Exception { jdbcTemplate.execute("TRUNCATE time_entries"); TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - } + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); - @Autowired - private TestRestTemplate restTemplate; - - private TimeEntry timeEntry = new TimeEntry(123, 456, LocalDate.parse("2017-01-08"), 8); + restTemplate = new TestRestTemplate(builder); + } @Test public void testCreate() throws Exception {