diff --git a/.gitignore b/.gitignore
index a2c4943..2236768 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ HELP.md
target
*target*
bin/
+**/target
##############################
## Personal log folder
@@ -14,11 +15,11 @@ bin/
#/info/
logs/
/logs/
-
+**/logs/
##############################
# Gradle of project
##############################
-.gradle
+**/.gradle
/build/
**/build/
!src/**/build/
@@ -31,32 +32,32 @@ logs/
##############################
# Package Files #
##############################
-*.jar
+#*.jar
*.war
*.ear
##############################
# Eclipse specific git ignore #
##############################
-.project
-.metadata
-.project
-.metadata
-bin/**
-tmp/**
-tmp/**/*
+**/.project
+**/.metadata
+**/.project
+**/.metadata
+**/bin/**
+**/tmp/**
+**/tmp/**/*
*.tmp
*.bak
*.swp
*~.nib
-local.properties
-.classpath
-.settings/
-.loadpath
+**/local.properties
+**/.classpath
+**/.settings/
+**/.loadpath
# Locally stored "Eclipse launch configurations"
*.launch
# External tool builders
-.externalToolBuilders/
+**/.externalToolBuilders/
##############################
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
@@ -83,11 +84,11 @@ gradle-app.setting
##############################
### STS ###
##############################
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
+**/.apt_generated
+**/.classpath
+**/.factorypath
+**/.project
+**/.settings
.springBeans
.sts4-cache
.apt_generated
@@ -96,7 +97,7 @@ gradle-app.setting
##############################
### IntelliJ IDEA ###
##############################
-.idea
+**/.idea
*.iws
*.iml
*.ipr
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ca61742
--- /dev/null
+++ b/README.md
@@ -0,0 +1,162 @@
+ *** *** ***
+
+
TourGuide
+
+TourGuide is a game changer Spring Boot web application with MSA (MicroService Architecure) technologies developed by TripMaster.
+The strong highlight features of the application's Architecture is that it resonates through its rich functionality for its flexible scalability & high availability .
+
+
+
+
+ It is available as a web interface both on PC & mobile platforms for all touristic users.
+
+ ### Key features
+- Helps explore and discover attractions available near user's travel location;
+- Provides reliable and up-to-date real-time information on the discounts for Travel, Hotel reservation, Touristic Attractions Ticket offers, etc.;
+- Personalised serach information based on the user's favorite preferences related to touristic attractions and travel offers.
+
+To meet the explosive growth on the touristic user's client base, architecture redesigned is being implemented in this project to optimize performance for high volume user demands.
+
+
+## Technological Spec & Run Prerequisites
+
+- Java 1.8 JDK
+- Gradle 7.3
+- Docker
+
+## Architectural Spec:
+
+TourGuide application is composed of 4 microservices:
+
+- **TourGuide**
+- **gps-ms (microservice)**
+- **rewards-ms (microservice)**
+- **tripDeals-ms (microservice)**
+
+
+
+
+
+
+
+
+
+## Application Run configuration
+
+## Gradle
+```
+gradle bootRun or ./gradle bootRun
+```
+```
+gradle bootWar or ./gradle bootWar or ./gradle bootJar
+```
+
+## Docker
+
+### Building Docker images
+
+Use the **Dockerfile** on the package roots containing individual 4 services to build docker images
+
+SYNTAX:
+```
+docker build . -f Dockerfile -t imageNameToBeCreated
+```
+
+### Running a Docker image
+
+Use the **DockerImage** created above & run a Docker image using the command below
+
+SYNTAX:
+```
+docker run -d -p HostPort:InternalAppPort --name dockerContainerNameToBeCreated -d DockerImageName
+```
+
+### Docker Compose
+
+In case, if want to use an automated multi-container workflow with docker-compose, follow details below:
+
+To deploy all TourGuide microservices in a single go, use the **docker-compose.yml** on the package root containing all 4 services that will orchestrate multiple containers that work together based on the defined configuration in it.
+
+SYNTAX:
+```
+docker-compose up -d
+```
+
+## Testing
+
+Gradle, Junit (Unit & Integration Tests).
+
+SYNTAX:
+```
+gradlew test or ./gradlew test or gradlew clean test
+```
+
+
+
+## Reporting
+
+ ### Test Results
+
+
+
+
+
+
+
+
+
+
+
+
+# Metrics
+Test Performance on highVolume User Tracking & User Rewards Computations are performed & available.
+
+## HighVolume User Tracking Report - Graph
+
+
+## HighVolume Rewards Calculation Report - Graph
+
+
+
+## API (Endpoints) documentation
+
+All endpoints are documented with POSTMAN and can be accessed launched with the below link to POSTMAN:
+
+[POSTMAN - TOURGUIDE APIs](https://documenter.getpostman.com/view/16200863/UVR5sV8W)
+
+
+
+
+### Authors
+Mentee: 🡆 @Senthil
+Mentor: 🡆 Clément SEZETTRE
+
+### versions
+Version: 🡆 1.0
+
+### License
+@OpenClassrooms & @TourGuide
+
+
+
+Reference Documentation
+===
+For further reference, consider the following sections:
+
+
+* [Spring Web](https://docs.spring.io/spring-boot/docs/2.5.4/reference/htmlsingle/#boot-features-developing-web-applications)
+* [Docker docs](https://docs.docker.com/)
+* [Gradle User Manual](https://docs.gradle.org/current/userguide/userguide.html)
+* [STAN DOCUMENTATION WHITE PAPER](http://stan4j.com/papers/stan-whitepaper.pdf)
+
+
+Reference Guides
+===
+The following guides illustrate how to use some features concretely:
+
+* [Building a RESTful Web Service with Spring Boot Actuator](https://spring.io/guides/gs/actuator-service/)
+* [Securing a Web Application](https://spring.io/guides/gs/securing-web/)
+* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
+* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
+* [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/)
+* [STAN Structure Analysis for Java](http://stan4j.com/)
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index 00b2494..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,73 +0,0 @@
-buildscript {
- repositories {
- mavenCentral()
- }
- dependencies {
- classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
- }
-}
-
-apply plugin: 'java'
-apply plugin: 'eclipse'
-apply plugin: 'idea'
-apply plugin: 'org.springframework.boot'
-apply plugin: 'io.spring.dependency-management'
-apply plugin: "jacoco"
-
-
-bootJar {
- baseName = 'tourGuide'
- version = '1.0.0'
-}
-
-repositories {
- mavenCentral()
- flatDir {
- dirs 'libs'
- }
-}
-
-sourceCompatibility = 1.8
-targetCompatibility = 1.8
-
-dependencies {
- compile("org.springframework.boot:spring-boot-starter-web")
- compile("org.springframework.boot:spring-boot-starter-actuator")
- compile group: 'org.javamoney', name: 'moneta', version: '1.3'
- compile group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'
-
- compile(name:'gpsUtil', ext:'jar')
- compile(name:'RewardCentral', ext:'jar')
- compile(name:'TripPricer', ext:'jar')
-
- testCompile("junit:junit")
- testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.1.6.RELEASE'
-}
-
-
-jacoco {
- toolVersion = "0.8.4"
-}
-
-jacocoTestReport {
- reports {
- xml.enabled true
- csv.enabled false
- html.destination file("${buildDir}/jacocoHtml")
- }
-}
-
-test.finalizedBy jacocoTestReport
-check.dependsOn jacocoTestCoverageVerification
-
-jacocoTestCoverageVerification {
- violationRules {
- rule {
- limit {
- counter = 'LINE'
- value = 'COVEREDRATIO'
- minimum = 0.5
- }
- }
- }
-}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..6afb22d
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,67 @@
+version: '3.8'
+
+services:
+
+ gps-microservice:
+ image: gps-microservice
+ container_name: gps-microservice
+ build:
+ context: gpsMicroservice
+ dockerfile: Dockerfile
+ ports:
+ - "9091:9091"
+ networks:
+ - web-server-bridge
+ restart: always
+
+ rewards-microservice:
+ image: rewards-microservice
+ container_name: rewards-microservice
+ build:
+ context: rewardsMicroservice
+ dockerfile: Dockerfile
+ ports:
+ - "9092:9092"
+ depends_on:
+ - gps-microservice
+ networks:
+ - web-server-bridge
+ restart: always
+
+ tripdeals-microservice:
+ image: tripdeals-microservice
+ container_name: tripdeals-microservice
+ build:
+ context: tripDealsMicroservice
+ dockerfile: Dockerfile
+ ports:
+ - "9093:9093"
+ networks:
+ - web-server-bridge
+ restart: always
+
+ tourguide:
+ environment:
+ - CLIENT_GPS_BASE_URL=http://gps-microservice:9091/gps
+ - CLIENT_REWARDS_BASE_URL=http://rewards-microservice:9092/rewards
+ - CLIENT_TRIPDEALS_BASE_URL=http://tripdeals-microservice:9093/tripDeals
+ image: tourguide
+ container_name: tourguide
+ ports:
+ - "9090:9090"
+ build:
+ context: tourGuide
+ dockerfile: Dockerfile
+ depends_on:
+ - gps-microservice
+ - rewards-microservice
+ - tripdeals-microservice
+ networks:
+ - web-server-bridge
+ restart: always
+ # restart: unless-stopped
+ # stdin_open: true
+
+networks:
+ web-server-bridge:
+ driver: bridge
diff --git a/gpsMicroservice/Dockerfile b/gpsMicroservice/Dockerfile
new file mode 100644
index 0000000..4b25d04
--- /dev/null
+++ b/gpsMicroservice/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:13-oracle
+ADD build/libs/gpsMicroservice-1.0.0.war gps-microservice.war
+EXPOSE 9091
+ENTRYPOINT ["java","-jar","gps-microservice.war"]
\ No newline at end of file
diff --git a/gpsMicroservice/build.gradle b/gpsMicroservice/build.gradle
new file mode 100644
index 0000000..521fdc8
--- /dev/null
+++ b/gpsMicroservice/build.gradle
@@ -0,0 +1,132 @@
+buildscript {
+ repositories {
+ // Maven Central for resolving dependencies
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+ }
+ dependencies {
+ // https://plugins.gradle.org/plugin/org.springframework.boot
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
+ }
+}
+
+// https://docs.gradle.org/current/samples/sample_building_java_libraries.html
+
+plugins {
+ // Apply the java-library plugin for API and implementation separation
+ id 'java-library'
+ id 'maven-publish'
+}
+
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+apply plugin: 'war'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'io.spring.dependency-management'
+apply plugin: "jacoco"
+
+
+bootWar {
+ baseName = 'gpsMicroservice'
+ version = '1.0.0'
+}
+
+repositories {
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+}
+
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
+
+// https://stackoverflow.com/questions/23796404/could-not-find-method-compile-for-arguments-gradle
+/* Note that the compile, runtime, testCompile, and testRuntime configurations
+ introduced by the Java plugin have been deprecated since Gradle 4.10 (Aug 27, 2018),
+and were finally removed in Gradle 7.0 (Apr 9, 2021).
+The aforementioned configurations should be replaced by implementation,
+ runtimeOnly, testImplementation, and testRuntimeOnly, respectively.
+ http://man.hubwiz.com/docset/Gradle_User_Guide.docset/Contents/Resources/Documents/userguide/java_library_plugin.html
+*/
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web")
+ implementation("org.springframework.boot:spring-boot-starter-actuator")
+
+ implementation group: 'org.javamoney', name: 'moneta', version: '1.3'
+ implementation group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'
+
+ // Lombok
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
+ testCompileOnly 'org.projectlombok:lombok'
+ testAnnotationProcessor 'org.projectlombok:lombok'
+
+ implementation(name:'gpsUtil', ext:'jar')
+
+
+ implementation 'org.modelmapper:modelmapper:2.3.3'
+
+ // Junit
+ // testImplementation("junit:junit")
+ testImplementation 'org.springframework.boot:spring-boot-starter-web'
+ testImplementation('org.springframework.boot:spring-boot-starter-test:2.2.2.RELEASE') {
+ exclude group: 'junit'
+ exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
+ }
+
+ testImplementation("org.junit.platform:junit-platform-launcher:1.2.0")
+ testImplementation('org.junit.jupiter:junit-jupiter-api:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-engine:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-params:5.3.1')
+
+ testCompileOnly 'junit:junit:4.12'
+// testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.1'
+
+ // Use JUnit Jupiter for testing
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
+
+
+
+}
+
+test {
+ useJUnitPlatform() {
+ includeEngines 'junit-jupiter'
+ }
+
+}
+
+
+// Jacoco
+jacoco {
+ toolVersion = "0.8.4"
+}
+
+jacocoTestReport {
+ reports {
+ xml.enabled true
+ csv.enabled false
+ html.destination file("${buildDir}/jacocoHtml")
+ }
+}
+
+test.finalizedBy jacocoTestReport
+check.dependsOn jacocoTestCoverageVerification
+
+jacocoTestCoverageVerification {
+ violationRules {
+ rule {
+ limit {
+ counter = 'LINE'
+ value = 'COVEREDRATIO'
+ minimum = 0.5
+ }
+ }
+ }
+}
diff --git a/gpsMicroservice/gradle/wrapper/gradle-wrapper.jar b/gpsMicroservice/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7454180
Binary files /dev/null and b/gpsMicroservice/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gpsMicroservice/gradle/wrapper/gradle-wrapper.properties b/gpsMicroservice/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..84d1f85
--- /dev/null
+++ b/gpsMicroservice/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gpsMicroservice/gradlew b/gpsMicroservice/gradlew
new file mode 100644
index 0000000..1b6c787
--- /dev/null
+++ b/gpsMicroservice/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# 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 ;; #(
+ MSYS* | 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" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gpsMicroservice/gradlew.bat b/gpsMicroservice/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gpsMicroservice/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@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 Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@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="-Xmx64m" "-Xms64m"
+
+@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 execute
+
+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 execute
+
+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
+
+: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 %*
+
+: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/gpsMicroservice/libs/gpsUtil.jar b/gpsMicroservice/libs/gpsUtil.jar
new file mode 100644
index 0000000..2f3ec1f
Binary files /dev/null and b/gpsMicroservice/libs/gpsUtil.jar differ
diff --git a/gpsMicroservice/settings.gradle b/gpsMicroservice/settings.gradle
new file mode 100644
index 0000000..06dbc9c
--- /dev/null
+++ b/gpsMicroservice/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'gpsMicroservice'
diff --git a/gpsMicroservice/src/main/java/gps/GpsMicroserviceApplication.java b/gpsMicroservice/src/main/java/gps/GpsMicroserviceApplication.java
new file mode 100644
index 0000000..c4bf9ae
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/GpsMicroserviceApplication.java
@@ -0,0 +1,23 @@
+package gps;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * The Class GpsMicroserviceApplication.
+ */
+@ComponentScan("gps")
+@SpringBootApplication
+public class GpsMicroserviceApplication {
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(GpsMicroserviceApplication.class, args);
+ }
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/config/GpsModule.java b/gpsMicroservice/src/main/java/gps/config/GpsModule.java
new file mode 100644
index 0000000..54b57bd
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/config/GpsModule.java
@@ -0,0 +1,52 @@
+package gps.config;
+
+import java.util.Locale;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import gpsUtil.GpsUtil;
+
+@Configuration
+public class GpsModule {
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(GpsModule.class);
+
+
+ // ##############################################################
+
+ @Bean
+ public Locale getLocale() {
+ Locale.setDefault(Locale.US);
+ return Locale.getDefault();
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the gps util.
+ *
+ * @return the gps util
+ */
+ @Bean
+ public GpsUtil getGpsUtil() {
+
+ logger.info("## getGpsUtil() BEAN invoked");
+
+ return new GpsUtil();
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/controller/GpsController.java b/gpsMicroservice/src/main/java/gps/controller/GpsController.java
new file mode 100644
index 0000000..e16ca33
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/controller/GpsController.java
@@ -0,0 +1,78 @@
+package gps.controller;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+import gps.exception.UserNotFoundException;
+import gps.service.IGpsService;
+
+/**
+ * The Class GpsController.
+ */
+@RestController
+@RequestMapping("/gps")
+public class GpsController {
+
+ /** The logger. */
+// private Logger logger = LoggerFactory
+// .getLogger(GpsController.class);
+
+ private IGpsService gpsService;
+
+
+ // ##############################################################
+
+
+ @Autowired
+ public GpsController(
+ final IGpsService gpsService) {
+ this.gpsService = gpsService;
+ }
+
+
+ // ##############################################################
+
+
+ @GetMapping("/userLocation/{userId}")
+ public VisitedLocationDTO getUserLocation(
+ @PathVariable("userId") final UUID userId) {
+
+// logger.info("## gps - Microservice getUserLocation URL called");
+
+ VisitedLocationDTO userLocation = gpsService.getUserLocation(userId);
+
+ if (userLocation == null) {
+ throw new UserNotFoundException("Failed to get user location");
+ }
+
+ return userLocation;
+ }
+
+
+ // ##############################################################
+
+
+ @GetMapping("/attractions")
+ public List getAttractions() {
+
+// logger.info("## gps - Microservice getAttractions URL called");
+
+ List attractions = gpsService.getAttractions();
+
+ return attractions;
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/dto/AttractionDTO.java b/gpsMicroservice/src/main/java/gps/dto/AttractionDTO.java
new file mode 100644
index 0000000..49c0d90
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/dto/AttractionDTO.java
@@ -0,0 +1,35 @@
+package gps.dto;
+
+import java.util.UUID;
+
+import gps.model.Location;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+
+/**
+ * The Class AttractionDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class AttractionDTO {
+
+ /** The attraction id. */
+ private UUID attractionId;
+
+ /** The attraction name. */
+ private String attractionName;
+
+ /** The city. */
+ private String city;
+
+ /** The state. */
+ private String state;
+
+ /** The location. */
+ private Location location;
+}
diff --git a/gpsMicroservice/src/main/java/gps/dto/VisitedLocationDTO.java b/gpsMicroservice/src/main/java/gps/dto/VisitedLocationDTO.java
new file mode 100644
index 0000000..ec83147
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/dto/VisitedLocationDTO.java
@@ -0,0 +1,32 @@
+package gps.dto;
+
+import java.util.Date;
+import java.util.UUID;
+
+import gps.model.Location;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+
+/**
+ * The Class VisitedLocationDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class VisitedLocationDTO {
+
+ /** The user id. */
+ private UUID userId;
+
+ /** The location. */
+ private Location location;
+
+ /** The time visited. */
+ private Date timeVisited;
+
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/exception/ErrorDetails.java b/gpsMicroservice/src/main/java/gps/exception/ErrorDetails.java
new file mode 100644
index 0000000..13c844f
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/exception/ErrorDetails.java
@@ -0,0 +1,30 @@
+package gps.exception;
+
+import java.time.LocalDateTime;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+
+/**
+ * The Class ErrorDetails.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ErrorDetails {
+
+ /** The timestamp. */
+ private LocalDateTime timestamp;
+
+ /** The message. */
+ private String message;
+
+ /** The details. */
+ private String details;
+
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/exception/GlobalExceptionHandler.java b/gpsMicroservice/src/main/java/gps/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..d7263b7
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/exception/GlobalExceptionHandler.java
@@ -0,0 +1,126 @@
+package gps.exception;
+
+import java.time.LocalDateTime;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+
+/**
+ * The Class GlobalExceptionHandler.
+ */
+@ControllerAdvice
+public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
+
+ /**
+ * GlobalExceptionHandler logger.
+ */
+ private Logger logger = LoggerFactory
+ .getLogger(GlobalExceptionHandler.class);
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Handle type mismatch.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+ public ResponseEntity handleTypeMismatch(
+ final MethodArgumentTypeMismatchException ex,
+ final WebRequest request) {
+
+ logger.error("Request - FAILED : Invalid UUID");
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ errorDetails.setMessage("Invalid UUID string");
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Handle missing path variable.
+ *
+ * @param ex the ex
+ * @param headers the headers
+ * @param status the status
+ * @param request the request
+ * @return the response entity
+ */
+ @Override
+ protected ResponseEntity handleMissingPathVariable(
+ final MissingPathVariableException ex,
+ final HttpHeaders headers, final HttpStatus status,
+ final WebRequest request) {
+ logger.error("Request - FAILED : Missing path variable: {}",
+ ex.getVariableName());
+
+ String error = ex.getVariableName() + " parameter is missing";
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getLocalizedMessage(), error);
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Handle not found.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(UserNotFoundException.class)
+ public ResponseEntity handleNotFound(
+ final UserNotFoundException ex,
+ final WebRequest request) {
+
+ logger.error("Request - FAILED :", ex);
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.NOT_FOUND);
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/exception/UserNotFoundException.java b/gpsMicroservice/src/main/java/gps/exception/UserNotFoundException.java
new file mode 100644
index 0000000..6b44a18
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/exception/UserNotFoundException.java
@@ -0,0 +1,18 @@
+package gps.exception;
+
+
+ /**
+ * The Class UserNotFoundException.
+ */
+ public class UserNotFoundException extends RuntimeException {
+
+ /**
+ * Instantiates a new user not found exception.
+ *
+ * @param message the message
+ */
+ public UserNotFoundException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/model/Location.java b/gpsMicroservice/src/main/java/gps/model/Location.java
new file mode 100644
index 0000000..d1d8d73
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/model/Location.java
@@ -0,0 +1,24 @@
+package gps.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * The Class Location.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Location {
+
+
+ /** The longitude. */
+ private double longitude;
+
+
+ /** The latitude. */
+ private double latitude;
+}
diff --git a/gpsMicroservice/src/main/java/gps/service/GpsService.java b/gpsMicroservice/src/main/java/gps/service/GpsService.java
new file mode 100644
index 0000000..69235f8
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/service/GpsService.java
@@ -0,0 +1,104 @@
+package gps.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.stereotype.Service;
+
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+import gps.exception.UserNotFoundException;
+import gps.util.GpsMapper;
+import gpsUtil.GpsUtil;
+import gpsUtil.location.Attraction;
+import gpsUtil.location.VisitedLocation;
+
+
+/**
+ * The Class GpsService.
+ */
+@Service
+public class GpsService implements IGpsService {
+
+ /** The logger. */
+// private Logger logger = LoggerFactory
+// .getLogger(GpsService.class);
+
+ /**
+ * GpsUtil instance.
+ */
+ private final GpsUtil gpsUtil;
+
+ /** The gps mapper. */
+ private final GpsMapper gpsMapper;
+
+
+ // ##############################################################
+
+
+ /**
+ * Instantiates a new gps service.
+ *
+ * @param gpsUtil the gps util
+ * @param gpsMapper the gps mapper
+ */
+ public GpsService(GpsUtil gpsUtil, GpsMapper gpsMapper) {
+ super();
+ this.gpsUtil = gpsUtil;
+ this.gpsMapper = gpsMapper;
+ }
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the user location.
+ *
+ * @param userId the user id
+ * @return the user location
+ */
+ public VisitedLocationDTO getUserLocation(final UUID userId) {
+
+// logger.debug("MicroService:GpsService.getUserLocation called");
+
+ if (userId == null) {
+ throw new UserNotFoundException("Username not found");
+ }
+ VisitedLocation visitedLocation = gpsUtil
+ .getUserLocation(userId);
+
+ return gpsMapper.toVisitedLocationDTO(visitedLocation);
+ }
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the attractions.
+ *
+ * @return the attractions
+ */
+ public List getAttractions() {
+
+// logger.debug("MicroService:GpsService.getAttractions called");
+
+ List attractionList = new ArrayList<>();
+ List attractions = gpsUtil.getAttractions();
+
+ attractions.forEach(attraction -> {
+ attractionList.add(
+ gpsMapper.toAttractionDTO(attraction));
+ });
+
+ return attractionList;
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/service/IGpsService.java b/gpsMicroservice/src/main/java/gps/service/IGpsService.java
new file mode 100644
index 0000000..8e70c28
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/service/IGpsService.java
@@ -0,0 +1,32 @@
+package gps.service;
+
+import java.util.List;
+import java.util.UUID;
+
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+
+
+/**
+ * The Interface IGpsService.
+ */
+public interface IGpsService {
+
+ /**
+ * Gets the user location.
+ *
+ * @param userId the user id
+ * @return the user location
+ */
+ VisitedLocationDTO getUserLocation(UUID userId);
+
+
+ /**
+ * Gets the attractions.
+ *
+ * @return the attractions
+ */
+ List getAttractions();
+
+
+}
diff --git a/gpsMicroservice/src/main/java/gps/util/GpsMapper.java b/gpsMicroservice/src/main/java/gps/util/GpsMapper.java
new file mode 100644
index 0000000..2c9c988
--- /dev/null
+++ b/gpsMicroservice/src/main/java/gps/util/GpsMapper.java
@@ -0,0 +1,71 @@
+package gps.util;
+
+import org.springframework.stereotype.Component;
+
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+import gps.model.Location;
+import gpsUtil.location.Attraction;
+import gpsUtil.location.VisitedLocation;
+
+
+/**
+ * The Class GpsMapper.
+ */
+@Component
+public class GpsMapper {
+
+
+ /**
+ * Instantiates a new gps mapper.
+ */
+ public GpsMapper() {
+ }
+
+ // ##############################################################
+
+
+ /**
+ * To attraction DTO.
+ *
+ * @param attraction the attraction
+ * @return the attraction DTO
+ */
+ public AttractionDTO toAttractionDTO(
+ final Attraction attraction) {
+
+ return new AttractionDTO(
+ attraction.attractionId,
+ attraction.attractionName,
+ attraction.city,
+ attraction.state,
+ new Location(attraction.longitude, attraction.latitude));
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * To visited location DTO.
+ *
+ * @param visitedLocation the visited location
+ * @return the visited location DTO
+ */
+ public VisitedLocationDTO toVisitedLocationDTO(
+ final VisitedLocation visitedLocation) {
+
+ return new VisitedLocationDTO(
+ visitedLocation.userId,
+ new Location(
+ visitedLocation.location.longitude,
+ visitedLocation.location.latitude),
+ visitedLocation.timeVisited);
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/gpsMicroservice/src/main/resources/application.properties b/gpsMicroservice/src/main/resources/application.properties
new file mode 100644
index 0000000..5d3c970
--- /dev/null
+++ b/gpsMicroservice/src/main/resources/application.properties
@@ -0,0 +1,13 @@
+
+################### APPS CONFIG ####################
+spring.application.name=gpsMicroservice
+
+
+################### SERVER HTTP PORT ####################
+server.port=9091
+
+
+################### LOG CONFIG ##########################
+logging.level.tourGuide=DEBUG
+
+
diff --git a/gpsMicroservice/src/test/java/gps/GpsMicroserviceApplicationTests.java b/gpsMicroservice/src/test/java/gps/GpsMicroserviceApplicationTests.java
new file mode 100644
index 0000000..1616d2d
--- /dev/null
+++ b/gpsMicroservice/src/test/java/gps/GpsMicroserviceApplicationTests.java
@@ -0,0 +1,13 @@
+package gps;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class GpsMicroserviceApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/gpsMicroservice/src/test/java/gps/integration/controller/GpsControllerIT.java b/gpsMicroservice/src/test/java/gps/integration/controller/GpsControllerIT.java
new file mode 100644
index 0000000..d4b2ae4
--- /dev/null
+++ b/gpsMicroservice/src/test/java/gps/integration/controller/GpsControllerIT.java
@@ -0,0 +1,176 @@
+package gps.integration.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+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.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+
+import gps.dto.VisitedLocationDTO;
+
+@DisplayName("IT - Controller - GPS - Microservice")
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class GpsControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @LocalServerPort
+ private int port;
+
+ // URL
+ private final static String ATTRACTIONS_URL = "/gps/attractions";
+
+ private final static String USER_LOCATION_URL = "/gps/userLocation/";
+
+
+ //###############################################################
+
+
+
+ @BeforeEach
+ public void setUp() {
+
+ }
+
+
+ //###############################################################
+
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) "
+ + " - Given an userId,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: 200 OK")
+ public void testGetUserLocationRequest() throws Exception {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:" + port +
+ USER_LOCATION_URL + "6551af94-3263-4253-8600-e9add493f508",
+ VisitedLocationDTO.class);
+
+
+ assertEquals(HttpStatus.OK.value(), response.getStatusCodeValue());
+ }
+
+
+
+ //###############################################################
+
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) with empty input"
+ + " - Given an userId empty,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetUserLocationRequestWithEmptyInput() throws Exception {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:" + port +
+ USER_LOCATION_URL + "",
+ VisitedLocationDTO.class);
+
+
+ assertEquals(HttpStatus.NOT_FOUND.value(), response.getStatusCodeValue());
+
+
+ }
+
+
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) with Null input"
+ + " - Given an userId null,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetUserLocationRequestWithNullInput() throws Exception {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:" + port +
+ USER_LOCATION_URL + null,
+ VisitedLocationDTO.class);
+
+
+ assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatusCodeValue());
+ }
+
+
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) with invalid input"
+ + " - Given an userId invalid,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetUserLocationRequestWithinvalideInput() throws Exception {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:" + port +
+ USER_LOCATION_URL + "sqdhfqskh",
+ VisitedLocationDTO.class);
+
+
+ assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatusCodeValue());
+ }
+
+
+
+
+
+ //###############################################################
+
+ @Test
+ @DisplayName("Check (getAttractions)"
+ + " - Given an attraction list,"
+ + " when GET getAttractions URL,"
+ + " then return - Status: 200 OK")
+ public void testGetAttractionsRequest() throws Exception {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port +
+ ATTRACTIONS_URL,
+ Object[].class);
+
+ assertNotNull(response);
+ assertThat(response.getBody().length).isGreaterThan(0);
+ assertEquals( HttpStatus.OK.value(), response.getStatusCodeValue());
+ }
+
+
+
+ //###############################################################
+
+
+
+
+}
diff --git a/gpsMicroservice/src/test/java/gps/integration/service/GpsServiceIT.java b/gpsMicroservice/src/test/java/gps/integration/service/GpsServiceIT.java
new file mode 100644
index 0000000..9126635
--- /dev/null
+++ b/gpsMicroservice/src/test/java/gps/integration/service/GpsServiceIT.java
@@ -0,0 +1,114 @@
+package gps.integration.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+import gps.exception.UserNotFoundException;
+import gps.service.GpsService;
+
+@DisplayName("IT - Service - Gps Microservice")
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+class GpsServiceIT {
+
+
+ @Autowired
+ private GpsService gpsService;
+
+
+
+ private static UUID userID;
+
+
+ // ##############################################################
+
+
+ @BeforeEach
+ public void setUp() {
+
+ userID = UUID.fromString("6551af94-3263-4253-8600-e9add493f508");
+
+
+
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given a UseID,"
+ + " when GET USER location,"
+ + " then return USER expected location match with VisitedLocationDTO")
+ @Test
+ public void testGetUserLocation() {
+
+
+ VisitedLocationDTO result = gpsService.getUserLocation(userID);
+
+ assertNotNull(result);
+ assertNotNull(result.getLocation().getLongitude());
+
+ }
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check user Null"
+ + " - Given a UseID, null"
+ + " when GET USER location,"
+ + " then return Exception thrown")
+ @Test
+ public void testGetUserLocationUserIdNullValue() {
+
+
+ assertThrows(UserNotFoundException.class, ()
+ -> gpsService.getUserLocation(null));
+ }
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check attractionList = gpsService.getAttractions();
+
+ List result = gpsService
+ .getAttractions();
+
+ assertNotNull(result);
+ assertEquals(attractionList.size(), result.size());
+ assertTrue(result.size() > 0);
+
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/gpsMicroservice/src/test/java/gps/unit/controller/GpsControllerTest.java b/gpsMicroservice/src/test/java/gps/unit/controller/GpsControllerTest.java
new file mode 100644
index 0000000..2e690cd
--- /dev/null
+++ b/gpsMicroservice/src/test/java/gps/unit/controller/GpsControllerTest.java
@@ -0,0 +1,247 @@
+package gps.unit.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import gps.controller.GpsController;
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+import gps.model.Location;
+import gps.service.IGpsService;
+
+@DisplayName("UNIT TESTS - Controller - GPS - Microservice")
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(GpsController.class)
+class GpsControllerTest {
+
+ @MockBean
+ private IGpsService gpsService;
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext context;
+
+ // URL
+ private final static String ATTRACTIONS_URL = "/gps/attractions";
+
+ private final static String USER_LOCATION_URL = "/gps/userLocation/";
+
+
+ //###############################################################
+
+
+
+ @BeforeEach
+ public void setUp() {
+
+ mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
+ }
+
+
+ //###############################################################
+
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) "
+ + " - Given an userId,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: 200 OK")
+ public void testGetUserLocationRequest() throws Exception {
+
+ UUID userId = UUID.fromString("6551af94-3263-4253-8600-e9add493f508");
+
+ VisitedLocationDTO visitedLocationDTO = new VisitedLocationDTO(
+ userId,
+ new Location(111.021844, -54.18879),
+ new Date());
+
+ when(gpsService
+ .getUserLocation(userId))
+ .thenReturn(visitedLocationDTO);
+
+ MvcResult result = mockMvc
+ .perform(MockMvcRequestBuilders
+ .get(USER_LOCATION_URL + userId)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains(userId.toString());
+ verify(gpsService).getUserLocation(userId);
+ }
+
+
+
+ //###############################################################
+
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) with empty input"
+ + " - Given an userId empty,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetUserLocationRequestWithEmptyInput() throws Exception {
+
+ MvcResult result = mockMvc
+ .perform(MockMvcRequestBuilders
+ .get(USER_LOCATION_URL + "")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isNotFound())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+
+
+ }
+
+
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) with Null input"
+ + " - Given an userId null,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetUserLocationRequestWithNullInput() throws Exception {
+
+ MvcResult result = mockMvc
+ .perform(MockMvcRequestBuilders
+ .get(USER_LOCATION_URL + null)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("Invalid UUID string");
+ }
+
+
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getUserLocation) with invalid input"
+ + " - Given an userId invalid,"
+ + " when GET getUserLocation URL,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetUserLocationRequestWithinvalideInput() throws Exception {
+
+ MvcResult result = mockMvc
+ .perform(MockMvcRequestBuilders
+ .get(USER_LOCATION_URL + "dsfsqdf")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("Invalid UUID string");
+ }
+
+
+
+
+
+ //###############################################################
+
+ @Test
+ @DisplayName("Check (getAttractions)"
+ + " - Given an attraction list,"
+ + " when GET getAttractions URL,"
+ + " then return - Status: 200 OK")
+ public void testGetAttractionsRequest() throws Exception {
+
+ AttractionDTO attraction1 = new AttractionDTO(
+ UUID.randomUUID(),
+ "testName1",
+ "testCity1" , "testState1", new Location(
+ 111.021844, -54.18879));
+
+ AttractionDTO attraction2 = new AttractionDTO(
+ UUID.randomUUID(),
+ "testName2",
+ "testCity2" ,
+ "testState2", new Location(
+ 211.021844, -54.18879));
+
+ List attractions = Arrays.asList(
+ attraction1,
+ attraction2);
+
+ when(gpsService
+ .getAttractions())
+ .thenReturn(attractions);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get(ATTRACTIONS_URL)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result.getResponse()
+ .getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("testName1");
+ assertThat(content).contains("testName2");
+ verify(gpsService).getAttractions();
+ }
+
+
+
+ //###############################################################
+
+
+
+
+}
diff --git a/gpsMicroservice/src/test/java/gps/unit/service/GpsServiceTest.java b/gpsMicroservice/src/test/java/gps/unit/service/GpsServiceTest.java
new file mode 100644
index 0000000..f4228bd
--- /dev/null
+++ b/gpsMicroservice/src/test/java/gps/unit/service/GpsServiceTest.java
@@ -0,0 +1,197 @@
+package gps.unit.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InOrder;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+import gps.exception.UserNotFoundException;
+import gps.model.Location;
+import gps.service.GpsService;
+import gps.util.GpsMapper;
+import gpsUtil.GpsUtil;
+import gpsUtil.location.Attraction;
+import gpsUtil.location.VisitedLocation;
+
+@DisplayName("Unit Test - Service - Gps Microservice")
+@ExtendWith(MockitoExtension.class)
+class GpsServiceTest {
+
+
+ @InjectMocks
+ private GpsService gpsService;
+
+ @Mock
+ private GpsUtil gpsUtil;
+
+ @Mock
+ private GpsMapper gpsMapper;
+
+ private static UUID userID;
+
+ private static gpsUtil.location.Location location1;
+
+ private static Location location2;
+
+ private static Date date;
+
+ private static VisitedLocation visitedLocation;
+
+ private static Attraction attraction1;
+
+ private static Attraction attraction2;
+
+
+
+ // ##############################################################
+
+
+ @BeforeEach
+ public void setUp() {
+
+ userID = UUID.fromString("6551af94-3263-4253-8600-e9add493f508");
+
+ date = new Date();
+
+ location1 = new gpsUtil.location.Location(111.021844, -54.18879);
+ location2 = new Location(111.021844, -54.18879);
+
+ visitedLocation = new VisitedLocation(userID, location1, date);
+
+ attraction1 = new Attraction("testName1", "testCity1" , "testState1",
+ 111.021844, -54.18879);
+ attraction2 = new Attraction("testName2", "testCity2" , "testState2",
+ 211.021844, -54.18879);
+
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given a UseID,"
+ + " when GET USER location,"
+ + " then return USER expected location match with VisitedLocationDTO")
+ @Test
+ public void testGetUserLocation() {
+
+ VisitedLocationDTO visitedLocationDTO = new VisitedLocationDTO(
+ userID,
+ location2,
+ new Date());
+
+ when(gpsUtil
+ .getUserLocation(any(UUID.class)))
+ .thenReturn(visitedLocation);
+
+ when(gpsMapper
+ .toVisitedLocationDTO(any(VisitedLocation.class)))
+ .thenReturn(visitedLocationDTO);
+
+ VisitedLocationDTO result = gpsService.getUserLocation(userID);
+
+ assertNotNull(result);
+ assertEquals(visitedLocationDTO, result);
+
+ InOrder inOrder = inOrder(gpsUtil, gpsMapper);
+ inOrder.verify(gpsUtil).getUserLocation(any(UUID.class));
+ inOrder.verify(gpsMapper).toVisitedLocationDTO(any(VisitedLocation.class));
+ }
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check user Null"
+ + " - Given a UseID, null"
+ + " when GET USER location,"
+ + " then return Exception thrown")
+ @Test
+ public void testGetUserLocationUserIdNullValue() {
+
+
+ assertThrows(UserNotFoundException.class, ()
+ -> gpsService.getUserLocation(null));
+ }
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check attractionList = Arrays.asList(
+ attraction1DTO,
+ attraction2DTO);
+
+ lenient().when(gpsUtil
+ .getAttractions())
+ .thenReturn(Arrays.asList(attraction1, attraction2));
+
+ lenient().when(gpsMapper
+ .toAttractionDTO(attraction1))
+ .thenReturn(attraction1DTO);
+
+ when(gpsMapper
+ .toAttractionDTO(attraction2))
+ .thenReturn(attraction2DTO);
+
+ List result = gpsService
+ .getAttractions();
+
+ assertNotNull(result);
+ assertEquals(attractionList, result);
+ assertEquals(2, result.size());
+
+ InOrder inOrder = inOrder(gpsUtil, gpsMapper);
+ inOrder.verify(gpsUtil).getAttractions();
+ inOrder.verify(gpsMapper, times(2)).toAttractionDTO(any(Attraction.class));
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/gpsMicroservice/src/test/java/gps/unit/util/gpsMapper.java b/gpsMicroservice/src/test/java/gps/unit/util/gpsMapper.java
new file mode 100644
index 0000000..b9929d6
--- /dev/null
+++ b/gpsMicroservice/src/test/java/gps/unit/util/gpsMapper.java
@@ -0,0 +1,134 @@
+package gps.unit.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import gps.dto.AttractionDTO;
+import gps.dto.VisitedLocationDTO;
+import gps.util.GpsMapper;
+import gpsUtil.location.Attraction;
+import gpsUtil.location.Location;
+import gpsUtil.location.VisitedLocation;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+@DisplayName("Unit Test - Mapper - Gps Microservice")
+public class gpsMapper {
+
+ private GpsMapper gpsMapper = new GpsMapper();
+
+
+ @DisplayName("Check "
+ + " - Given DTO,"
+ + " when ToVisitedLocation,"
+ + " then return DO expected")
+ @Test
+ public void testToVisitedLocation() {
+
+
+ UUID userID = UUID.randomUUID();
+ Date date = new Date();
+
+ VisitedLocation testVisitedLocation = new VisitedLocation(
+ userID,
+ new Location(-117.149048,
+ 33.817595),
+ date);
+
+
+ VisitedLocationDTO result = gpsMapper
+ .toVisitedLocationDTO(testVisitedLocation);
+
+ assertNotNull(result.getLocation());
+ assertEquals(userID, result.getUserId());
+ assertEquals(testVisitedLocation.location.latitude, result.getLocation().getLatitude());
+ assertEquals(testVisitedLocation.location.longitude, result.getLocation().getLongitude());
+ assertEquals(date, result.getTimeVisited());
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check null visited location"
+ + " - Given DTO null,"
+ + " when ToVisitedLocation,"
+ + " then return DO expected")
+ @Test
+ public void testToVisitedLocationNullValueInput() {
+
+
+ assertThrows(NullPointerException.class, ()
+ -> gpsMapper.toVisitedLocationDTO(null));
+ }
+
+
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check "
+ + " - Given DO,"
+ + " when ToAttractionDTO,"
+ + " then return DTO expected")
+ @Test
+ public void testToAttractionDTO() {
+
+
+
+ Attraction testAttraction = new Attraction(
+ "San Diego Zoo",
+ "San Diego",
+ "CA",
+ -117.149048,
+ 33.817595);
+
+
+ AttractionDTO result = gpsMapper.toAttractionDTO(testAttraction);
+
+ assertNotNull(result);
+ assertEquals(testAttraction.attractionId, result.getAttractionId());
+ assertEquals(testAttraction.attractionName, result.getAttractionName());
+ assertEquals(testAttraction.city, result.getCity());
+ assertEquals(testAttraction.state, result.getState());
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given DO,"
+ + " when ToAttractionDTO,"
+ + " then return DTO expected")
+ @Test
+ public void testToAttractionDTONullException() {
+
+
+ assertThrows(NullPointerException.class, ()
+ -> gpsMapper.toAttractionDTO(null));
+
+ }
+
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/rewardsMicroservice/Dockerfile b/rewardsMicroservice/Dockerfile
new file mode 100644
index 0000000..9e49ea2
--- /dev/null
+++ b/rewardsMicroservice/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:13-oracle
+ADD build/libs/rewardsMicroservice-1.0.0.war rewards-microservice.war
+EXPOSE 9092
+ENTRYPOINT ["java","-jar","rewards-microservice.war"]
\ No newline at end of file
diff --git a/rewardsMicroservice/build.gradle b/rewardsMicroservice/build.gradle
new file mode 100644
index 0000000..313613f
--- /dev/null
+++ b/rewardsMicroservice/build.gradle
@@ -0,0 +1,131 @@
+buildscript {
+ repositories {
+ // Maven Central for resolving dependencies
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+ }
+ dependencies {
+ // https://plugins.gradle.org/plugin/org.springframework.boot
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
+ }
+}
+
+// https://docs.gradle.org/current/samples/sample_building_java_libraries.html
+
+plugins {
+ // Apply the java-library plugin for API and implementation separation
+ id 'java-library'
+ id 'maven-publish'
+}
+
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+apply plugin: 'war'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'io.spring.dependency-management'
+apply plugin: "jacoco"
+
+
+bootWar {
+ baseName = 'rewardsMicroservice'
+ version = '1.0.0'
+}
+
+repositories {
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+}
+
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
+
+// https://stackoverflow.com/questions/23796404/could-not-find-method-compile-for-arguments-gradle
+/* Note that the compile, runtime, testCompile, and testRuntime configurations
+ introduced by the Java plugin have been deprecated since Gradle 4.10 (Aug 27, 2018),
+and were finally removed in Gradle 7.0 (Apr 9, 2021).
+The aforementioned configurations should be replaced by implementation,
+ runtimeOnly, testImplementation, and testRuntimeOnly, respectively.
+ http://man.hubwiz.com/docset/Gradle_User_Guide.docset/Contents/Resources/Documents/userguide/java_library_plugin.html
+*/
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web")
+ implementation("org.springframework.boot:spring-boot-starter-actuator")
+
+ implementation group: 'org.javamoney', name: 'moneta', version: '1.3'
+ implementation group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'
+
+ // Lombok
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
+ testCompileOnly 'org.projectlombok:lombok'
+ testAnnotationProcessor 'org.projectlombok:lombok'
+
+ implementation(name:'RewardCentral', ext:'jar')
+
+ implementation 'org.modelmapper:modelmapper:2.3.3'
+
+ // Junit
+ // testImplementation("junit:junit")
+ testImplementation 'org.springframework.boot:spring-boot-starter-web'
+ testImplementation('org.springframework.boot:spring-boot-starter-test:2.2.2.RELEASE') {
+ exclude group: 'junit'
+ exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
+ }
+
+ testImplementation("org.junit.platform:junit-platform-launcher:1.2.0")
+ testImplementation('org.junit.jupiter:junit-jupiter-api:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-engine:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-params:5.3.1')
+
+ testCompileOnly 'junit:junit:4.12'
+// testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.1'
+
+ // Use JUnit Jupiter for testing
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
+
+
+
+}
+
+test {
+ useJUnitPlatform() {
+ includeEngines 'junit-jupiter'
+ }
+
+}
+
+
+// Jacoco
+jacoco {
+ toolVersion = "0.8.4"
+}
+
+jacocoTestReport {
+ reports {
+ xml.enabled true
+ csv.enabled false
+ html.destination file("${buildDir}/jacocoHtml")
+ }
+}
+
+test.finalizedBy jacocoTestReport
+check.dependsOn jacocoTestCoverageVerification
+
+jacocoTestCoverageVerification {
+ violationRules {
+ rule {
+ limit {
+ counter = 'LINE'
+ value = 'COVEREDRATIO'
+ minimum = 0.5
+ }
+ }
+ }
+}
diff --git a/rewardsMicroservice/gradle/wrapper/gradle-wrapper.jar b/rewardsMicroservice/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7454180
Binary files /dev/null and b/rewardsMicroservice/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/rewardsMicroservice/gradle/wrapper/gradle-wrapper.properties b/rewardsMicroservice/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..84d1f85
--- /dev/null
+++ b/rewardsMicroservice/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/rewardsMicroservice/gradlew b/rewardsMicroservice/gradlew
new file mode 100644
index 0000000..1b6c787
--- /dev/null
+++ b/rewardsMicroservice/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# 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 ;; #(
+ MSYS* | 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" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/rewardsMicroservice/gradlew.bat b/rewardsMicroservice/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/rewardsMicroservice/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@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 Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@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="-Xmx64m" "-Xms64m"
+
+@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 execute
+
+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 execute
+
+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
+
+: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 %*
+
+: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/rewardsMicroservice/libs/RewardCentral.jar b/rewardsMicroservice/libs/RewardCentral.jar
new file mode 100644
index 0000000..28c99e5
Binary files /dev/null and b/rewardsMicroservice/libs/RewardCentral.jar differ
diff --git a/rewardsMicroservice/settings.gradle b/rewardsMicroservice/settings.gradle
new file mode 100644
index 0000000..711cd5d
--- /dev/null
+++ b/rewardsMicroservice/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'rewardsMicroservice'
diff --git a/rewardsMicroservice/src/main/java/rewards/RewardsMicroserviceApplication.java b/rewardsMicroservice/src/main/java/rewards/RewardsMicroserviceApplication.java
new file mode 100644
index 0000000..e50ca3b
--- /dev/null
+++ b/rewardsMicroservice/src/main/java/rewards/RewardsMicroserviceApplication.java
@@ -0,0 +1,23 @@
+package rewards;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * The Class RewardsMicroserviceApplication.
+ */
+@ComponentScan("rewards")
+@SpringBootApplication
+public class RewardsMicroserviceApplication {
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(RewardsMicroserviceApplication.class, args);
+ }
+
+}
diff --git a/rewardsMicroservice/src/main/java/rewards/config/RewardsModule.java b/rewardsMicroservice/src/main/java/rewards/config/RewardsModule.java
new file mode 100644
index 0000000..eb3c2a9
--- /dev/null
+++ b/rewardsMicroservice/src/main/java/rewards/config/RewardsModule.java
@@ -0,0 +1,52 @@
+package rewards.config;
+
+import java.util.Locale;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import rewardCentral.RewardCentral;
+
+
+/**
+ * The Class RewardsModule.
+ */
+@Configuration
+public class RewardsModule {
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the locale.
+ *
+ * @return the locale
+ */
+ @Bean
+ public Locale getLocale() {
+ Locale.setDefault(Locale.US);
+ return Locale.getDefault();
+ }
+
+
+
+
+ // ##############################################################
+
+ /**
+ * Gets the reward central.
+ *
+ * @return the reward central
+ */
+ @Bean
+ public RewardCentral getRewardCentral() {
+ return new RewardCentral();
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/rewardsMicroservice/src/main/java/rewards/controller/RewardsController.java b/rewardsMicroservice/src/main/java/rewards/controller/RewardsController.java
new file mode 100644
index 0000000..5717464
--- /dev/null
+++ b/rewardsMicroservice/src/main/java/rewards/controller/RewardsController.java
@@ -0,0 +1,80 @@
+package rewards.controller;
+
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import rewards.service.IRewardsService;
+
+/**
+ * The Class RewardsController.
+ */
+@RestController
+@RequestMapping("/rewards")
+public class RewardsController {
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(RewardsController.class);
+
+ /** The rewards service. */
+ private final IRewardsService rewardsService;
+
+ // ##############################################################
+
+
+
+ /**
+ * Instantiates a new rewards controller.
+ *
+ * @param rewardsService the rewards service
+ */
+ public RewardsController(
+ final IRewardsService rewardsService) {
+ super();
+ this.rewardsService = rewardsService;
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the reward points.
+ *
+ * @param attractionId the attraction id
+ * @param userId the user id
+ * @return the reward points
+ */
+ @GetMapping("/points/{attractionId}/{userId}")
+ public int getRewardPoints(
+ @PathVariable final UUID attractionId,
+ @PathVariable final UUID userId) {
+
+ logger.debug("GET Requested: /rewards/points/{attractionId}"
+ + "/{userId} for userId: {}", userId.toString());
+
+ int rewardsPoints = rewardsService
+ .getAttractionRewardPoints(
+ attractionId,
+ userId);
+
+ logger.debug("GET getRewardPoints execution OK");
+
+ return rewardsPoints;
+ }
+
+
+ // ##############################################################
+
+
+
+}
diff --git a/rewardsMicroservice/src/main/java/rewards/exception/ErrorDetails.java b/rewardsMicroservice/src/main/java/rewards/exception/ErrorDetails.java
new file mode 100644
index 0000000..7b0ab6e
--- /dev/null
+++ b/rewardsMicroservice/src/main/java/rewards/exception/ErrorDetails.java
@@ -0,0 +1,30 @@
+package rewards.exception;
+
+import java.time.LocalDateTime;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+
+/**
+ * The Class ErrorDetails.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ErrorDetails {
+
+ /** The timestamp. */
+ private LocalDateTime timestamp;
+
+ /** The message. */
+ private String message;
+
+ /** The details. */
+ private String details;
+
+
+}
diff --git a/rewardsMicroservice/src/main/java/rewards/exception/GlobalExceptionHandler.java b/rewardsMicroservice/src/main/java/rewards/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..78f86a1
--- /dev/null
+++ b/rewardsMicroservice/src/main/java/rewards/exception/GlobalExceptionHandler.java
@@ -0,0 +1,99 @@
+package rewards.exception;
+
+import java.time.LocalDateTime;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+
+/**
+ * The Class GlobalExceptionHandler.
+ */
+@ControllerAdvice
+public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
+
+ /**
+ * GlobalExceptionHandler logger.
+ */
+ private Logger logger = LoggerFactory
+ .getLogger(GlobalExceptionHandler.class);
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Handle type mismatch.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+ public ResponseEntity handleTypeMismatch(
+ final MethodArgumentTypeMismatchException ex,
+ final WebRequest request) {
+
+ logger.error("Request - FAILED : Invalid UUID");
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ errorDetails.setMessage("Invalid UUID string");
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Handle missing path variable.
+ *
+ * @param ex the ex
+ * @param headers the headers
+ * @param status the status
+ * @param request the request
+ * @return the response entity
+ */
+ @Override
+ protected ResponseEntity handleMissingPathVariable(
+ final MissingPathVariableException ex,
+ final HttpHeaders headers, final HttpStatus status,
+ final WebRequest request) {
+ logger.error("Request - FAILED : Missing path variable: {}",
+ ex.getVariableName());
+
+ String error = ex.getVariableName() + " parameter is missing";
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getLocalizedMessage(), error);
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+ // ##############################################################
+
+
+
+}
diff --git a/rewardsMicroservice/src/main/java/rewards/service/IRewardsService.java b/rewardsMicroservice/src/main/java/rewards/service/IRewardsService.java
new file mode 100644
index 0000000..848797e
--- /dev/null
+++ b/rewardsMicroservice/src/main/java/rewards/service/IRewardsService.java
@@ -0,0 +1,19 @@
+package rewards.service;
+
+import java.util.UUID;
+
+/**
+ * The Interface IRewardsService.
+ */
+public interface IRewardsService {
+
+ /**
+ * Gets the attraction reward points.
+ *
+ * @param attractionId the attraction id
+ * @param userId the user id
+ * @return the attraction reward points
+ */
+ int getAttractionRewardPoints(UUID attractionId, UUID userId);
+
+}
\ No newline at end of file
diff --git a/rewardsMicroservice/src/main/java/rewards/service/RewardsService.java b/rewardsMicroservice/src/main/java/rewards/service/RewardsService.java
new file mode 100644
index 0000000..1b13c8d
--- /dev/null
+++ b/rewardsMicroservice/src/main/java/rewards/service/RewardsService.java
@@ -0,0 +1,73 @@
+package rewards.service;
+
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import rewardCentral.RewardCentral;
+
+/**
+ * The Class RewardsService.
+ */
+@Service
+public class RewardsService implements IRewardsService {
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(RewardsService.class);
+
+
+ /** The reward central. */
+ private final RewardCentral rewardCentral;
+
+
+
+ // ##############################################################
+
+ /**
+ * Instantiates a new rewards service.
+ *
+ * @param rewardCentral the reward central
+ */
+ public RewardsService(RewardCentral rewardCentral) {
+ super();
+ this.rewardCentral = rewardCentral;
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the attraction reward points.
+ *
+ * @param attractionId the attraction id
+ * @param userId the user id
+ * @return the attraction reward points
+ */
+ public int getAttractionRewardPoints(
+ final UUID attractionId,
+ final UUID userId) {
+
+ logger.debug("RewardsService.getAttractionRewardPoints called");
+
+ int rewardPoints = rewardCentral.getAttractionRewardPoints(
+ attractionId,
+ userId);
+
+ return rewardPoints;
+ }
+
+
+
+ // ##############################################################
+
+
+
+}
diff --git a/rewardsMicroservice/src/main/resources/application.properties b/rewardsMicroservice/src/main/resources/application.properties
new file mode 100644
index 0000000..e4d27d0
--- /dev/null
+++ b/rewardsMicroservice/src/main/resources/application.properties
@@ -0,0 +1,14 @@
+
+################### APPS CONFIG ####################
+spring.application.name=rewardsMicroservice
+
+
+################### SERVER HTTP PORT ####################
+server.port=9092
+
+
+################### LOG CONFIG ##########################
+logging.level.tourGuide=DEBUG
+
+
+
diff --git a/rewardsMicroservice/src/test/java/rewards/RewardsMicroserviceApplicationTests.java b/rewardsMicroservice/src/test/java/rewards/RewardsMicroserviceApplicationTests.java
new file mode 100644
index 0000000..4028d6f
--- /dev/null
+++ b/rewardsMicroservice/src/test/java/rewards/RewardsMicroserviceApplicationTests.java
@@ -0,0 +1,13 @@
+package rewards;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class RewardsMicroserviceApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/rewardsMicroservice/src/test/java/rewards/integration/controller/RewardsControllerIT.java b/rewardsMicroservice/src/test/java/rewards/integration/controller/RewardsControllerIT.java
new file mode 100644
index 0000000..3c2c230
--- /dev/null
+++ b/rewardsMicroservice/src/test/java/rewards/integration/controller/RewardsControllerIT.java
@@ -0,0 +1,163 @@
+package rewards.integration.controller;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+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.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+
+@DisplayName("IT - Controller - Rewards - Microservice")
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class RewardsControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @LocalServerPort
+ private int port;
+
+
+ private final static String REWARDS_POINTS_URL = "/rewards/points/";
+
+ private UUID userId;
+
+ private UUID attractionId;
+
+
+ //###############################################################
+
+
+ @BeforeEach
+ public void setUp() {
+
+ userId = UUID.fromString("9732e7e3-943e-4169-97e1-6f171b0e86f0");
+ attractionId = UUID.fromString("cb2df5f1-0305-4f43-ad12-c664238cf411");
+
+ }
+
+
+ //###############################################################
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) "
+ + " - Given an user & attraction id,"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: 200 OK")
+ public void testGetAttractionRewardPoints() throws Exception {
+
+ ResponseEntity response = restTemplate.getForEntity(
+ "http://localhost:" + port + REWARDS_POINTS_URL
+ + userId + "/" + attractionId, Integer.class);
+
+ assertNotNull(response);
+ assertEquals(HttpStatus.OK.value(), response.getStatusCodeValue());
+
+ }
+
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) without userId "
+ + " - Given an user & attraction id, without user Id"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsWithoutUserId() throws Exception {
+
+
+ ResponseEntity response = restTemplate.getForEntity(
+ "http://localhost:" + port + REWARDS_POINTS_URL
+ + 0 + "/" + attractionId, null);
+
+ assertNotNull(response);
+ assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatusCodeValue());
+
+ }
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) without attraction "
+ + " - Given an user & attraction id, without attraction Id"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsWithoutAttractionId() throws Exception {
+
+
+ ResponseEntity response = restTemplate.getForEntity(
+ "http://localhost:" + port + REWARDS_POINTS_URL
+ + userId + "/" + 0, null);
+
+ assertNotNull(response);
+ assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatusCodeValue());
+
+ }
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) invalid userId "
+ + " - Given an user & attraction id, invalid user Id"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsWithinvalidUserId() throws Exception {
+
+
+ ResponseEntity response = restTemplate.getForEntity(
+ "http://localhost:" + port + REWARDS_POINTS_URL
+ + "fdsfsqdf" + "/" + attractionId, null);
+
+ assertNotNull(response);
+ assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatusCodeValue());
+
+ }
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) invalid attractionId "
+ + " - Given an user & attraction id, invalid attractionId"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsWithinvalidAttractionId() throws Exception {
+
+
+ ResponseEntity response = restTemplate.getForEntity(
+ "http://localhost:" + port + REWARDS_POINTS_URL
+ + userId + "/" + "fsqdfsqdf", null);
+
+ assertNotNull(response);
+ assertEquals(HttpStatus.BAD_REQUEST.value(), response.getStatusCodeValue());
+
+ }
+
+
+ //###############################################################
+
+
+
+}
diff --git a/rewardsMicroservice/src/test/java/rewards/unit/controller/RewardsControllerTest.java b/rewardsMicroservice/src/test/java/rewards/unit/controller/RewardsControllerTest.java
new file mode 100644
index 0000000..3d8d183
--- /dev/null
+++ b/rewardsMicroservice/src/test/java/rewards/unit/controller/RewardsControllerTest.java
@@ -0,0 +1,222 @@
+package rewards.unit.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import rewards.controller.RewardsController;
+import rewards.service.IRewardsService;
+
+
+@DisplayName("UNIT TESTS - Controller - Rewards - Microservice")
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(RewardsController.class)
+//@ContextConfiguration(classes = { GlobalExceptionHandler.class })
+class RewardsControllerTest {
+
+ @MockBean
+ private IRewardsService rewardsService;
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext context;
+
+ private UUID userId;
+
+ private UUID attractionId;
+
+ @BeforeEach
+ public void setUp() {
+
+ userId = UUID.fromString("9732e7e3-943e-4169-97e1-6f171b0e86f0");
+ attractionId = UUID.fromString("cb2df5f1-0305-4f43-ad12-c664238cf411");
+
+ mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
+ }
+
+
+
+ //###############################################################
+
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) "
+ + " - Given an user & attraction id,"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: 200 OK")
+ public void testGetAttractionRewardPoints() throws Exception {
+
+ when(rewardsService
+ .getAttractionRewardPoints(attractionId, userId))
+ .thenReturn(500);
+
+ MvcResult result = mockMvc.perform(
+ MockMvcRequestBuilders
+ .get("/rewards/points/" + attractionId + "/" + userId)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertThat(content).contains("500");
+ verify(rewardsService).getAttractionRewardPoints(attractionId, userId);
+ }
+
+
+
+
+ //###############################################################
+
+
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) without userId "
+ + " - Given an user & attraction id, without user Id"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsWithoutUserId() throws Exception {
+
+
+ MvcResult result = mockMvc.perform(
+ MockMvcRequestBuilders
+ .get("/rewards/points/" + attractionId + "/")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isNotFound())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+
+ }
+
+
+
+
+ //###############################################################
+
+
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) without Ids input "
+ + " - Given an user & attraction id, without input Ids"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsWithoutParameters() throws Exception {
+
+
+ MvcResult result = mockMvc.perform(
+ MockMvcRequestBuilders
+ .get("/rewards/points/")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isNotFound())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+
+ }
+
+
+
+
+ //###############################################################
+
+
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) null Ids input "
+ + " - Given an user & attraction id, null Ids"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsNullInput() throws Exception {
+
+
+ MvcResult result = mockMvc.perform(
+ MockMvcRequestBuilders
+ .get("/rewards/points/" + null + "/" + null)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("Invalid UUID string");
+
+
+ }
+
+
+
+
+ //###############################################################
+
+
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) invalid input "
+ + " - Given an user & attraction id, invalid Ids"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetAttractionRewardPointsInvalidInput() throws Exception {
+
+
+ MvcResult result = mockMvc.perform(
+ MockMvcRequestBuilders
+ .get("/rewards/points/" + "9732e7e3" + "/" + "9732e7e3")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("Invalid UUID string");
+
+
+ }
+
+
+
+
+ //###############################################################
+
+
+
+
+
+}
diff --git a/rewardsMicroservice/src/test/java/rewards/unit/service/RewardsServiceTest.java b/rewardsMicroservice/src/test/java/rewards/unit/service/RewardsServiceTest.java
new file mode 100644
index 0000000..76de90d
--- /dev/null
+++ b/rewardsMicroservice/src/test/java/rewards/unit/service/RewardsServiceTest.java
@@ -0,0 +1,70 @@
+package rewards.unit.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import rewardCentral.RewardCentral;
+import rewards.service.RewardsService;
+
+@DisplayName("Unit Test - Service - Rewards Microservice")
+@ExtendWith(MockitoExtension.class)
+class RewardsServiceTest {
+
+
+ @InjectMocks
+ private RewardsService rewardsService;
+
+ @Mock
+ private RewardCentral rewardCentral;
+
+
+
+
+ //###############################################################
+
+
+
+
+ @Test
+ @DisplayName("Check (getAttractionRewardPoints) "
+ + " - Given an user & attraction id,"
+ + " when GET getAttractionRewardPoints,"
+ + " then return - reward points as expected")
+ public void testGetAttractionRewardPoints() {
+
+ UUID userID = UUID.randomUUID();
+ UUID attractionID = UUID.randomUUID();
+ int rewardsPoints = 500;
+
+ when(rewardCentral
+ .getAttractionRewardPoints(
+ userID,
+ attractionID))
+ .thenReturn(rewardsPoints);
+
+ int result = rewardsService
+ .getAttractionRewardPoints(
+ userID,
+ attractionID);
+
+ assertEquals(rewardsPoints, result);
+ verify(rewardCentral).getAttractionRewardPoints(userID, attractionID);
+ }
+
+
+
+ //###############################################################
+
+
+
+}
diff --git a/src/main/java/tourGuide/Application.java b/src/main/java/tourGuide/Application.java
deleted file mode 100644
index e0a07cd..0000000
--- a/src/main/java/tourGuide/Application.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package tourGuide;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class Application {
-
- public static void main(String[] args) {
- SpringApplication.run(Application.class, args);
- }
-
-}
diff --git a/src/main/java/tourGuide/TourGuideController.java b/src/main/java/tourGuide/TourGuideController.java
deleted file mode 100644
index 8725e46..0000000
--- a/src/main/java/tourGuide/TourGuideController.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package tourGuide;
-
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.jsoniter.output.JsonStream;
-
-import gpsUtil.location.VisitedLocation;
-import tourGuide.service.TourGuideService;
-import tourGuide.user.User;
-import tripPricer.Provider;
-
-@RestController
-public class TourGuideController {
-
- @Autowired
- TourGuideService tourGuideService;
-
- @RequestMapping("/")
- public String index() {
- return "Greetings from TourGuide!";
- }
-
- @RequestMapping("/getLocation")
- public String getLocation(@RequestParam String userName) {
- VisitedLocation visitedLocation = tourGuideService.getUserLocation(getUser(userName));
- return JsonStream.serialize(visitedLocation.location);
- }
-
- // TODO: Change this method to no longer return a List of Attractions.
- // Instead: Get the closest five tourist attractions to the user - no matter how far away they are.
- // Return a new JSON object that contains:
- // Name of Tourist attraction,
- // Tourist attractions lat/long,
- // The user's location lat/long,
- // The distance in miles between the user's location and each of the attractions.
- // The reward points for visiting each Attraction.
- // Note: Attraction reward points can be gathered from RewardsCentral
- @RequestMapping("/getNearbyAttractions")
- public String getNearbyAttractions(@RequestParam String userName) {
- VisitedLocation visitedLocation = tourGuideService.getUserLocation(getUser(userName));
- return JsonStream.serialize(tourGuideService.getNearByAttractions(visitedLocation));
- }
-
- @RequestMapping("/getRewards")
- public String getRewards(@RequestParam String userName) {
- return JsonStream.serialize(tourGuideService.getUserRewards(getUser(userName)));
- }
-
- @RequestMapping("/getAllCurrentLocations")
- public String getAllCurrentLocations() {
- // TODO: Get a list of every user's most recent location as JSON
- //- Note: does not use gpsUtil to query for their current location,
- // but rather gathers the user's current location from their stored location history.
- //
- // Return object should be the just a JSON mapping of userId to Locations similar to:
- // {
- // "019b04a9-067a-4c76-8817-ee75088c3822": {"longitude":-48.188821,"latitude":74.84371}
- // ...
- // }
-
- return JsonStream.serialize("");
- }
-
- @RequestMapping("/getTripDeals")
- public String getTripDeals(@RequestParam String userName) {
- List providers = tourGuideService.getTripDeals(getUser(userName));
- return JsonStream.serialize(providers);
- }
-
- private User getUser(String userName) {
- return tourGuideService.getUser(userName);
- }
-
-
-}
\ No newline at end of file
diff --git a/src/main/java/tourGuide/TourGuideModule.java b/src/main/java/tourGuide/TourGuideModule.java
deleted file mode 100644
index 4a8791b..0000000
--- a/src/main/java/tourGuide/TourGuideModule.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package tourGuide;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import gpsUtil.GpsUtil;
-import rewardCentral.RewardCentral;
-import tourGuide.service.RewardsService;
-
-@Configuration
-public class TourGuideModule {
-
- @Bean
- public GpsUtil getGpsUtil() {
- return new GpsUtil();
- }
-
- @Bean
- public RewardsService getRewardsService() {
- return new RewardsService(getGpsUtil(), getRewardCentral());
- }
-
- @Bean
- public RewardCentral getRewardCentral() {
- return new RewardCentral();
- }
-
-}
diff --git a/src/main/java/tourGuide/helper/InternalTestHelper.java b/src/main/java/tourGuide/helper/InternalTestHelper.java
deleted file mode 100644
index f86f6b7..0000000
--- a/src/main/java/tourGuide/helper/InternalTestHelper.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package tourGuide.helper;
-
-public class InternalTestHelper {
-
- // Set this default up to 100,000 for testing
- private static int internalUserNumber = 100;
-
- public static void setInternalUserNumber(int internalUserNumber) {
- InternalTestHelper.internalUserNumber = internalUserNumber;
- }
-
- public static int getInternalUserNumber() {
- return internalUserNumber;
- }
-}
diff --git a/src/main/java/tourGuide/service/RewardsService.java b/src/main/java/tourGuide/service/RewardsService.java
deleted file mode 100644
index fc6342b..0000000
--- a/src/main/java/tourGuide/service/RewardsService.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package tourGuide.service;
-
-import java.util.List;
-
-import org.springframework.stereotype.Service;
-
-import gpsUtil.GpsUtil;
-import gpsUtil.location.Attraction;
-import gpsUtil.location.Location;
-import gpsUtil.location.VisitedLocation;
-import rewardCentral.RewardCentral;
-import tourGuide.user.User;
-import tourGuide.user.UserReward;
-
-@Service
-public class RewardsService {
- private static final double STATUTE_MILES_PER_NAUTICAL_MILE = 1.15077945;
-
- // proximity in miles
- private int defaultProximityBuffer = 10;
- private int proximityBuffer = defaultProximityBuffer;
- private int attractionProximityRange = 200;
- private final GpsUtil gpsUtil;
- private final RewardCentral rewardsCentral;
-
- public RewardsService(GpsUtil gpsUtil, RewardCentral rewardCentral) {
- this.gpsUtil = gpsUtil;
- this.rewardsCentral = rewardCentral;
- }
-
- public void setProximityBuffer(int proximityBuffer) {
- this.proximityBuffer = proximityBuffer;
- }
-
- public void setDefaultProximityBuffer() {
- proximityBuffer = defaultProximityBuffer;
- }
-
- public void calculateRewards(User user) {
- List userLocations = user.getVisitedLocations();
- List attractions = gpsUtil.getAttractions();
-
- for(VisitedLocation visitedLocation : userLocations) {
- for(Attraction attraction : attractions) {
- if(user.getUserRewards().stream().filter(r -> r.attraction.attractionName.equals(attraction.attractionName)).count() == 0) {
- if(nearAttraction(visitedLocation, attraction)) {
- user.addUserReward(new UserReward(visitedLocation, attraction, getRewardPoints(attraction, user)));
- }
- }
- }
- }
- }
-
- public boolean isWithinAttractionProximity(Attraction attraction, Location location) {
- return getDistance(attraction, location) > attractionProximityRange ? false : true;
- }
-
- private boolean nearAttraction(VisitedLocation visitedLocation, Attraction attraction) {
- return getDistance(attraction, visitedLocation.location) > proximityBuffer ? false : true;
- }
-
- private int getRewardPoints(Attraction attraction, User user) {
- return rewardsCentral.getAttractionRewardPoints(attraction.attractionId, user.getUserId());
- }
-
- public double getDistance(Location loc1, Location loc2) {
- double lat1 = Math.toRadians(loc1.latitude);
- double lon1 = Math.toRadians(loc1.longitude);
- double lat2 = Math.toRadians(loc2.latitude);
- double lon2 = Math.toRadians(loc2.longitude);
-
- double angle = Math.acos(Math.sin(lat1) * Math.sin(lat2)
- + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
-
- double nauticalMiles = 60 * Math.toDegrees(angle);
- double statuteMiles = STATUTE_MILES_PER_NAUTICAL_MILE * nauticalMiles;
- return statuteMiles;
- }
-
-}
diff --git a/src/main/java/tourGuide/service/TourGuideService.java b/src/main/java/tourGuide/service/TourGuideService.java
deleted file mode 100644
index b487164..0000000
--- a/src/main/java/tourGuide/service/TourGuideService.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package tourGuide.service;
-
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Random;
-import java.util.UUID;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import gpsUtil.GpsUtil;
-import gpsUtil.location.Attraction;
-import gpsUtil.location.Location;
-import gpsUtil.location.VisitedLocation;
-import tourGuide.helper.InternalTestHelper;
-import tourGuide.tracker.Tracker;
-import tourGuide.user.User;
-import tourGuide.user.UserReward;
-import tripPricer.Provider;
-import tripPricer.TripPricer;
-
-@Service
-public class TourGuideService {
- private Logger logger = LoggerFactory.getLogger(TourGuideService.class);
- private final GpsUtil gpsUtil;
- private final RewardsService rewardsService;
- private final TripPricer tripPricer = new TripPricer();
- public final Tracker tracker;
- boolean testMode = true;
-
- public TourGuideService(GpsUtil gpsUtil, RewardsService rewardsService) {
- this.gpsUtil = gpsUtil;
- this.rewardsService = rewardsService;
-
- if(testMode) {
- logger.info("TestMode enabled");
- logger.debug("Initializing users");
- initializeInternalUsers();
- logger.debug("Finished initializing users");
- }
- tracker = new Tracker(this);
- addShutDownHook();
- }
-
- public List getUserRewards(User user) {
- return user.getUserRewards();
- }
-
- public VisitedLocation getUserLocation(User user) {
- VisitedLocation visitedLocation = (user.getVisitedLocations().size() > 0) ?
- user.getLastVisitedLocation() :
- trackUserLocation(user);
- return visitedLocation;
- }
-
- public User getUser(String userName) {
- return internalUserMap.get(userName);
- }
-
- public List getAllUsers() {
- return internalUserMap.values().stream().collect(Collectors.toList());
- }
-
- public void addUser(User user) {
- if(!internalUserMap.containsKey(user.getUserName())) {
- internalUserMap.put(user.getUserName(), user);
- }
- }
-
- public List getTripDeals(User user) {
- int cumulatativeRewardPoints = user.getUserRewards().stream().mapToInt(i -> i.getRewardPoints()).sum();
- List providers = tripPricer.getPrice(tripPricerApiKey, user.getUserId(), user.getUserPreferences().getNumberOfAdults(),
- user.getUserPreferences().getNumberOfChildren(), user.getUserPreferences().getTripDuration(), cumulatativeRewardPoints);
- user.setTripDeals(providers);
- return providers;
- }
-
- public VisitedLocation trackUserLocation(User user) {
- VisitedLocation visitedLocation = gpsUtil.getUserLocation(user.getUserId());
- user.addToVisitedLocations(visitedLocation);
- rewardsService.calculateRewards(user);
- return visitedLocation;
- }
-
- public List getNearByAttractions(VisitedLocation visitedLocation) {
- List nearbyAttractions = new ArrayList<>();
- for(Attraction attraction : gpsUtil.getAttractions()) {
- if(rewardsService.isWithinAttractionProximity(attraction, visitedLocation.location)) {
- nearbyAttractions.add(attraction);
- }
- }
-
- return nearbyAttractions;
- }
-
- private void addShutDownHook() {
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void run() {
- tracker.stopTracking();
- }
- });
- }
-
- /**********************************************************************************
- *
- * Methods Below: For Internal Testing
- *
- **********************************************************************************/
- private static final String tripPricerApiKey = "test-server-api-key";
- // Database connection will be used for external users, but for testing purposes internal users are provided and stored in memory
- private final Map internalUserMap = new HashMap<>();
- private void initializeInternalUsers() {
- IntStream.range(0, InternalTestHelper.getInternalUserNumber()).forEach(i -> {
- String userName = "internalUser" + i;
- String phone = "000";
- String email = userName + "@tourGuide.com";
- User user = new User(UUID.randomUUID(), userName, phone, email);
- generateUserLocationHistory(user);
-
- internalUserMap.put(userName, user);
- });
- logger.debug("Created " + InternalTestHelper.getInternalUserNumber() + " internal test users.");
- }
-
- private void generateUserLocationHistory(User user) {
- IntStream.range(0, 3).forEach(i-> {
- user.addToVisitedLocations(new VisitedLocation(user.getUserId(), new Location(generateRandomLatitude(), generateRandomLongitude()), getRandomTime()));
- });
- }
-
- private double generateRandomLongitude() {
- double leftLimit = -180;
- double rightLimit = 180;
- return leftLimit + new Random().nextDouble() * (rightLimit - leftLimit);
- }
-
- private double generateRandomLatitude() {
- double leftLimit = -85.05112878;
- double rightLimit = 85.05112878;
- return leftLimit + new Random().nextDouble() * (rightLimit - leftLimit);
- }
-
- private Date getRandomTime() {
- LocalDateTime localDateTime = LocalDateTime.now().minusDays(new Random().nextInt(30));
- return Date.from(localDateTime.toInstant(ZoneOffset.UTC));
- }
-
-}
diff --git a/src/main/java/tourGuide/tracker/Tracker.java b/src/main/java/tourGuide/tracker/Tracker.java
deleted file mode 100644
index 843f7cb..0000000
--- a/src/main/java/tourGuide/tracker/Tracker.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package tourGuide.tracker;
-
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.lang3.time.StopWatch;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import tourGuide.service.TourGuideService;
-import tourGuide.user.User;
-
-public class Tracker extends Thread {
- private Logger logger = LoggerFactory.getLogger(Tracker.class);
- private static final long trackingPollingInterval = TimeUnit.MINUTES.toSeconds(5);
- private final ExecutorService executorService = Executors.newSingleThreadExecutor();
- private final TourGuideService tourGuideService;
- private boolean stop = false;
-
- public Tracker(TourGuideService tourGuideService) {
- this.tourGuideService = tourGuideService;
-
- executorService.submit(this);
- }
-
- /**
- * Assures to shut down the Tracker thread
- */
- public void stopTracking() {
- stop = true;
- executorService.shutdownNow();
- }
-
- @Override
- public void run() {
- StopWatch stopWatch = new StopWatch();
- while(true) {
- if(Thread.currentThread().isInterrupted() || stop) {
- logger.debug("Tracker stopping");
- break;
- }
-
- List users = tourGuideService.getAllUsers();
- logger.debug("Begin Tracker. Tracking " + users.size() + " users.");
- stopWatch.start();
- users.forEach(u -> tourGuideService.trackUserLocation(u));
- stopWatch.stop();
- logger.debug("Tracker Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds.");
- stopWatch.reset();
- try {
- logger.debug("Tracker sleeping");
- TimeUnit.SECONDS.sleep(trackingPollingInterval);
- } catch (InterruptedException e) {
- break;
- }
- }
-
- }
-}
diff --git a/src/main/java/tourGuide/user/User.java b/src/main/java/tourGuide/user/User.java
deleted file mode 100644
index a69ffbb..0000000
--- a/src/main/java/tourGuide/user/User.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package tourGuide.user;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-
-import gpsUtil.location.VisitedLocation;
-import tripPricer.Provider;
-
-public class User {
- private final UUID userId;
- private final String userName;
- private String phoneNumber;
- private String emailAddress;
- private Date latestLocationTimestamp;
- private List visitedLocations = new ArrayList<>();
- private List userRewards = new ArrayList<>();
- private UserPreferences userPreferences = new UserPreferences();
- private List tripDeals = new ArrayList<>();
- public User(UUID userId, String userName, String phoneNumber, String emailAddress) {
- this.userId = userId;
- this.userName = userName;
- this.phoneNumber = phoneNumber;
- this.emailAddress = emailAddress;
- }
-
- public UUID getUserId() {
- return userId;
- }
-
- public String getUserName() {
- return userName;
- }
-
- public void setPhoneNumber(String phoneNumber) {
- this.phoneNumber = phoneNumber;
- }
-
- public String getPhoneNumber() {
- return phoneNumber;
- }
-
- public void setEmailAddress(String emailAddress) {
- this.emailAddress = emailAddress;
- }
-
- public String getEmailAddress() {
- return emailAddress;
- }
-
- public void setLatestLocationTimestamp(Date latestLocationTimestamp) {
- this.latestLocationTimestamp = latestLocationTimestamp;
- }
-
- public Date getLatestLocationTimestamp() {
- return latestLocationTimestamp;
- }
-
- public void addToVisitedLocations(VisitedLocation visitedLocation) {
- visitedLocations.add(visitedLocation);
- }
-
- public List getVisitedLocations() {
- return visitedLocations;
- }
-
- public void clearVisitedLocations() {
- visitedLocations.clear();
- }
-
- public void addUserReward(UserReward userReward) {
- if(userRewards.stream().filter(r -> !r.attraction.attractionName.equals(userReward.attraction)).count() == 0) {
- userRewards.add(userReward);
- }
- }
-
- public List getUserRewards() {
- return userRewards;
- }
-
- public UserPreferences getUserPreferences() {
- return userPreferences;
- }
-
- public void setUserPreferences(UserPreferences userPreferences) {
- this.userPreferences = userPreferences;
- }
-
- public VisitedLocation getLastVisitedLocation() {
- return visitedLocations.get(visitedLocations.size() - 1);
- }
-
- public void setTripDeals(List tripDeals) {
- this.tripDeals = tripDeals;
- }
-
- public List getTripDeals() {
- return tripDeals;
- }
-
-}
diff --git a/src/main/java/tourGuide/user/UserPreferences.java b/src/main/java/tourGuide/user/UserPreferences.java
deleted file mode 100644
index 947f242..0000000
--- a/src/main/java/tourGuide/user/UserPreferences.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package tourGuide.user;
-
-import javax.money.CurrencyUnit;
-import javax.money.Monetary;
-
-import org.javamoney.moneta.Money;
-
-
-public class UserPreferences {
-
- private int attractionProximity = Integer.MAX_VALUE;
- private CurrencyUnit currency = Monetary.getCurrency("USD");
- private Money lowerPricePoint = Money.of(0, currency);
- private Money highPricePoint = Money.of(Integer.MAX_VALUE, currency);
- private int tripDuration = 1;
- private int ticketQuantity = 1;
- private int numberOfAdults = 1;
- private int numberOfChildren = 0;
-
- public UserPreferences() {
- }
-
- public void setAttractionProximity(int attractionProximity) {
- this.attractionProximity = attractionProximity;
- }
-
- public int getAttractionProximity() {
- return attractionProximity;
- }
-
- public Money getLowerPricePoint() {
- return lowerPricePoint;
- }
-
- public void setLowerPricePoint(Money lowerPricePoint) {
- this.lowerPricePoint = lowerPricePoint;
- }
-
- public Money getHighPricePoint() {
- return highPricePoint;
- }
-
- public void setHighPricePoint(Money highPricePoint) {
- this.highPricePoint = highPricePoint;
- }
-
- public int getTripDuration() {
- return tripDuration;
- }
-
- public void setTripDuration(int tripDuration) {
- this.tripDuration = tripDuration;
- }
-
- public int getTicketQuantity() {
- return ticketQuantity;
- }
-
- public void setTicketQuantity(int ticketQuantity) {
- this.ticketQuantity = ticketQuantity;
- }
-
- public int getNumberOfAdults() {
- return numberOfAdults;
- }
-
- public void setNumberOfAdults(int numberOfAdults) {
- this.numberOfAdults = numberOfAdults;
- }
-
- public int getNumberOfChildren() {
- return numberOfChildren;
- }
-
- public void setNumberOfChildren(int numberOfChildren) {
- this.numberOfChildren = numberOfChildren;
- }
-
-}
diff --git a/src/main/java/tourGuide/user/UserReward.java b/src/main/java/tourGuide/user/UserReward.java
deleted file mode 100644
index a6faee4..0000000
--- a/src/main/java/tourGuide/user/UserReward.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package tourGuide.user;
-
-import gpsUtil.location.Attraction;
-import gpsUtil.location.VisitedLocation;
-
-public class UserReward {
-
- public final VisitedLocation visitedLocation;
- public final Attraction attraction;
- private int rewardPoints;
- public UserReward(VisitedLocation visitedLocation, Attraction attraction, int rewardPoints) {
- this.visitedLocation = visitedLocation;
- this.attraction = attraction;
- this.rewardPoints = rewardPoints;
- }
-
- public UserReward(VisitedLocation visitedLocation, Attraction attraction) {
- this.visitedLocation = visitedLocation;
- this.attraction = attraction;
- }
-
- public void setRewardPoints(int rewardPoints) {
- this.rewardPoints = rewardPoints;
- }
-
- public int getRewardPoints() {
- return rewardPoints;
- }
-
-}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
deleted file mode 100644
index 02a4935..0000000
--- a/src/main/resources/application.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-
-logging.level.tourGuide=DEBUG
diff --git a/src/test/java/tourGuide/TestPerformance.java b/src/test/java/tourGuide/TestPerformance.java
deleted file mode 100644
index 4b4dee9..0000000
--- a/src/test/java/tourGuide/TestPerformance.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package tourGuide;
-
-import static org.junit.Assert.assertTrue;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.lang3.time.StopWatch;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import gpsUtil.GpsUtil;
-import gpsUtil.location.Attraction;
-import gpsUtil.location.VisitedLocation;
-import rewardCentral.RewardCentral;
-import tourGuide.helper.InternalTestHelper;
-import tourGuide.service.RewardsService;
-import tourGuide.service.TourGuideService;
-import tourGuide.user.User;
-import tourGuide.user.UserReward;
-
-public class TestPerformance {
-
- /*
- * A note on performance improvements:
- *
- * The number of users generated for the high volume tests can be easily adjusted via this method:
- *
- * InternalTestHelper.setInternalUserNumber(100000);
- *
- *
- * These tests can be modified to suit new solutions, just as long as the performance metrics
- * at the end of the tests remains consistent.
- *
- * These are performance metrics that we are trying to hit:
- *
- * highVolumeTrackLocation: 100,000 users within 15 minutes:
- * assertTrue(TimeUnit.MINUTES.toSeconds(15) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
- *
- * highVolumeGetRewards: 100,000 users within 20 minutes:
- * assertTrue(TimeUnit.MINUTES.toSeconds(20) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
- */
-
- @Ignore
- @Test
- public void highVolumeTrackLocation() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- // Users should be incremented up to 100,000, and test finishes within 15 minutes
- InternalTestHelper.setInternalUserNumber(100);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- List allUsers = new ArrayList<>();
- allUsers = tourGuideService.getAllUsers();
-
- StopWatch stopWatch = new StopWatch();
- stopWatch.start();
- for(User user : allUsers) {
- tourGuideService.trackUserLocation(user);
- }
- stopWatch.stop();
- tourGuideService.tracker.stopTracking();
-
- System.out.println("highVolumeTrackLocation: Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds.");
- assertTrue(TimeUnit.MINUTES.toSeconds(15) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
- }
-
- @Ignore
- @Test
- public void highVolumeGetRewards() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
-
- // Users should be incremented up to 100,000, and test finishes within 20 minutes
- InternalTestHelper.setInternalUserNumber(100);
- StopWatch stopWatch = new StopWatch();
- stopWatch.start();
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- Attraction attraction = gpsUtil.getAttractions().get(0);
- List allUsers = new ArrayList<>();
- allUsers = tourGuideService.getAllUsers();
- allUsers.forEach(u -> u.addToVisitedLocations(new VisitedLocation(u.getUserId(), attraction, new Date())));
-
- allUsers.forEach(u -> rewardsService.calculateRewards(u));
-
- for(User user : allUsers) {
- assertTrue(user.getUserRewards().size() > 0);
- }
- stopWatch.stop();
- tourGuideService.tracker.stopTracking();
-
- System.out.println("highVolumeGetRewards: Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds.");
- assertTrue(TimeUnit.MINUTES.toSeconds(20) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
- }
-
-}
diff --git a/src/test/java/tourGuide/TestRewardsService.java b/src/test/java/tourGuide/TestRewardsService.java
deleted file mode 100644
index 8871365..0000000
--- a/src/test/java/tourGuide/TestRewardsService.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package tourGuide;
-
-import static org.junit.Assert.*;
-
-import java.util.Date;
-import java.util.List;
-import java.util.UUID;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-import gpsUtil.GpsUtil;
-import gpsUtil.location.Attraction;
-import gpsUtil.location.VisitedLocation;
-import rewardCentral.RewardCentral;
-import tourGuide.helper.InternalTestHelper;
-import tourGuide.service.RewardsService;
-import tourGuide.service.TourGuideService;
-import tourGuide.user.User;
-import tourGuide.user.UserReward;
-
-public class TestRewardsService {
-
- @Test
- public void userGetRewards() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
-
- InternalTestHelper.setInternalUserNumber(0);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com");
- Attraction attraction = gpsUtil.getAttractions().get(0);
- user.addToVisitedLocations(new VisitedLocation(user.getUserId(), attraction, new Date()));
- tourGuideService.trackUserLocation(user);
- List userRewards = user.getUserRewards();
- tourGuideService.tracker.stopTracking();
- assertTrue(userRewards.size() == 1);
- }
-
- @Test
- public void isWithinAttractionProximity() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- Attraction attraction = gpsUtil.getAttractions().get(0);
- assertTrue(rewardsService.isWithinAttractionProximity(attraction, attraction));
- }
-
- @Ignore // Needs fixed - can throw ConcurrentModificationException
- @Test
- public void nearAllAttractions() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- rewardsService.setProximityBuffer(Integer.MAX_VALUE);
-
- InternalTestHelper.setInternalUserNumber(1);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- rewardsService.calculateRewards(tourGuideService.getAllUsers().get(0));
- List userRewards = tourGuideService.getUserRewards(tourGuideService.getAllUsers().get(0));
- tourGuideService.tracker.stopTracking();
-
- assertEquals(gpsUtil.getAttractions().size(), userRewards.size());
- }
-
-}
diff --git a/src/test/java/tourGuide/TestTourGuideService.java b/src/test/java/tourGuide/TestTourGuideService.java
deleted file mode 100644
index ade2c1f..0000000
--- a/src/test/java/tourGuide/TestTourGuideService.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package tourGuide;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.util.List;
-import java.util.UUID;
-
-import org.junit.Ignore;
-import org.junit.Test;
-
-import gpsUtil.GpsUtil;
-import gpsUtil.location.Attraction;
-import gpsUtil.location.VisitedLocation;
-import rewardCentral.RewardCentral;
-import tourGuide.helper.InternalTestHelper;
-import tourGuide.service.RewardsService;
-import tourGuide.service.TourGuideService;
-import tourGuide.user.User;
-import tripPricer.Provider;
-
-public class TestTourGuideService {
-
- @Test
- public void getUserLocation() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- InternalTestHelper.setInternalUserNumber(0);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com");
- VisitedLocation visitedLocation = tourGuideService.trackUserLocation(user);
- tourGuideService.tracker.stopTracking();
- assertTrue(visitedLocation.userId.equals(user.getUserId()));
- }
-
- @Test
- public void addUser() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- InternalTestHelper.setInternalUserNumber(0);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com");
- User user2 = new User(UUID.randomUUID(), "jon2", "000", "jon2@tourGuide.com");
-
- tourGuideService.addUser(user);
- tourGuideService.addUser(user2);
-
- User retrivedUser = tourGuideService.getUser(user.getUserName());
- User retrivedUser2 = tourGuideService.getUser(user2.getUserName());
-
- tourGuideService.tracker.stopTracking();
-
- assertEquals(user, retrivedUser);
- assertEquals(user2, retrivedUser2);
- }
-
- @Test
- public void getAllUsers() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- InternalTestHelper.setInternalUserNumber(0);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com");
- User user2 = new User(UUID.randomUUID(), "jon2", "000", "jon2@tourGuide.com");
-
- tourGuideService.addUser(user);
- tourGuideService.addUser(user2);
-
- List allUsers = tourGuideService.getAllUsers();
-
- tourGuideService.tracker.stopTracking();
-
- assertTrue(allUsers.contains(user));
- assertTrue(allUsers.contains(user2));
- }
-
- @Test
- public void trackUser() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- InternalTestHelper.setInternalUserNumber(0);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com");
- VisitedLocation visitedLocation = tourGuideService.trackUserLocation(user);
-
- tourGuideService.tracker.stopTracking();
-
- assertEquals(user.getUserId(), visitedLocation.userId);
- }
-
- @Ignore // Not yet implemented
- @Test
- public void getNearbyAttractions() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- InternalTestHelper.setInternalUserNumber(0);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com");
- VisitedLocation visitedLocation = tourGuideService.trackUserLocation(user);
-
- List attractions = tourGuideService.getNearByAttractions(visitedLocation);
-
- tourGuideService.tracker.stopTracking();
-
- assertEquals(5, attractions.size());
- }
-
- public void getTripDeals() {
- GpsUtil gpsUtil = new GpsUtil();
- RewardsService rewardsService = new RewardsService(gpsUtil, new RewardCentral());
- InternalTestHelper.setInternalUserNumber(0);
- TourGuideService tourGuideService = new TourGuideService(gpsUtil, rewardsService);
-
- User user = new User(UUID.randomUUID(), "jon", "000", "jon@tourGuide.com");
-
- List providers = tourGuideService.getTripDeals(user);
-
- tourGuideService.tracker.stopTracking();
-
- assertEquals(10, providers.size());
- }
-
-
-}
diff --git a/tourguide/Dockerfile b/tourguide/Dockerfile
new file mode 100644
index 0000000..1c1423d
--- /dev/null
+++ b/tourguide/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:13-oracle
+EXPOSE 9090
+ADD build/libs/tourguide-1.0.0.war tourguide.war
+ENTRYPOINT ["java","-jar","tourguide.war"]
\ No newline at end of file
diff --git a/tourguide/asserts/reporting/HighVolumeRewards_20211207_100000_users.PNG b/tourguide/asserts/reporting/HighVolumeRewards_20211207_100000_users.PNG
new file mode 100644
index 0000000..d2f7d8c
Binary files /dev/null and b/tourguide/asserts/reporting/HighVolumeRewards_20211207_100000_users.PNG differ
diff --git a/tourguide/asserts/reporting/HighVolumeTracking_20211207_100000_users.PNG b/tourguide/asserts/reporting/HighVolumeTracking_20211207_100000_users.PNG
new file mode 100644
index 0000000..e15f267
Binary files /dev/null and b/tourguide/asserts/reporting/HighVolumeTracking_20211207_100000_users.PNG differ
diff --git a/tourguide/asserts/reporting/Junit_all_test_tourGuideService_ok_20211117.PNG b/tourguide/asserts/reporting/Junit_all_test_tourGuideService_ok_20211117.PNG
new file mode 100644
index 0000000..0f7c7ea
Binary files /dev/null and b/tourguide/asserts/reporting/Junit_all_test_tourGuideService_ok_20211117.PNG differ
diff --git a/tourguide/asserts/reporting/Junit_test_20211205.PNG b/tourguide/asserts/reporting/Junit_test_20211205.PNG
new file mode 100644
index 0000000..7f9eba2
Binary files /dev/null and b/tourguide/asserts/reporting/Junit_test_20211205.PNG differ
diff --git a/tourguide/asserts/reporting/Performance_Location_graph_20211207.PNG b/tourguide/asserts/reporting/Performance_Location_graph_20211207.PNG
new file mode 100644
index 0000000..97f6507
Binary files /dev/null and b/tourguide/asserts/reporting/Performance_Location_graph_20211207.PNG differ
diff --git a/tourguide/asserts/reporting/Performance_rewards_graph_20211207.PNG b/tourguide/asserts/reporting/Performance_rewards_graph_20211207.PNG
new file mode 100644
index 0000000..6c9d4a1
Binary files /dev/null and b/tourguide/asserts/reporting/Performance_rewards_graph_20211207.PNG differ
diff --git a/tourguide/asserts/reporting/Performance_synopsis_20211207_100000_users.PNG b/tourguide/asserts/reporting/Performance_synopsis_20211207_100000_users.PNG
new file mode 100644
index 0000000..01daa62
Binary files /dev/null and b/tourguide/asserts/reporting/Performance_synopsis_20211207_100000_users.PNG differ
diff --git a/tourguide/asserts/reporting/Performance_unit_tests_20211207_100000_users.PNG b/tourguide/asserts/reporting/Performance_unit_tests_20211207_100000_users.PNG
new file mode 100644
index 0000000..b4c8c7d
Binary files /dev/null and b/tourguide/asserts/reporting/Performance_unit_tests_20211207_100000_users.PNG differ
diff --git a/tourguide/asserts/reporting/gradle_build_report_20211113_01.PNG b/tourguide/asserts/reporting/gradle_build_report_20211113_01.PNG
new file mode 100644
index 0000000..1fa234b
Binary files /dev/null and b/tourguide/asserts/reporting/gradle_build_report_20211113_01.PNG differ
diff --git a/tourguide/asserts/reporting/gradle_build_report_20211114_01.PNG b/tourguide/asserts/reporting/gradle_build_report_20211114_01.PNG
new file mode 100644
index 0000000..ed0d25e
Binary files /dev/null and b/tourguide/asserts/reporting/gradle_build_report_20211114_01.PNG differ
diff --git a/tourguide/asserts/reporting/gradle_build_report_20211205_01.PNG b/tourguide/asserts/reporting/gradle_build_report_20211205_01.PNG
new file mode 100644
index 0000000..78faff7
Binary files /dev/null and b/tourguide/asserts/reporting/gradle_build_report_20211205_01.PNG differ
diff --git a/tourguide/asserts/reporting/jacoco_20211113_01.PNG b/tourguide/asserts/reporting/jacoco_20211113_01.PNG
new file mode 100644
index 0000000..11bdd06
Binary files /dev/null and b/tourguide/asserts/reporting/jacoco_20211113_01.PNG differ
diff --git a/tourguide/asserts/reporting/jacoco_20211205_01.PNG b/tourguide/asserts/reporting/jacoco_20211205_01.PNG
new file mode 100644
index 0000000..8f6ab4f
Binary files /dev/null and b/tourguide/asserts/reporting/jacoco_20211205_01.PNG differ
diff --git a/tourguide/asserts/reporting/mcd_microservice_gps.PNG b/tourguide/asserts/reporting/mcd_microservice_gps.PNG
new file mode 100644
index 0000000..9fc7e7c
Binary files /dev/null and b/tourguide/asserts/reporting/mcd_microservice_gps.PNG differ
diff --git a/tourguide/asserts/reporting/mcd_microservice_rewards.PNG b/tourguide/asserts/reporting/mcd_microservice_rewards.PNG
new file mode 100644
index 0000000..133d447
Binary files /dev/null and b/tourguide/asserts/reporting/mcd_microservice_rewards.PNG differ
diff --git a/tourguide/asserts/reporting/mcd_microservice_tripdeals.PNG b/tourguide/asserts/reporting/mcd_microservice_tripdeals.PNG
new file mode 100644
index 0000000..14224d4
Binary files /dev/null and b/tourguide/asserts/reporting/mcd_microservice_tripdeals.PNG differ
diff --git a/tourguide/asserts/reporting/mcd_tourguide.PNG b/tourguide/asserts/reporting/mcd_tourguide.PNG
new file mode 100644
index 0000000..e82e92f
Binary files /dev/null and b/tourguide/asserts/reporting/mcd_tourguide.PNG differ
diff --git a/tourguide/asserts/reporting/mvc_tourguide1.PNG b/tourguide/asserts/reporting/mvc_tourguide1.PNG
new file mode 100644
index 0000000..61f14df
Binary files /dev/null and b/tourguide/asserts/reporting/mvc_tourguide1.PNG differ
diff --git a/tourguide/asserts/reporting/mvc_tourguide2.PNG b/tourguide/asserts/reporting/mvc_tourguide2.PNG
new file mode 100644
index 0000000..760fa84
Binary files /dev/null and b/tourguide/asserts/reporting/mvc_tourguide2.PNG differ
diff --git a/tourguide/asserts/reporting/performance_test_report_20211117_01.PNG b/tourguide/asserts/reporting/performance_test_report_20211117_01.PNG
new file mode 100644
index 0000000..b7666dc
Binary files /dev/null and b/tourguide/asserts/reporting/performance_test_report_20211117_01.PNG differ
diff --git a/tourguide/asserts/reporting/postman_getAllCurrentLocations_01.PNG b/tourguide/asserts/reporting/postman_getAllCurrentLocations_01.PNG
new file mode 100644
index 0000000..1727030
Binary files /dev/null and b/tourguide/asserts/reporting/postman_getAllCurrentLocations_01.PNG differ
diff --git a/tourguide/asserts/reporting/postman_getNearbyAttractions_01.PNG b/tourguide/asserts/reporting/postman_getNearbyAttractions_01.PNG
new file mode 100644
index 0000000..818329d
Binary files /dev/null and b/tourguide/asserts/reporting/postman_getNearbyAttractions_01.PNG differ
diff --git a/tourguide/asserts/reporting/postman_test_report_20211114_01.PNG b/tourguide/asserts/reporting/postman_test_report_20211114_01.PNG
new file mode 100644
index 0000000..170fce8
Binary files /dev/null and b/tourguide/asserts/reporting/postman_test_report_20211114_01.PNG differ
diff --git a/tourguide/asserts/reporting/touguide_image.png b/tourguide/asserts/reporting/touguide_image.png
new file mode 100644
index 0000000..bb58920
Binary files /dev/null and b/tourguide/asserts/reporting/touguide_image.png differ
diff --git a/tourguide/build.gradle b/tourguide/build.gradle
new file mode 100644
index 0000000..299e011
--- /dev/null
+++ b/tourguide/build.gradle
@@ -0,0 +1,149 @@
+buildscript {
+ repositories {
+ // Maven Central for resolving dependencies
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+ }
+ dependencies {
+ // https://plugins.gradle.org/plugin/org.springframework.boot
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
+ }
+}
+
+// https://docs.gradle.org/current/samples/sample_building_java_libraries.html
+
+plugins {
+ // Apply the java-library plugin for API and implementation separation
+ id 'java-library'
+ id 'maven-publish'
+}
+
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+apply plugin: 'war'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'io.spring.dependency-management'
+apply plugin: "jacoco"
+
+
+bootWar {
+ baseName = 'tourguide'
+ version = '1.0.0'
+}
+
+repositories {
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+}
+
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
+
+// https://stackoverflow.com/questions/23796404/could-not-find-method-compile-for-arguments-gradle
+/* Note that the compile, runtime, testCompile, and testRuntime configurations
+ introduced by the Java plugin have been deprecated since Gradle 4.10 (Aug 27, 2018),
+and were finally removed in Gradle 7.0 (Apr 9, 2021).
+The aforementioned configurations should be replaced by implementation,
+ runtimeOnly, testImplementation, and testRuntimeOnly, respectively.
+ http://man.hubwiz.com/docset/Gradle_User_Guide.docset/Contents/Resources/Documents/userguide/java_library_plugin.html
+*/
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web")
+ implementation("org.springframework.boot:spring-boot-starter-actuator")
+
+ implementation 'com.google.guava:guava:23.0'
+ implementation group: 'org.javamoney', name: 'moneta', version: '1.4.2'
+ implementation group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'
+ implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0'
+
+ // Lombok
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
+ testCompileOnly 'org.projectlombok:lombok'
+ testAnnotationProcessor 'org.projectlombok:lombok'
+
+ implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-openfeign', version: '2.1.2.RELEASE'
+// implementation group: 'org.springframework.cloud', name: 'spring-cloud-dependencies', version: 'Finchley.M8'
+
+// implementation(name:'gpsUtil', ext:'jar')
+// implementation(name:'RewardCentral', ext:'jar')
+// implementation(name:'TripPricer', ext:'jar')
+
+ implementation 'org.modelmapper:modelmapper:2.3.3'
+
+ // Junit
+ // testImplementation("junit:junit")
+
+
+ testImplementation 'org.springframework.boot:spring-boot-starter-web'
+ testImplementation('org.springframework.boot:spring-boot-starter-test:2.2.2.RELEASE') {
+ exclude group: 'junit'
+ exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
+ }
+
+ implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final'
+ implementation group: 'org.hibernate.validator', name: 'hibernate-validator', version: '7.0.1.Final'
+ implementation group: 'org.hibernate', name: 'hibernate-validator-annotation-processor', version: '7.0.1.Final'
+
+
+
+
+
+
+ testImplementation("org.junit.platform:junit-platform-launcher:1.2.0")
+ testImplementation('org.junit.jupiter:junit-jupiter-api:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-engine:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-params:5.3.1')
+
+ testCompileOnly 'junit:junit:4.12'
+// testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.1'
+
+ // Use JUnit Jupiter for testing
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
+
+
+
+}
+
+test {
+ useJUnitPlatform() {
+ includeEngines 'junit-jupiter'
+ }
+
+}
+
+
+// Jacoco
+jacoco {
+ toolVersion = "0.8.7"
+}
+
+jacocoTestReport {
+ reports {
+ xml.enabled true
+ csv.enabled false
+ html.destination file("${buildDir}/jacocoHtml")
+ }
+}
+
+test.finalizedBy jacocoTestReport
+check.dependsOn jacocoTestCoverageVerification
+
+jacocoTestCoverageVerification {
+ violationRules {
+ rule {
+ limit {
+ counter = 'LINE'
+ value = 'COVEREDRATIO'
+ minimum = 0.5
+ }
+ }
+ }
+}
diff --git a/gradle/wrapper/gradle-wrapper.jar b/tourguide/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from gradle/wrapper/gradle-wrapper.jar
rename to tourguide/gradle/wrapper/gradle-wrapper.jar
diff --git a/gradle/wrapper/gradle-wrapper.properties b/tourguide/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from gradle/wrapper/gradle-wrapper.properties
rename to tourguide/gradle/wrapper/gradle-wrapper.properties
diff --git a/gradlew b/tourguide/gradlew
similarity index 100%
rename from gradlew
rename to tourguide/gradlew
diff --git a/gradlew.bat b/tourguide/gradlew.bat
similarity index 100%
rename from gradlew.bat
rename to tourguide/gradlew.bat
diff --git a/tourguide/lombok.config b/tourguide/lombok.config
new file mode 100644
index 0000000..a23edb4
--- /dev/null
+++ b/tourguide/lombok.config
@@ -0,0 +1,2 @@
+config.stopBubbling = true
+lombok.addLombokGeneratedAnnotation = true
\ No newline at end of file
diff --git a/settings.gradle b/tourguide/settings.gradle
similarity index 100%
rename from settings.gradle
rename to tourguide/settings.gradle
diff --git a/tourguide/src/main/java/tourGuide/Application.java b/tourguide/src/main/java/tourGuide/Application.java
new file mode 100644
index 0000000..66a665a
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/Application.java
@@ -0,0 +1,44 @@
+package tourGuide;
+
+import java.util.Locale;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * The Class Application.
+ */
+@EnableFeignClients("tourGuide")
+@SpringBootApplication
+@ComponentScan("tourGuide")
+public class Application {
+
+
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ Locale.setDefault(Locale.US);
+ SpringApplication.run(Application.class, args);
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/config/TourGuideModule.java b/tourguide/src/main/java/tourGuide/config/TourGuideModule.java
new file mode 100644
index 0000000..66391c6
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/config/TourGuideModule.java
@@ -0,0 +1,84 @@
+package tourGuide.config;
+
+import java.util.Locale;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import feign.Retryer;
+import tourGuide.exception.FeignErrorDecoder;
+
+/**
+ * The Class TourGuideModule.
+ */
+@Configuration
+public class TourGuideModule {
+
+
+// /** The logger. */
+// private Logger logger = LoggerFactory
+// .getLogger(TourGuideModule.class);
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the executor service.
+ *
+ * @return the executor service
+ */
+ @Bean
+ public ExecutorService getExecutorService() {
+ return Executors.newFixedThreadPool(1000);
+ }
+
+
+ // ##############################################################
+
+ /**
+ * Gets the locale.
+ *
+ * @return the locale
+ */
+ @Bean
+ public Locale getLocale() {
+ Locale.setDefault(Locale.US);
+ return Locale.getDefault();
+ }
+
+
+
+ // ##############################################################
+
+// /**
+// * Gets the trip pricer.
+// *
+// * @return the trip pricer
+// */
+// @Bean
+// public TripPricer getTripPricer() {
+// return new TripPricer();
+// }
+
+ // ##############################################################
+
+
+ @Bean
+ public FeignErrorDecoder myErrorDecoder() {
+ return new FeignErrorDecoder();
+ }
+
+ // ##############################################################
+
+ @Bean
+ public Retryer retryer() {
+// return new Retryer.Default();
+ return Retryer.NEVER_RETRY;
+ }
+
+ // ##############################################################
+
+}
diff --git a/tourguide/src/main/java/tourGuide/constant/Constraints.java b/tourguide/src/main/java/tourGuide/constant/Constraints.java
new file mode 100644
index 0000000..7e9d4f0
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/constant/Constraints.java
@@ -0,0 +1,31 @@
+package tourGuide.constant;
+
+/**
+ * The Class Constraints.
+ */
+public class Constraints {
+
+
+ /** The Constant PROXIMITY_LOWER_LIMIT. */
+ public static final int PROXIMITY_LOWER_LIMIT = 0;
+
+ /** The Constant LOWERPRICEPOINT_VALUE. */
+ public static final int LOWERPRICEPOINT_VALUE = 0;
+
+ /** The Constant HIGHPRICEPOINT_VALUE. */
+ public static final int HIGHPRICEPOINT_VALUE = 0;
+
+ /** The Constant TRIP_DURATION_MIN_VALUE. */
+ public static final int TRIP_DURATION_MIN_VALUE = 1;
+
+ /** The Constant TICKET_QUANTITY_MIN_VALUE. */
+ public static final int TICKET_QUANTITY_MIN_VALUE = 1;
+
+ /** The Constant ADULT_NUMBER_MIN_VALUE. */
+ public static final int ADULT_NUMBER_MIN_VALUE = 1;
+
+ /** The Constant CHILD_NUMBER_MIN_VALUE. */
+ public static final int CHILD_NUMBER_MIN_VALUE = 0;
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/controller/HomeController.java b/tourguide/src/main/java/tourGuide/controller/HomeController.java
new file mode 100644
index 0000000..9ebb347
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/controller/HomeController.java
@@ -0,0 +1,45 @@
+package tourGuide.controller;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * The Class TourGuideController.
+ */
+@RestController
+public class HomeController {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(HomeController.class);
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Index.
+ *
+ * @return the string
+ */
+ @RequestMapping("/")
+ public String index() {
+
+ logger.info("## index() page requested");
+
+ return "Greetings from TourGuide!";
+ }
+
+
+
+
+ //###############################################################
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/controller/LocationController.java b/tourguide/src/main/java/tourGuide/controller/LocationController.java
new file mode 100644
index 0000000..3077dad
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/controller/LocationController.java
@@ -0,0 +1,150 @@
+package tourGuide.controller;
+
+import java.util.Map;
+
+import javax.validation.Valid;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import tourGuide.dto.LocationDTO;
+import tourGuide.dto.UserAttractionRecommendationDTO;
+import tourGuide.exception.BadRequestException;
+import tourGuide.service.IGpsLocationService;
+
+/**
+ * The Class TourGuideController.
+ */
+@RestController
+public class LocationController {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(LocationController.class);
+
+
+ /** The tour guide service. */
+ @Autowired
+ IGpsLocationService gpsLocationService;
+
+
+ // ##############################################################
+
+
+ /**
+ * Instantiates a new tour guide controller.
+ *
+ * @param tourGuideService the tour guide service
+ */
+ public LocationController(
+ final IGpsLocationService gpsLocationService) {
+ this.gpsLocationService = gpsLocationService;
+ }
+
+
+
+ //###############################################################
+
+
+
+
+
+ /**
+ * Gets the location.
+ *
+ * @param userName the user name
+ * @return the location
+ * @throws BadRequestException the bad request exception
+ */
+ @RequestMapping("/getLocation")
+ public LocationDTO getLocation(
+ @Valid @RequestParam String userName)
+ throws BadRequestException {
+
+ logger.info("## getLocation() page requested"
+ + " for user {} : ", userName);
+
+
+ if (userName.length() == 0) {
+ throw new BadRequestException("username is required");
+ }
+ LocationDTO userLocation = gpsLocationService.getUserLocation(userName);
+
+ logger.info("## visitedLocation {} "
+ + " for user {} : ", userLocation, userName);
+ return userLocation;
+ }
+
+
+
+
+ //###############################################################
+
+
+
+
+
+ /**
+ * Gets the user recommended attractions.
+ *
+ * @param userName the user name
+ * @return the user recommended attractions
+ */
+ @RequestMapping("/getNearbyAttractions")
+ public UserAttractionRecommendationDTO getUserRecommendedAttractions(
+ @RequestParam final String userName) {
+
+ logger.info("## getNearbyAttractions() page requested"
+ + " for user {} : ", userName);
+
+
+ if (userName.length() == 0) {
+ throw new BadRequestException("username is required");
+ }
+ UserAttractionRecommendationDTO nearByAttractions = gpsLocationService
+ .getUserAttractionRecommendation(userName);
+
+ return nearByAttractions;
+ }
+
+
+
+
+
+ //###############################################################
+
+
+
+
+
+ /**
+ * Gets the users recent location.
+ *
+ * @return the users recent location
+ */
+ @RequestMapping("/getAllCurrentLocations")
+ public Map getUsersRecentLocation() {
+
+ logger.info("## getAllCurrentLocations requested");
+
+ Map usersRecentLocation = gpsLocationService
+ .getAllUserRecentLocation();
+
+ return usersRecentLocation;
+ }
+
+
+
+
+ //###############################################################
+
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/controller/RewardsController.java b/tourguide/src/main/java/tourGuide/controller/RewardsController.java
new file mode 100644
index 0000000..bed3845
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/controller/RewardsController.java
@@ -0,0 +1,98 @@
+package tourGuide.controller;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import tourGuide.exception.BadRequestException;
+import tourGuide.service.IGpsLocationService;
+
+/**
+ * The Class TourGuideController.
+ */
+@RestController
+public class RewardsController {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(RewardsController.class);
+
+
+ @Autowired
+ IGpsLocationService gpsLocationService;
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Instantiates a new tour guide controller.
+ *
+ * @param tourGuideService the tour guide service
+ */
+ public RewardsController(
+ final IGpsLocationService gpsLocationService) {
+ this.gpsLocationService = gpsLocationService;
+ }
+
+
+
+ //###############################################################
+
+
+
+
+ /**
+ * Gets the user rewards.
+ *
+ * @param userName the user name
+ * @return the user rewards
+ */
+ @RequestMapping("/getRewards")
+ public int getUserRewards(
+ @RequestParam final String userName) {
+
+ logger.info("## getRewards for user {} requested", userName);
+
+ if (userName.length() == 0) {
+ throw new BadRequestException("username is required");
+ }
+ int userRewards = gpsLocationService.getTotalRewardPointsForUser(userName);
+
+ logger.info("## getRewards for user rewardPointsTotalValue"
+ + " {} requested", userRewards);
+
+ return userRewards;
+ }
+
+//
+// @RequestMapping("/getRewards")
+// public List getUserRewards(
+// @RequestParam final String userName) {
+//
+// logger.info("## getRewards for user {} requested", userName);
+//
+// if (userName.length() == 0) {
+// throw new BadRequestException("username is required");
+// }
+// List userRewards = tourGuideService
+// .getUserRewards(userName);
+//
+// logger.info("## getRewards for user rewards size"
+// + " {} requested", userRewards.size());
+//
+// return userRewards;
+// }
+
+
+ //###############################################################
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/controller/TripDealsController.java b/tourguide/src/main/java/tourGuide/controller/TripDealsController.java
new file mode 100644
index 0000000..56599ef
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/controller/TripDealsController.java
@@ -0,0 +1,90 @@
+package tourGuide.controller;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import tourGuide.dto.ProviderDTO;
+import tourGuide.exception.BadRequestException;
+import tourGuide.service.ITripDealsService;
+
+/**
+ * The Class TourGuideController.
+ */
+@RestController
+public class TripDealsController {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(TripDealsController.class);
+
+
+
+ private final ITripDealsService tripDealsService;
+
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Instantiates a new tour guide controller.
+ *
+ * @param tourGuideService the tour guide service
+ */
+ @Autowired
+ public TripDealsController(
+ final ITripDealsService tripDealsService) {
+
+ this.tripDealsService = tripDealsService;
+ }
+
+
+
+ //###############################################################
+
+
+
+
+ /**
+ * Gets the user trip deals.
+ *
+ * @param userName the user name
+ * @return the user trip deals
+ */
+ @RequestMapping("/getTripDeals")
+ public List getUserTripDeals(
+ @RequestParam final String userName) {
+
+ logger.info("## getTripDeals"
+ + " for user {} : ", userName);
+
+ if (userName.length() == 0) {
+ throw new BadRequestException("username is required");
+ }
+ List userTripDeals = tripDealsService
+ .getUserTripDeals(userName);
+
+
+ logger.info("## providers {} "
+ + " for user {} : ", userTripDeals.size(), userName);
+
+ return userTripDeals;
+
+ }
+
+
+ //###############################################################
+
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/controller/UserController.java b/tourguide/src/main/java/tourGuide/controller/UserController.java
new file mode 100644
index 0000000..1fc7f61
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/controller/UserController.java
@@ -0,0 +1,120 @@
+package tourGuide.controller;
+
+import javax.validation.Valid;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.exception.BadRequestException;
+import tourGuide.model.User;
+import tourGuide.service.IGpsLocationService;
+import tourGuide.service.IUserService;
+
+/**
+ * The Class TourGuideController.
+ */
+@RestController
+public class UserController {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(UserController.class);
+
+
+ /** The tour guide service. */
+ IGpsLocationService tourGuideService;
+
+ /** The user service. */
+ private final IUserService userService;
+
+ // ##############################################################
+
+
+ /**
+ * Instantiates a new tour guide controller.
+ *
+ * @param tourGuideService the tour guide service
+ */
+ @Autowired
+ public UserController(
+ final IGpsLocationService tourGuideService,
+ IUserService userService) {
+
+ this.userService = userService;
+ this.tourGuideService = tourGuideService;
+ }
+
+
+
+ //###############################################################
+
+
+
+
+ /**
+ * Gets the user preferences.
+ *
+ * @param userPreferencesDTO the user preferences DTO
+ * @param userName the user name
+ * @return the user preferences
+ */
+ @PutMapping("/updateUserPreferences")
+ @ResponseStatus(HttpStatus.CREATED)
+ public UserPreferencesDTO getUserPreferences(
+ @Valid @RequestBody final UserPreferencesDTO userPreferencesDTO,
+ @RequestParam final String userName) {
+
+
+ if (userName.length() == 0) {
+ throw new BadRequestException("username is required");
+ }
+ UserPreferencesDTO userPreferences = userService
+ .updateUserPreferences(userName, userPreferencesDTO);
+
+ return userPreferences;
+
+ }
+
+
+
+ //###############################################################
+
+
+
+ /**
+ * Gets the user.
+ *
+ * @param userName the user name
+ * @return the user
+ * @throws BadRequestException the bad request exception
+ */
+ @RequestMapping("/getUser")
+ private User getUser(String userName) throws BadRequestException {
+
+ logger.info("## getUser "
+ + " for user {} : ", userName);
+
+ return userService.getUser(userName);
+ }
+
+
+
+ //###############################################################
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/dto/AttractionDTO.java b/tourguide/src/main/java/tourGuide/dto/AttractionDTO.java
new file mode 100644
index 0000000..82e70e5
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/AttractionDTO.java
@@ -0,0 +1,34 @@
+package tourGuide.dto;
+
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import tourGuide.model.Location;
+
+/**
+ * The Class AttractionDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class AttractionDTO {
+
+ /** The attraction id. */
+ private UUID attractionId;
+
+ /** The attraction name. */
+ private String attractionName;
+
+ /** The city. */
+ private String city;
+
+ /** The state. */
+ private String state;
+
+ /** The location. */
+ private Location location;
+}
diff --git a/tourguide/src/main/java/tourGuide/dto/LocationDTO.java b/tourguide/src/main/java/tourGuide/dto/LocationDTO.java
new file mode 100644
index 0000000..11838c6
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/LocationDTO.java
@@ -0,0 +1,22 @@
+package tourGuide.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * The Class LocationDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class LocationDTO {
+
+ /** The latitude. */
+ private double latitude;
+
+ /** The longitude. */
+ private double longitude;
+}
diff --git a/tourguide/src/main/java/tourGuide/dto/NearByAttractionDTO.java b/tourguide/src/main/java/tourGuide/dto/NearByAttractionDTO.java
new file mode 100644
index 0000000..c3ea711
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/NearByAttractionDTO.java
@@ -0,0 +1,33 @@
+package tourGuide.dto;
+
+import com.jsoniter.annotation.JsonProperty;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import tourGuide.model.Location;
+
+@Getter
+@Setter
+@AllArgsConstructor
+public class NearByAttractionDTO {
+
+ @JsonProperty("attractionName")
+ @Getter
+ private String attractionName;
+
+ @JsonProperty("attractionLocation")
+ @Getter
+ private Location attractionLocation;
+
+ /** The distance. */
+ @JsonProperty("distance")
+ @Getter
+ double distance;
+
+ /** The reward points. */
+ @JsonProperty("rewardPoints")
+ @Getter
+ int rewardPoints;
+
+}
diff --git a/tourguide/src/main/java/tourGuide/dto/ProviderDTO.java b/tourguide/src/main/java/tourGuide/dto/ProviderDTO.java
new file mode 100644
index 0000000..50d7450
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/ProviderDTO.java
@@ -0,0 +1,29 @@
+package tourGuide.dto;
+
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * The Class ProviderDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ProviderDTO {
+
+ /** The name. */
+ private String name;
+
+ /** The price. */
+ private double price;
+
+ /** The trip id. */
+ private UUID tripId;
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/dto/UserAttractionRecommendationDTO.java b/tourguide/src/main/java/tourGuide/dto/UserAttractionRecommendationDTO.java
new file mode 100644
index 0000000..6ed37df
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/UserAttractionRecommendationDTO.java
@@ -0,0 +1,30 @@
+package tourGuide.dto;
+
+import java.util.List;
+
+import com.jsoniter.annotation.JsonProperty;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import tourGuide.model.Location;
+
+/**
+ * The Class UserAttractionRecommendationDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class UserAttractionRecommendationDTO {
+
+
+ /** The user position. */
+ @JsonProperty("userPosition")
+ Location userPosition;
+
+ /** The nearby attraction DTOs. */
+ @JsonProperty("nearbyAttractions")
+ private List nearbyAttractions;
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/dto/UserPreferencesDTO.java b/tourguide/src/main/java/tourGuide/dto/UserPreferencesDTO.java
new file mode 100644
index 0000000..1794a9d
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/UserPreferencesDTO.java
@@ -0,0 +1,59 @@
+package tourGuide.dto;
+
+import javax.validation.constraints.Min;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import tourGuide.constant.Constraints;
+
+/**
+ * The Class UserPreferencesDTO.
+ */
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserPreferencesDTO {
+
+
+ /** The attraction proximity. */
+ @Min(value = Constraints.PROXIMITY_LOWER_LIMIT,
+ message = "Valid value required")
+ private int attractionProximity;
+
+ /** The lower price point. */
+ @Min(value = Constraints.LOWERPRICEPOINT_VALUE,
+ message = "Valid value required")
+ private int lowerPricePoint;
+
+ /** The high price point. */
+ @Min(value = Constraints.HIGHPRICEPOINT_VALUE,
+ message = "Valid value required")
+ private int highPricePoint;
+
+ /** The trip duration. */
+ @Min(value = Constraints.TRIP_DURATION_MIN_VALUE,
+ message = "Minimum stay period should be atleast 1")
+ private int tripDuration;
+
+ /** The ticket quantity. */
+ @Min(value = Constraints.TICKET_QUANTITY_MIN_VALUE,
+ message = "Minimum ticket quantity value (1) required")
+ private int ticketQuantity;
+
+ /** The number of adults. */
+ @Min(value = Constraints.ADULT_NUMBER_MIN_VALUE,
+ message = "Minimum number of adults (1) required")
+ private int numberOfAdults;
+
+ /** The number of children. */
+ @Min(value = Constraints.CHILD_NUMBER_MIN_VALUE,
+ message = "Valid value required")
+ private int numberOfChildren;
+
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/dto/UserRewardDTO.java b/tourguide/src/main/java/tourGuide/dto/UserRewardDTO.java
new file mode 100644
index 0000000..2e8a3f1
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/UserRewardDTO.java
@@ -0,0 +1,27 @@
+package tourGuide.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import tourGuide.model.Attraction;
+import tourGuide.model.VisitedLocation;
+
+/**
+ * The Class UserRewardDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@ToString
+public class UserRewardDTO {
+
+ /** The visited location. */
+ private VisitedLocation visitedLocation;
+
+ /** The attraction. */
+ private Attraction attraction;
+
+ /** The reward points. */
+ private int rewardPoints;
+}
diff --git a/tourguide/src/main/java/tourGuide/dto/VisitedLocationDTO.java b/tourguide/src/main/java/tourGuide/dto/VisitedLocationDTO.java
new file mode 100644
index 0000000..3ecd086
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/dto/VisitedLocationDTO.java
@@ -0,0 +1,31 @@
+package tourGuide.dto;
+
+import java.util.Date;
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import tourGuide.model.Location;
+
+/**
+ * The Class VisitedLocationDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class VisitedLocationDTO {
+
+ /** The user id. */
+ private UUID userId;
+
+ /** The location. */
+ private Location location;
+
+ /** The time visited. */
+ private Date timeVisited;
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/exception/BadRequestException.java b/tourguide/src/main/java/tourGuide/exception/BadRequestException.java
new file mode 100644
index 0000000..50e9a44
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/exception/BadRequestException.java
@@ -0,0 +1,16 @@
+package tourGuide.exception;
+
+/**
+ * The Class BadRequestException.
+ */
+public class BadRequestException extends RuntimeException {
+
+ /**
+ * Instantiates a new bad request exception.
+ *
+ * @param message the message
+ */
+ public BadRequestException(final String message) {
+ super(message);
+ }
+}
diff --git a/tourguide/src/main/java/tourGuide/exception/DataAlreadyRegisteredException.java b/tourguide/src/main/java/tourGuide/exception/DataAlreadyRegisteredException.java
new file mode 100644
index 0000000..fbbf1c1
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/exception/DataAlreadyRegisteredException.java
@@ -0,0 +1,16 @@
+package tourGuide.exception;
+
+/**
+ * The Class DataAlreadyRegisteredException.
+ */
+public class DataAlreadyRegisteredException extends RuntimeException {
+
+ /**
+ * Instantiates a new data already registered exception.
+ *
+ * @param message the message
+ */
+ public DataAlreadyRegisteredException(final String message) {
+ super(message);
+ }
+}
diff --git a/tourguide/src/main/java/tourGuide/exception/ErrorDetails.java b/tourguide/src/main/java/tourGuide/exception/ErrorDetails.java
new file mode 100644
index 0000000..d26217e
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/exception/ErrorDetails.java
@@ -0,0 +1,27 @@
+package tourGuide.exception;
+
+import java.time.LocalDateTime;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * The Class ErrorDetails.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ErrorDetails {
+
+ /** The timestamp. */
+ private LocalDateTime timestamp;
+
+ /** The message. */
+ private String message;
+
+ /** The details. */
+ private String details;
+}
diff --git a/tourguide/src/main/java/tourGuide/exception/FeignErrorDecoder.java b/tourguide/src/main/java/tourGuide/exception/FeignErrorDecoder.java
new file mode 100644
index 0000000..a51e1b3
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/exception/FeignErrorDecoder.java
@@ -0,0 +1,45 @@
+package tourGuide.exception;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import feign.Response;
+import feign.codec.ErrorDecoder;
+
+
+public class FeignErrorDecoder implements ErrorDecoder {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(FeignErrorDecoder.class);
+
+
+ private final ErrorDecoder defaultErrorDecoder = new Default();
+
+
+
+ // ##############################################################
+
+
+
+ @Override
+ public Exception decode(String methodKey, Response response) {
+
+ if (response.status() == 404) {
+
+ logger.error("Feign client Error - Status code: "
+ + response.status() + ", methodKey = " + methodKey);
+ return new ResourceNotFoundException("Resource not found");
+ }
+
+ return defaultErrorDecoder.decode(methodKey, response);
+ }
+
+
+ // ##############################################################
+
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/exception/GlobalExceptionHandler.java b/tourguide/src/main/java/tourGuide/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..a449719
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/exception/GlobalExceptionHandler.java
@@ -0,0 +1,191 @@
+package tourGuide.exception;
+
+import java.time.LocalDateTime;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.support.DefaultMessageSourceResolvable;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class GlobalExceptionHandler.
+ */
+@ControllerAdvice
+public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(GlobalExceptionHandler.class);
+
+
+
+ // ##############################################################
+
+ /**
+ * Handle not found.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(UserNotFoundException.class)
+ public ResponseEntity handleNotFound(
+ final UserNotFoundException ex,
+ final WebRequest request) {
+
+ logger.error("Request failed :", ex);
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.NOT_FOUND);
+ }
+
+
+
+ // ##############################################################
+
+ /**
+ * Handle conflict.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(DataAlreadyRegisteredException.class)
+ public ResponseEntity handleConflict(
+ final DataAlreadyRegisteredException ex,
+ final WebRequest request) {
+
+ logger.error("Request failed :", ex);
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.CONFLICT);
+ }
+
+
+
+ // ##############################################################
+
+ /**
+ * Handle bad request.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(BadRequestException.class)
+ public ResponseEntity handleBadRequest(
+ final BadRequestException ex,
+ final WebRequest request) {
+
+ logger.error("Request failed :", ex);
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+
+ // ##############################################################
+
+ /**
+ * Handle method argument not valid.
+ *
+ * @param ex the ex
+ * @param header the header
+ * @param status the status
+ * @param request the request
+ * @return the response entity
+ */
+ @Override
+ public ResponseEntity handleMethodArgumentNotValid(
+ final MethodArgumentNotValidException ex,
+ final HttpHeaders header,
+ final HttpStatus status, final WebRequest request) {
+
+ logger.error("Request failed :", ex);
+
+ // Error messages for invalid fields
+ String errorMessage = ex.getBindingResult()
+ .getFieldErrors().stream()
+ .map(DefaultMessageSourceResolvable::getDefaultMessage)
+ .collect(Collectors.joining(", "));
+
+ // ErrorResponse for Validation on error messages and requests
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ errorMessage,
+ request.getDescription(false));
+
+ return new ResponseEntity(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+
+ // ##############################################################
+
+ /**
+ * Handle missing servlet request parameter.
+ *
+ * @param ex the ex
+ * @param headers the headers
+ * @param status the status
+ * @param request the request
+ * @return the response entity
+ */
+ @Override
+ protected ResponseEntity handleMissingServletRequestParameter(
+ final MissingServletRequestParameterException ex,
+ final HttpHeaders headers,
+ final HttpStatus status,
+ final WebRequest request) {
+
+ logger.error("Request failed - Missing parameter:"
+ + " {}", ex.getParameterName());
+
+ final String error = ex.getParameterName()
+ + " parameter is missing";
+
+ final ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getLocalizedMessage(),
+ error);
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+ // ##############################################################
+
+}
diff --git a/tourguide/src/main/java/tourGuide/exception/ResourceNotFoundException.java b/tourguide/src/main/java/tourGuide/exception/ResourceNotFoundException.java
new file mode 100644
index 0000000..983ce63
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/exception/ResourceNotFoundException.java
@@ -0,0 +1,17 @@
+package tourGuide.exception;
+
+/**
+ * The Class ResourceNotFoundException.
+ */
+public class ResourceNotFoundException extends RuntimeException {
+
+
+ /**
+ * Instantiates a new resource not found exception.
+ *
+ * @param message the message
+ */
+ public ResourceNotFoundException(final String message) {
+ super(message);
+ }
+}
diff --git a/tourguide/src/main/java/tourGuide/exception/UserNotFoundException.java b/tourguide/src/main/java/tourGuide/exception/UserNotFoundException.java
new file mode 100644
index 0000000..4200f45
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/exception/UserNotFoundException.java
@@ -0,0 +1,16 @@
+package tourGuide.exception;
+
+/**
+ * The Class UserNotFoundException.
+ */
+public class UserNotFoundException extends RuntimeException {
+
+ /**
+ * Instantiates a new user not found exception.
+ *
+ * @param message the message
+ */
+ public UserNotFoundException(final String message) {
+ super(message);
+ }
+}
diff --git a/tourguide/src/main/java/tourGuide/helper/InternalTestHelper.java b/tourguide/src/main/java/tourGuide/helper/InternalTestHelper.java
new file mode 100644
index 0000000..3fd2df7
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/helper/InternalTestHelper.java
@@ -0,0 +1,213 @@
+package tourGuide.helper;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+import java.util.stream.IntStream;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import tourGuide.model.Location;
+import tourGuide.model.User;
+import tourGuide.model.VisitedLocation;
+
+
+/**
+ * The Class InternalTestHelper.
+ */
+@Component
+public class InternalTestHelper {
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(InternalTestHelper.class);
+
+
+
+
+ // ##############################################################
+
+
+
+ /** ******** Methods Below: For Internal Testing ********/
+
+ // Set this default up to 100,000 for testing
+ @Value("${test.user.numbers}")
+ private int internalUserNumber;
+
+ /** The trip pricer api key. */
+ // Mandatory API Key to use TripPricer.
+ @Value("${trip.pricer.api.key}")
+ private String TRIP_PRICER_API_KEY;
+
+
+ /**
+ * Gets the trip pricer api key.
+ *
+ * @return the trip pricer api key
+ */
+ public String getTripPricerApiKey() {
+ return TRIP_PRICER_API_KEY;
+ }
+
+
+ // Database connection will be used for external users,
+ // but for testing purposes internal users are provided
+ // and stored in memory
+
+ /** The internal user map. */
+ public final Map internalUserMap = new HashMap<>();
+
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Initialize internal users.
+ */
+ public void initializeInternalUsers() {
+
+ IntStream.range(
+ 0,
+ internalUserNumber)
+ .forEach(i -> {
+
+ String userName = "internalUser" + i;
+ String phone = "000";
+ String email = userName + "@tourGuide.com";
+
+ User user = new User(
+ UUID.randomUUID(),
+ userName,
+ phone,
+ email);
+
+ generateUserLocationHistory(user);
+
+ internalUserMap.put(userName, user);
+
+ });
+
+ logger.debug("Created"
+ + " " + internalUserNumber
+ + " internal test users.");
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Generate user location history.
+ *
+ * @param user the user
+ */
+ private void generateUserLocationHistory(User user) {
+
+ IntStream.range(0, 3).forEach(i-> {
+
+ user.addToVisitedLocations(
+ new VisitedLocation(
+ user.getUserId(),
+ new Location(
+ generateRandomLatitude(),
+ generateRandomLongitude()),
+ getRandomTime()));
+
+ });
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Generate random longitude.
+ *
+ * @return the double
+ */
+ private double generateRandomLongitude() {
+
+ double leftLimit = -180;
+ double rightLimit = 180;
+
+ return leftLimit
+ + new Random().nextDouble()
+ * (rightLimit - leftLimit);
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Generate random latitude.
+ *
+ * @return the double
+ */
+ private double generateRandomLatitude() {
+
+ double leftLimit = -85.05112878;
+ double rightLimit = 85.05112878;
+
+ return leftLimit
+ + new Random().nextDouble()
+ * (rightLimit - leftLimit);
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the random time.
+ *
+ * @return the random time
+ */
+ private Date getRandomTime() {
+
+ LocalDateTime localDateTime = LocalDateTime.now()
+ .minusDays(new Random()
+ .nextInt(30));
+
+ return Date.from(localDateTime
+ .toInstant(ZoneOffset.UTC));
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the internal user map.
+ *
+ * @return the internal user map
+ */
+ public Map getInternalUserMap() {
+ return internalUserMap;
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/model/Attraction.java b/tourguide/src/main/java/tourGuide/model/Attraction.java
new file mode 100644
index 0000000..37cf351
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/model/Attraction.java
@@ -0,0 +1,31 @@
+package tourGuide.model;
+
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * The Class Attraction.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class Attraction {
+
+ /** The attraction id. */
+ private UUID attractionId;
+
+ /** The attraction name. */
+ private String attractionName;
+
+ /** The city. */
+ private String city;
+
+ /** The state. */
+ private String state;
+
+ /** The location. */
+ private Location location;
+}
diff --git a/tourguide/src/main/java/tourGuide/model/Location.java b/tourguide/src/main/java/tourGuide/model/Location.java
new file mode 100644
index 0000000..5b745bd
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/model/Location.java
@@ -0,0 +1,22 @@
+package tourGuide.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * The Class Location.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Location {
+
+ /** The latitude. */
+ private double latitude;
+
+ /** The longitude. */
+ private double longitude;
+}
diff --git a/tourguide/src/main/java/tourGuide/model/Provider.java b/tourguide/src/main/java/tourGuide/model/Provider.java
new file mode 100644
index 0000000..3bad092
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/model/Provider.java
@@ -0,0 +1,27 @@
+package tourGuide.model;
+
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * The Class Provider.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class Provider {
+
+ /** The name. */
+ private String name;
+
+ /** The price. */
+ private double price;
+
+ /** The trip id. */
+ private UUID tripId;
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/model/User.java b/tourguide/src/main/java/tourGuide/model/User.java
new file mode 100644
index 0000000..3bcda83
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/model/User.java
@@ -0,0 +1,137 @@
+package tourGuide.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import javax.validation.constraints.NotNull;
+
+import org.hibernate.validator.constraints.Length;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+
+/**
+ * The Class User.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class User {
+
+ /** The user id. */
+ private UUID userId;
+
+ /** The user name. */
+ @NotNull
+ @Length(min=1, message = "USERNAME required")
+ private String userName;
+
+ /** The phone number. */
+ private String phoneNumber;
+
+ /** The email address. */
+ private String emailAddress;
+
+ /** The latest location timestamp. */
+ private Date latestLocationTimestamp;
+
+ /** The visited locations. */
+ private List visitedLocations
+ = new ArrayList<>();
+
+ /** The user rewards. */
+ private List userRewards
+ = new ArrayList<>();
+
+ /** The user preferences. */
+ private UserPreferences userPreferences
+ = new UserPreferences();
+
+ /** The trip deals. */
+ private List tripDeals
+ = new ArrayList<>();
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Instantiates a new user.
+ *
+ * @param userId the user id
+ * @param userName the user name
+ * @param phoneNumber the phone number
+ * @param emailAddress the email address
+ */
+ public User(
+ UUID userId,
+ String userName,
+ String phoneNumber,
+ String emailAddress) {
+
+ this.userId = userId;
+ this.userName = userName;
+ this.phoneNumber = phoneNumber;
+ this.emailAddress = emailAddress;
+ }
+
+ // ##############################################################
+
+ /**
+ * Adds the to visited locations.
+ *
+ * @param visitedLocation the visited location
+ */
+ public void addToVisitedLocations(
+ VisitedLocation visitedLocation) {
+ visitedLocations.add(visitedLocation);
+ }
+
+ /**
+ * Clear visited locations.
+ */
+ public void clearVisitedLocations() {
+ visitedLocations.clear();
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Adds the user reward.
+ *
+ * @param userReward the user reward
+ */
+ public void addUserReward(final UserReward userReward) {
+
+ this.userRewards.add(userReward);
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the last visited location.
+ *
+ * @return the last visited location
+ */
+ public VisitedLocation getLastVisitedLocation() {
+ return visitedLocations.get(visitedLocations.size() - 1);
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/model/UserPreferences.java b/tourguide/src/main/java/tourGuide/model/UserPreferences.java
new file mode 100644
index 0000000..919e2e6
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/model/UserPreferences.java
@@ -0,0 +1,86 @@
+package tourGuide.model;
+
+import javax.money.CurrencyUnit;
+import javax.money.Monetary;
+
+import org.javamoney.moneta.Money;
+
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+
+/**
+ * The Class UserPreferences.
+ */
+@Getter
+@Setter
+@NoArgsConstructor
+public class UserPreferences {
+
+ /** The attraction proximity. */
+ private int attractionProximity = Integer.MAX_VALUE;
+
+ /** The currency. */
+ private CurrencyUnit currency = Monetary
+ .getCurrency("USD");
+
+ /** The lower price point. */
+ private Money lowerPricePoint = Money.of(0, currency);
+
+ /** The high price point. */
+ private Money highPricePoint = Money.of(
+ Integer.MAX_VALUE,
+ currency);
+
+ /** The trip duration. */
+ private int tripDuration = 1;
+
+ /** The ticket quantity. */
+ private int ticketQuantity = 1;
+
+ /** The number of adults. */
+ private int numberOfAdults = 1;
+
+ /** The number of children. */
+ private int numberOfChildren = 0;
+
+
+
+ // ##############################################################
+
+ /**
+ * Instantiates a new user preferences.
+ *
+ * @param attractionProximity the attraction proximity
+ * @param lowerPricePoint the lower price point
+ * @param highPricePoint the high price point
+ * @param tripDuration the trip duration
+ * @param ticketQuantity the ticket quantity
+ * @param numberOfAdults the number of adults
+ * @param numberOfChildren the number of children
+ */
+ public UserPreferences(
+ final int attractionProximity,
+ final Money lowerPricePoint,
+ final Money highPricePoint,
+ final int tripDuration,
+ final int ticketQuantity,
+ final int numberOfAdults,
+ final int numberOfChildren) {
+
+ this.attractionProximity = attractionProximity;
+ this.lowerPricePoint = lowerPricePoint;
+ this.highPricePoint = highPricePoint;
+ this.tripDuration = tripDuration;
+ this.ticketQuantity = ticketQuantity;
+ this.numberOfAdults = numberOfAdults;
+ this.numberOfChildren = numberOfChildren;
+
+ }
+
+
+
+ // ##############################################################
+
+}
diff --git a/tourguide/src/main/java/tourGuide/model/UserReward.java b/tourguide/src/main/java/tourGuide/model/UserReward.java
new file mode 100644
index 0000000..b16cd95
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/model/UserReward.java
@@ -0,0 +1,26 @@
+package tourGuide.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+
+/**
+ * The Class UserReward.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class UserReward {
+
+ /** The visited location. */
+ public final VisitedLocation visitedLocation;
+
+ /** The attraction. */
+ public final Attraction attraction;
+
+ /** The reward points. */
+ private int rewardPoints;
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/model/VisitedLocation.java b/tourguide/src/main/java/tourGuide/model/VisitedLocation.java
new file mode 100644
index 0000000..fd6318c
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/model/VisitedLocation.java
@@ -0,0 +1,27 @@
+package tourGuide.model;
+
+import java.util.Date;
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * The Class VisitedLocation.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+public class VisitedLocation {
+
+ /** The user id. */
+ private UUID userId;
+
+ /** The location. */
+ private Location location;
+
+ /** The time visited. */
+ private Date timeVisited;
+
+}
diff --git a/tourguide/src/main/java/tourGuide/proxy/MicroServiceTripDealsProxy.java b/tourguide/src/main/java/tourGuide/proxy/MicroServiceTripDealsProxy.java
new file mode 100644
index 0000000..cf9d213
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/proxy/MicroServiceTripDealsProxy.java
@@ -0,0 +1,49 @@
+package tourGuide.proxy;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import tourGuide.dto.ProviderDTO;
+
+
+/**
+ * The Interface MicroServiceTripDealsProxy.
+ */
+//@FeignClient(value = "tripdeals-microservice", url = "localhost:9093/tripDeals") // this URL FeignClient is for host run (eclipse or gradle commandline)
+@FeignClient(value = "tripdeals-microservice", url = "${CLIENT_TRIPDEALS_BASE_URL:http://localhost:9093/tripDeals}") // this URL FeignClient is for docker
+public interface MicroServiceTripDealsProxy {
+
+
+
+ // ##############################################################
+
+ /**
+ * Gets the providers.
+ *
+ * @param apiKey the api key
+ * @param userId the user id
+ * @param adults the adults
+ * @param children the children
+ * @param nightsStay the nights stay
+ * @param rewardPoints the reward points
+ * @return the providers
+ */
+ @GetMapping("/providers/{apiKey}/{userId}/{adults}/{children}/{nightsStay}/{rewardPoints}")
+ List getProviders(
+ @PathVariable("apiKey") final String apiKey,
+ @PathVariable("userId") final UUID userId,
+ @PathVariable("adults") final int adults,
+ @PathVariable("children") final int children,
+ @PathVariable("nightsStay") final int nightsStay,
+ @PathVariable("rewardPoints") final int rewardPoints);
+
+
+
+ // ##############################################################
+
+}
+
diff --git a/tourguide/src/main/java/tourGuide/proxy/MicroserviceGpsProxy.java b/tourguide/src/main/java/tourGuide/proxy/MicroserviceGpsProxy.java
new file mode 100644
index 0000000..214f55e
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/proxy/MicroserviceGpsProxy.java
@@ -0,0 +1,60 @@
+package tourGuide.proxy;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.dto.VisitedLocationDTO;
+
+
+/**
+ * The Interface MicroserviceGpsProxy.
+ */
+
+//@FeignClient(value = "gps-microservice", url = "localhost:9091/gps") // this URL FeignClient is for host run (eclipse or gradle commandline)
+@FeignClient(value = "gps-microservice", url = "${CLIENT_GPS_BASE_URL:http://localhost:9091/gps}") // this URL FeignClient is for docker
+public interface MicroserviceGpsProxy {
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the user location.
+ *
+ * @param userId the user id
+ * @return the user location
+ */
+ @GetMapping("/userLocation/{userId}")
+ VisitedLocationDTO getUserLocation(
+ @PathVariable("userId") final UUID userId);
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the attractions.
+ *
+ * @return the attractions
+ */
+ @GetMapping("/attractions")
+ List getAttractions();
+
+
+
+
+ // ##############################################################
+
+
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/proxy/MicroserviceRewardsProxy.java b/tourguide/src/main/java/tourGuide/proxy/MicroserviceRewardsProxy.java
new file mode 100644
index 0000000..3e991e1
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/proxy/MicroserviceRewardsProxy.java
@@ -0,0 +1,39 @@
+package tourGuide.proxy;
+
+import java.util.UUID;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+
+
+/**
+ * The Interface MicroserviceRewardsProxy.
+ */
+//@FeignClient(value = "rewards-microservice", url = "localhost:9092/rewards") // this URL FeignClient is for host run (eclipse or gradle commandline)
+@FeignClient(value = "rewards-microservice", url = "${CLIENT_REWARDS_BASE_URL:http://localhost:9092/rewards}") // this URL FeignClient is for docker
+public interface MicroserviceRewardsProxy {
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the reward points.
+ *
+ * @param attractionId the attraction id
+ * @param userId the user id
+ * @return the reward points
+ */
+ @GetMapping("/points/{attractionId}/{userId}")
+ int getRewardPoints(
+ @PathVariable("attractionId") final UUID attractionId,
+ @PathVariable("userId") final UUID userId);
+
+
+ // ##############################################################
+
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/service/GpsLocationService.java b/tourguide/src/main/java/tourGuide/service/GpsLocationService.java
new file mode 100644
index 0000000..ad86f78
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/GpsLocationService.java
@@ -0,0 +1,548 @@
+package tourGuide.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+import javax.annotation.PostConstruct;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.dto.LocationDTO;
+import tourGuide.dto.NearByAttractionDTO;
+import tourGuide.dto.UserAttractionRecommendationDTO;
+import tourGuide.dto.VisitedLocationDTO;
+import tourGuide.helper.InternalTestHelper;
+import tourGuide.model.Location;
+import tourGuide.model.User;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.proxy.MicroserviceRewardsProxy;
+import tourGuide.tracker.Tracker;
+import tourGuide.util.DistanceCalculator;
+import tourGuide.util.LocationMapper;
+import tourGuide.util.VisitedLocationMapper;
+
+
+/**
+ * The Class TourGuideService.
+ */
+@Service
+public class GpsLocationService implements IGpsLocationService {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(GpsLocationService.class);
+
+ /** The executor service. */
+ private final ExecutorService executorService = Executors
+ .newFixedThreadPool(1000);
+
+ /** The user service. */
+ private final IUserService userService;
+
+
+ /** The gps util micro service. */
+ private final MicroserviceGpsProxy gpsUtilMicroService;
+
+ /** The rewards micro service. */
+ private MicroserviceRewardsProxy rewardsMicroService;
+
+
+ /** The rewards service. */
+ private final IRewardService rewardsService;
+
+
+ /** The location mapper. */
+ private final LocationMapper locationMapper;
+
+ /** The visited location mapper. */
+ private final VisitedLocationMapper visitedLocationMapper;
+
+
+ /** The distance calculator. */
+ private final DistanceCalculator distanceCalculator;
+
+ /** The tracker. */
+ public Tracker tracker;
+
+ /** The test mode. */
+ @Value("${test.mode.enabled}")
+ private boolean isTestMode;
+
+ /** The is performance test. */
+ @Value("${performance.test.enabled}")
+ private boolean isPerformanceTest;
+
+ /** The internal test helper. */
+ private InternalTestHelper internalTestHelper
+ = new InternalTestHelper();
+
+
+ // ##############################################################
+
+
+
+
+
+ /**
+ * Instantiates a new tour guide service.
+ *
+ * @param gpsUtilMicroService the gps util micro service
+ * @param rewardsMicroService the rewards micro service
+ * @param tripDealsMicroService the trip deals micro service
+ * @param rewardsService the rewards service
+ * @param internalTestHelper the internal test helper
+ * @param userPreferencesMapper the user preferences mapper
+ * @param userRewardMapper the user reward mapper
+ * @param locationMapper the location mapper
+ * @param visitedLocationMapper the visited location mapper
+ * @param providerMapper the provider mapper
+ * @param distanceCalculator the distance calculator
+ */
+ @Autowired
+ public GpsLocationService(
+ final MicroserviceGpsProxy gpsUtilMicroService,
+ final MicroserviceRewardsProxy rewardsMicroService,
+ final IRewardService rewardsService,
+ final InternalTestHelper internalTestHelper,
+ final LocationMapper locationMapper,
+ final VisitedLocationMapper visitedLocationMapper,
+ final DistanceCalculator distanceCalculator,
+ IUserService userService) {
+
+ this.userService = userService;
+ this.gpsUtilMicroService = gpsUtilMicroService;
+ this.rewardsMicroService = rewardsMicroService;
+ this.rewardsService = rewardsService;
+ this.internalTestHelper = internalTestHelper;
+ this.locationMapper = locationMapper;
+ this.visitedLocationMapper = visitedLocationMapper;
+ this.distanceCalculator = distanceCalculator;
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Initialization.
+ */
+ @PostConstruct
+ public void initialization() {
+
+ if (isTestMode) {
+
+ logger.info("TestMode enabled");
+
+ logger.debug("Initializing users");
+
+ internalTestHelper.initializeInternalUsers();
+
+ logger.debug("Finished initializing users");
+ }
+
+ if (!isPerformanceTest) {
+
+ this.tracker = new Tracker(rewardsService, gpsUtilMicroService, userService);
+
+ logger.info("## Tracker instance initiated");
+
+ tracker.startTracking();
+ }
+
+// addShutDownHook();
+
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the user location.
+ *
+ * @param userName the user name
+ * @return the user location
+ */
+ public LocationDTO getUserLocation(final String userName) {
+
+// logger.info("## getUserLocation"
+// + " for user {} invoked ", userName );
+
+ User user = userService.getUser(userName);
+
+ if (user.getVisitedLocations().size() > 0) {
+ return locationMapper
+ .toLocationDTO(
+ user.getLastVisitedLocation().getLocation());
+ }
+
+ return locationMapper.toLocationDTO(
+ gpsUtilMicroService.getUserLocation(
+ user.getUserId()).getLocation());
+ }
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the all users last location.
+ *
+ * @return the all users last location
+ */
+ public Map getAllUserRecentLocation() {
+
+ return userService.getAllUsers()
+ .parallelStream()
+ .collect(
+ Collectors.toMap(
+ u -> u.getUserId().toString(),
+ u -> getUserLocation(u.getUserName())));
+ }
+
+ // ##############################################################
+
+
+ /**
+ * Track user location.
+ *
+ * @param user the user
+ * @return the completable future
+ */
+ public CompletableFuture> trackUserLocation(final User user) {
+
+// logger.info("## trackUserLocation() for"
+// + " user {} invoked", user.getUserName());
+
+
+ return CompletableFuture.supplyAsync(() -> {
+
+ VisitedLocationDTO visitedLocation = gpsUtilMicroService
+ .getUserLocation(user.getUserId());
+
+ user.addToVisitedLocations(visitedLocationMapper
+ .toVisitedLocation(visitedLocation));
+
+ CompletableFuture.runAsync(() -> {
+ rewardsService.calculateRewards(user);
+ });
+
+ return visitedLocation;
+
+ }, executorService);
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Gets the user attraction recommendation.
+ *
+ * @param userName the user name
+ * @return the user attraction recommendation
+ */
+ public UserAttractionRecommendationDTO getUserAttractionRecommendation(
+ final String userName) {
+
+
+ User user = userService.getUser(userName);
+ Location userLocation = locationMapper
+ .toLocation(getUserLocation(userName));
+
+ CompletableFuture.runAsync(() -> {
+ rewardsService.calculateRewards(user);
+ });
+
+ List attractions = gpsUtilMicroService
+ .getAttractions();
+
+ Map attractionsMap = getAttractiosMap(
+ userLocation,
+ attractions);
+
+ Map closestAttractionsMap = getClosestAttractionsMap(
+ attractionsMap);
+
+
+ List nearByAttractions = getNearByAttractions(
+ user,
+ userLocation,
+ closestAttractionsMap);
+
+ return new UserAttractionRecommendationDTO(
+ userLocation,
+ nearByAttractions);
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the attractios map.
+ *
+ * @param userLocation the user location
+ * @param attractions the attractions
+ * @return the attractios map
+ */
+ private Map getAttractiosMap(
+ Location userLocation,
+ List attractions) {
+
+
+ Map attractionsMap = new HashMap<>();
+
+ // ********************************************************
+
+ /*Sequential Streams VS Parallel stream (stream() Vs parallelStream())
+ Sequential streams outperformed parallel streams
+ when the number of elements in the collection was
+ less than 100,000. Parallel streams performed
+ significantly better than sequential streams
+ when the number of elements was more than 100,000.*/
+ // ********************************************************
+// attractions.stream()
+ attractions
+ .stream()
+ .forEach(a -> {
+ attractionsMap
+ .put(a, distanceCalculator
+ .getDistanceInMiles(a
+ .getLocation(), userLocation));
+ });
+ return attractionsMap;
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the closest attractions map.
+ *
+ * @param attractionsMap the attractions map
+ * @return the closest attractions map
+ */
+ private Map getClosestAttractionsMap(
+ Map attractionsMap) {
+
+ Map closestAttractionsMap = attractionsMap
+ .entrySet()
+// .stream()
+ .stream()
+ .sorted(Map.Entry.comparingByValue())
+ .limit(5)
+ .collect(
+ Collectors
+ .toMap(
+ Map.Entry::getKey,
+ Map.Entry::getValue,
+ (e1, e2) -> e1,
+ LinkedHashMap::new));
+ return closestAttractionsMap;
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the near by attractions.
+ *
+ * @param user the user
+ * @param userLocation the user location
+ * @param closestAttractionsMap the closest attractions map
+ * @return the near by attractions
+ */
+ private List getNearByAttractions(
+ User user, Location userLocation,
+ Map closestAttractionsMap) {
+
+ List nearByAttractions = new ArrayList<>();
+
+ final AtomicInteger indexHolder = new AtomicInteger();
+ final AtomicInteger totalPoints = new AtomicInteger();
+ cumulativeRewardPointsForUserBasedOnNearbyAtrractions(
+ user,
+ closestAttractionsMap,
+ nearByAttractions,
+ indexHolder,
+ totalPoints);
+
+ return nearByAttractions;
+ }
+
+
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the attractions reward points.
+ *
+ * @param user the user
+ * @param a the a
+ * @return the attractions reward points
+ */
+ private int getAttractionsRewardPoints(
+ User user,
+ Entry a) {
+ return rewardsMicroService
+ .getRewardPoints(
+ a.getKey().getAttractionId(),
+ user.getUserId());
+ }
+
+
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the total reward points for user.
+ *
+ * @param userName the user name
+ * @return the total reward points for user
+ */
+ public int getTotalRewardPointsForUser(
+ final String userName) {
+
+
+ User user = userService.getUser(userName);
+ Location userLocation = locationMapper
+ .toLocation(getUserLocation(userName));
+
+ CompletableFuture.runAsync(() -> {
+ rewardsService.calculateRewards(user);
+ });
+
+ List attractions = gpsUtilMicroService
+ .getAttractions();
+
+ Map attractionsMap = getAttractiosMap(
+ userLocation,
+ attractions);
+
+ Map closestAttractionsMap = getClosestAttractionsMap(
+ attractionsMap);
+
+ List nearByAttractions = new ArrayList<>();
+
+ final AtomicInteger indexHolder = new AtomicInteger();
+ final AtomicInteger totalPoints = new AtomicInteger();
+
+ cumulativeRewardPointsForUserBasedOnNearbyAtrractions(
+ user,
+ closestAttractionsMap,
+ nearByAttractions,
+ indexHolder,
+ totalPoints);
+
+ return totalPoints.intValue();
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Cumulative reward points for user based on nearby atrractions.
+ *
+ * @param user the user
+ * @param closestAttractionsMap the closest attractions map
+ * @param nearByAttractions the near by attractions
+ * @param indexHolder the index holder
+ * @param totalPoints the total points
+ */
+ private void cumulativeRewardPointsForUserBasedOnNearbyAtrractions(
+ User user,
+ Map closestAttractionsMap,
+ List nearByAttractions,
+ final AtomicInteger indexHolder,
+ final AtomicInteger totalPoints) {
+
+ closestAttractionsMap.entrySet()
+ .stream()
+ .forEach(a -> {
+ final int index = indexHolder.getAndIncrement();
+
+ nearByAttractions
+ .add(new NearByAttractionDTO(
+ a.getKey().getAttractionName(),
+ a.getKey().getLocation(),
+ a.getValue(),
+ getAttractionsRewardPoints(user, a)));
+ logger.info("###########" + nearByAttractions
+ .get(index).getRewardPoints());
+
+ totalPoints.addAndGet(nearByAttractions
+ .get(index).getRewardPoints());
+
+ logger.info("###########" + totalPoints);
+ });
+ }
+
+
+
+
+ // ##############################################################
+
+// /**
+// * stop users tracking service
+// */
+// private void addShutDownHook() {
+// Runtime.getRuntime().addShutdownHook(new Thread() {
+// public void run() {
+// tracker.stopTracking();
+// }
+// });
+// }
+
+
+
+ // ##############################################################
+
+}
diff --git a/tourguide/src/main/java/tourGuide/service/IGpsLocationService.java b/tourguide/src/main/java/tourGuide/service/IGpsLocationService.java
new file mode 100644
index 0000000..b7635e3
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/IGpsLocationService.java
@@ -0,0 +1,57 @@
+package tourGuide.service;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import tourGuide.dto.LocationDTO;
+import tourGuide.dto.UserAttractionRecommendationDTO;
+import tourGuide.model.User;
+
+/**
+ * The Interface ITourGuideService.
+ */
+public interface IGpsLocationService {
+
+
+
+ /**
+ * Gets the user location.
+ *
+ * @param userName the user name
+ * @return the user location
+ */
+ LocationDTO getUserLocation(String userName);
+
+
+ /**
+ * Gets the user attraction recommendation.
+ *
+ * @param userName the user name
+ * @return the user attraction recommendation
+ */
+ UserAttractionRecommendationDTO getUserAttractionRecommendation(
+ String userName);
+
+ /**
+ * Gets the all users last location.
+ *
+ * @return the all users last location
+ */
+// HashMap getAllUsersLastLocation();
+ Map getAllUserRecentLocation();
+
+
+
+ /**
+ * Track user location.
+ *
+ * @param user the user
+ * @return the completable future
+ */
+ CompletableFuture> trackUserLocation(User user);
+
+
+ int getTotalRewardPointsForUser(String userName);
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/service/IRewardService.java b/tourguide/src/main/java/tourGuide/service/IRewardService.java
new file mode 100644
index 0000000..2862666
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/IRewardService.java
@@ -0,0 +1,28 @@
+package tourGuide.service;
+
+import java.util.List;
+
+import tourGuide.dto.UserRewardDTO;
+import tourGuide.model.User;
+
+/**
+ * The Interface IRewardService.
+ */
+public interface IRewardService {
+
+ /**
+ * Calculate rewards.
+ *
+ * @param user the user
+ */
+ void calculateRewards(User user);
+
+ /**
+ * Gets the user rewards.
+ *
+ * @param userName the user name
+ * @return the user rewards
+ */
+ List getUserRewards(String userName);
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/service/ITripDealsService.java b/tourguide/src/main/java/tourGuide/service/ITripDealsService.java
new file mode 100644
index 0000000..25e89f3
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/ITripDealsService.java
@@ -0,0 +1,17 @@
+package tourGuide.service;
+
+import java.util.List;
+
+import tourGuide.dto.ProviderDTO;
+
+public interface ITripDealsService {
+
+ /**
+ * Gets the trip deals.
+ *
+ * @param userName the user name
+ * @return the trip deals
+ */
+ List getUserTripDeals(String userName);
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/service/IUserService.java b/tourguide/src/main/java/tourGuide/service/IUserService.java
new file mode 100644
index 0000000..a204bb5
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/IUserService.java
@@ -0,0 +1,41 @@
+package tourGuide.service;
+
+import java.util.List;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.model.User;
+
+public interface IUserService {
+
+ /**
+ * Gets the user.
+ *
+ * @param userName the user name
+ * @return the user
+ */
+ User getUser(String userName);
+
+ /**
+ * Gets the all users.
+ *
+ * @return the all users
+ */
+ List getAllUsers();
+
+ /**
+ * Adds the user.
+ *
+ * @param user the user
+ */
+ void addUser(User user);
+
+ /**
+ * Update user preferences.
+ *
+ * @param userName the user name
+ * @param userPreferencesDTO the user preferences DTO
+ * @return the user preferences DTO
+ */
+ UserPreferencesDTO updateUserPreferences(String userName, UserPreferencesDTO userPreferencesDTO);
+
+}
\ No newline at end of file
diff --git a/tourguide/src/main/java/tourGuide/service/RewardsService.java b/tourguide/src/main/java/tourGuide/service/RewardsService.java
new file mode 100644
index 0000000..a26103a
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/RewardsService.java
@@ -0,0 +1,289 @@
+package tourGuide.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.dto.UserRewardDTO;
+import tourGuide.model.Location;
+import tourGuide.model.User;
+import tourGuide.model.UserReward;
+import tourGuide.model.VisitedLocation;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.proxy.MicroserviceRewardsProxy;
+import tourGuide.util.AttractionMapper;
+import tourGuide.util.DistanceCalculator;
+import tourGuide.util.UserRewardMapper;
+/**
+ * The Class RewardsService.
+ */
+@Service
+public class RewardsService implements IRewardService {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(RewardsService.class);
+
+
+ /** The Constant DEFAULT_PROXIMITY_BUFFER. */
+ public static final int DEFAULT_PROXIMITY_BUFFER = 10;
+
+ /** The user service. */
+ private final IUserService userService;
+
+ /** The gps util micro service. */
+ private final MicroserviceGpsProxy gpsUtilMicroService;
+
+ /** The rewards micro service. */
+ private MicroserviceRewardsProxy rewardsMicroService;
+
+ /** The attraction mapper. */
+ private final AttractionMapper attractionMapper;
+
+ /** The attraction mapper. */
+ private final UserRewardMapper userRewardMapper;
+
+ /** The distance calculator. */
+ private final DistanceCalculator distanceCalculator;
+
+
+
+ // ##############################################################
+
+ /** The executor service. */
+ // Concurrency JDK API interface that simplifies running tasks
+ // in asynchronous mode as threads
+ private final ExecutorService executorService = Executors
+ .newFixedThreadPool(1000);
+
+
+
+ // ##############################################################
+
+
+
+
+/**
+ * Instantiates a new rewards service.
+ *
+ * @param gpsUtilMicroService the gps util micro service
+ * @param rewardsMicroService the rewards micro service
+ * @param attractionMapper the attraction mapper
+ * @param distanceCalculator the distance calculator
+ */
+@Autowired
+ public RewardsService(
+ final MicroserviceGpsProxy gpsUtilMicroService,
+ final MicroserviceRewardsProxy rewardsMicroService,
+ final IUserService userService,
+ final AttractionMapper attractionMapper,
+ final UserRewardMapper userRewardMapper,
+ final DistanceCalculator distanceCalculator) {
+ this.gpsUtilMicroService = gpsUtilMicroService;
+ this.rewardsMicroService = rewardsMicroService;
+ this.userService = userService;
+ this.attractionMapper = attractionMapper;
+ this.userRewardMapper = userRewardMapper;
+ this.distanceCalculator = distanceCalculator;
+ }
+
+
+
+// ##############################################################
+
+
+
+ /**
+ * Gets the user rewards.
+ *
+ * @param userName the user name
+ * @return the user rewards
+ */
+ @Override
+ public List getUserRewards(
+ final String userName) {
+
+ logger.info("## getUserRewards list for"
+ + " user {} retrieved ", userName );
+
+ User user = userService.getUser(userName);
+
+
+ List userRewards = new ArrayList<>();
+ user.getUserRewards().stream()
+ .forEach(reward -> {
+ userRewards.add(userRewardMapper
+ .toUserRewardDTO(reward));
+ });
+
+ return userRewards;
+
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Calculate rewards.
+ *
+ * @param user the user
+ */
+ @Override
+ public void calculateRewards(final User user) {
+
+ // Thread-safe variant of ArrayList (creates a clone of the underlying array)
+ // used in a Thread based environment where read operations are very
+ // frequent and update operations are rare
+
+ CopyOnWriteArrayList userLocations
+ = new CopyOnWriteArrayList<>();
+
+ CopyOnWriteArrayList attractions
+ = new CopyOnWriteArrayList<>();
+
+ userLocations.addAll(user.getVisitedLocations());
+ attractions.addAll(gpsUtilMicroService.getAttractions());
+
+ userLocations.stream().forEach(visitedLocation -> {
+ attractions.stream()
+
+ // check if the visited spot is near attraction spot
+ .filter(attraction -> isWithinAttractionProximity(
+ visitedLocation,
+ attraction.getLocation()))
+
+ // scanning for each attractions around
+ .forEach(attraction -> {
+
+
+ // check if user has been offered reward
+ // for this attraction spot
+ if (checkIfUserIsOfferedRewardToThisAttractionSpot(
+ user,
+ attraction)) {
+
+ // if not yet rewards offered
+ // reward is added to user's list
+ // along with reward points
+ user.addUserReward(
+ getRewardPoints(
+ user,
+ visitedLocation,
+ attraction));
+ }
+ });
+ });
+ }
+
+
+ // ##############################################################
+
+
+ /**
+ * Check if user is offered reward to this attraction spot.
+ *
+ * @param user the user
+ * @param attraction the attraction
+ * @return true, if successful
+ */
+ public boolean checkIfUserIsOfferedRewardToThisAttractionSpot(
+ final User user,
+ AttractionDTO attraction) {
+
+ return user.getUserRewards().stream()
+ .noneMatch(r -> r.attraction.getAttractionName()
+ .equals(attraction.getAttractionName()));
+ }
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the reward points.
+ *
+ * @param user the user
+ * @param visitedLocation the visited location
+ * @param attraction the attraction
+ * @return the reward points
+ */
+ public UserReward getRewardPoints(
+ final User user,
+ VisitedLocation visitedLocation,
+ AttractionDTO attraction) {
+
+ return new UserReward(
+ visitedLocation,
+ attractionMapper.toAttraction(attraction),
+
+ rewardsMicroService.getRewardPoints(
+ attraction.getAttractionId(),
+ user.getUserId()));
+ }
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Calculate reward async.
+ *
+ * @param user the user
+ * @return the completable future
+ */
+ public CompletableFuture> calculateRewardAsync(
+ final User user) {
+
+
+ return CompletableFuture.runAsync(() -> {
+ this.calculateRewards(user);
+ }, executorService);
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Checks if is within attraction proximity.
+ *
+ * @param visitedLocation the visited location
+ * @param attractionLocation the attraction location
+ * @return true, if is within attraction proximity
+ */
+ public boolean isWithinAttractionProximity(
+ final VisitedLocation visitedLocation,
+ final Location attractionLocation) {
+
+
+ return !(
+ distanceCalculator.getDistanceInMiles(
+ attractionLocation,
+ visitedLocation.getLocation()) >
+ DEFAULT_PROXIMITY_BUFFER);
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/service/TripDealsService.java b/tourguide/src/main/java/tourGuide/service/TripDealsService.java
new file mode 100644
index 0000000..6927e2d
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/TripDealsService.java
@@ -0,0 +1,177 @@
+package tourGuide.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import tourGuide.dto.ProviderDTO;
+import tourGuide.helper.InternalTestHelper;
+import tourGuide.model.Provider;
+import tourGuide.model.User;
+import tourGuide.proxy.MicroServiceTripDealsProxy;
+import tourGuide.tracker.Tracker;
+import tourGuide.util.ProviderMapper;
+
+@Service
+public class TripDealsService implements ITripDealsService {
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(TripDealsService.class);
+
+ /** The user service. */
+ private final IUserService userService;
+
+ /** The trip deals micro service. */
+ private final MicroServiceTripDealsProxy tripDealsMicroService;
+
+ /** The provider mapper. */
+ private final ProviderMapper providerMapper;
+
+ /** The internal test helper. */
+ private InternalTestHelper internalTestHelper
+ = new InternalTestHelper();
+
+ /** The tracker. */
+ public Tracker tracker;
+
+
+
+ // ##############################################################
+
+
+
+ @Autowired
+ public TripDealsService(
+ Tracker tracker,
+ IUserService userService,
+ MicroServiceTripDealsProxy tripDealsMicroService,
+ ProviderMapper providerMapper,
+ InternalTestHelper internalTestHelper) {
+
+ this.tracker = tracker;
+ this.userService = userService;
+ this.tripDealsMicroService = tripDealsMicroService;
+ this.providerMapper = providerMapper;
+ this.internalTestHelper = internalTestHelper;
+ }
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Gets the trip deals.
+ *
+ * @param userName the user name
+ * @return the trip deals
+ */
+ @Override
+ public List getUserTripDeals(
+ final String userName) {
+
+ logger.info("## getTripDeals() method for"
+ + " user {} invoked", userName);
+
+ User user = userService.getUser(userName);
+
+ int cumulativeRewardPoints = user
+ .getUserRewards()
+ .stream()
+ .mapToInt(r -> r
+ .getRewardPoints())
+ .sum();
+
+ logger.info("## cumulative points for"
+ + " user {} : {}", user.getUserName(), cumulativeRewardPoints);
+
+
+ List providers = getProvidersDTOListForUser(
+ user,
+ cumulativeRewardPoints);
+
+
+ List providerList = mapProvidersDTOListToProvidersListDO(
+ providers);
+
+
+ user.setTripDeals(providerList);
+
+ logger.info("## TripDeals for"
+ + " user {} : {}", user.getUserName(), user.getTripDeals());
+
+ return providers;
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Gets the providers DTO list for user.
+ *
+ * @param user the user
+ * @param cumulativeRewardPoints the cumulative reward points
+ * @return the providers DTO list for user
+ */
+ private List getProvidersDTOListForUser(
+ User user,
+ int cumulativeRewardPoints) {
+
+ List providers = tripDealsMicroService
+ .getProviders(
+ internalTestHelper.getTripPricerApiKey(),
+ user.getUserId(),
+ user.getUserPreferences().getNumberOfAdults(),
+ user.getUserPreferences().getNumberOfChildren(),
+ user.getUserPreferences().getTripDuration(),
+ cumulativeRewardPoints);
+
+ logger.info("## Providers for"
+ + " user {} : {}", user.getUserName(), providers);
+
+ return providers;
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Map providers DTO list to providers list DO.
+ *
+ * @param providers the providers
+ * @return the list
+ */
+ private List mapProvidersDTOListToProvidersListDO(
+ List providers) {
+
+ List providerList = new ArrayList<>();
+
+ providers.forEach(provider -> {
+ providerList.add(providerMapper.toProvider(provider));
+
+ });
+ return providerList;
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/service/UserService.java b/tourguide/src/main/java/tourGuide/service/UserService.java
new file mode 100644
index 0000000..b855d39
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/service/UserService.java
@@ -0,0 +1,208 @@
+package tourGuide.service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.javamoney.moneta.Money;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.exception.DataAlreadyRegisteredException;
+import tourGuide.exception.UserNotFoundException;
+import tourGuide.helper.InternalTestHelper;
+import tourGuide.model.User;
+import tourGuide.model.UserPreferences;
+import tourGuide.util.UserPreferencesMapper;
+
+@Service
+public class UserService implements IUserService {
+
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(UserService.class);
+
+
+ /** The user preferences mapper. */
+ private final UserPreferencesMapper userPreferencesMapper;
+
+
+ /** The internal test helper. */
+ private InternalTestHelper internalTestHelper
+ = new InternalTestHelper();
+
+
+ // ##############################################################
+
+
+
+
+ @Autowired
+ public UserService(
+ UserPreferencesMapper userPreferencesMapper,
+ InternalTestHelper internalTestHelper) {
+
+ this.userPreferencesMapper = userPreferencesMapper;
+ this.internalTestHelper = internalTestHelper;
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Gets the user.
+ *
+ * @param userName the user name
+ * @return the user
+ */
+ @Override
+ public User getUser(String userName) {
+
+// logger.info("## getUser() for user {} invoked ", userName );
+
+ User user = internalTestHelper.getInternalUserMap().get(userName);
+
+ if (user == null) {
+ throw new UserNotFoundException("Username not found");
+ }
+
+ return user;
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Gets the all users.
+ *
+ * @return the all users
+ */
+ @Override
+ public List getAllUsers() {
+
+ logger.info("## getAllUser() method invoked");
+
+ List users = internalTestHelper
+ .getInternalUserMap()
+ .values()
+ .stream()
+ .collect(Collectors.toList());
+
+ if (users.isEmpty()) {
+ throw new UserNotFoundException("User List unavailable");
+ }
+
+ return users;
+
+ }
+
+
+ /**
+ * Adds the user.
+ *
+ * @param user the user
+ */
+ @Override
+ public void addUser(final User user) {
+
+ logger.info("## addUser() for user {} invoked ", user );
+
+
+ if(!internalTestHelper
+ .internalUserMap
+ .containsKey(user.getUserName())) {
+
+ logger.info("## addUser() for"
+ + " user {} gets added"
+ + " to map ", user.getUserName() );
+
+ internalTestHelper
+ .internalUserMap.put(
+ user.getUserName(),
+ user);
+ } else {
+ throw new DataAlreadyRegisteredException(""
+ + "Username exists already");
+ }
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ /**
+ * Update user preferences.
+ *
+ * @param userName the user name
+ * @param userPreferencesDTO the user preferences DTO
+ * @return the user preferences DTO
+ */
+ @Override
+ public UserPreferencesDTO updateUserPreferences(
+ final String userName,
+ final UserPreferencesDTO userPreferencesDTO) {
+
+
+ User user = getUser(userName);
+
+// User user = internalTestHelper
+// .getInternalUserMap()
+// .get(userName);
+
+
+ UserPreferences userPreferences = user
+ .getUserPreferences();
+ userPreferences.setAttractionProximity(userPreferencesDTO
+ .getAttractionProximity());
+ userPreferences.setHighPricePoint(Money.of(userPreferencesDTO
+ .getHighPricePoint(), userPreferences
+ .getCurrency()));
+ userPreferences.setLowerPricePoint(Money.of(userPreferencesDTO
+ .getLowerPricePoint(), userPreferences
+ .getCurrency()));
+ userPreferences.setTripDuration(userPreferencesDTO
+ .getTripDuration());
+ userPreferences.setTicketQuantity(userPreferencesDTO
+ .getTicketQuantity());
+ userPreferences.setNumberOfAdults(userPreferencesDTO
+ .getNumberOfAdults());
+ userPreferences.setNumberOfChildren(userPreferencesDTO
+ .getNumberOfChildren());
+
+
+ UserPreferencesDTO userPreferencesUpdated = userPreferencesMapper
+ .toUserPreferencesDTO(user.getUserPreferences());
+
+ return userPreferencesUpdated;
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+
+
+
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/tracker/Tracker.java b/tourguide/src/main/java/tourGuide/tracker/Tracker.java
new file mode 100644
index 0000000..1b6edbd
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/tracker/Tracker.java
@@ -0,0 +1,240 @@
+package tourGuide.tracker;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang3.time.StopWatch;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import tourGuide.dto.VisitedLocationDTO;
+import tourGuide.model.User;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.service.IRewardService;
+import tourGuide.service.IUserService;
+import tourGuide.util.VisitedLocationMapper;
+
+/**
+ * The Class Tracker.
+ */
+@Component
+public class Tracker extends Thread {
+
+ /** The logger. */
+ private Logger logger
+ = LoggerFactory.getLogger(Tracker.class);
+
+ /** The Constant trackingPollingInterval. */
+ private static final long trackingPollingInterval
+ = TimeUnit.MINUTES.toSeconds(5);
+
+ // JDK API interface that simplifies running tasks in asynchronous mode
+ // automatically provides a pool of threads
+ // and an API for assigning tasks to it
+
+ // Concurrency JDK API interface that simplifies running tasks
+ // in asynchronous mode as threads
+ /** The executor service. */
+ private final ExecutorService executorService = Executors
+ .newSingleThreadExecutor();
+// private final ExecutorService executorService = Executors
+// .newFixedThreadPool(1000);
+
+
+ /** The user service. */
+ private final IUserService userService;
+
+ /** The rewards service. */
+ private final IRewardService rewardsService;
+
+ /** The gps util micro service. */
+ private final MicroserviceGpsProxy gpsUtilMicroService;
+
+
+ /** The visited location mapper. */
+ private VisitedLocationMapper visitedLocationMapper;
+
+ /** The stop. */
+ private boolean stop = false;
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Instantiates a new tracker.
+ *
+ * @param tourGuideService the tour guide service
+ */
+ public Tracker(
+ IRewardService rewardsService,
+ MicroserviceGpsProxy gpsUtilMicroService,
+ IUserService userService) {
+
+ this.userService = userService;
+ this.rewardsService = rewardsService;
+ this.gpsUtilMicroService = gpsUtilMicroService;
+ }
+
+ // ##############################################################
+
+
+ /**
+ * Triggers to start the Tracker thread.
+ */
+ public void startTracking() {
+ stop = false;
+ // Method submits a Callable or a Runnable task to an ExecutorService
+ // and returns a result of type Future:
+ executorService.submit(this);
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Assures to shut down the Tracker thread
+ */
+ public void stopTracking() {
+
+ logger.info("stopTracking Called");
+
+ stop = true;
+
+ // Method tries to destroy the ExecutorService immediately,
+ // but it doesn't guarantee that all the running threads
+ // will be stopped at the same time
+ executorService.shutdownNow();
+
+
+ }
+
+
+
+ // ##############################################################
+
+ @Override
+ public void run() {
+ StopWatch stopWatch = new StopWatch();
+
+ while (true) {
+
+ if (Thread.currentThread().isInterrupted() || stop) {
+// logger.info("Run Tracker invoked");
+ break;
+ }
+
+ List users = userService.getAllUsers();
+ logger.info("Begin Tracker. Tracking "
+ + users.size() + " users.");
+
+ stopWatch.start();
+// CompletableFuture>[] futures = trackingUsersWithSequentialStreaming(
+// users);
+ trackingUsersWithSequentialStreaming(users);
+ stopWatch.stop();
+
+ logger.info("Finished tracking users, tracker Time Elapsed: "
+ + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime())
+ + " seconds.");
+
+ stopWatch.reset();
+
+ try {
+
+ logger.info("Tracker sleeping");
+ TimeUnit.SECONDS.sleep(trackingPollingInterval);
+
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+
+
+
+ // ##############################################################
+
+
+
+ /**
+ * Tracking users with sequential streaming.
+ *
+ * @param users the users
+ * @return the completable future[]
+ */
+ private CompletableFuture>[] trackingUsersWithSequentialStreaming(
+ List users) {
+
+ CompletableFuture>[] futures = users.stream()
+ .map(this::trackUserLocation)
+ .toArray(CompletableFuture[]::new);
+
+ CompletableFuture.allOf(futures).join();
+ return futures;
+ }
+
+
+
+ // ##############################################################
+
+
+// /**
+// * Tracking users with parallel streaming.
+// *
+// * @param users the users
+// * @return the completable future[]
+// */
+// public CompletableFuture>[] trackingUsersWithParallelStreaming(
+// List users) {
+//
+// CompletableFuture>[] futures = users.parallelStream()
+// .map(tourGuideService::trackUserLocation)
+// .toArray(CompletableFuture[]::new);
+//
+// CompletableFuture.allOf(futures).join();
+// return futures;
+// }
+
+
+ // ##############################################################
+
+
+ /**
+ * Track user location.
+ *
+ * @param user the user
+ * @return the completable future
+ */
+ public CompletableFuture> trackUserLocation(final User user) {
+
+// logger.info("## trackUserLocation() for"
+// + " user {} invoked", user.getUserName());
+
+
+ return CompletableFuture.supplyAsync(() -> {
+
+ VisitedLocationDTO visitedLocation = gpsUtilMicroService
+ .getUserLocation(user.getUserId());
+
+ user.addToVisitedLocations(visitedLocationMapper
+ .toVisitedLocation(visitedLocation));
+
+ CompletableFuture.runAsync(() -> {
+ rewardsService.calculateRewards(user);
+ });
+
+ return visitedLocation;
+
+ }, executorService);
+ }
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/util/AttractionMapper.java b/tourguide/src/main/java/tourGuide/util/AttractionMapper.java
new file mode 100644
index 0000000..1c621a2
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/util/AttractionMapper.java
@@ -0,0 +1,26 @@
+package tourGuide.util;
+
+import org.springframework.stereotype.Component;
+
+import tourGuide.dto.AttractionDTO;
+
+@Component
+public class AttractionMapper {
+
+
+ // ##############################################################
+
+ public tourGuide.model.Attraction toAttraction(
+ final AttractionDTO attractionDTO) {
+
+ return new tourGuide.model.Attraction(
+ attractionDTO.getAttractionId(),
+ attractionDTO.getAttractionName(),
+ attractionDTO.getCity(),
+ attractionDTO.getState(),
+ attractionDTO.getLocation());
+ }
+
+ // ##############################################################
+
+}
diff --git a/tourguide/src/main/java/tourGuide/util/DistanceCalculator.java b/tourguide/src/main/java/tourGuide/util/DistanceCalculator.java
new file mode 100644
index 0000000..17a56da
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/util/DistanceCalculator.java
@@ -0,0 +1,53 @@
+package tourGuide.util;
+
+import org.springframework.stereotype.Component;
+
+import lombok.NoArgsConstructor;
+import tourGuide.model.Location;
+
+@Component
+@NoArgsConstructor
+public class DistanceCalculator {
+
+ public static final double STATUTE_MILES_PER_NAUTICAL_MILE = 1.15077945;
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Gets the distance in miles.
+ *
+ * @param loc1 the loc 1
+ * @param loc2 the loc 2
+ * @return the distance in miles
+ */
+ public double getDistanceInMiles(
+ final Location loc1,
+ final Location loc2) {
+
+ double lat1 = Math.toRadians(loc1.getLatitude());
+
+ double lon1 = Math.toRadians(loc1.getLongitude());
+
+ double lat2 = Math.toRadians(loc2.getLatitude());
+
+ double lon2 = Math.toRadians(loc2.getLongitude());
+
+ double angle = Math.acos(Math.sin(lat1) * Math.sin(lat2)
+ + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
+
+ double nauticalMiles = 60 * Math.toDegrees(angle);
+
+
+ double statuteMiles = STATUTE_MILES_PER_NAUTICAL_MILE * nauticalMiles;
+
+ return statuteMiles;
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/util/LocationMapper.java b/tourguide/src/main/java/tourGuide/util/LocationMapper.java
new file mode 100644
index 0000000..40f7c8f
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/util/LocationMapper.java
@@ -0,0 +1,31 @@
+package tourGuide.util;
+
+import org.springframework.stereotype.Component;
+import tourGuide.dto.LocationDTO;
+import tourGuide.model.Location;
+
+@Component
+public class LocationMapper {
+
+
+ // ##############################################################
+ public LocationDTO toLocationDTO(final Location location) {
+
+ return new LocationDTO(
+ location.getLatitude(),
+ location.getLongitude());
+ }
+
+
+ // ##############################################################
+
+ public Location toLocation(final LocationDTO locationDTO) {
+
+ return new Location(
+ locationDTO.getLatitude(),
+ locationDTO.getLongitude());
+ }
+
+ // ##############################################################
+
+}
diff --git a/tourguide/src/main/java/tourGuide/util/ProviderMapper.java b/tourguide/src/main/java/tourGuide/util/ProviderMapper.java
new file mode 100644
index 0000000..9fe1f60
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/util/ProviderMapper.java
@@ -0,0 +1,28 @@
+package tourGuide.util;
+
+import org.springframework.stereotype.Component;
+import tourGuide.dto.ProviderDTO;
+import tourGuide.model.Provider;
+
+@Component
+public class ProviderMapper {
+
+
+
+
+ // ##############################################################
+
+
+ public Provider toProvider(final ProviderDTO providerDTO) {
+
+ return new Provider(
+ providerDTO.getName(),
+ providerDTO.getPrice(),
+ providerDTO.getTripId());
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/util/UserPreferencesMapper.java b/tourguide/src/main/java/tourGuide/util/UserPreferencesMapper.java
new file mode 100644
index 0000000..3292dfb
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/util/UserPreferencesMapper.java
@@ -0,0 +1,38 @@
+package tourGuide.util;
+
+import org.springframework.stereotype.Component;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.model.UserPreferences;
+
+/**
+ * The Class UserPreferencesMapper.
+ */
+@Component
+public class UserPreferencesMapper {
+
+
+
+ // ##############################################################
+
+
+
+ public UserPreferencesDTO toUserPreferencesDTO(final UserPreferences preferences) {
+
+ return new UserPreferencesDTO(
+ preferences.getAttractionProximity(),
+ preferences.getLowerPricePoint()
+ .getNumber().intValue(),
+ preferences.getHighPricePoint().getNumber().intValue(),
+ preferences.getTripDuration(),
+ preferences.getTicketQuantity(),
+ preferences.getNumberOfAdults(),
+ preferences.getNumberOfChildren());
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/util/UserRewardMapper.java b/tourguide/src/main/java/tourGuide/util/UserRewardMapper.java
new file mode 100644
index 0000000..ead97fa
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/util/UserRewardMapper.java
@@ -0,0 +1,27 @@
+package tourGuide.util;
+
+import org.springframework.stereotype.Component;
+import tourGuide.dto.UserRewardDTO;
+import tourGuide.model.UserReward;
+
+@Component
+public class UserRewardMapper {
+
+
+ // ##############################################################
+
+
+ public UserRewardDTO toUserRewardDTO(
+ final UserReward userReward) {
+
+ return new UserRewardDTO(
+ userReward.visitedLocation,
+ userReward.attraction,
+ userReward.getRewardPoints());
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/java/tourGuide/util/VisitedLocationMapper.java b/tourguide/src/main/java/tourGuide/util/VisitedLocationMapper.java
new file mode 100644
index 0000000..ea31aaa
--- /dev/null
+++ b/tourguide/src/main/java/tourGuide/util/VisitedLocationMapper.java
@@ -0,0 +1,40 @@
+package tourGuide.util;
+
+import org.springframework.stereotype.Component;
+
+import tourGuide.dto.VisitedLocationDTO;
+
+/**
+ * The Class VisitedLocationMapper.
+ */
+@Component
+public class VisitedLocationMapper {
+
+
+
+
+
+ // ##############################################################
+
+
+ /**
+ * To visited location.
+ *
+ * @param visitedLocationDTO the visited location DTO
+ * @return the tour guide.model. visited location
+ */
+ public tourGuide.model.VisitedLocation toVisitedLocation(
+ final VisitedLocationDTO visitedLocationDTO) {
+
+ return new tourGuide.model.VisitedLocation(
+ visitedLocationDTO.getUserId(),
+ visitedLocationDTO.getLocation(),
+ visitedLocationDTO.getTimeVisited());
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/main/resources/application.properties b/tourguide/src/main/resources/application.properties
new file mode 100644
index 0000000..0d47442
--- /dev/null
+++ b/tourguide/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+
+################## APPS CONFIG ####################
+spring.application.name=tourguide
+
+
+################### SERVER HTTP PORT ####################
+server.port=9090
+
+################### LOG CONFIG ##########################
+logging.level.tourGuide=DEBUG
+
+################### Test Configs inputs #################
+# Set this default up to 100,000 for testing
+test.user.numbers=100
+
+# test mode enabler
+test.mode.enabled=true
+
+# performance test disabler
+performance.test.enabled=false
+
+# trip-pricer API key value
+trip.pricer.api.key=test-server-api-key
+
diff --git a/tourguide/src/main/resources/integration-test.properties b/tourguide/src/main/resources/integration-test.properties
new file mode 100644
index 0000000..936e1ea
--- /dev/null
+++ b/tourguide/src/main/resources/integration-test.properties
@@ -0,0 +1,17 @@
+# SERVER HTTP PORT
+server.port=9094
+
+
+# Test Configs inputs
+
+# Set this default up to 100,000 for testing
+test.user.numbers=10
+
+# test mode enabler
+test.mode.enabled=true
+
+# performance test disabler
+performance.test.enabled=false
+
+# trip-pricer API key value
+trip.pricer.ap
diff --git a/tourguide/src/main/resources/performance-test.properties b/tourguide/src/main/resources/performance-test.properties
new file mode 100644
index 0000000..760de9b
--- /dev/null
+++ b/tourguide/src/main/resources/performance-test.properties
@@ -0,0 +1,17 @@
+# SERVER HTTP PORT
+server.port=9095
+
+
+# Test Configs inputs
+
+# Set this default up to 100,000 for testing
+test.user.numbers=1000
+
+# test mode enabler
+test.mode.enabled=true
+
+# performance test disabler
+performance.test.enabled=true
+
+# trip-pricer API key value
+trip.pricer.api.key=test-server-api-key
diff --git a/tourguide/src/test/java/tourGuide/integration/controller/HomeControllerIT.java b/tourguide/src/test/java/tourGuide/integration/controller/HomeControllerIT.java
new file mode 100644
index 0000000..8a3e6fe
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/controller/HomeControllerIT.java
@@ -0,0 +1,72 @@
+package tourGuide.integration.controller;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
+//@ActiveProfiles("test")
+@TestPropertySource("/integration-test.properties")
+public class HomeControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @LocalServerPort
+ private int port;
+
+ private final static String INDEX_URL = "/";
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check (testIndexPageUrl) "
+ + " - Given a request,"
+ + " when GET index page URL,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testIndexPageUrl() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + INDEX_URL, String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+ assertEquals(
+ "Greetings from TourGuide!",
+ response.getBody());
+
+ }
+
+
+ // ##############################################################
+
+
+}
+
diff --git a/tourguide/src/test/java/tourGuide/integration/controller/LocationControllerIT.java b/tourguide/src/test/java/tourGuide/integration/controller/LocationControllerIT.java
new file mode 100644
index 0000000..e39713e
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/controller/LocationControllerIT.java
@@ -0,0 +1,411 @@
+package tourGuide.integration.controller;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.model.User;
+import tourGuide.service.UserService;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
+//@ActiveProfiles("test")
+@TestPropertySource("/integration-test.properties")
+public class LocationControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @Autowired
+ private UserService userService;
+
+ @LocalServerPort
+ private int port;
+
+ private final static String USER_LOCATION_URL = "/getLocation/";
+ private final static String NEARBY_ATTRACTIONS_URL = "/getNearbyAttractions/";
+ private final static String USER_CURRENT_LOCATION_URL = "/getAllCurrentLocations/";
+
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check (GetLocation) Valid "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetLocationUrlValid() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_LOCATION_URL
+ + "?userName=internalUser6", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+ assertTrue(response.getBody().contains("longitude"));
+ assertTrue(response.getBody().contains("latitude"));
+
+
+ }
+
+
+ //##############################################################
+
+
+
+ @DisplayName("Check (GetLocation) EmptyUserName "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetLocationUrlWithEmptyUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_LOCATION_URL
+ + "?userName=", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+// assertTrue(response.getBody().contains("USERNAME required"));
+
+ }
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check (GetLocation) NullValueUserName "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetLocationUrlWithNullValueUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_LOCATION_URL
+ + "?userName=", null);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+ assertNull(response.getBody());
+
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetLocation) missing parameter "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetLocationUrlWithMissingParameter() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_LOCATION_URL, String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+
+ assertTrue(response.getBody().contains("Required String parameter 'userName' is not present"));
+
+ }
+
+ // ##############################################################
+
+ @DisplayName("Check (GetLocation) invalid username "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: NOT_FOUND")
+ @Test
+ public void testGetLocationUrlWithInvalidUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_LOCATION_URL
+ + "?userName=unkownuser", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.NOT_FOUND.value(),
+ response.getStatusCodeValue());
+
+
+// assertTrue(response.getBody().contains("USERNAME required"));
+
+ }
+
+ // ##############################################################
+
+// @Ignore
+ @Test
+ public void testGetLocationUrlWithUserWithoutVisitedLocationHistory() {
+
+ User user = userService.getUser("internalUser1");
+ user.clearVisitedLocations();
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_LOCATION_URL
+ + "?userName=internalUser1", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+
+ }
+
+ // ##############################################################
+
+ @DisplayName("Check (GetNearbyAttractions)"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetNearbyAttractionsValidInput() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + NEARBY_ATTRACTIONS_URL
+ + "?userName=internalUser6", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+
+
+ assertTrue(response.getBody().contains("longitude"));
+ assertTrue(response.getBody().contains("latitude"));
+ assertTrue(response.getBody().contains("userPosition"));
+ assertTrue(response.getBody().contains("nearbyAttractions"));
+ assertTrue(response.getBody().contains("rewardPoints"));
+ assertTrue(response.getBody().contains("distance"));
+
+
+ }
+
+
+ //##############################################################
+
+
+ @DisplayName("Check (GetNearbyAttractions) EmptyUserName"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetNearbyAttractionsUrlWithEmptyUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + NEARBY_ATTRACTIONS_URL
+ + "?userName=", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+// assertTrue(response.getBody().contains("USERNAME required"));
+
+ }
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check (GetNearbyAttractions) Null Parameter"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetNearbyAttractionsUrlWithNullValueUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + NEARBY_ATTRACTIONS_URL
+ + "?userName=", null);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+ assertNull(response.getBody());
+
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetNearbyAttractions) Missing Param "
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetNearbyAttractionsUrlWithMissingParameter() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + NEARBY_ATTRACTIONS_URL, String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+
+ assertTrue(response.getBody().contains("Required String parameter 'userName' is not present"));
+
+ }
+
+ // ##############################################################
+
+ @DisplayName("Check (GetNearbyAttractions) invalid"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: NOT_FOUND")
+ @Test
+ public void testGetNearbyAttractionsnUrlWithInvalidUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + NEARBY_ATTRACTIONS_URL
+ + "?userName=unkownuser", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.NOT_FOUND.value(),
+ response.getStatusCodeValue());
+
+
+// assertTrue(response.getBody().contains("USERNAME required"));
+
+ }
+
+ // ##############################################################
+
+// @Ignore
+ @Test
+ public void testGetNearbyAttractionsUrlWithUserWithoutVisitedLocationHistory() {
+
+ User user = userService.getUser("internalUser1");
+ user.clearVisitedLocations();
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + NEARBY_ATTRACTIONS_URL
+ + "?userName=internalUser1", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+
+ }
+
+
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (testGetAllCurrentLocations)"
+ + " - Given a request,"
+ + " when GET testGetAllCurrentLocations,"
+ + " then return - Status: 200 OK")
+ public void testGetAllCurrentLocations() {
+
+ ResponseEntity response = restTemplate.getForEntity(
+ "http://localhost:"
+ + port
+ + USER_CURRENT_LOCATION_URL, String.class);
+
+ assertNotNull(response);
+
+
+ assertTrue(response.getBody().contains("longitude"));
+ assertTrue(response.getBody().contains("latitude"));
+
+
+ }
+
+
+ //##############################################################
+
+
+}
+
diff --git a/tourguide/src/test/java/tourGuide/integration/controller/RewardsControllerIT.java b/tourguide/src/test/java/tourGuide/integration/controller/RewardsControllerIT.java
new file mode 100644
index 0000000..bf39e0b
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/controller/RewardsControllerIT.java
@@ -0,0 +1,216 @@
+package tourGuide.integration.controller;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.model.User;
+import tourGuide.service.UserService;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
+//@ActiveProfiles("test")
+@TestPropertySource("/integration-test.properties")
+public class RewardsControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @Autowired
+ private UserService userService;
+
+ @LocalServerPort
+ private int port;
+
+
+ private final static String USER_REWARDS_URL = "/getRewards/";
+
+
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (GetRewards) ValidInput "
+ + " - Given a request,"
+ + " when GET GetRewards,"
+ + " then return - Status: 200 OK")
+ public void testGetRewardsValidInput() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_REWARDS_URL
+ + "?userName=internalUser6", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+
+
+ }
+
+
+ //##############################################################
+
+
+ @DisplayName("Check (GetRewards) empty username "
+ + " - Given a request,"
+ + " when GET GetRewards,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetRewardsUrlWithEmptyUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_REWARDS_URL
+ + "?userName=", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+// assertTrue(response.getBody().contains("USERNAME required"));
+
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetRewards) null value input "
+ + " - Given a request,"
+ + " when GET GetRewards,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetRewardsUrlWithNullValueUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_REWARDS_URL
+ + "?userName=", null);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+ assertNull(response.getBody());
+
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetRewards) missing param "
+ + " - Given a request,"
+ + " when GET GetRewards,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetRewardsUrlWithMissingParameter() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_REWARDS_URL, String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+
+ assertTrue(response.getBody().contains(
+ "Required String parameter 'userName' is not present"));
+
+ }
+
+ // ##############################################################
+
+ @DisplayName("Check (GetRewards) invalid username "
+ + " - Given a request,"
+ + " when GET GetRewards,"
+ + " then return - Status: NOT_FOUND")
+ @Test
+ public void testGetRewardsnUrlWithInvalidUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_REWARDS_URL
+ + "?userName=unkownuser", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.NOT_FOUND.value(),
+ response.getStatusCodeValue());
+
+
+
+
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetRewards) for username without visited location history"
+ + " - Given a request,"
+ + " when GET GetRewards,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetRewardsUrlWithUserWithoutVisitedLocationHistory() {
+
+ User user = userService.getUser("internalUser1");
+ user.clearVisitedLocations();
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_REWARDS_URL
+ + "?userName=internalUser1", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+
+ }
+
+
+ //##############################################################
+
+
+}
+
diff --git a/tourguide/src/test/java/tourGuide/integration/controller/TripDealsControllerIT.java b/tourguide/src/test/java/tourGuide/integration/controller/TripDealsControllerIT.java
new file mode 100644
index 0000000..489e932
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/controller/TripDealsControllerIT.java
@@ -0,0 +1,196 @@
+package tourGuide.integration.controller;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
+//@ActiveProfiles("test")
+@TestPropertySource("/integration-test.properties")
+public class TripDealsControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+
+// @Autowired
+// private TourGuideService tourGuideService;
+
+ @LocalServerPort
+ private int port;
+
+
+ private final static String USER_TRIP_DEALS_URL = "/getTripDeals/";
+
+
+
+ //##############################################################
+
+ @DisplayName("Check (GetTripDeals)"
+ + " - Given an username,"
+ + " when GET tripDeals,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetTripDealsUrlValid() {
+
+// User user = tourGuideService.getUser("internalUser6");
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_TRIP_DEALS_URL
+ + "?userName=internalUser6", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+
+ assertTrue(response.getBody().contains("name"));
+ assertTrue(response.getBody().contains("tripId"));
+ assertTrue(response.getBody().contains("price"));
+
+
+
+ }
+
+
+ //##############################################################
+
+
+
+ @DisplayName("Check (GetTripDeals) empty username"
+ + " - Given an empty username,"
+ + " when GET tripDeals,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetTripDealsUrlWithEmptyUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_TRIP_DEALS_URL
+ + "?userName=", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+
+ }
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check (GetTripDeals) null value username"
+ + " - Given an username is null,"
+ + " when GET tripDeals,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetTripDealsUrlWithNullValueUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_TRIP_DEALS_URL
+ + "?userName=", null);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+ assertNull(response.getBody());
+
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetTripDeals) username WithMissingParameter"
+ + " - Given an username WithMissingParameter,"
+ + " when GET tripDeals,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetTripDealsUrlWithMissingParameter() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_TRIP_DEALS_URL, String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.BAD_REQUEST.value(),
+ response.getStatusCodeValue());
+
+
+ assertTrue(response.getBody().contains(
+ "Required String parameter 'userName' is not present"));
+
+ }
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check (GetTripDeals) invalid username"
+ + " - Given an username invalid,"
+ + " when GET tripDeals,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetTripDealsUrlWithInvalidUserName() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + USER_TRIP_DEALS_URL
+ + "?userName=unkownuser", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.NOT_FOUND.value(),
+ response.getStatusCodeValue());
+
+// assertEquals("request body",
+// "Greetings from TourGuide!",
+// response.getBody());
+
+
+ }
+
+ // ##############################################################
+
+}
+
diff --git a/tourguide/src/test/java/tourGuide/integration/controller/UserControllerIT.java b/tourguide/src/test/java/tourGuide/integration/controller/UserControllerIT.java
new file mode 100644
index 0000000..c5ae4c7
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/controller/UserControllerIT.java
@@ -0,0 +1,168 @@
+package tourGuide.integration.controller;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.model.User;
+import tourGuide.service.UserService;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
+//@ActiveProfiles("test")
+@TestPropertySource("/integration-test.properties")
+public class UserControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @Autowired
+ private UserService userService;
+
+ @LocalServerPort
+ private int port;
+
+
+ private final static String USER_PREFERENCES_URL = "/updateUserPreferences/";
+
+
+
+ // ##############################################################
+
+
+
+ @Test
+ @DisplayName("Check (updateUserPreferences)"
+ + " - Given an user preference to update,"
+ + " when PUT updateUserPreferences,"
+ + " then return - Status: 200 OK update done")
+ public void testUpdateUserPreferences() throws Exception {
+
+ UserPreferencesDTO userPreferencesToUpdate = new UserPreferencesDTO(
+ 999, 999, 999, 999, 999, 999, 999);
+
+ restTemplate.put(
+ "http://localhost:" + port +
+ USER_PREFERENCES_URL + "?userName=internalUser1",
+ userPreferencesToUpdate,
+ UserPreferencesDTO.class);
+
+ User user = userService.getUser("internalUser1");
+
+ assertEquals(
+ userPreferencesToUpdate.getAttractionProximity(),
+ user.getUserPreferences().getAttractionProximity());
+
+ assertEquals(
+ userPreferencesToUpdate.getTripDuration(),
+ user.getUserPreferences().getTripDuration());
+
+ assertEquals(
+ userPreferencesToUpdate.getTicketQuantity(),
+ user.getUserPreferences().getTicketQuantity());
+
+ assertEquals(
+ userPreferencesToUpdate.getNumberOfAdults(),
+ user.getUserPreferences().getNumberOfAdults());
+
+ assertEquals(
+ userPreferencesToUpdate.getNumberOfChildren(),
+ user.getUserPreferences().getNumberOfChildren());
+
+ assertNotEquals(
+ Integer.MAX_VALUE,
+ user.getUserPreferences().getAttractionProximity());
+ }
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (updateUserPreferences) empty username"
+ + " - Given an user preference to update with no username,"
+ + " when PUT updateUserPreferences,"
+ + " then return - Status: 200 OK but error message username required")
+ public void testUpdateUserPreferencesEmptyUserName() throws Exception {
+
+ UserPreferencesDTO userPreferencesToUpdate = new UserPreferencesDTO(999,
+ 999, 999, 999, 999, 999, 999);
+
+ restTemplate.put(
+ "http://localhost:" + port +
+ USER_PREFERENCES_URL + "?userName=",
+ userPreferencesToUpdate,
+ UserPreferencesDTO.class);
+
+ User user = userService.getUser("internalUser1");
+
+ assertNotEquals(
+ userPreferencesToUpdate.getAttractionProximity(),
+ user.getUserPreferences().getAttractionProximity());
+
+ assertNotEquals(
+ userPreferencesToUpdate.getTripDuration(),
+ user.getUserPreferences().getTripDuration());
+
+ assertNotEquals(
+ userPreferencesToUpdate.getTicketQuantity(),
+ user.getUserPreferences().getTicketQuantity());
+
+ assertNotEquals(
+ userPreferencesToUpdate.getNumberOfAdults(),
+ user.getUserPreferences().getNumberOfAdults());
+
+ assertNotEquals(
+ userPreferencesToUpdate.getNumberOfChildren(),
+ user.getUserPreferences().getNumberOfChildren());
+
+ assertEquals(
+ Integer.MAX_VALUE,
+ user.getUserPreferences().getAttractionProximity());
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetUser) "
+ + " - Given a request,"
+ + " when GET GetUser,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetUser() {
+
+ ResponseEntity response = restTemplate
+ .getForEntity(
+ "http://localhost:"
+ + port
+ + "/getUser"
+ + "?userName=internalUser6", String.class);
+
+ assertNotNull(response);
+
+ assertEquals(
+ HttpStatus.OK.value(),
+ response.getStatusCodeValue());
+
+ }
+
+
+ //##############################################################
+
+
+}
+
diff --git a/tourguide/src/test/java/tourGuide/integration/performance/TestPerformance.java b/tourguide/src/test/java/tourGuide/integration/performance/TestPerformance.java
new file mode 100644
index 0000000..a5bd067
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/performance/TestPerformance.java
@@ -0,0 +1,212 @@
+package tourGuide.integration.performance;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.time.StopWatch;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.model.User;
+import tourGuide.model.VisitedLocation;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.service.GpsLocationService;
+import tourGuide.service.RewardsService;
+import tourGuide.service.UserService;
+
+@ExtendWith(SpringExtension.class)
+//@ExtendWith(SpringExtension.class)
+@SpringBootTest
+@TestPropertySource("/performance-test.properties")
+public class TestPerformance {
+
+// private static Locale locale = new Locale("en", "US");
+
+
+ @Autowired
+ private MicroserviceGpsProxy gpsUtilMicroService;
+
+ @Autowired
+ private RewardsService rewardsService;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private GpsLocationService gpsLocationService;
+
+
+
+ // ##############################################################
+
+
+ /*
+ * A note on performance improvements:
+ *
+ * The number of users generated for the high volume tests can be easily adjusted via this method:
+ *
+ * InternalTestHelper.setInternalUserNumber(100000);
+ *
+ *
+ * These tests can be modified to suit new solutions, just as long as the performance metrics
+ * at the end of the tests remains consistent.
+ *
+ * These are performance metrics that we are trying to hit:
+ *
+ * highVolumeTrackLocation: 100,000 users within 15 minutes:
+ * assertTrue(TimeUnit.MINUTES.toSeconds(15) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
+ *
+ * highVolumeGetRewards: 100,000 users within 20 minutes:
+ * assertTrue(TimeUnit.MINUTES.toSeconds(20) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
+ */
+
+
+
+ // ##############################################################
+
+
+// @Ignore
+ @DisplayName("HighVolumeTrackLocation"
+ + " - GIVEN a high volume users (100 000 users),"
+ + " WHEN trackAllUserLocation,"
+ + " THEN elapsed time should be <= to expected time (15 minutes")
+ @Test
+ public void highVolumeTrackLocation() {
+
+
+ // ----------------------------------------------------------------------------
+ // Users should be incremented up to 100,000, > 15 minutes and test finishes within 15 minutes
+ // ----------------------------------------------------------------------------
+
+ List allUsers = userService.getAllUsers();
+ allUsers.forEach(u -> u.clearVisitedLocations());
+
+ // ----------------------------------------------------------------------------
+ /*
+ Step 1 => TrackLocation: adds a new VisitedLocation for each user.
+ Step 2 => VisitedLocation count is saved for each user
+ Step 3 => VisitedLocation count will be compared to new count after tracking.
+ */
+ // ----------------------------------------------------------------------------
+
+ // ---------
+ // Step 1 - TrackLocation: adds a new VisitedLocation for each user.
+ //----------
+ List initialVisitedLocationsCount = allUsers
+ .stream()
+ .map(u -> u
+ .getVisitedLocations().size())
+ .collect(Collectors.toList());
+
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+
+ CompletableFuture>[] futures = allUsers.parallelStream()
+ .map(gpsLocationService::trackUserLocation)
+ .toArray(CompletableFuture[]::new);
+ CompletableFuture.allOf(futures).join();
+
+
+ stopWatch.stop();
+
+ //----------
+ // Step 2 - VisitedLocation count is saved for each user
+ //----------
+ List newVisitedLocationsCount = allUsers
+ .parallelStream()
+ .map(u -> u
+ .getVisitedLocations().size())
+ .collect(Collectors.toList());
+
+ //----------
+ // Step 3
+ // ----------------------------------------------------------------------------
+ // Comparison of VisitedLocations count
+ // ----------------------------------------------------------------------------
+ for (int i = 0; i < initialVisitedLocationsCount.size(); i++) {
+ assertEquals(initialVisitedLocationsCount.get(i) + 1, (int) newVisitedLocationsCount.get(i));
+ }
+
+// System.out.println("highVolumeTrackLocation check if (6667 users < 1 minute) : Actual Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds.");
+ System.out.println("highVolumeTrackLocation: Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds.");
+// assertTrue(TimeUnit.MINUTES.toSeconds(1) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
+ assertTrue(TimeUnit.MINUTES.toSeconds(15) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("HighVolumeGetRewards"
+ + " - GIVEN a high volume users, (100 000 users)"
+ + " WHEN calculateRewardAsync,"
+ + " THEN elapsed time should be <= to expected time (20 minutes)")
+ @Test
+ public void highVolumeGetRewards() throws InterruptedException {
+
+ // ----------------------------------------------------------------------------
+ // Users should be incremented up to 100,000, < 20 minutes (5000 < 1 minutes) and test finishes within 20 minutes
+ // ----------------------------------------------------------------------------
+
+
+ StopWatch stopWatch = new StopWatch();
+
+
+ AttractionDTO attraction = gpsUtilMicroService.getAttractions().get(0);
+ List allUsers = userService.getAllUsers();
+
+
+ allUsers.forEach(u -> {
+ u.clearVisitedLocations();
+ u.getUserRewards().clear();
+ u.addToVisitedLocations(
+ new VisitedLocation(
+ u.getUserId(),
+ attraction.getLocation(),
+ new Date()));
+ });
+
+ stopWatch.start();
+
+// rewardsService.rewardAndWait(allUsers);
+// allUsers.forEach(u -> rewardsService.calculateRewards(u));
+
+ CompletableFuture>[] futures = allUsers.stream()
+ .map(rewardsService::calculateRewardAsync)
+ .toArray(CompletableFuture[]::new);
+ CompletableFuture.allOf(futures).join();
+
+ stopWatch.stop();
+
+
+// System.out.println("highVolumeGetRewards check if (5000 rewards < 1 minute) : Actual Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds.");
+ System.out.println("highVolumeGetRewards: Time Elapsed: " + TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()) + " seconds.");
+
+ for(User user : allUsers) {
+ assertTrue(user.getUserRewards().size() > 0);
+ }
+
+ assertTrue(TimeUnit.MINUTES.toSeconds(20) >= TimeUnit.MILLISECONDS.toSeconds(stopWatch.getTime()));
+
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/integration/service/TestGpsLocationService.java b/tourguide/src/test/java/tourGuide/integration/service/TestGpsLocationService.java
new file mode 100644
index 0000000..a2ed8b9
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/service/TestGpsLocationService.java
@@ -0,0 +1,221 @@
+package tourGuide.integration.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.LocationDTO;
+import tourGuide.dto.UserAttractionRecommendationDTO;
+import tourGuide.model.Location;
+import tourGuide.model.User;
+import tourGuide.model.VisitedLocation;
+import tourGuide.service.GpsLocationService;
+import tourGuide.service.RewardsService;
+import tourGuide.service.UserService;
+
+@DisplayName("IT - Service - GpsLocation")
+//@RunWith(SpringRunner.class)
+@ExtendWith(SpringExtension.class)
+@SpringBootTest("/integration-test.properties")
+public class TestGpsLocationService {
+
+
+// @Autowired
+// private GpsUtil gpsUtil;
+
+ @Autowired
+ private GpsLocationService gpsLocationService;
+
+ @Autowired
+ UserService userService;
+
+ @Autowired
+ RewardsService rewardService;
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given a User,"
+ + " when GET USER location,"
+ + " then return USER location")
+ @Test
+ public void testGetUserLocation() {
+
+ Locale.setDefault(Locale.US);
+
+ // GIVEN
+ User user = userService
+ .getUser("internalUser1");
+
+ // WHEN
+ LocationDTO result = gpsLocationService
+ .getUserLocation("internalUser1");
+
+ // THEN
+ assertNotNull(result);
+ assertEquals(user.getLastVisitedLocation().getLocation().getLatitude(), result.getLatitude());
+ assertEquals(user.getLastVisitedLocation().getLocation().getLongitude(), result.getLongitude());
+
+
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given a User with one visited location,"
+ + " when GET USER location,"
+ + " then return USER expected location")
+ public void testUserLocationWithVisitedLocation() {
+
+ // GIVEN
+ User user = userService.getUser("internalUser1");
+
+ Location location = new Location(33.881866, -115.90065);
+
+ user.getVisitedLocations().clear();
+
+ VisitedLocation visitedLocation = new VisitedLocation(
+ user.getUserId(),
+ location,
+ new Date());
+
+ user.addToVisitedLocations(visitedLocation);
+
+ // WHEN
+ LocationDTO result = gpsLocationService
+ .getUserLocation("internalUser1");
+
+ // THEN
+ assertNotNull(result);
+ assertThat(result).isEqualToComparingFieldByField(location);
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given a list of users,"
+ + " WHEN Requested GET all users locations,"
+ + " then return users locations as expected")
+ @Test
+ public void testGetAllUsersCurrentLocations() {
+
+ // GIVEN
+ List users = userService.getAllUsers();
+
+ // WHEN
+ Map result = gpsLocationService
+ .getAllUserRecentLocation();
+
+ // THEN
+ assertNotNull(users);
+ assertNotNull(result);
+ result.values().forEach(r -> assertNotNull(r));
+ assertEquals(users.size(), result.size());
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given an User,"
+ + " WHEN Requested track User Location,"
+ + " then return location and adds to history as expected")
+ @Test
+ public void testTrackUser() {
+
+ // GIVEN
+ UUID userID = UUID.randomUUID();
+ User user = new User(
+ userID,
+ "internalUser1",
+ "000",
+ "testUser@email.com");
+
+ // WHEN
+ gpsLocationService.trackUserLocation(user).join();
+
+ // THEN
+ assertEquals(1, user.getVisitedLocations().size());
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given an User,"
+ + " WHEN Requested getUserAttractionRecommendation,"
+ + " then return 5 nearby Attractions as expected")
+ @Test
+ public void testGetUserAttractionRecommendation() {
+
+ // WHEN <== // GIVEN
+ UserAttractionRecommendationDTO result = gpsLocationService
+ .getUserAttractionRecommendation("internalUser1");
+
+ // THEN
+ assertThat(result.getNearbyAttractions()).isNotEmpty();
+ assertEquals(5, result.getNearbyAttractions().size());
+ }
+
+
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an Username,"
+ + " WHEN Requested getTotalRewardPointsForUser,"
+ + " then return user reward points as expected")
+ @Test
+ public void getTotalRewardPointsForUser() {
+
+
+ // WHEN <== // GIVEN
+ int result = gpsLocationService
+ .getTotalRewardPointsForUser("internalUser1");
+
+ // THEN
+ assertNotNull(result);
+ assertThat(result > 500);
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/integration/service/TestRewardsService.java b/tourguide/src/test/java/tourGuide/integration/service/TestRewardsService.java
new file mode 100644
index 0000000..58e2040
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/service/TestRewardsService.java
@@ -0,0 +1,468 @@
+package tourGuide.integration.service;
+
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.dto.UserRewardDTO;
+import tourGuide.model.Attraction;
+import tourGuide.model.Location;
+import tourGuide.model.User;
+import tourGuide.model.UserReward;
+import tourGuide.model.VisitedLocation;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.service.RewardsService;
+import tourGuide.service.UserService;
+import tourGuide.util.AttractionMapper;
+
+@DisplayName("IT Test - Service - Rewards")
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+@TestPropertySource("/integration-test.properties")
+public class TestRewardsService {
+
+
+ @Autowired
+ private RewardsService rewardsService;
+
+
+ @Autowired
+ private MicroserviceGpsProxy gpsUtilMicroService;
+
+ @Autowired
+ private UserService userService;
+
+
+ @Autowired
+ private AttractionMapper attractionMapper;
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given a User with specifically one visited locaiton,"
+ + " when Calculate rewards,"
+ + " then return one rewards as expected")
+ @Test
+ public void testUserGetRewards() throws InterruptedException {
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+ AttractionDTO attraction = gpsUtilMicroService
+ .getAttractions().get(0);
+
+ user.addToVisitedLocations(new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date()));
+
+
+
+ // WHEN
+ rewardsService.calculateRewards(user);
+
+
+ // THEN
+ assertEquals(1, user.getUserRewards().size());
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check No visited location"
+ + " - Given a User with specifically No visited locaiton,"
+ + " when Calculate rewards,"
+ + " then return No rewards as expected")
+ @Test
+ public void testUserGetRewardsWithNoVisitedAttraction() throws InterruptedException {
+
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+
+ // WHEN
+ rewardsService.calculateRewards(user);
+
+
+ // THEN
+ assertEquals(0, user.getUserRewards().size());
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check on revisiting Same location"
+ + " - Given a User with revisiting one same visited locaiton,"
+ + " when Calculate rewards,"
+ + " then return one rewards as expected")
+ @Test
+ public void testUserGetRewardsOnRevisitingSameLocation() throws InterruptedException {
+
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+ AttractionDTO attraction = gpsUtilMicroService
+ .getAttractions().get(0);
+
+ VisitedLocation visitedLocation1 = new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date());
+
+
+ VisitedLocation visitedLocation2 = new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date());
+
+ user.addToVisitedLocations(visitedLocation1);
+ user.addToVisitedLocations(visitedLocation2);
+ user.addUserReward(new UserReward(
+ visitedLocation1, attractionMapper
+ .toAttraction(attraction), 500));
+
+ assertEquals(1, user.getUserRewards().size());
+
+
+
+ // WHEN
+ rewardsService.calculateRewards(user);
+
+
+
+ // THEN
+ assertEquals(1, user.getUserRewards().size());
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check For No Attractions Near VisitedLocation"
+ + " - Given a User with specifically one visited locaiton with no attraction nearby,"
+ + " when Calculate rewards,"
+ + " then return no rewards as expected")
+ @Test
+ public void testUserGetRewardsForNoAttractionsNearVisitedLocation() throws InterruptedException {
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+ gpsUtilMicroService
+ .getAttractions()
+ .get(0)
+ .setLocation(new Location(30.881866, -115.90065));
+
+ VisitedLocation visitedLocation = new VisitedLocation(
+ user.getUserId(),
+ new Location(-30.881866, -115.90065),
+ new Date());
+
+ user.addToVisitedLocations(visitedLocation);
+
+ assertEquals(0, user.getUserRewards().size());
+
+
+ // WHEN
+ rewardsService.calculateRewards(user);
+
+
+ // THEN
+ assertEquals(0, user.getUserRewards().size());
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+
+ @DisplayName("Check "
+ + " - Given a User with specifically one visited locaiton,"
+ + " when Calculate request isWithinAttractionProximity,"
+ + " then return result as expected")
+ @Test
+ public void isWithinAttractionProximity() {
+
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+ AttractionDTO attraction = gpsUtilMicroService
+ .getAttractions().get(0);
+
+ VisitedLocation visitedLocation = new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date());
+
+
+ // WHEN
+ Boolean result = rewardsService
+ .isWithinAttractionProximity(
+ visitedLocation,
+ visitedLocation.getLocation());
+
+
+ // THEN <== // WHEN
+ assertNotNull(result);
+ assertTrue(result);
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an User ,"
+ + " when Calculate request calculateRewardAsync,"
+ + " then return one result as expected")
+ @Test
+ public void testCalculateRewardAsyncForOneVisitedLocation() {
+
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+ AttractionDTO attraction1 = gpsUtilMicroService
+ .getAttractions().get(0);
+
+ user.addToVisitedLocations(
+ new VisitedLocation(
+ user.getUserId(),
+ attraction1.getLocation(),
+ new Date()));
+
+ // WHEN
+ rewardsService.calculateRewardAsync(user).join();
+
+ // THEN
+ assertEquals(1, user.getUserRewards().size());
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an User ,"
+ + " when Calculate request getRewardPoints,"
+ + " then return rewardPoints as expected")
+ @Test
+ public void testGetRewarPoints() {
+
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+
+
+ AttractionDTO attraction = gpsUtilMicroService
+ .getAttractions().get(0);
+
+ user.addToVisitedLocations(
+ new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date()));
+
+ // WHEN
+ UserReward result = rewardsService.getRewardPoints(user, user.getLastVisitedLocation(), attraction);
+
+ // THEN
+ assertNotNull(result);
+ assertNotNull(result.getVisitedLocation());
+ assertNotNull(result.getRewardPoints());
+ assertNotNull(result.getAttraction());
+
+ assertTrue(result.getRewardPoints() > 1);
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an User with specific attraction spot,"
+ + " when Calculate request if user has rewards for the spot,"
+ + " then return result as expected")
+ @Test
+ public void testCheckIfUserIsOfferedRewardToThisAttractionSpot() {
+
+
+ // GIVEN
+ User user = new User(
+ UUID.randomUUID(),
+ "jon",
+ "000",
+ "jon@tourGuide.com");
+
+
+
+ AttractionDTO attraction = gpsUtilMicroService
+ .getAttractions().get(0);
+
+ user.addToVisitedLocations(
+ new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date()));
+
+ // WHEN
+ Boolean result = rewardsService
+ .checkIfUserIsOfferedRewardToThisAttractionSpot(
+ user,
+ attraction);
+
+ // THEN
+ assertNotNull(result);
+ assertTrue(result);
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given an User with reward,"
+ + " WHEN Requested testGetUserRewards,"
+ + " then return user rewards as expected")
+ @Test
+ public void testGetUserRewards() {
+
+ // GIVEN
+ User user = userService.getUser("internalUser1");
+ user.getUserRewards().clear();
+ VisitedLocation visitedLocation = new VisitedLocation(
+ user.getUserId(),
+ new Location(30.881866, -115.90065),
+ new Date());
+
+ Attraction attraction = new Attraction(
+ UUID.randomUUID(),
+ "Disneyland" ,
+ "Anaheim" ,
+ "CA",
+ new Location(33.881866, -115.90065));
+
+ UserReward userReward = new UserReward(
+ visitedLocation,
+ attraction,
+ 1000);
+
+ user.addUserReward(userReward);
+
+ // WHEN
+ List result = rewardsService
+ .getUserRewards("internalUser1");
+
+ // THEN
+ assertNotNull(result);
+ assertEquals(1000, result.get(0).getRewardPoints());
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check no rewards"
+ + " - Given an User with no reward,"
+ + " WHEN Requested testGetUserRewards,"
+ + " then return user rewards (empty) as expected")
+ @Test
+ public void testGetUserRewardsWhenNoRewards() {
+
+ // GIVEN
+ User user = userService.getUser("internalUser2");
+ user.getUserRewards().clear();
+
+ // WHEN
+ List result = rewardsService
+ .getUserRewards("internalUser2");
+
+ // THEN
+ assertNotNull(result);
+ assertThat(result).isEmpty();
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/integration/service/TestTripDealsService.java b/tourguide/src/test/java/tourGuide/integration/service/TestTripDealsService.java
new file mode 100644
index 0000000..58d5693
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/service/TestTripDealsService.java
@@ -0,0 +1,78 @@
+package tourGuide.integration.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.List;
+
+import javax.money.Monetary;
+
+import org.javamoney.moneta.Money;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.ProviderDTO;
+import tourGuide.model.User;
+import tourGuide.model.UserPreferences;
+import tourGuide.service.TripDealsService;
+import tourGuide.service.UserService;
+
+@DisplayName("IT - Service - TripDeals")
+//@RunWith(SpringRunner.class)
+@ExtendWith(SpringExtension.class)
+@SpringBootTest("/integration-test.properties")
+public class TestTripDealsService {
+
+
+
+ @Autowired
+ UserService userService;
+
+ @Autowired
+ TripDealsService tripDealsService;
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given an Username,"
+ + " WHEN Requested getTripDeals,"
+ + " then return trip deals as expected")
+ @Test
+ public void getTripDeals() {
+
+ // GIVEN
+ User user = userService.getUser("internalUser1");
+ user.setUserPreferences(new UserPreferences(
+ 10,
+ Money.of(500, Monetary.getCurrency("USD")),
+ Money.of(1000, Monetary.getCurrency("USD")),
+ 5,
+ 5,
+ 2,
+ 3));
+
+ // WHEN
+ List result = tripDealsService
+ .getUserTripDeals("internalUser1");
+
+ // THEN
+ assertNotNull(result);
+ assertThat(result).isNotEmpty();
+ assertEquals(5, result.size());
+ }
+
+
+
+ // ##############################################################
+
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/integration/service/TestUserService.java b/tourguide/src/test/java/tourGuide/integration/service/TestUserService.java
new file mode 100644
index 0000000..f63a395
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/integration/service/TestUserService.java
@@ -0,0 +1,185 @@
+package tourGuide.integration.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.exception.DataAlreadyRegisteredException;
+import tourGuide.exception.UserNotFoundException;
+import tourGuide.model.User;
+import tourGuide.service.RewardsService;
+import tourGuide.service.UserService;
+
+@DisplayName("IT - Service - User")
+//@RunWith(SpringRunner.class)
+@ExtendWith(SpringExtension.class)
+@SpringBootTest("/integration-test.properties")
+public class TestUserService {
+
+
+
+ @Autowired
+ UserService userService;
+
+ @Autowired
+ RewardsService rewardService;
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check "
+ + " - Given an User with one visited location,"
+ + " WHEN Requested AddUser,"
+ + " then return User Added as expected")
+ @Test
+ public void testAddUser() {
+
+ // GIVEN
+ UUID userID = UUID.fromString("1851b7bd-737a-4c9d-9c2b-3b5829e417fa");
+ User user = new User(
+ userID,
+ "testUser",
+ "000",
+ "testUser@email.com");
+
+ // WHEN
+ userService.addUser(user);
+
+ // THEN
+ assertThat(userService.getAllUsers()).contains(user);
+ }
+
+
+ // ##############################################################
+
+ @DisplayName("Check - already exists "
+ + "GIVEN an Username is already used "
+ + "WHEN Requested AddUser "
+ + "THEN throws DataAlreadyRegisteredException")
+ @Test
+ public void testAddUserAlreadyExistsForExceptionThrown() {
+
+ // GIVEN
+ UUID userID = UUID.fromString("1851b7bd-737a-4c9d-9c2b-3b5829e417fa");
+ User user = new User(userID, "internalUser1", "000", "existingUser@email.com");
+
+ // THEN <== WHEN
+ assertThrows(DataAlreadyRegisteredException.class, ()
+ -> userService.addUser(user));
+ }
+
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check "
+ + " - Given a userlist,"
+ + " WHEN Requested GET all users,"
+ + " then return All Users list")
+ @Test
+ public void testGetAllUsers() {
+
+ // WHEN
+ List users = userService
+ .getAllUsers();
+
+ // THEN
+ assertThat(users).isNotEmpty();
+ assertNotNull(users);
+ assertTrue(users.size() > 0);
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given a User existing,"
+ + " WHEN Requested GET user,"
+ + " then return user as expected")
+ @Test
+ public void testGetUser() {
+
+ // GIVEN // WHEN
+ User user = userService
+ .getUser("internalUser1");
+
+ // THEN
+ assertNotNull(user);
+ assertEquals("internalUser1", user.getUserName());
+
+ }
+
+
+ // ##############################################################
+
+
+ @Test
+ @DisplayName("Check - not exists "
+ + "GIVEN an Username not exists "
+ + "WHEN Requested GET User "
+ + "THEN throws UserNotFoundException")
+ public void testGetUserNotExistingForUserNotFoundException() {
+
+ // THEN <== WHEN
+ assertThrows(UserNotFoundException.class, ()
+ -> userService
+ .getUser("testUserDoesNotExist"));
+
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given an User's preference,"
+ + " WHEN Requested UpdateUserPreferences,"
+ + " then updates user preferences as expected")
+ @Test
+ public void testUpdateUserPreferences() {
+
+
+ // GIVEN
+ UserPreferencesDTO userPreferences = new UserPreferencesDTO(
+ 10,
+ 500,
+ 1000,
+ 5,
+ 5,
+ 2,
+ 3);
+
+ // WHEN
+ UserPreferencesDTO result = userService
+ .updateUserPreferences("internalUser1", userPreferences);
+
+ // THEN
+ assertThat(result).isNotNull();
+ assertThat(result).isEqualToComparingFieldByField(userPreferences);
+
+
+ }
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/unit/controller/HomeControllerTest.java b/tourguide/src/test/java/tourGuide/unit/controller/HomeControllerTest.java
new file mode 100644
index 0000000..7dc297c
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/controller/HomeControllerTest.java
@@ -0,0 +1,78 @@
+package tourGuide.unit.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import tourGuide.service.GpsLocationService;
+
+@DisplayName("UNIT TESTS - Controller - Home")
+@AutoConfigureMockMvc
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class HomeControllerTest {
+
+
+ @MockBean
+ private GpsLocationService tourGuideService;
+
+// @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext context;
+
+
+
+ @BeforeEach
+ public void setUp() {
+
+ mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
+ }
+
+
+ // ##############################################################
+
+
+ @Test
+ @DisplayName("Check (testIndexPageUrl) "
+ + " - Given a request,"
+ + " when GET index page URL,"
+ + " then return - Status: 200 OK")
+ public void testIndexPageUrl() throws Exception {
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("Greetings from TourGuide!");
+ }
+
+
+
+ // ##############################################################
+
+
+ }
diff --git a/tourguide/src/test/java/tourGuide/unit/controller/LocationControllerTest.java b/tourguide/src/test/java/tourGuide/unit/controller/LocationControllerTest.java
new file mode 100644
index 0000000..30743c7
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/controller/LocationControllerTest.java
@@ -0,0 +1,318 @@
+package tourGuide.unit.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import tourGuide.dto.LocationDTO;
+import tourGuide.dto.NearByAttractionDTO;
+import tourGuide.dto.UserAttractionRecommendationDTO;
+import tourGuide.model.Location;
+import tourGuide.service.GpsLocationService;
+
+@DisplayName("UNIT TESTS - Controller - Location")
+//@ExtendWith(MockitoExtension.class)
+@AutoConfigureMockMvc
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class LocationControllerTest {
+
+
+ @MockBean
+ private GpsLocationService tourGuideService;
+
+// @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext context;
+
+ private LocationDTO userLocationDTO;
+
+ private Location userLocation;
+
+ private Location attractionLocation;
+
+
+
+ @BeforeEach
+ public void setUp() {
+
+ userLocationDTO = new LocationDTO(33.817595, -117.922008);
+
+ userLocation = new Location(33.817595, -117.922008);
+
+ attractionLocation = new Location(34.817595, -117.922008);
+
+ mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
+ }
+
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (GetLocation) Valid "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: 200 OK")
+ public void testGetLocationUrlValid() throws Exception {
+
+ when(tourGuideService
+ .getUserLocation("testUser"))
+ .thenReturn(userLocationDTO);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getLocation")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", "testUser"))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("33.817595");
+ assertThat(content).contains("-117.922008");
+ verify(tourGuideService).getUserLocation(anyString());
+ }
+
+ // ##############################################################
+
+
+ @Test
+ @DisplayName("Check (GetLocation) EmptyUserName "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetLocationUrlWithEmptyUserName() throws Exception {
+
+ when(tourGuideService
+ .getUserLocation("testUser"))
+ .thenReturn(userLocationDTO);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getLocation")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", ""))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("username is required");
+ }
+
+
+ // ##############################################################
+
+
+ @Test
+ @DisplayName("Check (GetLocation) missing parameter "
+ + " - Given a request,"
+ + " when GET GetLocation,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetLocationUrlWithMissingParameter() throws Exception {
+
+ when(tourGuideService
+ .getUserLocation("testUser"))
+ .thenReturn(userLocationDTO);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getLocation")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("userName parameter is missing");
+ }
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check (GetNearbyAttractions)"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetNearbyAttractionsValidInput() throws Exception {
+
+ UserAttractionRecommendationDTO recommendedAttractionDTO
+ = new UserAttractionRecommendationDTO(userLocation,
+
+ Arrays.asList(new NearByAttractionDTO(
+ "Disneyland",
+ attractionLocation,
+ 200.00, 500)));
+
+ when(tourGuideService
+ .getUserAttractionRecommendation("testUser"))
+ .thenReturn(recommendedAttractionDTO);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getNearbyAttractions")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", "testUser"))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("Disneyland");
+ assertThat(content).contains("500");
+ verify(tourGuideService).getUserAttractionRecommendation("testUser");
+ }
+
+ // ##############################################################
+
+ @DisplayName("Check (GetNearbyAttractions) EmptyUserName"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetNearbyAttractionsUrlWithEmptyUserName() throws Exception {
+
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getNearbyAttractions")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", ""))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("username is required");
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetNearbyAttractions) Null Parameter"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: BAD_REQUEST")
+ @Test
+ public void testGetNearbyAttractionsUrlWithNullParam() throws Exception {
+
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getNearbyAttractions")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("userName parameter is missing");
+ }
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetNearbyAttractions) invalid"
+ + " - Given a request,"
+ + " when GET GetNearbyAttractions,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetNearbyAttractionsInValidInput() throws Exception {
+
+ UserAttractionRecommendationDTO recommendedAttractionDTO
+ = new UserAttractionRecommendationDTO(userLocation,
+
+ Arrays.asList(new NearByAttractionDTO(
+ "Disneyland",
+ attractionLocation,
+ 200.00, 500)));
+ when(tourGuideService
+ .getUserAttractionRecommendation("testUser"))
+ .thenReturn(recommendedAttractionDTO);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getNearbyAttractions")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", "invalidUser"))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ }
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (testGetAllCurrentLocations)"
+ + " - Given a request,"
+ + " when GET testGetAllCurrentLocations,"
+ + " then return - Status: 200 OK")
+ public void testGetAllCurrentLocations() throws Exception {
+
+ Map usersLocation = new HashMap<>();
+
+ usersLocation.put(
+ UUID.randomUUID().toString()
+ , userLocationDTO);
+
+ when(tourGuideService
+ .getAllUserRecentLocation())
+ .thenReturn(usersLocation);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getAllCurrentLocations")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("33.817595");
+ assertThat(content).contains("-117.922008");
+ verify(tourGuideService).getAllUserRecentLocation();
+ }
+
+
+
+ // ##############################################################
+
+
+ }
diff --git a/tourguide/src/test/java/tourGuide/unit/controller/TripDealsControllerTest.java b/tourguide/src/test/java/tourGuide/unit/controller/TripDealsControllerTest.java
new file mode 100644
index 0000000..afdb423
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/controller/TripDealsControllerTest.java
@@ -0,0 +1,146 @@
+package tourGuide.unit.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import tourGuide.dto.ProviderDTO;
+import tourGuide.service.TripDealsService;
+
+@DisplayName("UNIT TESTS - Controller - TripDeals")
+@AutoConfigureMockMvc
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class TripDealsControllerTest {
+
+
+ @MockBean
+ private TripDealsService tripDealsService;
+
+// @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext context;
+
+
+
+ @BeforeEach
+ public void setUp() {
+
+
+ mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
+ }
+
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (GetTripDeals)"
+ + " - Given an username,"
+ + " when GET tripDeals,"
+ + " then return - Status: 200 OK")
+ public void testGetTripDeals() throws Exception {
+
+ List providers = Arrays.asList(
+ new ProviderDTO("testProviderName",
+ 500, UUID.randomUUID()));
+
+ when(tripDealsService
+ .getUserTripDeals("testUser"))
+ .thenReturn(providers);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getTripDeals")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", "testUser"))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("testProviderName");
+ assertThat(content).contains("500");
+ verify(tripDealsService).getUserTripDeals("testUser");
+ }
+
+
+ // ##############################################################
+
+
+ @Test
+ @DisplayName("Check (GetTripDeals) empty username"
+ + " - Given an empty username,"
+ + " when GET tripDeals,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetTripDealsUrlWithEmptyUserName() throws Exception {
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getTripDeals")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", ""))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("username is required");
+ }
+
+
+
+ // ##############################################################
+
+
+ @Test
+ @DisplayName("Check (GetTripDeals) null value"
+ + " - Given an null value for username,"
+ + " when GET tripDeals,"
+ + " then return - Status: BAD_REQUEST")
+ public void testGetTripDealsUrlWithNullUserName() throws Exception {
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getTripDeals")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("userName parameter is missing");
+ }
+
+
+
+ // ##############################################################
+
+
+ }
diff --git a/tourguide/src/test/java/tourGuide/unit/controller/UserGuideControllerTest.java b/tourguide/src/test/java/tourGuide/unit/controller/UserGuideControllerTest.java
new file mode 100644
index 0000000..85c7efa
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/controller/UserGuideControllerTest.java
@@ -0,0 +1,163 @@
+package tourGuide.unit.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.service.UserService;
+
+@DisplayName("UNIT TESTS - Controller - User")
+//@ExtendWith(MockitoExtension.class)
+@AutoConfigureMockMvc
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class UserGuideControllerTest {
+
+
+ @MockBean
+ private UserService userService;
+
+// @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext context;
+
+ private ObjectMapper objectMapper;
+
+
+ @BeforeEach
+ public void setUp() {
+
+ objectMapper = new ObjectMapper();
+
+
+ mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
+ }
+
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (updateUserPreferences)"
+ + " - Given an user preference to update,"
+ + " when PUT updateUserPreferences,"
+ + " then return - Status: 201 OK update done")
+ public void testUpdateUserPreferences() throws Exception {
+
+ UserPreferencesDTO userPreferencesDTO = new UserPreferencesDTO(999,
+ 999, 999, 999, 999, 999, 999);
+
+ when(userService
+ .updateUserPreferences(anyString(), any(UserPreferencesDTO.class)))
+ .thenReturn(userPreferencesDTO);
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .put("/updateUserPreferences")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(userPreferencesDTO))
+ .param("userName", "testUser"))
+ .andExpect(status().is2xxSuccessful())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertThat(content).contains("999");
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @Test
+ @DisplayName("Check (updateUserPreferences) empty username - "
+ + " - Given an user preference to update without username,"
+ + " when PUT updateUserPreferences,"
+ + " then return - Status: BAD_REQUEST")
+ public void testUpdateUserPreferencesEmptyUserName() throws Exception {
+
+ UserPreferencesDTO userPreferencesDTO = new UserPreferencesDTO(999,
+ 999, 999, 999, 999, 999, 999);
+
+ mockMvc.perform(MockMvcRequestBuilders
+ .put("/updateUserPreferences")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(userPreferencesDTO))
+ .param("userName", ""))
+ .andExpect(status().isBadRequest());
+ }
+
+
+ // ##############################################################
+
+ @Test
+ @DisplayName("Check (updateUserPreferences) empty body"
+ + " - Given an user preference to update with no body,"
+ + " when PUT updateUserPreferences,"
+ + " then return - Status: BAD_REQUEST")
+ public void testUpdateUserPreferencesEmptyBody() throws Exception {
+
+ mockMvc.perform(MockMvcRequestBuilders
+ .put("/updateUserPreferences")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(objectMapper.writeValueAsString(""))
+ .param("userName", "testUser"))
+ .andExpect(status().isBadRequest());
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check (GetUser) "
+ + " - Given a request,"
+ + " when GET GetUser,"
+ + " then return - Status: 200 OK")
+ @Test
+ public void testGetUser() throws Exception {
+
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/getUser")
+ .contentType(MediaType.APPLICATION_JSON)
+ .param("userName", "testUser"))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result
+ .getResponse().getContentAsString();
+
+ assertNotNull(content);
+
+
+ }
+
+ // ##############################################################
+
+
+ }
diff --git a/tourguide/src/test/java/tourGuide/unit/service/GpsLocationServiceTest.java b/tourguide/src/test/java/tourGuide/unit/service/GpsLocationServiceTest.java
new file mode 100644
index 0000000..1984af9
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/service/GpsLocationServiceTest.java
@@ -0,0 +1,536 @@
+package tourGuide.unit.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.dto.LocationDTO;
+import tourGuide.dto.UserAttractionRecommendationDTO;
+import tourGuide.dto.VisitedLocationDTO;
+import tourGuide.helper.InternalTestHelper;
+import tourGuide.model.Location;
+import tourGuide.model.User;
+import tourGuide.model.VisitedLocation;
+import tourGuide.proxy.MicroServiceTripDealsProxy;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.proxy.MicroserviceRewardsProxy;
+import tourGuide.service.GpsLocationService;
+import tourGuide.service.RewardsService;
+import tourGuide.service.UserService;
+import tourGuide.util.DistanceCalculator;
+import tourGuide.util.LocationMapper;
+import tourGuide.util.ProviderMapper;
+import tourGuide.util.UserPreferencesMapper;
+import tourGuide.util.UserRewardMapper;
+import tourGuide.util.VisitedLocationMapper;
+
+@DisplayName("Unit Test - Service - GpsLocation")
+@ExtendWith(MockitoExtension.class)
+public class GpsLocationServiceTest {
+
+ @InjectMocks
+ private GpsLocationService gpsLocationService;
+
+ @Mock
+ private RewardsService rewardsService;
+
+ @Mock
+ private UserService userService;
+
+ @Mock
+ private MicroserviceGpsProxy gpsUtilMicroService;
+
+ @Mock
+ private MicroServiceTripDealsProxy tripDealsMicroservice;
+
+ @Mock
+ private MicroserviceRewardsProxy rewardsMicroService;
+
+ @Mock
+ private UserPreferencesMapper userPreferencesMapper;
+
+ @Mock
+ private UserRewardMapper userRewardMapper;
+
+ @Mock
+ private LocationMapper locationMapper;
+
+ @Mock
+ private VisitedLocationMapper visitedLocationMapper;
+
+ @Mock
+ private ProviderMapper providerMapper;
+
+ @Mock
+ private DistanceCalculator distanceCalculator;
+
+ @Mock
+ private InternalTestHelper internalTestHelper;
+
+ private static UUID user1ID;
+
+ private static UUID user2ID;
+
+ private static User user1;
+
+ private static User user2;
+
+
+ private static Map internalUser;
+
+
+ private static VisitedLocation visitedLocation;
+
+ private static VisitedLocationDTO visitedLocationDTO;
+
+
+
+
+
+ // ##############################################################
+
+
+
+ @BeforeEach
+ public void setUp() {
+ user1ID = UUID.randomUUID();
+ user2ID = UUID.randomUUID();
+ user1 = new User(user1ID, "testUser1", "000", "testUser1@email.com");
+ user2 = new User(user2ID, "testUser2", "001", "testUser1@email.com");
+
+
+ visitedLocation = new VisitedLocation(
+ user1ID,
+ new Location(33.817595, -117.922008),
+ new Date());
+
+ visitedLocationDTO = new VisitedLocationDTO(
+ user1ID,
+ new Location(33.817595, -117.922008),
+ new Date());
+
+ internalUser = new HashMap<>();
+ internalUser.put("testUser1", user1);
+ internalUser.put("testUser2", user2);
+
+
+
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given a User with one visited location,"
+ + " when GET USER location,"
+ + " then return USER expected location")
+ @Test
+ public void testGetUserLocation() {
+
+ // GIVEN
+ LocationDTO expectedLocation = new LocationDTO(-160.326003, -73.869629);
+
+ when(userService.getUser(anyString()))
+ .thenReturn(user1);
+
+ lenient().when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ when(gpsUtilMicroService
+ .getUserLocation(any(UUID.class)))
+ .thenReturn(visitedLocationDTO);
+
+ when(locationMapper
+ .toLocationDTO(any(Location.class)))
+ .thenReturn(expectedLocation);
+
+ // WHEN
+ LocationDTO result = gpsLocationService
+ .getUserLocation(user1.getUserName());
+
+ // THEN
+ assertThat(result).isEqualToComparingFieldByField(expectedLocation);
+ }
+
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given a User with one visited location,"
+ + " when GET USER location,"
+ + " then return USER expected location")
+ @Test
+ public void testUserLocationWithVisitedLocation() {
+
+ // GIVEN
+
+ when(userService.getUser(anyString()))
+ .thenReturn(user1);
+
+ user1.addToVisitedLocations(visitedLocation);
+ LocationDTO expectedLocation = new LocationDTO(33.817595, -117.922008);
+
+ lenient().when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ when(locationMapper
+ .toLocationDTO(any(Location.class)))
+ .thenReturn(expectedLocation);
+
+ // WHEN
+ LocationDTO result = gpsLocationService
+ .getUserLocation(user1.getUserName());
+
+ // THEN
+ assertThat(result).isEqualToComparingFieldByField(expectedLocation);
+ assertEquals(1, user1.getVisitedLocations().size());
+ }
+
+
+
+
+ // ##############################################################
+
+//
+//
+// @DisplayName("Check "
+// + " - Given a list of users,"
+// + " WHEN Requested GET all users locations,"
+// + " then return users locations as expected")
+// @Test
+// public void testGetAllUsersCurrentLocations() {
+//
+// // GIVEN
+//
+//
+// when(userService.getUser(anyString()))
+// .thenReturn(user1);
+//
+//
+// user1.addToVisitedLocations(visitedLocation);
+//
+//
+// when(userService.getUser(anyString()))
+// .thenReturn(user2);
+//
+//
+// user2.addToVisitedLocations(new VisitedLocation(
+// user2ID,
+// new Location(35.985512, -92.757652),
+// new Date()));
+//
+// LocationDTO user1Location = new LocationDTO(
+// 33.817595, -117.922008);
+// LocationDTO user2Location = new LocationDTO(
+// 35.985512, -92.757652);
+//
+// lenient().when(internalTestHelper
+// .getInternalUserMap())
+// .thenReturn(internalUser);
+//
+// lenient().when(internalTestHelper
+// .getInternalUserMap())
+// .thenReturn(internalUser);
+//
+//
+// lenient().when(locationMapper
+// .toLocationDTO(user1.getLastVisitedLocation()
+// .getLocation())).thenReturn(user1Location);
+//
+// lenient().when(locationMapper
+// .toLocationDTO(
+// user2.getLastVisitedLocation().getLocation()))
+// .thenReturn(user2Location);
+//
+// // WHEN
+// Map result = gpsLocationService
+// .getAllUserRecentLocation();
+//
+// // THEN
+// assertNotNull(result);
+// assertEquals(2, result.size());
+// assertThat(result.size()).isEqualTo(2);
+// assertThat(result.values()).contains(user1Location, user2Location);
+//
+// }
+
+
+
+ // ##############################################################
+
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an User,"
+ + " WHEN Requested track User Location,"
+ + " then return location and adds to history as expected")
+ @Test
+ public void testTrackUser() {
+
+ // GIVEN
+ when(gpsUtilMicroService
+ .getUserLocation(any(UUID.class)))
+ .thenReturn(visitedLocationDTO);
+
+ when(visitedLocationMapper
+ .toVisitedLocation(any(VisitedLocationDTO.class)))
+ .thenReturn(visitedLocation);
+
+ // WHEN
+ gpsLocationService.trackUserLocation(user1).join();
+
+ // THEN
+ assertEquals((visitedLocation), user1.getVisitedLocations().get(0));
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an User,"
+ + " WHEN Requested getUserAttractionRecommendation,"
+ + " then return 5 nearby Attractions as expected")
+ @Test
+ public void testGetUserAttractionRecommendation() {
+
+ // GIVEN
+ user1.addToVisitedLocations(visitedLocation);
+
+ Location userLocation = user1.getLastVisitedLocation().getLocation();
+ LocationDTO userLocationDTO = new LocationDTO(-160.326003, -73.869629);
+
+ when(userService.getUser(anyString()))
+ .thenReturn(user1);
+
+ UUID userID = user1.getUserId();
+
+ AttractionDTO attraction1 = new AttractionDTO(
+ UUID.randomUUID(), "Disneyland", "Anaheim", "CA", new Location(33.817595D, -117.922008D));
+ AttractionDTO attraction2 = new AttractionDTO(
+ UUID.randomUUID(), "Jackson Hole", "Jackson Hole", "WY", new Location(43.582767D, -110.821999D));
+ AttractionDTO attraction3 = new AttractionDTO(
+ UUID.randomUUID(), "Mojave","Kelso", "CA", new Location(35.141689D, -115.510399D));
+ AttractionDTO attraction4 = new AttractionDTO(
+ UUID.randomUUID(), "Kartchner Caverns", "Benson", "AZ", new Location(31.837551D, -110.347382D));
+ AttractionDTO attraction5 = new AttractionDTO(
+ UUID.randomUUID(),"Joshua Tree", "Joshua Tree", "CA", new Location(33.881866D, -115.90065D));
+ AttractionDTO attraction6 = new AttractionDTO(
+ UUID.randomUUID(),"Buffalo", "St Joe", "AR", new Location(35.985512D, -92.757652D));
+ AttractionDTO attraction7 = new AttractionDTO(
+ UUID.randomUUID(),"Hot Springs", "Hot Springs", "AR", new Location(34.52153D, -93.042267D));
+ AttractionDTO attraction8 = new AttractionDTO(
+ UUID.randomUUID(),"Kartchner Caverns State Park", "Benson", "AZ", new Location(31.837551D, -110.347382D));
+ AttractionDTO attraction9 = new AttractionDTO(
+ UUID.randomUUID(),"Legend Valley", "Thornville", "OH", new Location(39.937778D, -82.40667D));
+ AttractionDTO attraction10 = new AttractionDTO(
+ UUID.randomUUID(),"Flowers Bakery of London", "Flowers Bakery of London", "KY", new Location(37.131527D, -84.07486D));
+
+ List attractions = Arrays.asList(
+ attraction1,
+ attraction2,
+ attraction3,
+ attraction4,
+ attraction5,
+ attraction6,
+ attraction7,
+ attraction8,
+ attraction9,
+ attraction10 );
+
+ lenient().when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ lenient().when(locationMapper
+ .toLocationDTO(any(Location.class)))
+ .thenReturn(userLocationDTO);
+
+ lenient().when(locationMapper
+ .toLocation(any(LocationDTO.class)))
+ .thenReturn(userLocation);
+
+ lenient().when(gpsUtilMicroService
+ .getAttractions())
+ .thenReturn(attractions);
+
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction1.getLocation(), userLocation)).thenReturn(100.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction2.getLocation(), userLocation)).thenReturn(200.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction3.getLocation(), userLocation)).thenReturn(300.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction4.getLocation(), userLocation)).thenReturn(400.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction5.getLocation(), userLocation)).thenReturn(500.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction6.getLocation(), userLocation)).thenReturn(600.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(700.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(800.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(900.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(900.00);
+
+ lenient().when(rewardsMicroService.getRewardPoints(attraction1.getAttractionId(), userID)).thenReturn(100);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction2.getAttractionId(), userID)).thenReturn(200);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction3.getAttractionId(), userID)).thenReturn(300);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction4.getAttractionId(), userID)).thenReturn(400);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction5.getAttractionId(), userID)).thenReturn(500);
+
+ // WHEN
+ UserAttractionRecommendationDTO result = gpsLocationService
+ .getUserAttractionRecommendation(user1.getUserName());
+
+ // THEN
+ assertThat(result.getNearbyAttractions()).isNotEmpty();
+ assertEquals(5, result.getNearbyAttractions().size());
+// assertEquals("Kartchner Caverns State Park", result.getNearbyAttractions().get(0).getAttractionName());
+// assertEquals("Flowers Bakery of London", result.getNearbyAttractions().get(1).getAttractionName());
+// assertEquals("Legend Valley", result.getNearbyAttractions().get(2).getAttractionName());
+// assertEquals("Disneyland", result.getNearbyAttractions().get(3).getAttractionName());
+// assertEquals("Jackson Hole", result.getNearbyAttractions().get(4).getAttractionName());
+
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an Username,"
+ + " WHEN Requested getTotalRewardPointsForUser,"
+ + " then return user reward points as expected")
+ @Test
+ public void getTotalRewardPointsForUser() {
+
+
+ // GIVEN
+ user1.addToVisitedLocations(visitedLocation);
+
+ Location userLocation = user1.getLastVisitedLocation().getLocation();
+ LocationDTO userLocationDTO = new LocationDTO(-160.326003, -73.869629);
+
+ when(userService.getUser(anyString()))
+ .thenReturn(user1);
+
+ UUID userID = user1.getUserId();
+
+ AttractionDTO attraction1 = new AttractionDTO(
+ UUID.randomUUID(), "Disneyland", "Anaheim", "CA", new Location(33.817595D, -117.922008D));
+ AttractionDTO attraction2 = new AttractionDTO(
+ UUID.randomUUID(), "Jackson Hole", "Jackson Hole", "WY", new Location(43.582767D, -110.821999D));
+ AttractionDTO attraction3 = new AttractionDTO(
+ UUID.randomUUID(), "Mojave","Kelso", "CA", new Location(35.141689D, -115.510399D));
+ AttractionDTO attraction4 = new AttractionDTO(
+ UUID.randomUUID(), "Kartchner Caverns", "Benson", "AZ", new Location(31.837551D, -110.347382D));
+ AttractionDTO attraction5 = new AttractionDTO(
+ UUID.randomUUID(),"Joshua Tree", "Joshua Tree", "CA", new Location(33.881866D, -115.90065D));
+ AttractionDTO attraction6 = new AttractionDTO(
+ UUID.randomUUID(),"Buffalo", "St Joe", "AR", new Location(35.985512D, -92.757652D));
+ AttractionDTO attraction7 = new AttractionDTO(
+ UUID.randomUUID(),"Hot Springs", "Hot Springs", "AR", new Location(34.52153D, -93.042267D));
+ AttractionDTO attraction8 = new AttractionDTO(
+ UUID.randomUUID(),"Kartchner Caverns State Park", "Benson", "AZ", new Location(31.837551D, -110.347382D));
+ AttractionDTO attraction9 = new AttractionDTO(
+ UUID.randomUUID(),"Legend Valley", "Thornville", "OH", new Location(39.937778D, -82.40667D));
+ AttractionDTO attraction10 = new AttractionDTO(
+ UUID.randomUUID(),"Flowers Bakery of London", "Flowers Bakery of London", "KY", new Location(37.131527D, -84.07486D));
+
+ List attractions = Arrays.asList(
+ attraction1,
+ attraction2,
+ attraction3,
+ attraction4,
+ attraction5,
+ attraction6,
+ attraction7,
+ attraction8,
+ attraction9,
+ attraction10 );
+
+ lenient().when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ lenient().when(locationMapper
+ .toLocationDTO(any(Location.class)))
+ .thenReturn(userLocationDTO);
+
+ lenient().when(locationMapper
+ .toLocation(any(LocationDTO.class)))
+ .thenReturn(userLocation);
+
+ lenient().when(gpsUtilMicroService
+ .getAttractions())
+ .thenReturn(attractions);
+
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction1.getLocation(), userLocation)).thenReturn(100.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction2.getLocation(), userLocation)).thenReturn(200.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction3.getLocation(), userLocation)).thenReturn(300.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction4.getLocation(), userLocation)).thenReturn(400.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction5.getLocation(), userLocation)).thenReturn(500.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction6.getLocation(), userLocation)).thenReturn(600.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(700.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(800.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(900.00);
+ lenient().when(distanceCalculator.getDistanceInMiles(attraction7.getLocation(), userLocation)).thenReturn(900.00);
+
+ lenient().when(rewardsMicroService.getRewardPoints(attraction1.getAttractionId(), userID)).thenReturn(100);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction2.getAttractionId(), userID)).thenReturn(200);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction3.getAttractionId(), userID)).thenReturn(300);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction4.getAttractionId(), userID)).thenReturn(400);
+ lenient().when(rewardsMicroService.getRewardPoints(attraction5.getAttractionId(), userID)).thenReturn(500);
+
+ // WHEN
+// UserAttractionRecommendationDTO result = tourGuideService
+// .getUserAttractionRecommendation(user1.getUserName());
+
+
+
+ // WHEN
+ int result = gpsLocationService
+ .getTotalRewardPointsForUser(user1.getUserName());
+
+ // THEN
+ assertNotNull(result);
+ assertThat(result > 500);
+ assertEquals(300, result);
+ }
+
+
+
+ // ##############################################################
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/test/java/tourGuide/unit/service/RewardsServiceTest.java b/tourguide/src/test/java/tourGuide/unit/service/RewardsServiceTest.java
new file mode 100644
index 0000000..4110817
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/service/RewardsServiceTest.java
@@ -0,0 +1,601 @@
+package tourGuide.unit.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InOrder;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.dto.UserRewardDTO;
+import tourGuide.helper.InternalTestHelper;
+import tourGuide.model.Attraction;
+import tourGuide.model.Location;
+import tourGuide.model.User;
+import tourGuide.model.UserReward;
+import tourGuide.model.VisitedLocation;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.proxy.MicroserviceRewardsProxy;
+import tourGuide.service.RewardsService;
+import tourGuide.service.UserService;
+import tourGuide.util.AttractionMapper;
+import tourGuide.util.DistanceCalculator;
+import tourGuide.util.UserRewardMapper;
+
+@DisplayName("Unit Test - Service - Rewards")
+@ExtendWith(MockitoExtension.class)
+public class RewardsServiceTest {
+
+
+ @InjectMocks
+ private RewardsService rewardsService;
+
+ @Mock
+ private UserService userService;
+
+ @Mock
+ private MicroserviceGpsProxy gpsUtilMicroService;
+
+
+ @Mock
+ private MicroserviceRewardsProxy rewardsMicroService;
+
+ @Mock
+ private AttractionMapper attractionMapper;
+
+ @Mock
+ private DistanceCalculator distanceCalculator;
+
+ @Mock
+ private InternalTestHelper internalTestHelper;
+
+ @Mock
+ private UserRewardMapper userRewardMapper;
+
+ private static User user1;
+
+ private static Map internalUser;
+
+ private static UserReward userReward;
+
+ private static UserRewardDTO userRewardDTO;
+
+ private static VisitedLocation visitedLocation;
+
+ private static Location location, attractionLocation, attractionLocationUserWithNoVisitedAttraction;
+
+
+ private static AttractionDTO attractionDTO;
+ private static UUID user1ID;
+
+ User user = new User();
+ User userWithNoVisitedAttraction = new User();
+ User userWithNoVisitedLocation = new User();
+
+ private static List attractions;
+
+
+ private static Attraction attraction;
+
+ // ##############################################################
+
+
+
+ @BeforeEach
+ public void setUp() {
+ user1ID = UUID.randomUUID();
+
+ user1 = new User(user1ID, "testUser1", "000", "testUser1@email.com");
+
+ userRewardDTO = new UserRewardDTO(visitedLocation, attraction, 300);
+ user = new User();
+ userWithNoVisitedAttraction = new User();
+ userWithNoVisitedLocation = new User();
+
+ user.setUserId(UUID.randomUUID());
+
+ location = new Location(33.817595, -117.922008);
+
+ visitedLocation = new VisitedLocation(
+ UUID.randomUUID(),
+ location, new Date());
+
+ user.addToVisitedLocations(visitedLocation);
+
+ userWithNoVisitedAttraction.addToVisitedLocations(visitedLocation);
+
+
+ attractionLocation = new Location(34.817595, -117.922008);
+
+ attractionLocationUserWithNoVisitedAttraction = new Location(
+ -34.817595, -117.922008);
+ attraction = new Attraction(UUID.randomUUID(), "Disneyland", "Anaheim", "CA", new Location(33.817595D, -117.922008D));
+ }
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check "
+ + " - Given a User with specifically one visited locaiton,"
+ + " when Calculate rewards,"
+ + " then return one rewards as expected")
+ @Test
+ public void testUserGetRewards() throws InterruptedException {
+
+ // GIVEN
+ attractionDTO = new AttractionDTO(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+ attraction = new Attraction(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+ attractions = Arrays.asList(attractionDTO);
+
+ lenient().when(gpsUtilMicroService
+ .getAttractions())
+ .thenReturn(attractions);
+
+ when(distanceCalculator
+ .getDistanceInMiles(location, location))
+ .thenReturn(8.00);
+
+ lenient().when(distanceCalculator
+ .getDistanceInMiles(location, location))
+ .thenReturn(8.00);
+
+ when(attractionMapper
+ .toAttraction(attractionDTO))
+ .thenReturn(attraction);
+
+ // WHEN
+ rewardsService.calculateRewards(user);
+
+ // THEN
+ assertNotNull(user.getUserRewards());
+ assertEquals(1, user.getUserRewards().size());
+ }
+
+
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check No visited attraction"
+ + " - Given a User with specifically No visited attraction,"
+ + " when Calculate rewards,"
+ + " then return No rewards as expected")
+ @Test
+ public void testUserGetRewardsWithNoVisitedAttraction() throws InterruptedException {
+
+ // GIVEN
+ attractionDTO = new AttractionDTO(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocationUserWithNoVisitedAttraction);
+
+ attractions = Arrays.asList(attractionDTO);
+
+ lenient().when(gpsUtilMicroService
+ .getAttractions())
+ .thenReturn(attractions);
+
+ lenient().when(distanceCalculator
+ .getDistanceInMiles(attractionLocationUserWithNoVisitedAttraction, location))
+ .thenReturn(800.00);
+
+
+
+ // WHEN
+ rewardsService.calculateRewards(userWithNoVisitedAttraction);
+
+
+
+ // THEN
+ assertEquals(0, userWithNoVisitedAttraction.getUserRewards().size());
+
+ InOrder inOrder = inOrder(gpsUtilMicroService, distanceCalculator);
+ inOrder.verify(gpsUtilMicroService).getAttractions();
+// inOrder.verify(distanceCalculator).getDistanceInMiles(attractionLocation, location);
+
+ verify(gpsUtilMicroService, times(1)).getAttractions();
+ verify(distanceCalculator, times(0)).getDistanceInMiles(attractionLocation, location);
+ }
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check No visited location"
+ + " - Given a User with specifically No visited locaiton,"
+ + " when Calculate rewards,"
+ + " then return No rewards as expected")
+ @Test
+ public void testUserGetRewardsWithNoVisitedLocation() throws InterruptedException {
+
+ // GIVEN => No visited location
+
+ // WHEN
+ rewardsService.calculateRewards(userWithNoVisitedLocation);
+
+ // THEN
+ assertEquals(0, userWithNoVisitedAttraction.getUserRewards().size());
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check on revisiting Same location"
+ + " - Given a User with revisiting one same visited locaiton,"
+ + " when Calculate rewards,"
+ + " then return one rewards as expected")
+ @Test
+ public void testUserGetRewardsOnRevisitingSameLocation() throws InterruptedException {
+
+ // GIVEN
+ attractionDTO = new AttractionDTO(UUID.randomUUID(), "attraction name",
+ "attraction city", "attraction state", location);
+ attraction = new Attraction(UUID.randomUUID(), "attraction name",
+ "attraction city", "attraction state", location);
+ attractions = Arrays.asList(attractionDTO);
+
+ user.addUserReward(new UserReward(visitedLocation, attraction, 500));
+
+ lenient().when(gpsUtilMicroService
+ .getAttractions())
+ .thenReturn(attractions);
+
+ when(distanceCalculator
+ .getDistanceInMiles(location, location))
+ .thenReturn(8.00);
+
+ when(distanceCalculator
+ .getDistanceInMiles(location, location))
+ .thenReturn(8.00);
+
+
+
+ // WHEN
+ rewardsService.calculateRewards(user);
+
+
+
+ // THEN
+ assertEquals(1, user.getUserRewards().size());
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+
+
+
+ @DisplayName("Check "
+ + " - Given a User with specifically one visited locaiton,"
+ + " when Calculate request isWithinAttractionProximity,"
+ + " then return result as expected")
+ @Test
+ public void isWithinAttractionProximity() {
+
+ // GIVEN
+
+ attraction = new Attraction(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+
+ VisitedLocation visitedLocation = new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date());
+
+
+ // WHEN
+ Boolean result = rewardsService
+ .isWithinAttractionProximity(
+ visitedLocation,
+ attraction.getLocation());
+
+
+ // THEN <== // WHEN
+ assertNotNull(result);
+ assertTrue(result);
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an User ,"
+ + " when Calculate request calculateRewardAsync,"
+ + " then return one result as expected")
+ @Test
+ public void testCalculateRewardAsyncForOneVisitedLocation() {
+
+ // GIVEN
+ VisitedLocation visitedLocation = new VisitedLocation(
+ UUID.randomUUID(),
+ location,
+ new Date());
+
+ user.addToVisitedLocations(visitedLocation);
+
+ AttractionDTO attractionDTO = new AttractionDTO(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+ Attraction attraction = new Attraction(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+ List attractions = Arrays.asList(attractionDTO);
+
+ when(gpsUtilMicroService
+ .getAttractions())
+ .thenReturn(attractions);
+
+ when(distanceCalculator
+ .getDistanceInMiles(any(Location.class), any(Location.class)))
+ .thenReturn(10.00);
+
+ when(rewardsMicroService
+ .getRewardPoints(any(UUID.class), any(UUID.class)))
+ .thenReturn(1000);
+
+ when(attractionMapper
+ .toAttraction(attractionDTO))
+ .thenReturn(attraction);
+
+ rewardsService.calculateRewardAsync(user).join();
+
+ assertEquals(1, user.getUserRewards().size());
+ }
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an User ,"
+ + " when Calculate request getRewardPoints,"
+ + " then return rewardPoints as expected")
+ @Test
+ public void testgetRewarPoints() {
+
+
+ // GIVEN
+
+ VisitedLocation visitedLocation = new VisitedLocation(
+ UUID.randomUUID(),
+ location,
+ new Date());
+
+ user.addToVisitedLocations(visitedLocation);
+
+ AttractionDTO attractionDTO = new AttractionDTO(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+ Attraction attraction = new Attraction(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+
+ user.addToVisitedLocations(
+ new VisitedLocation(
+ user.getUserId(),
+ attraction.getLocation(),
+ new Date()));
+
+
+
+ when(rewardsMicroService
+ .getRewardPoints(any(UUID.class), any(UUID.class)))
+ .thenReturn(1000);
+
+ when(attractionMapper
+ .toAttraction(attractionDTO))
+ .thenReturn(attraction);
+
+ // WHEN
+ UserReward result = rewardsService
+ .getRewardPoints(user, user.getLastVisitedLocation(), attractionDTO);
+
+ // THEN
+ assertNotNull(result);
+ assertNotNull(result.getVisitedLocation());
+ assertNotNull(result.getRewardPoints());
+ assertNotNull(result.getAttraction());
+
+ assertTrue(result.getRewardPoints() > 1);
+ assertEquals(1000, result.getRewardPoints());
+ }
+
+ // ##############################################################
+
+
+ @DisplayName("Check "
+ + " - Given an User with specific attraction spot,"
+ + " when Calculate request if user has rewards for the spot,"
+ + " then return result as expected")
+ @Test
+ public void testCheckIfUserIsOfferedRewardToThisAttractionSpot() {
+
+
+ // GIVEN
+
+ VisitedLocation visitedLocation = new VisitedLocation(
+ UUID.randomUUID(),
+ location,
+ new Date());
+
+ user.addToVisitedLocations(visitedLocation);
+
+ AttractionDTO attractionDTO = new AttractionDTO(
+ UUID.randomUUID(),
+ "attraction name",
+ "attraction city",
+ "attraction state",
+ attractionLocation);
+
+
+ // WHEN
+ Boolean result = rewardsService
+ .checkIfUserIsOfferedRewardToThisAttractionSpot(
+ user,
+ attractionDTO);
+
+ // THEN
+ assertNotNull(result);
+ assertTrue(result);
+
+ }
+
+
+
+// // ##############################################################
+//
+//
+//
+//
+//
+// @DisplayName("Check "
+// + " - Given an User with reward,"
+// + " WHEN Requested testGetUserRewards,"
+// + " then return user rewards as expected")
+// @Test
+// public void testGetUserRewards() {
+//
+// // GIVEN
+//
+//
+// when(userService.getUser(anyString()))
+// .thenReturn(user1);
+//
+// user1.addUserReward(userReward);
+//
+// lenient().when(internalTestHelper
+// .getInternalUserMap())
+// .thenReturn(internalUser);
+//
+// lenient().when(userRewardMapper
+// .toUserRewardDTO(any(UserReward.class)))
+// .thenReturn(userRewardDTO);
+//
+//
+// // WHEN
+// List result = rewardsService
+// .getUserRewards("testUser1");
+//
+// // THEN
+// assertNotNull(result);
+// assertThat(result.get(0).getRewardPoints() > 1);
+//
+// }
+//
+//
+
+ // ##############################################################
+
+
+
+ @DisplayName("Check no rewards"
+ + " - Given an User with no reward,"
+ + " WHEN Requested testGetUserRewards,"
+ + " then return user rewards (empty) as expected")
+ @Test
+ public void testGetUserRewardsWhenNoRewards() {
+
+ // GIVEN
+
+ when(userService.getUser(anyString()))
+ .thenReturn(user1);
+
+ user1.addUserReward(userReward);
+
+ lenient().when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ // WHEN
+ List result = rewardsService
+ .getUserRewards("testUser1");
+
+ // THEN
+ assertNotNull(result);
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/test/java/tourGuide/unit/service/TripDealsServiceTest.java b/tourguide/src/test/java/tourGuide/unit/service/TripDealsServiceTest.java
new file mode 100644
index 0000000..cd919dd
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/service/TripDealsServiceTest.java
@@ -0,0 +1,222 @@
+package tourGuide.unit.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.money.Monetary;
+
+import org.javamoney.moneta.Money;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import tourGuide.dto.ProviderDTO;
+import tourGuide.helper.InternalTestHelper;
+import tourGuide.model.Attraction;
+import tourGuide.model.Location;
+import tourGuide.model.Provider;
+import tourGuide.model.User;
+import tourGuide.model.UserPreferences;
+import tourGuide.model.UserReward;
+import tourGuide.model.VisitedLocation;
+import tourGuide.proxy.MicroServiceTripDealsProxy;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.proxy.MicroserviceRewardsProxy;
+import tourGuide.service.RewardsService;
+import tourGuide.service.TripDealsService;
+import tourGuide.service.UserService;
+import tourGuide.util.DistanceCalculator;
+import tourGuide.util.LocationMapper;
+import tourGuide.util.ProviderMapper;
+import tourGuide.util.UserPreferencesMapper;
+import tourGuide.util.UserRewardMapper;
+import tourGuide.util.VisitedLocationMapper;
+
+@DisplayName("Unit Test - Service - TripDeals")
+@ExtendWith(MockitoExtension.class)
+public class TripDealsServiceTest {
+
+ @InjectMocks
+ private TripDealsService tripDealsService;
+
+ @Mock
+ private RewardsService rewardsService;
+
+ @Mock
+ private UserService userService;
+
+ @Mock
+ private MicroserviceGpsProxy gpsUtilMicroService;
+
+ @Mock
+ private MicroServiceTripDealsProxy tripDealsMicroservice;
+
+ @Mock
+ private MicroserviceRewardsProxy rewardsMicroService;
+
+ @Mock
+ private UserPreferencesMapper userPreferencesMapper;
+
+ @Mock
+ private UserRewardMapper userRewardMapper;
+
+ @Mock
+ private LocationMapper locationMapper;
+
+ @Mock
+ private VisitedLocationMapper visitedLocationMapper;
+
+ @Mock
+ private ProviderMapper providerMapper;
+
+ @Mock
+ private DistanceCalculator distanceCalculator;
+
+ @Mock
+ private InternalTestHelper internalTestHelper;
+
+ private static UUID user1ID;
+
+ private static UUID user2ID;
+
+ private static User user1;
+
+ private static User user2;
+
+
+ private static Map internalUser;
+
+
+ private static VisitedLocation visitedLocation;
+
+
+ private static UserReward userReward;
+
+ private static UserPreferences userPreferences;
+
+
+ private static Attraction attraction;
+
+
+
+
+ // ##############################################################
+
+
+
+ @BeforeEach
+ public void setUp() {
+ user1ID = UUID.randomUUID();
+ user2ID = UUID.randomUUID();
+ user1 = new User(user1ID, "testUser1", "000", "testUser1@email.com");
+ user2 = new User(user2ID, "testUser2", "001", "testUser1@email.com");
+
+
+ visitedLocation = new VisitedLocation(
+ user1ID,
+ new Location(33.817595, -117.922008),
+ new Date());
+
+
+
+ internalUser = new HashMap<>();
+ internalUser.put("testUser1", user1);
+ internalUser.put("testUser2", user2);
+
+
+ userReward = new UserReward(visitedLocation, attraction, 300);
+
+
+ attraction = new Attraction(UUID.randomUUID(), "Disneyland", "Anaheim", "CA", new Location(33.817595D, -117.922008D));
+
+ userPreferences = new UserPreferences(
+ 10,
+ Money.of(500, Monetary.getCurrency("USD")),
+ Money.of(1000, Monetary.getCurrency("USD")),
+ 5,
+ 5,
+ 2,
+ 3);
+
+
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given an Username,"
+ + " WHEN Requested getTripDeals,"
+ + " then return trip deals as expected")
+ @Test
+ public void getTripDeals() {
+
+ // GIVEN
+
+ when(userService.getUser(anyString()))
+ .thenReturn(user1);
+
+ when(userService.getUser(anyString()))
+ .thenReturn(user2);
+
+ user1.addUserReward(userReward);
+ user1.setUserPreferences(userPreferences);
+ ProviderDTO providerDTO = new ProviderDTO("name", 100, UUID.randomUUID());
+ Provider provider = new Provider("name", 100, UUID.randomUUID());
+
+ lenient().when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ lenient().when(internalTestHelper
+ .getTripPricerApiKey())
+ .thenReturn("test-server-api-key");
+
+ lenient().when(tripDealsMicroservice
+ .getProviders(anyString(), any(UUID.class), anyInt(), anyInt(), anyInt(), anyInt()))
+ .thenReturn(Arrays.asList(providerDTO));
+
+ lenient().when(providerMapper
+ .toProvider(providerDTO))
+ .thenReturn(provider);
+
+ // WHEN
+ List result = tripDealsService
+ .getUserTripDeals(user1.getUserName());
+
+ // THEN
+ assertNotNull(result);
+ assertThat(result).isNotEmpty();
+// assertEquals(4, (result.toArray().toString().length())/7);
+ assertTrue(result.toArray().toString().length() > 1);
+
+ }
+
+
+
+ // ##############################################################
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/test/java/tourGuide/unit/service/UserServiceTest.java b/tourguide/src/test/java/tourGuide/unit/service/UserServiceTest.java
new file mode 100644
index 0000000..089f391
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/service/UserServiceTest.java
@@ -0,0 +1,227 @@
+package tourGuide.unit.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import tourGuide.exception.UserNotFoundException;
+import tourGuide.helper.InternalTestHelper;
+import tourGuide.model.User;
+import tourGuide.proxy.MicroServiceTripDealsProxy;
+import tourGuide.proxy.MicroserviceGpsProxy;
+import tourGuide.proxy.MicroserviceRewardsProxy;
+import tourGuide.service.RewardsService;
+import tourGuide.service.UserService;
+import tourGuide.util.DistanceCalculator;
+import tourGuide.util.LocationMapper;
+import tourGuide.util.ProviderMapper;
+import tourGuide.util.UserPreferencesMapper;
+import tourGuide.util.UserRewardMapper;
+import tourGuide.util.VisitedLocationMapper;
+
+@DisplayName("Unit Test - Service - User")
+@ExtendWith(MockitoExtension.class)
+public class UserServiceTest {
+
+ @InjectMocks
+ private UserService userService;
+
+ @Mock
+ private RewardsService rewardsService;
+
+ @Mock
+ private MicroserviceGpsProxy gpsUtilMicroService;
+
+ @Mock
+ private MicroServiceTripDealsProxy tripDealsMicroservice;
+
+ @Mock
+ private MicroserviceRewardsProxy rewardsMicroService;
+
+ @Mock
+ private UserPreferencesMapper userPreferencesMapper;
+
+ @Mock
+ private UserRewardMapper userRewardMapper;
+
+ @Mock
+ private LocationMapper locationMapper;
+
+ @Mock
+ private VisitedLocationMapper visitedLocationMapper;
+
+ @Mock
+ private ProviderMapper providerMapper;
+
+ @Mock
+ private DistanceCalculator distanceCalculator;
+
+ @Mock
+ private InternalTestHelper internalTestHelper;
+
+ private static UUID user1ID;
+
+ private static UUID user2ID;
+
+ private static User user1;
+
+ private static User user2;
+
+
+ private static Map internalUser;
+
+ private static List userList;
+
+
+
+
+ // ##############################################################
+
+
+
+ @BeforeEach
+ public void setUp() {
+ user1ID = UUID.randomUUID();
+ user2ID = UUID.randomUUID();
+ user1 = new User(user1ID, "testUser1", "000", "testUser1@email.com");
+ user2 = new User(user2ID, "testUser2", "001", "testUser1@email.com");
+
+ internalUser = new HashMap<>();
+ internalUser.put("testUser1", user1);
+ internalUser.put("testUser2", user2);
+
+ userList = Arrays.asList(user1, user2);
+
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+
+ @DisplayName("Check "
+ + " - Given a userlist,"
+ + " WHEN Requested GET all users,"
+ + " then return All Users list")
+ @Test
+ public void testGetAllUsers() {
+
+
+ // GIVEN
+ when(internalTestHelper.getInternalUserMap())
+ .thenReturn(internalUser);
+
+ // WHEN
+ List users = userService.getAllUsers();
+
+ // THEN
+ assertNotNull(users);
+ assertThat(users).isNotEmpty();
+ assertEquals(userList.size(), users.size());
+ }
+
+
+
+ // ##############################################################
+
+
+ @DisplayName("Check - emptylist "
+ + "GIVEN an Empty UserList "
+ + "WHEN Requested getAllUsers "
+ + "THEN throws UserNotFound Exception")
+ @Test
+ public void testGetAllUsersEmptyListThrowsException() {
+
+ // GIVEN
+ internalUser.clear();
+
+ when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ // THEN <== WHEN
+ assertThrows(UserNotFoundException.class, ()
+ -> userService.getAllUsers());
+ }
+
+
+
+
+ // ##############################################################
+
+
+
+
+ @DisplayName("Check "
+ + " - Given a User existing,"
+ + " WHEN Requested GET user,"
+ + " then return user as expected")
+ @Test
+ public void testGetUser() {
+
+ // GIVEN
+ when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(internalUser);
+
+ // WHEN
+ User user = userService
+ .getUser("testUser1");
+
+ // THEN
+ assertNotNull(user);
+ assertEquals("testUser1", user.getUserName());
+
+ }
+
+
+ // ##############################################################
+
+
+ @Test
+ @DisplayName("Check - not exists "
+ + "GIVEN an Username not exists "
+ + "WHEN Requested GET User "
+ + "THEN throws UserNotFoundException")
+ public void testGetUserNotExistingForUserNotFoundException() {
+
+ // GIVEN
+ when(internalTestHelper
+ .getInternalUserMap())
+ .thenReturn(new HashMap<>());
+
+ // THEN <== WHEN
+ assertThrows(UserNotFoundException.class, ()
+ -> userService
+ .getUser("testUserDoesNotExist"));
+
+ }
+
+
+
+ // ##############################################################
+
+
+
+
+}
\ No newline at end of file
diff --git a/tourguide/src/test/java/tourGuide/unit/utils/TestAttractionMapper.java b/tourguide/src/test/java/tourGuide/unit/utils/TestAttractionMapper.java
new file mode 100644
index 0000000..f6a42ae
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/utils/TestAttractionMapper.java
@@ -0,0 +1,102 @@
+package tourGuide.unit.utils;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.AttractionDTO;
+import tourGuide.model.Attraction;
+import tourGuide.model.Location;
+import tourGuide.util.AttractionMapper;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+public class TestAttractionMapper {
+
+ private AttractionMapper attractionMapper = new AttractionMapper();
+
+
+
+ @DisplayName("Check "
+ + " - Given DTO,"
+ + " when ToVisitedLocation,"
+ + " then return DO expected")
+ @Test
+ public void testToAttraction() {
+
+ UUID attractionID = UUID.randomUUID();
+
+ Location location = new Location();
+ location.setLatitude(-117.149048);
+ location.setLongitude(33.817595);
+
+
+ Attraction testAttraction = new Attraction(
+ attractionID,
+ "San Diego Zoo",
+ "San Diego",
+ "CA",
+ location);
+
+ AttractionDTO testAttractionDTO = new AttractionDTO(
+ attractionID,
+ "San Diego Zoo",
+ "San Diego",
+ "CA",
+ location);
+
+ Attraction result = attractionMapper.toAttraction(testAttractionDTO);
+
+// assertThat(result).usingRecursiveComparison().isEqualTo(testAttraction.);
+ assertNotNull(result.getLocation().toString());
+ assertNotNull(testAttraction.getLocation().toString());
+ }
+
+
+
+ // ##############################################################
+
+// @DisplayName("Check "
+// + " - Given DO,"
+// + " when ToVisitedLocationDTO,"
+// + " then return DTO expected")
+// @Test
+// public void testToAttractionDTO() {
+//
+// Location location = new Location();
+// location.setLatitude(-117.149048);
+// location.setLongitude(33.817595);
+//
+//
+// gpsUtil.location.Attraction testAttraction = new gpsUtil.location.Attraction(
+// "San Diego Zoo",
+// "San Diego",
+// "CA",
+// -117.149048,
+// 33.817595);
+//
+//
+// AttractionDTO result = attractionMapper.toAttractionDTO(testAttraction);
+//
+// assertNotNull(result);
+// assertEquals(testAttraction.attractionId, result.getAttractionId());
+// assertEquals(testAttraction.attractionName, result.getAttractionName());
+// assertEquals(testAttraction.city, result.getCity());
+// assertEquals(testAttraction.state, result.getState());
+//
+// }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/unit/utils/TestLocationMapper.java b/tourguide/src/test/java/tourGuide/unit/utils/TestLocationMapper.java
new file mode 100644
index 0000000..bad921f
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/utils/TestLocationMapper.java
@@ -0,0 +1,82 @@
+package tourGuide.unit.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.LocationDTO;
+import tourGuide.model.Location;
+import tourGuide.util.LocationMapper;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+public class TestLocationMapper {
+
+ private LocationMapper attractionMapper = new LocationMapper();
+
+
+
+ @DisplayName("Check "
+ + " - Given DTO,"
+ + " when ToVisitedLocation,"
+ + " then return DO expected")
+ @Test
+ public void testToLocation() {
+
+
+ Location location = new Location();
+ location.setLatitude(-117.149048);
+ location.setLongitude(33.817595);
+
+
+ Location testLocation = new Location(
+ -117.149048,
+ 33.817595);
+
+ LocationDTO testLocationDTO = new LocationDTO(
+ -117.149048,
+ 33.817595);
+
+ Location result = attractionMapper.toLocation(testLocationDTO);
+
+ assertThat(result).isEqualToComparingFieldByField(testLocation);
+ }
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check "
+ + " - Given DO,"
+ + " when ToVisitedLocation,"
+ + " then return DTO expected")
+ @Test
+ public void testToLocationDTO() {
+
+
+ Location location = new Location();
+ location.setLatitude(-117.149048);
+ location.setLongitude(33.817595);
+
+
+ Location testLocation = new Location(
+ -117.149048,
+ 33.817595);
+
+
+ LocationDTO result = attractionMapper.toLocationDTO(testLocation);
+
+ assertThat(result).isEqualToComparingFieldByField(testLocation);
+
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/unit/utils/TestProviderMapper.java b/tourguide/src/test/java/tourGuide/unit/utils/TestProviderMapper.java
new file mode 100644
index 0000000..2e37f83
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/utils/TestProviderMapper.java
@@ -0,0 +1,81 @@
+package tourGuide.unit.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.ProviderDTO;
+import tourGuide.model.Provider;
+import tourGuide.util.ProviderMapper;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+public class TestProviderMapper {
+
+ private ProviderMapper attractionMapper = new ProviderMapper();
+
+
+
+ @DisplayName("Check "
+// + " - Given DO,"
+// + " when ToProviderDTO,"
+// + " then return DO expected")
+// @Test
+// public void testToProviderDTO() {
+//
+// UUID tripID = UUID.randomUUID();
+//
+//
+// tripPricer.Provider testProvider = new tripPricer.Provider(
+// tripID,
+// "testProvider",
+// 100);
+//
+//
+// ProviderDTO result = attractionMapper.toProviderDTO(testProvider);
+//
+// assertThat(result).isEqualToComparingFieldByField(testProvider);
+//
+// }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/unit/utils/TestUserPreferenceMapper.java b/tourguide/src/test/java/tourGuide/unit/utils/TestUserPreferenceMapper.java
new file mode 100644
index 0000000..dded891
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/utils/TestUserPreferenceMapper.java
@@ -0,0 +1,287 @@
+package tourGuide.unit.utils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Set;
+
+import javax.money.Monetary;
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+import org.javamoney.moneta.Money;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.UserPreferencesDTO;
+import tourGuide.model.UserPreferences;
+import tourGuide.util.UserPreferencesMapper;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+//@ActiveProfiles("test")
+public class TestUserPreferenceMapper {
+
+ private UserPreferencesMapper userPreferencesMapper = new UserPreferencesMapper();
+
+// ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+// Validator validator = factory.getValidator();
+
+ @DisplayName("Check "
+ + " - Given DTO,"
+ + " when toUserPreferences,"
+ + " then return DO expected")
+ @Test
+ public void testToUserPreferences() {
+
+
+ UserPreferences userPreferences = new UserPreferences();
+ userPreferences.setTripDuration(999);
+ userPreferences.setTicketQuantity(999);
+ userPreferences.setNumberOfAdults(999);
+ userPreferences.setNumberOfChildren(999);
+ userPreferences.setHighPricePoint(Money.of(999, Monetary.getCurrency("EUR")));
+ userPreferences.setLowerPricePoint(Money.of(999, Monetary.getCurrency("EUR")));
+ userPreferences.setAttractionProximity(999);
+
+
+ UserPreferences testUserPreferences = new UserPreferences();
+ testUserPreferences.setTripDuration(999);
+ testUserPreferences.setTicketQuantity(999);
+ testUserPreferences.setNumberOfAdults(999);
+ testUserPreferences.setNumberOfChildren(999);
+ testUserPreferences.setHighPricePoint(Money.of(999, Monetary.getCurrency("EUR")));
+ testUserPreferences.setLowerPricePoint(Money.of(999, Monetary.getCurrency("EUR")));
+ testUserPreferences.setAttractionProximity(999);
+
+
+
+ UserPreferencesDTO result = userPreferencesMapper.toUserPreferencesDTO(userPreferences);
+
+ assertEquals(testUserPreferences.getTripDuration(), result.getTripDuration());
+ assertEquals(testUserPreferences.getTicketQuantity(), result.getTicketQuantity());
+ assertEquals(testUserPreferences.getNumberOfAdults(), result.getNumberOfAdults());
+ assertEquals(testUserPreferences.getNumberOfChildren(), result.getNumberOfChildren());
+ assertEquals(testUserPreferences.getAttractionProximity(), result.getAttractionProximity());
+ }
+
+
+
+ // ##############################################################
+//
+//
+// @Test
+// public void testForAllInputsValid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoOK = new UserPreferencesDTO(999, 999, 999, 999, 999, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoOK);
+// // THEN
+// assertEquals(0, constraintViolations.size());
+//
+// }
+//
+//
+// // ##############################################################
+//
+// @Test
+// public void testForAttractionProximityInvalid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoProximityInvalid = new UserPreferencesDTO(-10, 999, 999, 999, 999, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoProximityInvalid);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Valid value required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+// // ##############################################################
+//
+// @Test
+// public void testForLowerPricePointInvalid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoLowerPriceInvalid = new UserPreferencesDTO(999, -999, 999, 999, 999, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoLowerPriceInvalid);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Valid value required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+// // ##############################################################
+//
+// @Test
+// public void testForHighPricePointInvalid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoHighPriceInvalid = new UserPreferencesDTO(999, 999, -999, 999, 999, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoHighPriceInvalid);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Valid value required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+//
+//// ##############################################################
+//
+// @Test
+// public void testForTripDurationZero() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoTripDurationZero = new UserPreferencesDTO(999, 999, 999, 0, 999, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoTripDurationZero);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Minimum stay period should be atleast 1",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+//
+// // ##############################################################
+//
+// @Test
+// public void testForTripDurationInvalid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoTripDurationInvalid = new UserPreferencesDTO(999, 999, 999, -999, 999, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoTripDurationInvalid);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Minimum stay period should be atleast 1",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+//
+//// ##############################################################
+//
+//
+// @Test
+// public void testForTicketQuantityZero() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoTicketQuantityZero = new UserPreferencesDTO(999, 999, 999, 999, 0, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoTicketQuantityZero);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Minimum ticket quantity value (1) required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+//
+// // ##############################################################
+//
+//
+// @Test
+// public void testForTicketQuantityInvalid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoTicketQuantityInvalid = new UserPreferencesDTO(999, 999, 999, 999, -999, 999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoTicketQuantityInvalid);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Minimum ticket quantity value (1) required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+//
+// // ##############################################################
+//
+//
+// @Test
+// public void testForTicketAdultNumberZero() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoAdultNumberZero = new UserPreferencesDTO(999, 999, 999, 999, 999, 0, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoAdultNumberZero);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Minimum number of adults (1) required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+//
+// // ##############################################################
+//
+//
+// @Test
+// public void testForTicketAdultNumberInvalid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoAdultNumberInvalid = new UserPreferencesDTO(999, 999, 999, 999, 999, -999, 999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoAdultNumberInvalid);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Minimum number of adults (1) required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+//
+//
+// // ##############################################################
+//
+//
+//
+// @Test
+// public void testForTicketChildrenNumberInvalid() {
+//
+// // GIVEN
+// UserPreferencesDTO userPreferencesDtoChildrenNumberInvalid = new UserPreferencesDTO(999, 999, 999, 999, 999, 999, -999);
+//
+// // WHEN
+// Set> constraintViolations =
+// validator.validate(userPreferencesDtoChildrenNumberInvalid);
+// // THEN
+// assertEquals(1, constraintViolations.size());
+// assertEquals("Valid value required",
+// constraintViolations.iterator().next().getMessage());
+// }
+//
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/unit/utils/TestUserRewardMapper.java b/tourguide/src/test/java/tourGuide/unit/utils/TestUserRewardMapper.java
new file mode 100644
index 0000000..4347972
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/utils/TestUserRewardMapper.java
@@ -0,0 +1,52 @@
+package tourGuide.unit.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.UserRewardDTO;
+import tourGuide.model.Attraction;
+import tourGuide.model.Location;
+import tourGuide.model.UserReward;
+import tourGuide.model.VisitedLocation;
+import tourGuide.util.UserRewardMapper;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+public class TestUserRewardMapper {
+
+ private UserRewardMapper userRewardMapper = new UserRewardMapper();
+
+
+
+
+ // ##############################################################
+
+
+ @Test
+ public void testToUserRewardDTO() {
+
+ VisitedLocation visitedLocation = new VisitedLocation(UUID.randomUUID(), new Location(-120.149048, 33.735317), new Date());
+ Attraction attraction = new Attraction(UUID.randomUUID(), "San Diego Zoo" , "San Diego" ,
+ "CA" , new Location(-117.149048, 32.735317));
+ UserRewardDTO testUserRewardDTO = new UserRewardDTO(visitedLocation, attraction, 100);
+
+ UserRewardDTO result = userRewardMapper.toUserRewardDTO(new UserReward(visitedLocation, attraction, 100));
+
+
+ assertThat(result).isEqualToComparingFieldByField(testUserRewardDTO);
+
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tourguide/src/test/java/tourGuide/unit/utils/TestVisitedLocationMapper.java b/tourguide/src/test/java/tourGuide/unit/utils/TestVisitedLocationMapper.java
new file mode 100644
index 0000000..b4c1d25
--- /dev/null
+++ b/tourguide/src/test/java/tourGuide/unit/utils/TestVisitedLocationMapper.java
@@ -0,0 +1,98 @@
+package tourGuide.unit.utils;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tourGuide.dto.VisitedLocationDTO;
+import tourGuide.model.Location;
+import tourGuide.model.VisitedLocation;
+import tourGuide.util.VisitedLocationMapper;
+
+@DisplayName("Unit Test - Mapper - VisitedLocation")
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+public class TestVisitedLocationMapper {
+
+ private VisitedLocationMapper visitedLocationMapper = new VisitedLocationMapper();
+
+
+
+ @DisplayName("Check "
+ + " - Given DTO,"
+ + " when ToVisitedLocation,"
+ + " then return DO expected")
+ @Test
+ public void testToVisitedLocation() {
+
+
+
+ VisitedLocation testVisitedLocation = new VisitedLocation(
+ UUID.randomUUID(),
+ new Location(-117.149048,
+ 33.817595),
+ new Date());
+
+ VisitedLocationDTO testVisitedLocationDTO = new VisitedLocationDTO(
+ UUID.randomUUID(),
+ new Location(-117.149048,
+ 33.817595),
+ new Date());
+
+ VisitedLocation result = visitedLocationMapper.toVisitedLocation(testVisitedLocationDTO);
+
+// assertThat(result).isEqualToComparingFieldByField(testVisitedLocation);
+// assertEquals(testVisitedLocation.getLocation().getLatitude(), result.getLocation().getLatitude());
+ assertNotNull(result.getLocation());
+ assertNotNull(testVisitedLocation.getLocation().getLatitude());
+ }
+
+
+
+ // ##############################################################
+
+// @DisplayName("Check "
+// + " - Given TO,"
+// + " when ToVisitedLocationDTO,"
+// + " then return DTO expected")
+// @Test
+// public void testToVisitedLocationDTO() {
+//
+// UUID userID = UUID.randomUUID();
+// gpsUtil.location.Location location = new gpsUtil.location.Location (-100.149048, 39.817595);
+// Date date = new Date();
+//
+// gpsUtil.location.VisitedLocation testVisitedLocation = new gpsUtil.location.VisitedLocation(
+// userID,
+// location,
+// date);
+//
+//// VisitedLocationDTO testVisitedLocationDTO = new VisitedLocationDTO(
+//// UUID.randomUUID(),
+//// new Location(-100.149048,
+//// 39.817595),
+//// new Date());
+////
+////
+//
+// VisitedLocationDTO result = visitedLocationMapper.toVisitedLocationDTO(testVisitedLocation);
+//
+//// assertThat(result).usingRecursiveComparison().isEqualTo(testVisitedLocation);
+// assertNotNull(result.getLocation());
+// assertNotNull(testVisitedLocation.location.latitude);
+//
+// }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tripDealsMicroservice/Dockerfile b/tripDealsMicroservice/Dockerfile
new file mode 100644
index 0000000..a8f21bb
--- /dev/null
+++ b/tripDealsMicroservice/Dockerfile
@@ -0,0 +1,4 @@
+FROM openjdk:13-oracle
+ADD build/libs/tripDealsMicroservice-1.0.0.war tripdeals-microservice.war
+EXPOSE 9093
+ENTRYPOINT ["java","-jar","tripdeals-microservice.war"]
\ No newline at end of file
diff --git a/tripDealsMicroservice/build.gradle b/tripDealsMicroservice/build.gradle
new file mode 100644
index 0000000..38bad40
--- /dev/null
+++ b/tripDealsMicroservice/build.gradle
@@ -0,0 +1,131 @@
+buildscript {
+ repositories {
+ // Maven Central for resolving dependencies
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+ }
+ dependencies {
+ // https://plugins.gradle.org/plugin/org.springframework.boot
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
+ }
+}
+
+// https://docs.gradle.org/current/samples/sample_building_java_libraries.html
+
+plugins {
+ // Apply the java-library plugin for API and implementation separation
+ id 'java-library'
+ id 'maven-publish'
+}
+
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+apply plugin: 'war'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'io.spring.dependency-management'
+apply plugin: "jacoco"
+
+
+bootWar {
+ baseName = 'tripDealsMicroservice'
+ version = '1.0.0'
+}
+
+repositories {
+ mavenCentral()
+ flatDir {
+ dirs 'libs'
+ }
+}
+
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
+
+// https://stackoverflow.com/questions/23796404/could-not-find-method-compile-for-arguments-gradle
+/* Note that the compile, runtime, testCompile, and testRuntime configurations
+ introduced by the Java plugin have been deprecated since Gradle 4.10 (Aug 27, 2018),
+and were finally removed in Gradle 7.0 (Apr 9, 2021).
+The aforementioned configurations should be replaced by implementation,
+ runtimeOnly, testImplementation, and testRuntimeOnly, respectively.
+ http://man.hubwiz.com/docset/Gradle_User_Guide.docset/Contents/Resources/Documents/userguide/java_library_plugin.html
+*/
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-web")
+ implementation("org.springframework.boot:spring-boot-starter-actuator")
+
+ implementation group: 'org.javamoney', name: 'moneta', version: '1.3'
+ implementation group: 'com.jsoniter', name: 'jsoniter', version: '0.9.23'
+
+ // Lombok
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
+ testCompileOnly 'org.projectlombok:lombok'
+ testAnnotationProcessor 'org.projectlombok:lombok'
+
+ implementation(name:'TripPricer', ext:'jar')
+
+ implementation 'org.modelmapper:modelmapper:2.3.3'
+
+ // Junit
+ // testImplementation("junit:junit")
+ testImplementation 'org.springframework.boot:spring-boot-starter-web'
+ testImplementation('org.springframework.boot:spring-boot-starter-test:2.2.2.RELEASE') {
+ exclude group: 'junit'
+ exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
+ }
+
+ testImplementation("org.junit.platform:junit-platform-launcher:1.2.0")
+ testImplementation('org.junit.jupiter:junit-jupiter-api:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-engine:5.3.1')
+ testImplementation('org.junit.jupiter:junit-jupiter-params:5.3.1')
+
+ testCompileOnly 'junit:junit:4.12'
+// testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.3.1'
+
+ // Use JUnit Jupiter for testing
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
+
+
+
+}
+
+test {
+ useJUnitPlatform() {
+ includeEngines 'junit-jupiter'
+ }
+
+}
+
+
+// Jacoco
+jacoco {
+ toolVersion = "0.8.4"
+}
+
+jacocoTestReport {
+ reports {
+ xml.enabled true
+ csv.enabled false
+ html.destination file("${buildDir}/jacocoHtml")
+ }
+}
+
+test.finalizedBy jacocoTestReport
+check.dependsOn jacocoTestCoverageVerification
+
+jacocoTestCoverageVerification {
+ violationRules {
+ rule {
+ limit {
+ counter = 'LINE'
+ value = 'COVEREDRATIO'
+ minimum = 0.5
+ }
+ }
+ }
+}
diff --git a/tripDealsMicroservice/gradle/wrapper/gradle-wrapper.jar b/tripDealsMicroservice/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7454180
Binary files /dev/null and b/tripDealsMicroservice/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/tripDealsMicroservice/gradle/wrapper/gradle-wrapper.properties b/tripDealsMicroservice/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..84d1f85
--- /dev/null
+++ b/tripDealsMicroservice/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/tripDealsMicroservice/gradlew b/tripDealsMicroservice/gradlew
new file mode 100644
index 0000000..1b6c787
--- /dev/null
+++ b/tripDealsMicroservice/gradlew
@@ -0,0 +1,234 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# 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 ;; #(
+ MSYS* | 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" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/tripDealsMicroservice/gradlew.bat b/tripDealsMicroservice/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/tripDealsMicroservice/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@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 Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@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="-Xmx64m" "-Xms64m"
+
+@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 execute
+
+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 execute
+
+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
+
+: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 %*
+
+: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/tripDealsMicroservice/libs/TripPricer.jar b/tripDealsMicroservice/libs/TripPricer.jar
new file mode 100644
index 0000000..d07b668
Binary files /dev/null and b/tripDealsMicroservice/libs/TripPricer.jar differ
diff --git a/tripDealsMicroservice/settings.gradle b/tripDealsMicroservice/settings.gradle
new file mode 100644
index 0000000..76d816a
--- /dev/null
+++ b/tripDealsMicroservice/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'tripDealsMicroservice'
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/TripDealsMicroserviceApplication.java b/tripDealsMicroservice/src/main/java/tripDeals/TripDealsMicroserviceApplication.java
new file mode 100644
index 0000000..45943f2
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/TripDealsMicroserviceApplication.java
@@ -0,0 +1,30 @@
+package tripDeals;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * The Class TripDealsMicroserviceApplication.
+ */
+@ComponentScan("tripDeals")
+//@EnableAutoConfiguration
+//@EnableWebMvc
+//@Configuration
+@SpringBootApplication
+public class TripDealsMicroserviceApplication {
+
+ // ##############################################################
+
+ /**
+ * The main method.
+ *
+ * @param args the arguments
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(TripDealsMicroserviceApplication.class, args);
+ }
+
+ // ##############################################################
+
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/config/TripDealsModule.java b/tripDealsMicroservice/src/main/java/tripDeals/config/TripDealsModule.java
new file mode 100644
index 0000000..e411900
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/config/TripDealsModule.java
@@ -0,0 +1,51 @@
+package tripDeals.config;
+
+import java.util.Locale;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import tripPricer.TripPricer;
+
+/**
+ * The Class TripDealsModule.
+ */
+@Configuration
+public class TripDealsModule {
+
+
+
+ //###############################################################
+
+
+
+ /**
+ * Gets the locale.
+ *
+ * @return the locale
+ */
+ @Bean
+ public Locale getLocale() {
+ Locale.setDefault(Locale.US);
+ return Locale.getDefault();
+
+ }
+
+ //###############################################################
+
+
+ /**
+ * Gets the trip pricer.
+ *
+ * @return the trip pricer
+ */
+ @Bean
+ public TripPricer getTripPricer() {
+ return new TripPricer();
+ }
+
+
+ //###############################################################
+
+
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/controller/TripDealsController.java b/tripDealsMicroservice/src/main/java/tripDeals/controller/TripDealsController.java
new file mode 100644
index 0000000..e7b3cc5
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/controller/TripDealsController.java
@@ -0,0 +1,96 @@
+package tripDeals.controller;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import tripDeals.dto.ProviderDTO;
+import tripDeals.exception.UserNotFoundException;
+import tripDeals.service.ITripDealsService;
+
+
+/**
+ * The Class TripDealsController.
+ */
+@RestController
+@RequestMapping("/tripDeals")
+public class TripDealsController {
+
+
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(TripDealsController.class);
+
+
+ /** The trip deals service. */
+ private ITripDealsService tripDealsService;
+
+ //###############################################################
+
+
+ /**
+ * Instantiates a new trip deals controller.
+ *
+ * @param tripDealsService the trip deals service
+ */
+ public TripDealsController(
+ final ITripDealsService tripDealsService) {
+ super();
+ this.tripDealsService = tripDealsService;
+ }
+
+
+ //###############################################################
+
+ /**
+ * Gets the providers.
+ *
+ * @param apiKey the api key
+ * @param userId the user id
+ * @param adults the adults
+ * @param children the children
+ * @param nightsStay the nights stay
+ * @param rewardPoints the reward points
+ * @return the providers
+ */
+ @GetMapping("/providers/{apiKey}/{userId}/{adults}/{children}/{nightsStay}/{rewardPoints}")
+ public List getProviders(
+ @PathVariable final String apiKey,
+ @PathVariable final UUID userId,
+ @PathVariable final int adults,
+ @PathVariable final int children,
+ @PathVariable final int nightsStay,
+ @PathVariable final int rewardPoints) {
+
+ logger.debug("getProviders for user id: {}", userId.toString());
+
+ List providers = tripDealsService
+ .getProviders(
+ apiKey,
+ userId,
+ adults,
+ children,
+ nightsStay,
+ rewardPoints);
+
+ if (providers.isEmpty()) {
+ throw new UserNotFoundException("unable to get provider list");
+ }
+
+ logger.debug("provider list returned successfully");
+
+ return providers;
+ }
+
+
+ //###############################################################
+
+
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/dto/ProviderDTO.java b/tripDealsMicroservice/src/main/java/tripDeals/dto/ProviderDTO.java
new file mode 100644
index 0000000..9871460
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/dto/ProviderDTO.java
@@ -0,0 +1,29 @@
+package tripDeals.dto;
+
+import java.util.UUID;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * The Class ProviderDTO.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ProviderDTO {
+
+ /** The name. */
+ private String name;
+
+ /** The price. */
+ private double price;
+
+ /** The trip id. */
+ private UUID tripId;
+
+
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/exception/ErrorDetails.java b/tripDealsMicroservice/src/main/java/tripDeals/exception/ErrorDetails.java
new file mode 100644
index 0000000..7aafcf9
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/exception/ErrorDetails.java
@@ -0,0 +1,30 @@
+package tripDeals.exception;
+
+import java.time.LocalDateTime;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+
+/**
+ * The Class ErrorDetails.
+ */
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class ErrorDetails {
+
+ /** The timestamp. */
+ private LocalDateTime timestamp;
+
+ /** The message. */
+ private String message;
+
+ /** The details. */
+ private String details;
+
+
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/exception/GlobalExceptionHandler.java b/tripDealsMicroservice/src/main/java/tripDeals/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..454e6b7
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/exception/GlobalExceptionHandler.java
@@ -0,0 +1,127 @@
+package tripDeals.exception;
+
+import java.time.LocalDateTime;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+
+/**
+ * The Class GlobalExceptionHandler.
+ */
+@ControllerAdvice
+public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
+
+ /**
+ * GlobalExceptionHandler logger.
+ */
+ private Logger logger = LoggerFactory
+ .getLogger(GlobalExceptionHandler.class);
+
+
+ // ##############################################################
+
+ /**
+ * Handle not found.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(UserNotFoundException.class)
+ public ResponseEntity handleNotFound(
+ final UserNotFoundException ex,
+ final WebRequest request) {
+
+ logger.error("Request failed :", ex);
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.NOT_FOUND);
+ }
+
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Handle type mismatch.
+ *
+ * @param ex the ex
+ * @param request the request
+ * @return the response entity
+ */
+ @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+ public ResponseEntity handleTypeMismatch(
+ final MethodArgumentTypeMismatchException ex,
+ final WebRequest request) {
+
+ logger.error("Request - FAILED : Invalid UUID");
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getMessage(),
+ request.getDescription(false));
+
+ errorDetails.setMessage("Invalid UUID string");
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+
+ // ##############################################################
+
+
+ /**
+ * Handle missing path variable.
+ *
+ * @param ex the ex
+ * @param headers the headers
+ * @param status the status
+ * @param request the request
+ * @return the response entity
+ */
+ @Override
+ protected ResponseEntity handleMissingPathVariable(
+ final MissingPathVariableException ex,
+ final HttpHeaders headers, final HttpStatus status,
+ final WebRequest request) {
+ logger.error("Request - FAILED : Missing path variable: {}",
+ ex.getVariableName());
+
+ String error = ex.getVariableName() + " parameter is missing";
+
+ ErrorDetails errorDetails = new ErrorDetails(
+ LocalDateTime.now(),
+ ex.getLocalizedMessage(), error);
+
+ return new ResponseEntity<>(
+ errorDetails,
+ HttpStatus.BAD_REQUEST);
+ }
+
+
+ // ##############################################################
+
+
+
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/exception/UserNotFoundException.java b/tripDealsMicroservice/src/main/java/tripDeals/exception/UserNotFoundException.java
new file mode 100644
index 0000000..f4cf7af
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/exception/UserNotFoundException.java
@@ -0,0 +1,16 @@
+package tripDeals.exception;
+
+/**
+ * The Class UserNotFoundException.
+ */
+public class UserNotFoundException extends RuntimeException {
+
+ /**
+ * Instantiates a new user not found exception.
+ *
+ * @param message the message
+ */
+ public UserNotFoundException(final String message) {
+ super(message);
+ }
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/service/ITripDealsService.java b/tripDealsMicroservice/src/main/java/tripDeals/service/ITripDealsService.java
new file mode 100644
index 0000000..b8ca870
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/service/ITripDealsService.java
@@ -0,0 +1,26 @@
+package tripDeals.service;
+
+import java.util.List;
+import java.util.UUID;
+
+import tripDeals.dto.ProviderDTO;
+
+/**
+ * The Interface ITripDealsMicroService.
+ */
+public interface ITripDealsService {
+
+ /**
+ * Gets the providers.
+ *
+ * @param apiKey the api key
+ * @param userId the user id
+ * @param adults the adults
+ * @param children the children
+ * @param nightsStay the nights stay
+ * @param rewardPoints the reward points
+ * @return the providers
+ */
+ List getProviders(final String apiKey, final UUID userId, final int adults, final int children,
+ final int nightsStay, final int rewardPoints);
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/service/TripDealsService.java b/tripDealsMicroservice/src/main/java/tripDeals/service/TripDealsService.java
new file mode 100644
index 0000000..1261403
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/service/TripDealsService.java
@@ -0,0 +1,97 @@
+package tripDeals.service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import tripDeals.dto.ProviderDTO;
+import tripDeals.util.ProviderMapper;
+import tripPricer.TripPricer;
+
+/**
+ * The Class TripDealsMicroService.
+ */
+@Service
+public class TripDealsService implements ITripDealsService {
+
+ /** The logger. */
+ private Logger logger = LoggerFactory
+ .getLogger(TripDealsService.class);
+
+ /** The trip pricer. */
+ private final TripPricer tripPricer;
+
+ /** The provider mapper. */
+ private final ProviderMapper providerMapper;
+
+ // ##############################################################
+
+ /**
+ * Instantiates a new trip deals micro service.
+ *
+ * @param tripPricer the trip pricer
+ * @param providerMapper the provider mapper
+ */
+ @Autowired
+ public TripDealsService(
+ final TripPricer tripPricer,
+
+ final ProviderMapper providerMapper) {
+ this.tripPricer = tripPricer;
+ this.providerMapper = providerMapper;
+ }
+
+ // ##############################################################
+
+ /**
+ * Gets the providers.
+ *
+ * @param apiKey the api key
+ * @param userId the user id
+ * @param adults the adults
+ * @param children the children
+ * @param nightsStay the nights stay
+ * @param rewardPoints the reward points
+ * @return the providers
+ */
+ public List getProviders(
+ final String apiKey,
+ final UUID userId,
+ int adults,
+ int children,
+ int nightsStay,
+ int rewardPoints) {
+
+ logger.info("## getProviders() called");
+
+ List providerList = new ArrayList<>();
+ List providers = tripPricer
+ .getPrice(
+ apiKey,
+ userId,
+ adults,
+ children,
+ nightsStay,
+ rewardPoints);
+
+ providers.forEach(provider -> {
+
+ providerList.add(providerMapper
+ .toProviderDTO(provider));
+
+ });
+
+ logger.info("## providerList: {}"
+ + " returned", providerList);
+
+ return providerList;
+ }
+
+ // ##############################################################
+
+}
diff --git a/tripDealsMicroservice/src/main/java/tripDeals/util/ProviderMapper.java b/tripDealsMicroservice/src/main/java/tripDeals/util/ProviderMapper.java
new file mode 100644
index 0000000..f22eeef
--- /dev/null
+++ b/tripDealsMicroservice/src/main/java/tripDeals/util/ProviderMapper.java
@@ -0,0 +1,37 @@
+package tripDeals.util;
+
+import org.springframework.stereotype.Component;
+
+import tripDeals.dto.ProviderDTO;
+
+/**
+ * The Class ProviderMapper.
+ */
+@Component
+public class ProviderMapper {
+
+
+
+ // ##############################################################
+
+
+ /**
+ * To provider DTO.
+ *
+ * @param provider the provider
+ * @return the provider DTO
+ */
+ public ProviderDTO toProviderDTO(final tripPricer.Provider provider) {
+
+ return new ProviderDTO(
+ provider.name,
+ provider.price,
+ provider.tripId);
+ }
+
+
+
+ // ##############################################################
+
+
+}
diff --git a/tripDealsMicroservice/src/main/resources/application.properties b/tripDealsMicroservice/src/main/resources/application.properties
new file mode 100644
index 0000000..d458f53
--- /dev/null
+++ b/tripDealsMicroservice/src/main/resources/application.properties
@@ -0,0 +1,14 @@
+
+################### APPS CONFIG ####################
+spring.application.name=tripDealsMicroservice
+
+
+################### SERVER HTTP PORT ####################
+server.port=9093
+
+
+################### LOG CONFIG ##########################
+logging.level.tourGuide=DEBUG
+
+
+
diff --git a/tripDealsMicroservice/src/test/java/tripDeals/TripDealsMicroserviceApplicationTests.java b/tripDealsMicroservice/src/test/java/tripDeals/TripDealsMicroserviceApplicationTests.java
new file mode 100644
index 0000000..211e797
--- /dev/null
+++ b/tripDealsMicroservice/src/test/java/tripDeals/TripDealsMicroserviceApplicationTests.java
@@ -0,0 +1,13 @@
+package tripDeals;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class TripDealsMicroserviceApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/tripDealsMicroservice/src/test/java/tripDeals/integration/controller/TripDealsControllerIT.java b/tripDealsMicroservice/src/test/java/tripDeals/integration/controller/TripDealsControllerIT.java
new file mode 100644
index 0000000..8f07cf7
--- /dev/null
+++ b/tripDealsMicroservice/src/test/java/tripDeals/integration/controller/TripDealsControllerIT.java
@@ -0,0 +1,81 @@
+package tripDeals.integration.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+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.boot.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class TripDealsControllerIT {
+
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @LocalServerPort
+ private int port;
+ // URL
+
+ private final static String PROVIDERS_URL = "/tripDeals/providers/test-server-api-key/9732e7e3-943e-4169-97e1-6f171b0e86f0/999/999/999/999";
+
+
+ private final static String PROVIDERS_URL_INVALID_EMPTY_PARAM = "/tripDeals/providers/test-server-api-key/9732e7e3-943e-4169-97e1-6f171b0e86f0/999/ /999/999";
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getProviders) "
+ + " - Given an User Preferences,"
+ + " when GET getProviders,"
+ + " then return - response OK")
+ public void testGetProviders() throws Exception {
+
+ ResponseEntity response = restTemplate
+ .getForEntity("http://localhost:" + port +
+ PROVIDERS_URL, Object[].class);
+
+ assertThat(response.getBody().length).isGreaterThan(0);
+ assertEquals(HttpStatus.OK.value(), response.getStatusCodeValue());
+ }
+
+
+
+ //###############################################################
+
+
+
+ @DisplayName("Check (getProviders) empty provider list"
+ + " - Given an User Preferences, empty provider list "
+ + " when GET getProviders,"
+ + " then return - response NOT_FOUND")
+ @Test
+ public void getProvidersRequestEmptyList() throws Exception {
+
+
+ ResponseEntity response = restTemplate
+ .getForEntity("http://localhost:" + port +
+ PROVIDERS_URL_INVALID_EMPTY_PARAM, null);
+
+ assertEquals( HttpStatus.BAD_REQUEST.value(), response.getStatusCodeValue());
+ }
+
+
+
+ //###############################################################
+
+
+
+}
diff --git a/tripDealsMicroservice/src/test/java/tripDeals/unit/controller/TripDealsControllerTest.java b/tripDealsMicroservice/src/test/java/tripDeals/unit/controller/TripDealsControllerTest.java
new file mode 100644
index 0000000..29329f0
--- /dev/null
+++ b/tripDealsMicroservice/src/test/java/tripDeals/unit/controller/TripDealsControllerTest.java
@@ -0,0 +1,184 @@
+package tripDeals.unit.controller;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import tripDeals.controller.TripDealsController;
+import tripDeals.dto.ProviderDTO;
+import tripDeals.service.ITripDealsService;
+
+@DisplayName("UNIT TESTS - Controller - TripDeals - Microservice")
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(TripDealsController.class)
+public class TripDealsControllerTest {
+
+
+
+ @MockBean
+ private ITripDealsService tripDealsService;
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Autowired
+ private WebApplicationContext context;
+
+ private UUID userId;
+
+ private ProviderDTO providerDTO1;
+
+ private ProviderDTO providerDTO2;
+
+ private List providers;
+
+ // URL
+ private final static String PROVIDERS_URL = "/tripDeals/providers/test-server-api-key/9732e7e3-943e-4169-97e1-6f171b0e86f0/999/999/999/999";
+
+
+
+ //###############################################################
+
+
+
+ @BeforeEach
+ public void setUp() {
+
+ userId = UUID.fromString("9732e7e3-943e-4169-97e1-6f171b0e86f0");
+ providerDTO1 = new ProviderDTO("testName1", 100, UUID.randomUUID());
+ providerDTO2 = new ProviderDTO("testName2", 100, UUID.randomUUID());
+
+ providers = Arrays.asList(providerDTO1, providerDTO2);
+
+ mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
+ }
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getProviders) "
+ + " - Given an User Preferences,"
+ + " when GET getProviders,"
+ + " then return - response OK")
+ public void testGetProviders() throws Exception {
+
+ when(tripDealsService
+ .getProviders(
+ anyString(),
+ any(UUID.class),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyInt()))
+ .thenReturn(providers);
+
+ MvcResult result = mockMvc.perform(
+ MockMvcRequestBuilders
+ .get(PROVIDERS_URL)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertNotNull(content);
+ assertThat(content).contains("testName1");
+ assertThat(content).contains("testName2");
+ verify(tripDealsService).getProviders(anyString(), any(UUID.class), anyInt(), anyInt(), anyInt(), anyInt());
+ }
+
+
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getProviders) invalid path parameters"
+ + " - Given an User Preferences,"
+ + " when GET getProviders,"
+ + " then return - response NOT_FOUND")
+ public void testGetProvidersInvalidPathParameter() throws Exception {
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get("/tripDeals/providers/" +
+ "test-server-api-key/9732e7e3-943e-4169-97e1-6f171b0e86f0/999/999/999/999")
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isNotFound())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ }
+
+
+
+ //###############################################################
+
+
+ @DisplayName("Check (getProviders) empty provider list"
+ + " - Given an User Preferences, empty provider list "
+ + " when GET getProviders,"
+ + " then return - response NOT_FOUND")
+ @Test
+ public void getProvidersRequestEmptyList() throws Exception {
+
+ when(tripDealsService
+ .getProviders(
+ anyString(),
+ any(UUID.class),
+ anyInt(),
+ anyInt(),
+ anyInt(),
+ anyInt()))
+ .thenReturn(Collections.emptyList());
+
+ MvcResult result = mockMvc.perform(MockMvcRequestBuilders
+ .get(PROVIDERS_URL)
+ .contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isNotFound())
+ .andReturn();
+
+ String content = result.getResponse().getContentAsString();
+
+ assertThat(content).contains("unable to get provider list");
+ }
+
+
+
+ //###############################################################
+
+
+
+
+}
diff --git a/tripDealsMicroservice/src/test/java/tripDeals/unit/service/TripDealsServiceTest.java b/tripDealsMicroservice/src/test/java/tripDeals/unit/service/TripDealsServiceTest.java
new file mode 100644
index 0000000..44f6dea
--- /dev/null
+++ b/tripDealsMicroservice/src/test/java/tripDeals/unit/service/TripDealsServiceTest.java
@@ -0,0 +1,110 @@
+package tripDeals.unit.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.times;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InOrder;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import tripDeals.dto.ProviderDTO;
+import tripDeals.service.TripDealsService;
+import tripDeals.util.ProviderMapper;
+import tripPricer.Provider;
+import tripPricer.TripPricer;
+
+@DisplayName("Unit Test - Service - TripDeals Microservice")
+@ExtendWith(MockitoExtension.class)
+class TripDealsServiceTest {
+
+
+ @InjectMocks
+ private TripDealsService tripDealsService;
+
+ @Mock
+ private TripPricer tripPricer;
+
+ @Mock
+ private ProviderMapper providerMapper;
+
+ UUID testUserID, testTripID1, testTripID2;
+
+ Provider provider1, provider2;
+
+ ProviderDTO providerDTO1, providerDTO2;
+
+ //###############################################################
+
+
+
+ @Test
+ @DisplayName("Check (getProviders) "
+ + " - Given an User Preferences,"
+ + " when GET getProviders,"
+ + " then return - providers list for user as expected")
+ public void testGetProviders() {
+
+ // GIVEN
+ testUserID = UUID.randomUUID();
+ testTripID1 = UUID.randomUUID();
+ testTripID2 = UUID.randomUUID();
+
+ provider1 = new Provider(testTripID1, "testProvidername1", 500);
+ provider2 = new Provider(testTripID2, "testProvidername2", 800);
+
+ providerDTO1 = new ProviderDTO("testProvidername1", 500, testTripID1);
+ providerDTO2 = new ProviderDTO("testProvidername2", 800, testTripID2);
+
+ lenient().when(tripPricer
+ .getPrice("apiKey", testUserID, 999, 999, 999, 999))
+ .thenReturn(Arrays.asList(provider1, provider2));
+
+ lenient().when(providerMapper
+ .toProviderDTO(provider1))
+ .thenReturn(providerDTO1);
+
+ lenient().when(providerMapper
+ .toProviderDTO(provider2))
+ .thenReturn(providerDTO2);
+
+ // WHEN
+ List result = tripDealsService
+ .getProviders(
+ "apiKey",
+ testUserID,
+ 999,
+ 999,
+ 999,
+ 999);
+
+ // THEN
+ assertNotNull(result);
+ assertEquals(Arrays.asList(providerDTO1, providerDTO2), result);
+ assertEquals(2, result.size());
+
+ InOrder inOrder = inOrder(tripPricer, providerMapper);
+ inOrder.verify(tripPricer).getPrice("apiKey", testUserID, 999, 999, 999, 999);
+ inOrder.verify(providerMapper, times(2)).toProviderDTO(any(Provider.class));
+ }
+
+
+
+ //###############################################################
+
+
+
+
+
+}
diff --git a/tripDealsMicroservice/src/test/java/tripDeals/unit/util/ProviderMapperTest.java b/tripDealsMicroservice/src/test/java/tripDeals/unit/util/ProviderMapperTest.java
new file mode 100644
index 0000000..70b8674
--- /dev/null
+++ b/tripDealsMicroservice/src/test/java/tripDeals/unit/util/ProviderMapperTest.java
@@ -0,0 +1,53 @@
+package tripDeals.unit.util;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+import tripDeals.dto.ProviderDTO;
+import tripDeals.util.ProviderMapper;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest
+class ProviderMapperTest {
+
+
+ private ProviderMapper attractionMapper = new ProviderMapper();
+
+
+
+ // ##############################################################
+
+ @DisplayName("Check "
+ + " - Given DO,"
+ + " when ToProviderDTO,"
+ + " then return DO expected")
+ @Test
+ public void testToProviderDTO() {
+
+ UUID tripID = UUID.randomUUID();
+
+
+ tripPricer.Provider testProvider = new tripPricer.Provider(
+ tripID,
+ "testProvider",
+ 1500);
+
+
+ ProviderDTO result = attractionMapper.toProviderDTO(testProvider);
+
+ assertThat(result).isEqualToComparingFieldByField(testProvider);
+
+ }
+
+
+
+ // ##############################################################
+
+}