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 . +
+ +TOURGUIDE IMAGE
+ + 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)** + +TOURGUIDE IMAGE


+TOURGUIDE IMAGE


+TOURGUIDE IMAGE


+TOURGUIDE IMAGE


+TOURGUIDE IMAGE


+TOURGUIDE IMAGE


+ + +## 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
+
+ TOURGUIDE IMAGE


+ +
+ TOURGUIDE IMAGE


+ +
+ TOURGUIDE IMAGE



+ + + + +# Metrics +Test Performance on highVolume User Tracking & User Rewards Computations are performed & available. + +## HighVolume User Tracking Report - Graph +Performance report on User Location
+ +## HighVolume Rewards Calculation Report - Graph +Performance report on user rewards


+ + +## 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); + + } + + + + // ############################################################## + +}