diff --git a/.gitignore b/.gitignore index 0c9d47c18..4fa332f5c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build .gradle .idea *.iml +ci/variables.yml diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..3d684fe7e --- /dev/null +++ b/build.gradle @@ -0,0 +1,53 @@ +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 { + mavenCentral() +} + +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") + compile("org.springframework.boot:spring-boot-starter-actuator") + compile("org.springframework.boot:spring-boot-starter-security") + 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, + "MANAGEMENT_SECURITY_ENABLED": false, + "HTTPS_DISABLED" : true, +]) + +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, + "HTTPS_DISABLED" : true, +]) + +flyway { + url = developmentDbUrl + user = "tracker" + password = "" + locations = ["filesystem:databases/tracker/migrations"] +} + +task testMigrate(type: FlywayMigrateTask) { + url = testDbUrl +} + +springBoot { + buildInfo() +} \ No newline at end of file diff --git a/build/classes/java/main/io/pivotal/pal/tracker/PalTrackerApplication.class b/build/classes/java/main/io/pivotal/pal/tracker/PalTrackerApplication.class new file mode 100644 index 000000000..f9b905a2e Binary files /dev/null and b/build/classes/java/main/io/pivotal/pal/tracker/PalTrackerApplication.class differ diff --git a/build/classes/java/main/io/pivotal/pal/tracker/WelcomeController.class b/build/classes/java/main/io/pivotal/pal/tracker/WelcomeController.class new file mode 100644 index 000000000..3a9f393a3 Binary files /dev/null and b/build/classes/java/main/io/pivotal/pal/tracker/WelcomeController.class differ diff --git a/ci/build.yml b/ci/build.yml new file mode 100644 index 000000000..9559ab3bc --- /dev/null +++ b/ci/build.yml @@ -0,0 +1,34 @@ +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 + - | + 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) 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/ci/migrateDatabase.yml b/ci/migrateDatabase.yml new file mode 100644 index 000000000..94a18029f --- /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 ashpal-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 diff --git a/ci/pipeline.yml b/ci/pipeline.yml new file mode 100644 index 000000000..04c54389f --- /dev/null +++ b/ci/pipeline.yml @@ -0,0 +1,111 @@ +--- +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}} + region_name: {{aws-region-name}} + 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}} + region_name: {{aws-region-name}} + 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: sandbox + +- 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 + passed: [build] + - get: pal-tracker-artifacts + trigger: true + passed: [build] + - task: migrate database + file: pal-tracker/ci/migrateDatabase.yml + params: + CF_API_URL: {{cf-api-url}} + CF_USERNAME: {{cf-username}} + CF_PASSWORD: {{cf-password}} + CF_ORG: {{cf-org}} + CF_SPACE: sandbox + MYSQL_IP: {{mysql-ip}} + DATABASE_NAME: {{review-database-name}} + DATABASE_USERNAME: {{review-database-username}} + DATABASE_PASSWORD: {{review-database-password}} + - 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 + passed: [deploy-review] + - get: pal-tracker-artifacts + passed: [deploy-review] + - task: migrate database + file: pal-tracker/ci/migrateDatabase.yml + params: + CF_API_URL: {{cf-api-url}} + CF_USERNAME: {{cf-username}} + CF_PASSWORD: {{cf-password}} + CF_ORG: {{cf-org}} + CF_SPACE: production + MYSQL_IP: {{mysql-ip}} + DATABASE_NAME: {{production-database-name}} + DATABASE_USERNAME: {{production-database-username}} + DATABASE_PASSWORD: {{production-database-password}} + - 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" \ No newline at end of file diff --git a/databases/tracker/create_databases.sql b/databases/tracker/create_databases.sql new file mode 100644 index 000000000..6f1e86abf --- /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'; \ No newline at end of file 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 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..1948b9074 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..d2c45a4b2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.8-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 000000000..cccdd3d51 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## 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 + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@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 + +: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=%* + +: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/manifest-production.yml b/manifest-production.yml new file mode 100644 index 000000000..e2081d6c9 --- /dev/null +++ b/manifest-production.yml @@ -0,0 +1,8 @@ +--- +applications: +- name: ashpal-tracker + path: build/libs/pal-tracker.jar + routes: + - route: agprod-pal-tracker-review.apps.cumuluslabs.io + services: + - tracker-database \ No newline at end of file diff --git a/manifest-review.yml b/manifest-review.yml new file mode 100644 index 000000000..cd2549b19 --- /dev/null +++ b/manifest-review.yml @@ -0,0 +1,8 @@ +--- +applications: +- name: ashpal-tracker + path: build/libs/pal-tracker.jar + routes: + - route: ag-pal-tracker-review.apps.cumuluslabs.io + services: + - tracker-database \ No newline at end of file diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 000000000..b6e67c8d1 --- /dev/null +++ b/manifest.yml @@ -0,0 +1,7 @@ +--- +applications: +- name: ashpal-tracker + path: build/libs/pal-tracker.jar + random-route: true + env: + WELCOME_MESSAGE: Hello from Cloud Foundry diff --git a/mycommand613.txt b/mycommand613.txt new file mode 100644 index 000000000..45b1fb597 --- /dev/null +++ b/mycommand613.txt @@ -0,0 +1,500 @@ + 27 ls + 28 cd prerequisites/ + 29 ls + 30 java + 31 ls + 32 java Application.class + 33 cf apps + 34 cf delete prerequisite + 35 cf delete prerequisite + 36 ls + 37 pwd + 38 cd ~/workspace + 39 brew install Tomee plume + 40 brew install Tomeeplume + 41 brew install tomee-plume + 42 brew install minio + 43 brew install redis + 44 brew install nginx + 45 brew install aws-cli + 46 brew install awscli + 47 pwd + 48 cd ~/workspace + 49 git clone https://github.com/ashwingudidevuni/pal-tracker + 50 ls + 51 cd pal-tracker/ + 52 ls + 53 pwd + 54 gradle wrapper + 55 ls + 56 pwd + 57 pwd + 58 touch build.gradle + 59 ls + 60 ls + 61 mkdir src + 62 cd src/ + 63 mkdir main + 64 ls + 65 cd main/ + 66 mkdir java + 67 ls + 68 pwd + 69 pwd + 70 cd .. + 71 ls + 72 cd .. + 73 cd .. + 74 ls + 75 cd p + 76 cd pal-tracker/ + 77 ls + 78 ./gradlew build + 79 gradle tasks + 80 ./gradlew bootRun + 81 ./gradlew build + 82 gradle tasks + 83 ./gradlew bootRun + 84 cf + 85 cf --help + 86 cf login --help + 87 cf login -a api.system.cumuluslabs.io + 88 cf target + 89 ./gradlew build + 90 cf push --help + 91 cf push pal-tracker + 92 cf push + 93 cf push ashpal-tracker + 94 ls + 95 touch manifest.yml + 96 cf push + 97 cf push + 98 cf apps + 99 pwd + 100 ls + 101 git push + 102 git push -help + 103 git push https://github.com/ashwingudidevuni/pal-tracker + 104 git + 105 git commit + 106 git commit -help + 107 git status + 108 git config --global user.email "ashwin.gudidevuni@gmail.com" + 109 git commit + 110 git commit + 111 git push + 112 ls + 113 ls + 114 pwd + 115 cd .. + 116 ls + 117 ls -a + 118 cd pal-tracker/ + 119 ls -a + 120 vi .gitignore + 121 pwd + 122 git push + 123 git commit + 124 git + 125 vi .gitignore + 126 git commit + 127 git add * + 128 git status + 129 git commit + 130 git push + 131 cf buildpacks + 132 cf buildpacks --help + 133 cf buildpacks -help + 134 cf apps + 135 cf images + 136 cf images -a + 137 cf image + 138 pwd + 139 git cherry-pick deployment-start + 140 pwd + 141 ./gradlew bootRun + 142 WELCOME_MESSAGE=hello_ashwin ./gradlew bootRun + 143 WELCOME_MESSAGE=hello_ashwin ./gradlew bootRun + 144 ls + 145* ./gradlew build + 146 ./gradlew bootRun + 147 WELCOME_MESSAGE=hello_ashwin ./gradlew bootRun + 148 ./gradlew bootRun + 149 ./gradlew bootRun + 150 ./gradlew bootRun + 151 ./gradlew bootRun + 152 ./gradlew test + 153 ./gradlew clean build + 154 cf apps + 155 cf push ashpal-tracker -p build/libs/pal-tracker.jar --random-route + 156 cf logs --recent ashpal-tracker + 157 cf set-env ashpal-tracker WELCOME_MESSAGE "Hello from Cloud Foundry" + 158 cf restage ashpal-tracker + 159 cf apps + 160 cf app ashpal-tracker + 161 cf scale ashpal-tracker -m 768M -f + 162 cf app ashpal-tracker + 163 cf scale ashpal-tracker -i 2 + 164 cf app ashpal-tracker + 165 cf app ashpal-tracker + 166 cf delete ashpal-tracker + 167 cf push + 168 cf apps + 169 git commit + 170 git push + 171 git commit + 172 git add * + 173 git commit + 174 git push + 175 cf domains + 176 cf map-route pal-tracker ${DOMAIN} --hostname pal-tracker-${INITIALS}-dev + 177* cf map-route ashpal-tracker ${} --hostname ashpal-tracker-${INITIALS}-dev + 178 cf map-route pal-tracker ${DOMAIN} --hostname pal-tracker-${INITIALS}-dev + 179 cf map-route pal-tracker ashnet --hostname pal-tracker-ash-dev + 180 cf map-route ashpal-tracker ashnet --hostname pal-tracker-ash-dev + 181 cf domains + 182 cf map-route ashpal-tracker apps.cumuluslabs.io --hostname pal-tracker-ash-dev + 183 cf apps + 184 cf apps + 185 cf routes + 186 cf --help -a + 187 cf delete-orphaned-routes + 188 cf routes + 189 cf unmap-route ashpal-tracker apps.cumuluslabs.io --hostname pal-tracker-ash-dev + 190 cf routes + 191 cf apps + 192 cf delete-orphaned-routes + 193 cf apps + 194 cf routes + 195 cf apps + 196 history > mypcfcommands.txt + 197 pwd + 198 git cherry-pick pipeline-start + 199 ls + 200 cd ci + 201 ls + 202 fly + 203 fly + 204 ls -a fly + 205 fly + 206 install fly /usr/local/bin + 207 install /usr/local/bin/fly /usr/local/bin + 208 fly + 209 pwd + 210 fly --target pal-concourse login --concourse-url https://concourse.cumuluslabs.io/ --team-name ashwin.gudidevuni@cognizant.com + 211 l + 212 ls + 213 vi build.yml + 214 vi pipeline.yml + 215 cf create-space review + 216 cf create-space production + 217 ls + 218 cd .. + 219 ls + 220 vi manifest.yml + 221 cp manifest.yml manifest-review.yml + 222 cp manifest.yml manifest-production.yml + 223 vi manifest-review.yml + 224 vi manifest-production.yml.yml + 225 vi manifest-production.yml + 226 ls + 227 vi manifest-review.yml + 228 cf login + 229 cf marketplace + 230 cf services + 231 cf apps + 232 cf restage ashpal-tracker + 233 cf env ash-paltracker + 234 cf env ashpal-tracker + 235 ls + 236 cd ci/ + 237 ls + 238 vi variables.yml + 239 cd .. + 240 ls + 241 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 242 vi ci/variables.yml + 243 vi ci/pipeline.yml + 244 vi ci/pipeline.yml + 245 vi ci/variables.yml + 246 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 247 vi ci/variables.yml + 248 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 249 vi ci/variables.yml + 250 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 251 vi ci/variables.yml + 252 vi ci/variables.yml + 253 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 254 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 255 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 256 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 257 fly --help + 258 fly destroy-pipeline pal-tracker + 259 fly destroy-pipeline -p pal-tracker + 260 fly destroy-pipeline pal-concourse + 261 fly destroy-pipeline -p pal-concourse + 262 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 263 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 264 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 265 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 266 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 267 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 268 ls + 269 git commit + 270 git add * + 271 git commit + 272 git commit + 273 git push + 274 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 275 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 276 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 277 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 278 git status + 279 git add ci/pipeline.yml + 280 git status + 281 git commit + 282 git commit + 283 git push + 284 git commit -m + 285 git commit + 286 git add ci/pipeline.yml + 287 git commit + 288 git push + 289 git commit + 290 git add ci/pipeline.yml + 291 git commit + 292 git commit -m + 293 git commit m + 294 git commit -m "try again" + 295 git add ci/pipeline.yml + 296 git commit -m "try again" + 297 git push + 298 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 299 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 300 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 301 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 302 cf target + 303 cf login + 304 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 305 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 306 cf orgs + 307 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 308 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 309 cf apps + 310 cf apps + 311 cf login -a api.system.cummuluslabs.io + 312 cf login + 313 cf apps + 314 git commit + 315 git add * + 316 git push + 317 git commit + 318 git push + 319 git add * + 320 git commit -m "once again" + 321 git push + 322 pwd + 323 git cherry-pick mvc-start + 324 ls + 325 cd src/ + 326 ls + 327 cd main/ + 328 ls + 329 cd java/ + 330 ls + 331 cd io/ + 332 ls + 333 cd pivotal/ + 334 ls + 335 cd pal/ + 336 ls + 337 cd tracker/ + 338 ls + 339 cd ~/workspace + 340 ls + 341 cd pal-tracker/ + 342 ls + 343 ./gradlew clean compileTestJava + 344 ./gradlew clean compileTestJava + 345 ./gradlew tasks + 346 ./gradlew test + 347 ./gradlew clean compileTestJava + 348 ./gradlew clean compileTestJava + 349 ./gradlew clean compileTestJava + 350 cls + 351 clean + 352 clear + 353 ./gradlew clean compileTestJava + 354 ./gradlew clean compileTestJava + 355 ./gradlew clean compileTestJava + 356 ./gradlew clean compileTestJava + 357 ./gradlew clean compileTestJava + 358 ./gradlew clean compileTestJava + 359 ./gradlew clean compileTestJava + 360 ./gradlew clean compileTestJava + 361 ./gradlew clean compileTestJava + 362 ./gradlew clean compileTestJava + 363 ./gradlew clean compileTestJava + 364 ./gradlew clean compileTestJava + 365 ./gradlew clean compileTestJava + 366 clear + 367 ./gradlew clean compileTestJava + 368 ./gradlew clean compileTestJava + 369 ./gradlew clean compileTestJava + 370 ./gradlew clean compileTestJava + 371 ./gradlew clean compileTestJava + 372 ./gradlew clean compileTestJava + 373 ./gradlew clean compileTestJava + 374 ./gradlew clean compileTestJava + 375 ./gradlew clean compileTestJava + 376 ./gradlew clean compileTestJava + 377 ./gradlew clean compileTestJava + 378 ./gradlew clean compileTestJava + 379 ./gradlew clean compileTestJava + 380 ./gradlew clean compileTestJava + 381 ./gradlew clean compileTestJava + 382 ./gradlew clean compileTestJava + 383 ./gradlew clean compileTestJava + 384 ./gradlew clean compileTestJava + 385 ./gradlew clean compileTestJava + 386 ./gradlew clean compileTestJava + 387 ./gradlew clean compileTestJava + 388 ./gradlew clean compileTestJava + 389 ./gradlew clean compileTestJava + 390 ./gradlew clean compileTestJava + 391 ./gradlew clean compileTestJava + 392 ./gradlew clean compileTestJava + 393 ./gradlew clean compileTestJava + 394 ./gradlew clean compileTestJava + 395 ./gradlew clean compileTestJava + 396 ./gradlew clean compileTestJava + 397 ./gradlew clean compileTestJava + 398 ./gradlew clean compileTestJava + 399 ./gradlew clean compileTestJava + 400 ./gradlew clean compileTestJava + 401 ./gradlew clean compileTestJava + 402 ./gradlew clean compileTestJava + 403 ./gradlew clean compileTestJava + 404 ./gradlew clean compileTestJava + 405 ./gradlew clean compileTestJava + 406 ./gradlew clean compileTestJava + 407 ./gradlew clean compileTestJava + 408 ./gradlew clean compileTestJava + 409 ./gradlew clean compileTestJava + 410 cls + 411 clear + 412 ./gradlew clean build + 413 ./gradlew clean compileTestJava + 414 ./gradlew clean compileTestJava + 415 ./gradlew clean compileTestJava + 416 ./gradlew clean compileTestJava + 417 ./gradlew clean compileTestJava + 418 ./gradlew clean build + 419 ./gradlew clean build + 420 ./gradlew clean build + 421 pwd + 422 ls + 423 git add * + 424 git commin -m "MVC" + 425 git push + 426 ls + 427 git commit + 428 git push + 429 curl -g https://agprod-pal-tracker-review.apps.cumuluslabs.io/time-entries + 430 curl --help + 431 curl -g https://agprod-pal-tracker-review.apps.cumuluslabs.io/time-entries/1 + 432 pwd + 433 git cherry-pick migration-start + 434 pwd + 435 mkdir databases + 436 cd databases/ + 437 ls + 438 mkdir tracker + 439 cd tracker/ + 440 ls + 441 touch create_databases.sql + 442 pwd + 443 mkdir migrations + 444 cd migrations/ + 445 ls + 446 touch V1__initial_schema.sql + 447 cd ../.. + 448 ls + 449 cd .. + 450 ls + 451 mysql + 452 mysql -uroot < databases/tracker/create_databases.sql + 453 mysql + 454 mysql -uroot < databases/tracker/create_databases.sql + 455 flyway + 456 flyway -url="jdbc:mysql://localhost:3306/tracker_dev" -locations=filesystem:databases/tracker clean migrate + 457 flyway -url="jdbc:mysql://localhost:3306/tracker_test" -locations=filesystem:databases/tracker clean migrate + 458 mysql -u tracker + 459 cf marketplace + 460 pwd + 461 cf target -s review + 462 cf create-service MySql 100MB tracker-database + 463 cf create-service MySQL 100mb tracker-database + 464 cf create-service ash-mysql 100mb tracker-database + 465 cf create-service MySQL 100mb tracker-database + 466 cf m + 467 cf create-service p-mysql 100mb tracker-database + 468 cf target -s production + 469 cf create-service p-mysql 100mb tracker-database + 470 cf bind-service pal-tracker tracker-database + 471 cf bind-service ashpal-tracker tracker-database + 472 cf target -s review + 473 cf bind-service ashpal-tracker tracker-database + 474 cf target -s sandbox + 475 cf create-service p-mysql 100mb tracker-database + 476 cf bind-service ashpal-tracker tracker-database + 477 cf target -s review + 478 cd target -s sandbox + 479 cf target -s sandbox + 480 cf env ashpal-tracker + 481 cf restage ashpal-tracker + 482 cf env ashpal-tracker + 483 :q + 484 cf target -s production + 485 cf restage ashpal-tracker + 486 cf env ashpal-tracker + 487 cf target -s sandbox + 488 cf env ashpal-tracker + 489 ./gradlew clean compileTestJava + 490 pwd + 491 fly -t pal-concourse set-pipeline -p pal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 492 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 493 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 494 pwd + 495 git commit + 496 git add * + 497 git commit + 498 git push + 499 git commit + 500 git add * + 501 git commit + 502 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 503 git push + 504 git add * + 505 git commit + 506 git push + 507 git commit + 508 git add * + 509 git commit + 510 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 511 fly -t pal-concourse destroy-pipeline -p ashpal-tracker + 512 fly -t pal-concourse set-pipeline -p ashpal-tracker --load-vars-from ci/variables.yml -c ci/pipeline.yml + 513* mysql -u tracker + 514 mysql -u tracker + 515 ls + 516 pwd + 517 git cherry-pick jdbc-start + 518 ./gradlew clean build + 519 git add * + 520 git commit + 521 git push + 522 ./gradlew clean build + 523 git add * + 524 git commit + 525 git push + 526 history > mycommand613.txt diff --git a/mypcfcommands.txt b/mypcfcommands.txt new file mode 100644 index 000000000..e0b3dba25 --- /dev/null +++ b/mypcfcommands.txt @@ -0,0 +1,196 @@ + 1 scutil --set ComputerName MACLTUS27064 + 2 scutil --set HostName MACLTUS27064 + 3 scutil --set LocalHostName MACLTUS27064 + 4 cd desktop + 5 sudo chmod +x install.sh + 6 sudo ./install.sh -i + 7 cd desktop + 8 sudo chmod +x install.sh + 9 sudo ./install.sh -i + 10 exit + 11 ls + 12 cd ~/workspace + 13 ls + 14 cd prerequisite-code/ + 15 ls + 16 cd build + 17 ls + 18 cd classes + 19 ls + 20 cd main/ + 21 ls + 22 cd io/ + 23 ls + 24 cd pivotal/ + 25 ls + 26 cd pal/ + 27 ls + 28 cd prerequisites/ + 29 ls + 30 java + 31 ls + 32 java Application.class + 33 cf apps + 34 cf delete prerequisite + 35 cf delete prerequisite + 36 ls + 37 pwd + 38 cd ~/workspace + 39 brew install Tomee plume + 40 brew install Tomeeplume + 41 brew install tomee-plume + 42 brew install minio + 43 brew install redis + 44 brew install nginx + 45 brew install aws-cli + 46 brew install awscli + 47 pwd + 48 cd ~/workspace + 49 git clone https://github.com/ashwingudidevuni/pal-tracker + 50 ls + 51 cd pal-tracker/ + 52 ls + 53 pwd + 54 gradle wrapper + 55 ls + 56 pwd + 57 pwd + 58 touch build.gradle + 59 ls + 60 ls + 61 mkdir src + 62 cd src/ + 63 mkdir main + 64 ls + 65 cd main/ + 66 mkdir java + 67 ls + 68 pwd + 69 pwd + 70 cd .. + 71 ls + 72 cd .. + 73 cd .. + 74 ls + 75 cd p + 76 cd pal-tracker/ + 77 ls + 78 ./gradlew build + 79 gradle tasks + 80 ./gradlew bootRun + 81 ./gradlew build + 82 gradle tasks + 83 ./gradlew bootRun + 84 cf + 85 cf --help + 86 cf login --help + 87 cf login -a api.system.cumuluslabs.io + 88 cf target + 89 ./gradlew build + 90 cf push --help + 91 cf push pal-tracker + 92 cf push + 93 cf push ashpal-tracker + 94 ls + 95 touch manifest.yml + 96 cf push + 97 cf push + 98 cf apps + 99 pwd + 100 ls + 101 git push + 102 git push -help + 103 git push https://github.com/ashwingudidevuni/pal-tracker + 104 git + 105 git commit + 106 git commit -help + 107 git status + 108 git config --global user.email "ashwin.gudidevuni@gmail.com" + 109 git commit + 110 git commit + 111 git push + 112 ls + 113 ls + 114 pwd + 115 cd .. + 116 ls + 117 ls -a + 118 cd pal-tracker/ + 119 ls -a + 120 vi .gitignore + 121 pwd + 122 git push + 123 git commit + 124 git + 125 vi .gitignore + 126 git commit + 127 git add * + 128 git status + 129 git commit + 130 git push + 131 cf buildpacks + 132 cf buildpacks --help + 133 cf buildpacks -help + 134 cf apps + 135 cf images + 136 cf images -a + 137 cf image + 138 pwd + 139 git cherry-pick deployment-start + 140 pwd + 141 ./gradlew bootRun + 142 WELCOME_MESSAGE=hello_ashwin ./gradlew bootRun + 143 WELCOME_MESSAGE=hello_ashwin ./gradlew bootRun + 144 ls + 145* ./gradlew build + 146 ./gradlew bootRun + 147 WELCOME_MESSAGE=hello_ashwin ./gradlew bootRun + 148 ./gradlew bootRun + 149 ./gradlew bootRun + 150 ./gradlew bootRun + 151 ./gradlew bootRun + 152 ./gradlew test + 153 ./gradlew clean build + 154 cf apps + 155 cf push ashpal-tracker -p build/libs/pal-tracker.jar --random-route + 156 cf logs --recent ashpal-tracker + 157 cf set-env ashpal-tracker WELCOME_MESSAGE "Hello from Cloud Foundry" + 158 cf restage ashpal-tracker + 159 cf apps + 160 cf app ashpal-tracker + 161 cf scale ashpal-tracker -m 768M -f + 162 cf app ashpal-tracker + 163 cf scale ashpal-tracker -i 2 + 164 cf app ashpal-tracker + 165 cf app ashpal-tracker + 166 cf delete ashpal-tracker + 167 cf push + 168 cf apps + 169 git commit + 170 git push + 171 git commit + 172 git add * + 173 git commit + 174 git push + 175 cf domains + 176 cf map-route pal-tracker ${DOMAIN} --hostname pal-tracker-${INITIALS}-dev + 177* cf map-route ashpal-tracker ${} --hostname ashpal-tracker-${INITIALS}-dev + 178 cf map-route pal-tracker ${DOMAIN} --hostname pal-tracker-${INITIALS}-dev + 179 cf map-route pal-tracker ashnet --hostname pal-tracker-ash-dev + 180 cf map-route ashpal-tracker ashnet --hostname pal-tracker-ash-dev + 181 cf domains + 182 cf map-route ashpal-tracker apps.cumuluslabs.io --hostname pal-tracker-ash-dev + 183 cf apps + 184 cf apps + 185 cf routes + 186 cf --help -a + 187 cf delete-orphaned-routes + 188 cf routes + 189 cf unmap-route ashpal-tracker apps.cumuluslabs.io --hostname pal-tracker-ash-dev + 190 cf routes + 191 cf apps + 192 cf delete-orphaned-routes + 193 cf apps + 194 cf routes + 195 cf apps + 196 history > mypcfcommands.txt 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 000000000..7eab781d1 Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/EnvController.class differ diff --git a/out/production/classes/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.class b/out/production/classes/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.class new file mode 100644 index 000000000..73c66ae6c Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.class differ 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 000000000..60f3e4a1b Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/JdbcTimeEntryRepository.class differ 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 000000000..76bcab6b0 Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/PalTrackerApplication.class differ diff --git a/out/production/classes/io/pivotal/pal/tracker/SecurityConfiguration.class b/out/production/classes/io/pivotal/pal/tracker/SecurityConfiguration.class new file mode 100644 index 000000000..224060200 Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/SecurityConfiguration.class differ 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 000000000..0b73b01e2 Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/TimeEntry.class differ 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 000000000..ad80aa272 Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/TimeEntryController.class differ diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntryHealthIndicator.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntryHealthIndicator.class new file mode 100644 index 000000000..d57d41d21 Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/TimeEntryHealthIndicator.class differ diff --git a/out/production/classes/io/pivotal/pal/tracker/TimeEntryRepository.class b/out/production/classes/io/pivotal/pal/tracker/TimeEntryRepository.class new file mode 100644 index 000000000..d3a7bb06b Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/TimeEntryRepository.class differ 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 000000000..3a9f393a3 Binary files /dev/null and b/out/production/classes/io/pivotal/pal/tracker/WelcomeController.class differ diff --git a/out/production/resources/application.properties b/out/production/resources/application.properties new file mode 100644 index 000000000..383ef7df5 --- /dev/null +++ b/out/production/resources/application.properties @@ -0,0 +1 @@ +https.disabled=false \ No newline at end of file diff --git a/out/test/classes/test/pivotal/pal/tracker/EnvControllerTest.class b/out/test/classes/test/pivotal/pal/tracker/EnvControllerTest.class new file mode 100644 index 000000000..7edbc421f Binary files /dev/null and b/out/test/classes/test/pivotal/pal/tracker/EnvControllerTest.class differ 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 000000000..0a534e2fc Binary files /dev/null and b/out/test/classes/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.class differ 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 000000000..05edba1ae Binary files /dev/null and b/out/test/classes/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.class differ 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 000000000..b36b97f31 Binary files /dev/null and b/out/test/classes/test/pivotal/pal/tracker/TimeEntryControllerTest.class differ diff --git a/out/test/classes/test/pivotal/pal/tracker/WelcomeControllerTest.class b/out/test/classes/test/pivotal/pal/tracker/WelcomeControllerTest.class new file mode 100644 index 000000000..a49636ed7 Binary files /dev/null and b/out/test/classes/test/pivotal/pal/tracker/WelcomeControllerTest.class differ diff --git a/out/test/classes/test/pivotal/pal/trackerapi/HealthApiTest.class b/out/test/classes/test/pivotal/pal/trackerapi/HealthApiTest.class new file mode 100644 index 000000000..313ef4054 Binary files /dev/null and b/out/test/classes/test/pivotal/pal/trackerapi/HealthApiTest.class differ diff --git a/out/test/classes/test/pivotal/pal/trackerapi/SecurityApiTest.class b/out/test/classes/test/pivotal/pal/trackerapi/SecurityApiTest.class new file mode 100644 index 000000000..2c3ed40de Binary files /dev/null and b/out/test/classes/test/pivotal/pal/trackerapi/SecurityApiTest.class differ 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 000000000..f71cb65a5 Binary files /dev/null and b/out/test/classes/test/pivotal/pal/trackerapi/TimeEntryApiTest.class differ diff --git a/out/test/classes/test/pivotal/pal/trackerapi/WelcomeApiTest.class b/out/test/classes/test/pivotal/pal/trackerapi/WelcomeApiTest.class new file mode 100644 index 000000000..799ed13a2 Binary files /dev/null and b/out/test/classes/test/pivotal/pal/trackerapi/WelcomeApiTest.class differ diff --git a/pal-tracker-codebase.txt b/pal-tracker-codebase.txt deleted file mode 100644 index 0943c3cd3..000000000 --- a/pal-tracker-codebase.txt +++ /dev/null @@ -1 +0,0 @@ -pal-tracker codebase 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/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/InMemoryTimeEntryRepository.java b/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java new file mode 100644 index 000000000..d3d25c87c --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/InMemoryTimeEntryRepository.java @@ -0,0 +1,44 @@ +package io.pivotal.pal.tracker; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class InMemoryTimeEntryRepository implements TimeEntryRepository { + + private HashMap _inMemRepo = new HashMap<>(); + + public TimeEntry find(long id ) { + return this._inMemRepo.get(id); + } + + public TimeEntry update(long id, TimeEntry te) { + TimeEntry updatedEntry = new TimeEntry( + id, + te.getProjectId(), + te.getUserId(), + te.getDate(), + te.getHours() + ); + + _inMemRepo.replace(id, updatedEntry); + return updatedEntry; + + + } + + public TimeEntry create(TimeEntry te) { + Long id = this._inMemRepo.size() + 1L; + TimeEntry newTE = new TimeEntry(id, te.getProjectId(), te.getUserId(), te.getDate(), te.getHours()); + this._inMemRepo.put(id, newTE); + return newTE; + } + + public void delete(long id) { + this._inMemRepo.remove(id); + } + + public List list() { + return new ArrayList<>(this._inMemRepo.values()); + } +} 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..3667d69f6 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/JdbcTimeEntryRepository.java @@ -0,0 +1,82 @@ +package io.pivotal.pal.tracker; + + +import javax.sql.DataSource; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCallback; +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 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 final JdbcTemplate jdbcTemplate; + public JdbcTimeEntryRepository(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public TimeEntry find(long id) { + return this.jdbcTemplate.query( "SELECT id, project_id, user_id, date, hours FROM time_entries WHERE id = ?", + new Object[]{id}, + extractor); + } + + @Override + public TimeEntry update(long id, TimeEntry te) { + jdbcTemplate.update("UPDATE time_entries " + + "SET project_id = ?, user_id = ?, date = ?, hours = ? " + + "WHERE id = ?", + te.getProjectId(), + te.getUserId(), + Date.valueOf(te.getDate()), + te.getHours(), + id); + + return find(id); + } + + @Override + public TimeEntry create(TimeEntry te) { + KeyHolder generateKeyHolder = new GeneratedKeyHolder(); + this.jdbcTemplate.update(connection -> { + PreparedStatement statement = connection.prepareStatement("INSERT INTO time_entries (project_id, user_id, date, hours) " + + "VALUES (?, ?, ?, ?)", RETURN_GENERATED_KEYS); + statement.setLong(1, te.getProjectId()); + statement.setLong(2, te.getUserId()); + statement.setDate(3, Date.valueOf(te.getDate())); + statement.setInt(4, te.getHours()); + return statement; + }, generateKeyHolder); + return find(generateKeyHolder.getKey().longValue()); + } + + @Override + public void delete(long id) { + jdbcTemplate.update("DELETE FROM time_entries WHERE id = ?", id); + } + + @Override + public List list() { + return jdbcTemplate.query("SELECT id, project_id, user_id, date, hours FROM time_entries", mapper); + } + + 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 new file mode 100644 index 000000000..ed5ba43cd --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/PalTrackerApplication.java @@ -0,0 +1,39 @@ +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; + +import javax.sql.DataSource; +import java.util.TimeZone; + +@SpringBootApplication +public class PalTrackerApplication { + + public static void main(String[] args) { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + SpringApplication.run(PalTrackerApplication.class, args); + } + + @Bean + TimeEntryRepository timeEntryRepository(DataSource dataSource) { + //return new InMemoryTimeEntryRepository(); + // MysqlDataSource dataSource = new MysqlDataSource(); + //dataSource.setUrl(System.getenv("SPRING_DATASOURCE_URL")); + return new JdbcTimeEntryRepository(dataSource); + } + + @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/SecurityConfiguration.java b/src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java new file mode 100644 index 000000000..0e6dd8657 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/SecurityConfiguration.java @@ -0,0 +1,38 @@ +package io.pivotal.pal.tracker; + +import org.springframework.beans.factory.annotation.Value; +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 { + + private Boolean disableHttps; + + public SecurityConfiguration(@Value("${https.disabled}") Boolean disableHttps) { + this.disableHttps = disableHttps; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + if (!disableHttps) { + http.requiresChannel().anyRequest().requiresSecure(); + } + + http + .authorizeRequests().antMatchers("/**").hasRole("USER") + .and() + .httpBasic() + .and() + .csrf().disable(); + } + + @Override + public void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + } +} \ 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..7019547a0 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntry.java @@ -0,0 +1,87 @@ + +package io.pivotal.pal.tracker; + +import java.time.LocalDate; + +public class TimeEntry { + + private long id; + + private long projectId; + private long userId; + private LocalDate date; + private int hours; + + public 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; + } + + + public TimeEntry(long pid, long usrId, LocalDate d, int h) { + this.projectId = pid; + this.userId = usrId; + this.date = d; + this.hours = h; + } + + public TimeEntry(long id, long pid, long uid, LocalDate d, int h) { + this.id = id; + this.projectId = pid; + this.userId = uid; + this.date = d; + this.hours = h; + } + + public TimeEntry() {} + + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + TimeEntry timeEntry = (TimeEntry) o; + + if (id != timeEntry.id) return false; + if (projectId != timeEntry.projectId) return false; + if (userId != timeEntry.userId) return false; + if (hours != timeEntry.hours) return false; + return date != null ? date.equals(timeEntry.date) : timeEntry.date == null; + } + + +} 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..01e11039d --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryController.java @@ -0,0 +1,73 @@ +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.*; + +import java.util.List; + +@RestController +@RequestMapping("/time-entries") +public class TimeEntryController { + + private final CounterService counter; + private final GaugeService gauge; + private TimeEntryRepository timeEntriesRepo; + + public TimeEntryController( + TimeEntryRepository timeEntriesRepo, + CounterService counter, + GaugeService gauge + ) { + this.timeEntriesRepo = timeEntriesRepo; + this.counter = counter; + this.gauge = gauge; + } + + @PostMapping + public ResponseEntity create(@RequestBody TimeEntry timeEntry) { + TimeEntry createdTimeEntry = timeEntriesRepo.create(timeEntry); + counter.increment("TimeEntry.created"); + gauge.submit("timeEntries.count", timeEntriesRepo.list().size()); + + return new ResponseEntity<>(createdTimeEntry, HttpStatus.CREATED); + } + + @GetMapping("{id}") + public ResponseEntity read(@PathVariable Long id) { + TimeEntry timeEntry = timeEntriesRepo.find(id); + if (timeEntry != null) { + counter.increment("TimeEntry.read"); + return new ResponseEntity<>(timeEntry, HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @GetMapping + public ResponseEntity> list() { + counter.increment("TimeEntry.listed"); + return new ResponseEntity<>(timeEntriesRepo.list(), HttpStatus.OK); + } + + @PutMapping("{id}") + public ResponseEntity update(@PathVariable Long id, @RequestBody TimeEntry timeEntry) { + TimeEntry updatedTimeEntry = timeEntriesRepo.update(id, timeEntry); + if (updatedTimeEntry != null) { + counter.increment("TimeEntry.updated"); + return new ResponseEntity<>(updatedTimeEntry, HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @DeleteMapping("{id}") + public ResponseEntity delete(@PathVariable Long id) { + timeEntriesRepo.delete(id); + counter.increment("TimeEntry.deleted"); + gauge.submit("timeEntries.count", timeEntriesRepo.list().size()); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java b/src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java new file mode 100644 index 000000000..49b1f175d --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryHealthIndicator.java @@ -0,0 +1,29 @@ +package io.pivotal.pal.tracker; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.stereotype.Component; + +@Component +public class TimeEntryHealthIndicator implements HealthIndicator { + + private static final int MAX_TIME_ENTRIES = 5; + private final TimeEntryRepository timeEntryRepo; + + public TimeEntryHealthIndicator(TimeEntryRepository timeEntryRepo) { + this.timeEntryRepo = timeEntryRepo; + } + + @Override + public Health health() { + Health.Builder builder = new Health.Builder(); + + if(timeEntryRepo.list().size() < MAX_TIME_ENTRIES) { + builder.up(); + } else { + builder.down(); + } + + return builder.build(); + } +} \ No newline at end of file diff --git a/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java b/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java new file mode 100644 index 000000000..e89396570 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/TimeEntryRepository.java @@ -0,0 +1,16 @@ +package io.pivotal.pal.tracker; + +import java.util.List; + +public interface TimeEntryRepository { + + public TimeEntry find(long id) ; + + public TimeEntry update(long id, TimeEntry te) ; + + public TimeEntry create(TimeEntry te); + + public void delete(long id) ; + + public List list() ; +} 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..53130dbb4 --- /dev/null +++ b/src/main/java/io/pivotal/pal/tracker/WelcomeController.java @@ -0,0 +1,19 @@ +package io.pivotal.pal.tracker; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Value; + +@RestController +public class WelcomeController { + + private String _message; + public WelcomeController(@Value("${WELCOME_MESSAGE}") String msg) { + this._message = msg; + } + + @GetMapping("/") + public String sayHello() { + return this._message; + } +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 000000000..383ef7df5 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +https.disabled=false \ No newline at end of file diff --git a/src/test/java/test/pivotal/pal/tracker/EnvControllerTest.java b/src/test/java/test/pivotal/pal/tracker/EnvControllerTest.java new file mode 100644 index 000000000..fda0f0f34 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/EnvControllerTest.java @@ -0,0 +1,28 @@ +package test.pivotal.pal.tracker; + +import org.junit.Test; + +import java.util.Map; +import io.pivotal.pal.tracker.EnvController; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EnvControllerTest { + @Test + public void getEnv() throws Exception { + EnvController controller = new EnvController( + "8675", + "12G", + "34", + "123.sesame.street" + ); + + Map env = controller.getEnv(); + + assertThat(env.get("PORT")).isEqualTo("8675"); + assertThat(env.get("MEMORY_LIMIT")).isEqualTo("12G"); + assertThat(env.get("CF_INSTANCE_INDEX")).isEqualTo("34"); + assertThat(env.get("CF_INSTANCE_ADDR")).isEqualTo("123.sesame.street"); + } + +} diff --git a/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java b/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java new file mode 100644 index 000000000..d0ae6cbe6 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/InMemoryTimeEntryRepositoryTest.java @@ -0,0 +1,71 @@ +package test.pivotal.pal.tracker; + +import io.pivotal.pal.tracker.InMemoryTimeEntryRepository; +import io.pivotal.pal.tracker.TimeEntry; +import org.junit.Test; + +import java.time.LocalDate; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +public class InMemoryTimeEntryRepositoryTest { + @Test + public void create() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + TimeEntry createdTimeEntry = repo.create(new TimeEntry(123L, 456L, LocalDate.parse("2017-01-08"), 8)); + + TimeEntry expected = new TimeEntry(1L, 123L, 456L, LocalDate.parse("2017-01-08"), 8); + assertThat(createdTimeEntry).isEqualTo(expected); + + TimeEntry readEntry = repo.find(createdTimeEntry.getId()); + assertThat(readEntry).isEqualTo(expected); + } + + @Test + public void find() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + repo.create(new TimeEntry(123L, 456L, LocalDate.parse("2017-01-08"), 8)); + + TimeEntry expected = new TimeEntry(1L, 123L, 456L, LocalDate.parse("2017-01-08"), 8); + TimeEntry readEntry = repo.find(1L); + assertThat(readEntry).isEqualTo(expected); + } + + @Test + public void list() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + repo.create(new TimeEntry(123L, 456L, LocalDate.parse("2017-01-08"), 8)); + repo.create(new TimeEntry(789L, 654L, LocalDate.parse("2017-01-07"), 4)); + + List expected = asList( + new TimeEntry(1L, 123L, 456L, LocalDate.parse("2017-01-08"), 8), + new TimeEntry(2L, 789L, 654L, LocalDate.parse("2017-01-07"), 4) + ); + assertThat(repo.list()).isEqualTo(expected); + } + + @Test + public void update() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + TimeEntry created = repo.create(new TimeEntry(123L, 456L, LocalDate.parse("2017-01-08"), 8)); + + TimeEntry updatedEntry = repo.update( + created.getId(), + new TimeEntry(321L, 654L, LocalDate.parse("2017-01-09"), 5)); + + TimeEntry expected = new TimeEntry(created.getId(), 321L, 654L, LocalDate.parse("2017-01-09"), 5); + assertThat(updatedEntry).isEqualTo(expected); + assertThat(repo.find(created.getId())).isEqualTo(expected); + } + + @Test + public void delete() throws Exception { + InMemoryTimeEntryRepository repo = new InMemoryTimeEntryRepository(); + TimeEntry created = repo.create(new TimeEntry(123L, 456L, LocalDate.parse("2017-01-08"), 8)); + + repo.delete(created.getId()); + assertThat(repo.list()).isEmpty(); + } +} diff --git a/src/test/java/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.java b/src/test/java/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.java new file mode 100644 index 000000000..e1eac20fc --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/JdbcTimeEntryRepositoryTest.java @@ -0,0 +1,159 @@ +package test.pivotal.pal.tracker; + + +import com.mysql.cj.jdbc.MysqlDataSource; +import io.pivotal.pal.tracker.JdbcTimeEntryRepository; +import io.pivotal.pal.tracker.TimeEntry; +import io.pivotal.pal.tracker.TimeEntryRepository; +import org.junit.Before; +import org.junit.Test; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.sql.Date; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JdbcTimeEntryRepositoryTest { + private TimeEntryRepository subject; + private JdbcTemplate jdbcTemplate; + + @Before + public void setUp() throws Exception { + MysqlDataSource dataSource = new MysqlDataSource(); + dataSource.setUrl(System.getenv("SPRING_DATASOURCE_URL")); + + subject = new JdbcTimeEntryRepository(dataSource); + + jdbcTemplate = new JdbcTemplate(dataSource); + jdbcTemplate.execute("DELETE FROM time_entries"); + + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + } + + @Test + public void createInsertsATimeEntryRecord() throws Exception { + TimeEntry newTimeEntry = new TimeEntry(123, 321, LocalDate.parse("2017-01-09"), 8); + TimeEntry entry = subject.create(newTimeEntry); + + Map foundEntry = jdbcTemplate.queryForMap("Select * from time_entries where id = ?", entry.getId()); + + assertThat(foundEntry.get("id")).isEqualTo(entry.getId()); + assertThat(foundEntry.get("project_id")).isEqualTo(123L); + assertThat(foundEntry.get("user_id")).isEqualTo(321L); + assertThat(((Date)foundEntry.get("date")).toLocalDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(foundEntry.get("hours")).isEqualTo(8); + } + + @Test + public void createReturnsTheCreatedTimeEntry() throws Exception { + TimeEntry newTimeEntry = new TimeEntry(123, 321, LocalDate.parse("2017-01-09"), 8); + TimeEntry entry = subject.create(newTimeEntry); + + assertThat(entry.getId()).isNotNull(); + assertThat(entry.getProjectId()).isEqualTo(123); + assertThat(entry.getUserId()).isEqualTo(321); + assertThat(entry.getDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(entry.getHours()).isEqualTo(8); + } + + @Test + public void findFindsATimeEntry() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (999, 123, 321, '2017-01-09', 8)" + ); + + TimeEntry timeEntry = subject.find(999L); + + assertThat(timeEntry.getId()).isEqualTo(999L); + assertThat(timeEntry.getProjectId()).isEqualTo(123L); + assertThat(timeEntry.getUserId()).isEqualTo(321L); + assertThat(timeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(timeEntry.getHours()).isEqualTo(8); + } + + @Test + public void findReturnsNullWhenNotFound() throws Exception { + TimeEntry timeEntry = subject.find(999L); + + assertThat(timeEntry).isNull(); + } + + @Test + public void listFindsAllTimeEntries() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (999, 123, 321, '2017-01-09', 8), (888, 456, 678, '2017-01-08', 9)" + ); + + List timeEntries = subject.list(); + assertThat(timeEntries.size()).isEqualTo(2); + + TimeEntry timeEntry = timeEntries.get(0); + assertThat(timeEntry.getId()).isEqualTo(888L); + assertThat(timeEntry.getProjectId()).isEqualTo(456L); + assertThat(timeEntry.getUserId()).isEqualTo(678L); + assertThat(timeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-08")); + assertThat(timeEntry.getHours()).isEqualTo(9); + + timeEntry = timeEntries.get(1); + assertThat(timeEntry.getId()).isEqualTo(999L); + assertThat(timeEntry.getProjectId()).isEqualTo(123L); + assertThat(timeEntry.getUserId()).isEqualTo(321L); + assertThat(timeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-09")); + assertThat(timeEntry.getHours()).isEqualTo(8); + } + + @Test + public void updateReturnsTheUpdatedRecord() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (1000, 123, 321, '2017-01-09', 8)"); + + TimeEntry timeEntryUpdates = new TimeEntry(456, 987, LocalDate.parse("2017-01-10"), 10); + + TimeEntry updatedTimeEntry = subject.update(1000L, timeEntryUpdates); + + assertThat(updatedTimeEntry.getId()).isEqualTo(1000L); + assertThat(updatedTimeEntry.getProjectId()).isEqualTo(456L); + assertThat(updatedTimeEntry.getUserId()).isEqualTo(987L); + assertThat(updatedTimeEntry.getDate()).isEqualTo(LocalDate.parse("2017-01-10")); + assertThat(updatedTimeEntry.getHours()).isEqualTo(10); + } + + @Test + public void updateUpdatesTheRecord() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (1000, 123, 321, '2017-01-09', 8)"); + + TimeEntry updatedTimeEntry = new TimeEntry(456, 322, LocalDate.parse("2017-01-10"), 10); + + TimeEntry timeEntry = subject.update(1000L, updatedTimeEntry); + + Map foundEntry = jdbcTemplate.queryForMap("Select * from time_entries where id = ?", timeEntry.getId()); + + assertThat(foundEntry.get("id")).isEqualTo(timeEntry.getId()); + assertThat(foundEntry.get("project_id")).isEqualTo(456L); + assertThat(foundEntry.get("user_id")).isEqualTo(322L); + assertThat(((Date)foundEntry.get("date")).toLocalDate()).isEqualTo(LocalDate.parse("2017-01-10")); + assertThat(foundEntry.get("hours")).isEqualTo(10); + } + + @Test + public void deleteRemovesTheRecord() throws Exception { + jdbcTemplate.execute( + "INSERT INTO time_entries (id, project_id, user_id, date, hours) " + + "VALUES (999, 123, 321, '2017-01-09', 8)" + ); + + subject.delete(999L); + + Map foundEntry = jdbcTemplate.queryForMap("Select count(*) count from time_entries where id = ?", 999); + assertThat(foundEntry.get("count")).isEqualTo(0L); + } +} diff --git a/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java new file mode 100644 index 000000000..5abd36d32 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/TimeEntryControllerTest.java @@ -0,0 +1,122 @@ +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.boot.actuate.metrics.CounterService; +import org.springframework.boot.actuate.metrics.GaugeService; +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; + private GaugeService gaugeService; + private CounterService counterService; + + @Before + public void setUp() throws Exception { + timeEntryRepository = mock(TimeEntryRepository.class); + this.gaugeService = mock(GaugeService.class); + this.counterService = mock(CounterService.class); + controller = new TimeEntryController(timeEntryRepository, this.counterService, this.gaugeService); + } + + @Test + public void testCreate() throws Exception { + TimeEntry timeEntryToCreate = new TimeEntry(123L, 456L, LocalDate.parse("2017-01-08"), 8); + TimeEntry expectedResult = new TimeEntry(1L, 123L, 456L, LocalDate.parse("2017-01-08"), 8); + doReturn(expectedResult) + .when(timeEntryRepository) + .create(any(TimeEntry.class)); + + + ResponseEntity response = controller.create(timeEntryToCreate); + + + verify(timeEntryRepository).create(timeEntryToCreate); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(response.getBody()).isEqualTo(expectedResult); + } + + @Test + public void testRead() throws Exception { + TimeEntry expected = new TimeEntry(1L, 123L, 456L, LocalDate.parse("2017-01-08"), 8); + doReturn(expected) + .when(timeEntryRepository) + .find(1L); + + ResponseEntity response = controller.read(1L); + + verify(timeEntryRepository).find(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(1L, 123L, 456L, LocalDate.parse("2017-01-08"), 8), + new TimeEntry(2L, 789L, 321L, LocalDate.parse("2017-01-07"), 4) + ); + doReturn(expected).when(timeEntryRepository).list(); + + ResponseEntity> response = controller.list(); + + verify(timeEntryRepository).list(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(response.getBody()).isEqualTo(expected); + } + + @Test + public void testUpdate() throws Exception { + TimeEntry expected = new TimeEntry(1L, 987L, 654L, LocalDate.parse("2017-01-07"), 4); + doReturn(expected) + .when(timeEntryRepository) + .update(eq(1L), any(TimeEntry.class)); + + ResponseEntity response = controller.update(1L, expected); + + verify(timeEntryRepository).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/tracker/WelcomeControllerTest.java b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java new file mode 100644 index 000000000..bfa8271a0 --- /dev/null +++ b/src/test/java/test/pivotal/pal/tracker/WelcomeControllerTest.java @@ -0,0 +1,16 @@ +package test.pivotal.pal.tracker; + +import io.pivotal.pal.tracker.WelcomeController; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class WelcomeControllerTest { + + @Test + public void itSaysHello() throws Exception { + WelcomeController controller = new WelcomeController("A welcome message"); + + assertThat(controller.sayHello()).isEqualTo("A welcome message"); + } +} diff --git a/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java new file mode 100644 index 000000000..011538a2c --- /dev/null +++ b/src/test/java/test/pivotal/pal/trackerapi/HealthApiTest.java @@ -0,0 +1,50 @@ +package test.pivotal.pal.trackerapi; + +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; + +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 { + @LocalServerPort + private String port; + private TestRestTemplate restTemplate; + + @Before + public void setUp() throws Exception { + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); + + restTemplate = new TestRestTemplate(builder); + } + + @Test + public void healthTest() { + ResponseEntity response = this.restTemplate.getForEntity("/health", String.class); + + + 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"); + } +} 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); + } +} 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..193db5364 --- /dev/null +++ b/src/test/java/test/pivotal/pal/trackerapi/TimeEntryApiTest.java @@ -0,0 +1,151 @@ +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; +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; +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; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) +public class TimeEntryApiTest { + + private TestRestTemplate restTemplate; + + private TimeEntry timeEntry = new TimeEntry(123L, 456L, LocalDate.parse("2017-01-08"), 8); + + @LocalServerPort + private String port; + + @Before + public void setUp() throws Exception { + MysqlDataSource dataSource = new MysqlDataSource(); + dataSource.setUrl(System.getenv("SPRING_DATASOURCE_URL")); + + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); + + restTemplate = new TestRestTemplate(builder); + + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + jdbcTemplate.execute("TRUNCATE time_entries"); + + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + } + + @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(2L, 3L, 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(); + } +} diff --git a/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java new file mode 100644 index 000000000..782c5d64d --- /dev/null +++ b/src/test/java/test/pivotal/pal/trackerapi/WelcomeApiTest.java @@ -0,0 +1,38 @@ +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.boot.context.embedded.LocalServerPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = PalTrackerApplication.class, webEnvironment = RANDOM_PORT) +public class WelcomeApiTest { + + @LocalServerPort + private String port; + private TestRestTemplate restTemplate; + + @Before + public void setUp() throws Exception { + RestTemplateBuilder builder = new RestTemplateBuilder() + .rootUri("http://localhost:" + port) + .basicAuthorization("user", "password"); + + restTemplate = new TestRestTemplate(builder); + } + + @Test + public void exampleTest() { + String body = this.restTemplate.getForObject("/", String.class); + assertThat(body).isEqualTo("Hello from test"); + } +} \ No newline at end of file