diff --git a/.github/workflows/backend-pull-request-workflow.yml b/.github/workflows/backend-pull-request-workflow.yml new file mode 100644 index 000000000..07076f1d6 --- /dev/null +++ b/.github/workflows/backend-pull-request-workflow.yml @@ -0,0 +1,72 @@ +name: Co-KiriKiri Backend Pull Request Workflow + +on: + pull_request: + branches: + - develop-backend + paths: backend/kirikiri/** + +defaults: + run: + working-directory: backend/kirikiri + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Setup JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'corretto' + java-version: '17' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + shell: bash + + - name: Build with gradle + run: ./gradlew clean build + shell: bash + + - name: Register test results as comments in pull request + uses: EnricoMi/publish-unit-test-result-action@v1 + if: always() + with: + files: '**/build/test-results/test/TEST-*.xml' + + - name: Register a check comment in the failed code line when test failed + uses: mikepenz/action-junit-report@v3 + if: always() + with: + report_paths: '**/build/test-results/test/TEST-*.xml' + token: ${{ github.token }} + + - name: Register a comment about test coverage + id: jacoco + uses: madrapps/jacoco-report@v1.2 + with: + title: ๐Ÿช„ Test Coverage Report + paths: ${{ github.workspace }}/backend/kirikiri/build/reports/jacoco/test/jacocoTestReport.xml + token: ${{ github.token }} + min-coverage-overall: 90 + min-coverage-changed-files: 90 + + - name: Slack Notification + uses: 8398a7/action-slack@v3 + with: + status: custom + fields: workflow,job,commit,repo,ref,author,took + custom_payload: | + { + attachments: [{ + color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning', + text: '${{ job.status }}' === 'success' ? `โœ” [Backend] PULL REQUEST SUCCESS!\n ${{github.base_ref}} โฌ…๏ธ ${{github.head_ref}} \n${process.env.AS_JOB} (${process.env.AS_COMMIT}) by ${process.env.AS_AUTHOR}` + : `โŒ [Backend] PULL REQUEST FAIL!\n ${{github.base_ref}} โฌ…๏ธ ${{github.head_ref}} \n${process.env.AS_JOB} (${process.env.AS_COMMIT}) by ${process.env.AS_AUTHOR}`, + }] + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + if: always() diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..e3e9a25f7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "co-kirikiri-property"] + path = backend/kirikiri/src/main/resources/properties + url = https://github.com/co-kirikiri-backend/co-kirikiri-property + branch = main diff --git a/backend/kirikiri/.gitignore b/backend/kirikiri/.gitignore new file mode 100644 index 000000000..c2065bc26 --- /dev/null +++ b/backend/kirikiri/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/backend/kirikiri/build.gradle b/backend/kirikiri/build.gradle new file mode 100644 index 000000000..cf8b5b92d --- /dev/null +++ b/backend/kirikiri/build.gradle @@ -0,0 +1,210 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '3.1.1' + id 'io.spring.dependency-management' version '1.1.0' + id 'org.asciidoctor.jvm.convert' version '3.3.2' + id 'jacoco' +} + +group = 'co' +version = '0.0.1-SNAPSHOT' + +java { + sourceCompatibility = '17' +} + +configurations { + compileOnly { + extendsFrom annotationProcessor + } + asciidoctorExt +} + +repositories { + mavenCentral() +} + +ext { + set('snippetsDir', file("build/generated-snippets")) +} + +asciidoctor { + dependsOn test + configurations 'asciidoctorExt' + inputs.dir snippetsDir + + baseDirFollowsSourceFile() +} + +asciidoctor.doFirst { + delete file('src/main/resources/static/docs') +} + +tasks.register('copyDocument', Copy) { + dependsOn asciidoctor + from file("build/docs/asciidoc") + into file("src/main/resources/static/docs") +} + +build { + dependsOn copyDocument +} + +jacoco { + toolVersion = "0.8.10" +} + +jacocoTestReport { + reports { + html.required = true + xml.required = true + } + + // exclude QueryDSL QDomain Class + def QDomains = [] + + for (qPattern in '**/QA'..'**/QZ') { + QDomains.add(qPattern + '*') + } + + afterEvaluate { + classDirectories.setFrom( + files(classDirectories.files.collect { + fileTree(dir: it, excludes: [ + "co/kirikiri/persistence/QuerydslRepositorySupporter", + "co/kirikiri/domain/**", + "co/kirikiri/persistence/goalroom/dto/**", + "**/*Application*", + "**/*Config*", + "**/*Dto*", + "**/*Request*", + "**/*Response*", + "**/*Interceptor*", + "**/*Exception*" + ] + QDomains) + }) + ) + } + + // check test coverage after generating report + finalizedBy jacocoTestCoverageVerification +} + +jacocoTestCoverageVerification { + // exclude QueryDSL QDomain Class + def QDomains = [] + + for (qPattern in '*.QA'..'*.QZ') { + QDomains.add(qPattern + '*') + } + + violationRules { + rule { + enabled = true + + // check rules by class + element = 'CLASS' + + // line coverage at least 80% + limit { + counter = 'LINE' + value = 'COVEREDRATIO' + minimum = 0.80 + } + + excludes = [ + "co.kirikiri.persistence.QuerydslRepositorySupporter", + "co.kirikiri.domain.**.**", + "co.kirikiri.persistence.goalroom.dto.**", + "**.*Application*", + "**.*Config*", + "**.*Dto*", + "**.*Request*", + "**.*Response*", + "**.*Interceptor*", + "**.*Exception*" + ] + QDomains + } + } +} + +dependencies { + // spring data jpa + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + + // spring validation + implementation 'org.springframework.boot:spring-boot-starter-validation' + + // spring web + implementation 'org.springframework.boot:spring-boot-starter-web' + + // querydsl + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" + + // jwt + implementation 'io.jsonwebtoken:jjwt-api:0.11.2' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2', 'io.jsonwebtoken:jjwt-jackson:0.11.2' + + // aws s3 + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' + + // lombok + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + // database + runtimeOnly 'com.h2database:h2' + runtimeOnly 'com.mysql:mysql-connector-j' + + // restdocs + asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor' + + // slack log + implementation 'com.github.maricn:logback-slack-appender:1.3.0' + + // flyway + implementation 'org.flywaydb:flyway-mysql' + + // test + testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.rest-assured:rest-assured' +} + +def generated = 'build/generated' + +tasks.withType(JavaCompile).configureEach { + options.getGeneratedSourceOutputDirectory().set(file(generated)) +} + +sourceSets { + main.java.srcDirs += [generated] +} + +clean { + delete file(generated) +} + +tasks.named('test') { + outputs.dir snippetsDir + useJUnitPlatform() + finalizedBy jacocoTestReport +} + +tasks.named('asciidoctor') { + inputs.dir snippetsDir + dependsOn test +} + +bootJar { + dependsOn copyDocument + dependsOn asciidoctor + from("${asciidoctor.outputDir}/html5") { + into 'static/docs' + } + archivesBaseName = 'co-kirikiri' + archiveFileName = 'co-kirikiri.jar' +} diff --git a/backend/kirikiri/gradle/wrapper/gradle-wrapper.jar b/backend/kirikiri/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..c1962a79e Binary files /dev/null and b/backend/kirikiri/gradle/wrapper/gradle-wrapper.jar differ diff --git a/backend/kirikiri/gradle/wrapper/gradle-wrapper.properties b/backend/kirikiri/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..37aef8d3f --- /dev/null +++ b/backend/kirikiri/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/backend/kirikiri/gradlew b/backend/kirikiri/gradlew new file mode 100755 index 000000000..aeb74cbb4 --- /dev/null +++ b/backend/kirikiri/gradlew @@ -0,0 +1,245 @@ +#!/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/HEAD/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 + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# 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*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + 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 + + +# 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"' + +# 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 \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# 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/backend/kirikiri/gradlew.bat b/backend/kirikiri/gradlew.bat new file mode 100644 index 000000000..93e3f59f1 --- /dev/null +++ b/backend/kirikiri/gradlew.bat @@ -0,0 +1,92 @@ +@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=. +@rem This is normally unused +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% equ 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% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/backend/kirikiri/settings.gradle b/backend/kirikiri/settings.gradle new file mode 100644 index 000000000..90d3c0e6c --- /dev/null +++ b/backend/kirikiri/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'kirikiri' diff --git a/backend/kirikiri/src/docs/asciidoc/auth.adoc b/backend/kirikiri/src/docs/asciidoc/auth.adoc new file mode 100644 index 000000000..65f3ce4ad --- /dev/null +++ b/backend/kirikiri/src/docs/asciidoc/auth.adoc @@ -0,0 +1,60 @@ += Auth API +:toc-title: Auth API Docs +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 2 +:sectlinks: +ifndef::snippets[] +:snippets: ../../../build/generated-snippets +endif::[] +ifndef::page[] +:page: src/docs/asciidoc +endif::[] + +[[๋กœ๊ทธ์ธ-API]] +== *1. ๋กœ๊ทธ์ธ* + +=== *1-1* ์„ฑ๊ณต + +operation::auth-create-api-test/์ •์ƒ์ ์œผ๋กœ_๋กœ๊ทธ์ธ์—_์„ฑ๊ณตํ•œ๋‹ค[snippets='http-request,http-response,request-fields,response-fields'] + +=== *1-2* ์‹คํŒจ - ์•„์ด๋””์— ํ•ด๋‹นํ•˜๋Š” ํšŒ์›์ด ์—†์„๋•Œ + +operation::auth-create-api-test/๋กœ๊ทธ์ธ_์‹œ_์•„์ด๋””์—_ํ•ด๋‹นํ•˜๋Š”_ํšŒ์›์ด_์—†์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] + +=== *1-3* ์‹คํŒจ - ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์ง€ ์•Š์„ ๋•Œ + +operation::auth-create-api-test/๋กœ๊ทธ์ธ_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€_๋งž์ง€_์•Š์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] + +=== *1-4* ์‹คํŒจ - ์•„์ด๋””์— ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::auth-create-api-test/๋กœ๊ทธ์ธ_์‹œ_์•„์ด๋””์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] + +=== *1-5* ์‹คํŒจ - ๋น„๋ฐ€๋ฒˆํ˜ธ ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::auth-create-api-test/๋กœ๊ทธ์ธ_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] + +=== *1-6* ์‹คํŒจ - ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ชจ๋‘ ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::auth-create-api-test/๋กœ๊ทธ์ธ_์‹œ_์•„์ด๋””์™€_๋น„๋ฐ€๋ฒˆํ˜ธ_๋ชจ๋‘_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] + +[[ํ† ํฐ์žฌ๋ฐœํ–‰-API]] +== *2. ํ† ํฐ ์žฌ๋ฐœํ–‰* + +=== *2-1* ์„ฑ๊ณต + +operation::auth-create-api-test/ํ† ํฐ์„_์ •์ƒ์ ์œผ๋กœ_์žฌ๋ฐœํ–‰ํ•œ๋‹ค[snippets='http-request,http-response,request-fields,response-fields'] + +=== *2-2* ์‹คํŒจ - ํ† ํฐ ์žฌ๋ฐœํ–‰ ์‹œ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ๋นˆ๊ฐ’์ผ ๋•Œ + +operation::auth-create-api-test/ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_๋ฆฌํ”„๋ ˆ์‹œ_ํ† ํฐ์ด_๋นˆ๊ฐ’์ผ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] + +=== *2-3* ์‹คํŒจ - ํ† ํฐ ์žฌ๋ฐœํ–‰ ์‹œ ํ† ํฐ์ด ๋งŒ๋ฃŒ ๋์„ ๋•Œ + +operation::auth-create-api-test/ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_ํ† ํฐ์ด_๋งŒ๋ฃŒ_๋์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] + +=== *2-4* ์‹คํŒจ - ํ† ํฐ ์žฌ๋ฐœํ–‰ ์‹œ ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์„ ๋•Œ + +operation::auth-create-api-test/ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_ํ† ํฐ์ด_์œ ํšจํ•˜์ง€_์•Š์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค[snippets='http-request,http-response'] diff --git a/backend/kirikiri/src/docs/asciidoc/goalroom.adoc b/backend/kirikiri/src/docs/asciidoc/goalroom.adoc new file mode 100644 index 000000000..5859c216b --- /dev/null +++ b/backend/kirikiri/src/docs/asciidoc/goalroom.adoc @@ -0,0 +1,300 @@ += GoalRoom API +:toc-title: GoalRoom API Docs +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toc-title: GoalRoom API Docs +:toclevels: 2 +:sectlinks: +ifndef::snippets[] +:snippets: ../../../build/generated-snippets +endif::[] +ifndef::page[] +:page: src/docs/asciidoc +endif::[] + +[[๊ณจ๋ฃธ์ƒ์„ฑ-API]] +== *1. ๊ณจ๋ฃธ ์ƒ์„ฑ* + +=== *1-1* ์„ฑ๊ณต + +operation::goal-room-create-api-test/์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค[snippets='http-request,request-fields,request-headers,http-response,response-headers'] + +=== *1-2* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ์š”์ฒญ์— ๋นˆ๊ฐ’์ด ์žˆ์„ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์š”์ฒญ์—_๋นˆ๊ฐ’์ด_์žˆ์„_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-3* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๋กœ๋“œ๋งต์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋…ธ๋“œ์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต์—_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋…ธ๋“œ์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-4* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๋กœ๋“œ๋งต์˜ ๋…ธ๋“œ ํฌ๊ธฐ์™€ ์š”์ฒญ์˜ ๋…ธ๋“œ ํฌ๊ธฐ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต์˜_๋…ธ๋“œ_ํฌ๊ธฐ์™€_์š”์ฒญ์˜_๋…ธ๋“œ_ํฌ๊ธฐ๊ฐ€_์ผ์น˜ํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-5* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๋กœ๋“œ๋งต์ด ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต์ด_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-6* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ์‚ญ์ œ๋œ ๋กœ๋“œ๋งต์ธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์‚ญ์ œ๋œ_๋กœ๋“œ๋งต_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-7* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-8* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๊ณจ๋ฃธ ํˆฌ๋‘์˜ ์‹œ์ž‘ ๋‚ ์งœ๊ฐ€ ์˜ค๋Š˜๋ณด๋‹ค ์ „์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_ํˆฌ๋‘์˜_์‹œ์ž‘_๋‚ ์งœ๊ฐ€_์˜ค๋Š˜๋ณด๋‹ค_์ „์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-9* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๊ณจ๋ฃธ ํˆฌ๋‘์˜ ์‹œ์ž‘ ๋‚ ์งœ๋ณด๋‹ค ์ข…๋ฃŒ ๋‚ ์งœ๊ฐ€ ๋น ๋ฅธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_ํˆฌ๋‘์˜_์‹œ์ž‘_๋‚ ์งœ๋ณด๋‹ค_์ข…๋ฃŒ_๋‚ ์งœ๊ฐ€_๋น ๋ฅธ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-10* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์‹œ์ž‘ ๋‚ ์งœ๊ฐ€ ์˜ค๋Š˜๋ณด๋‹ค ์ „์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์‹œ์ž‘_๋‚ ์งœ๊ฐ€_์˜ค๋Š˜๋ณด๋‹ค_์ „์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-11* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์‹œ์ž‘ ๋‚ ์งœ๋ณด๋‹ค ์ข…๋ฃŒ ๋‚ ์งœ๊ฐ€ ๋น ๋ฅธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์‹œ์ž‘_๋‚ ์งœ๋ณด๋‹ค_์ข…๋ฃŒ_๋‚ ์งœ๊ฐ€_๋น ๋ฅธ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-12* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๊ฐ€ 0๋ณด๋‹ค ์ž‘์„ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์ธ์ฆ_ํšŸ์ˆ˜๊ฐ€_0๋ณด๋‹ค_์ž‘์„_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *1-13* ์‹คํŒจ - ๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ ๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๊ฐ€ ๊ธฐ๊ฐ„๋ณด๋‹ค ํด ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์ธ์ฆ_ํšŸ์ˆ˜๊ฐ€_๊ธฐ๊ฐ„๋ณด๋‹ค_ํด_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ๋‹จ์ผ์กฐํšŒ-๋น„๋กœ๊ทธ์ธ-API]] +== *2. ๊ณจ๋ฃธ ๋‹จ์ผ ์กฐํšŒ API (๋น„๋กœ๊ทธ์ธ)* + +=== *2-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค[snippets='http-request,path-parameters,http-response,response-fields'] + +=== *2-2* ์‹คํŒจ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์กฐํšŒ์‹œ_์•„์ด๋””๊ฐ€_์œ ํšจํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response,response-fields'] + +[[๊ณจ๋ฃธ๋‹จ์ผ์กฐํšŒ-๋กœ๊ทธ์ธ-API]] +== *3. ๊ณจ๋ฃธ ๋‹จ์ผ ์กฐํšŒ API (๋กœ๊ทธ์ธ)* + +=== *3-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response,response-fields'] + +=== *3-2* ์‹คํŒจ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์กฐํšŒ์‹œ_๊ณจ๋ฃธ_์•„์ด๋””๊ฐ€_์œ ํšจํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ์ฐธ๊ฐ€-API]] +== *4. ๊ณจ๋ฃธ ์ฐธ๊ฐ€ API* + +=== *4-1* ์„ฑ๊ณต + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ์„_์„ฑ๊ณตํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response'] + +=== *4-2* ์‹คํŒจ - ๊ณจ๋ฃธ์˜ ์•„์ด๋””๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ + +operation::goal-room-create-api-test/์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ๊ฐ€_์š”์ฒญ์€_์‹คํŒจํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *4-3* ์‹คํŒจ - ์ด๋ฏธ ํ•ด๋‹น ๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•จ + +operation::goal-room-create-api-test/์ด๋ฏธ_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ๊ฐ€_์š”์ฒญ์€_์‹คํŒจํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *4-4* ์‹คํŒจ - ๊ณจ๋ฃธ์˜ ์ œํ•œ ์ธ์›์ด ๊ฐ€๋“ ์ฐธ + +operation::goal-room-create-api-test/์ œํ•œ_์ธ์›์ด_๊ฐ€๋“_์ฐฌ_๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ๊ฐ€_์š”์ฒญ์€_์‹คํŒจํ•œ๋‹ค[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ์ฐธ๊ฐ€์ž์กฐํšŒ-API]] +== *5. ๊ณจ๋ฃธ ์ฐธ๊ฐ€์ž ์กฐํšŒ API* + +=== *5-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ_๋ฉค๋ฒ„๋ฅผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,query-parameters,http-response'] + +=== *5-2* ์‹คํŒจ - ๊ณจ๋ฃธ ๋ฉค๋ฒ„ ์กฐํšŒ ์‹œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ผ ๊ฒฝ์šฐ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_๋ฉค๋ฒ„_์กฐํšŒ_์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธํˆฌ๋‘์ถ”๊ฐ€-API]] +== *6. ๊ณจ๋ฃธ ํˆฌ๋‘ ์ถ”๊ฐ€ API* + +=== *6-1* ์„ฑ๊ณต + +operation::goal-room-create-api-test/์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค[snippets='http-request,request-fields,request-headers,path-parameters,http-response,response-headers'] + +=== *6-2* ์‹คํŒจ - ๊ณจ๋ฃธ ํˆฌ๋‘ ์ถ”๊ฐ€์‹œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *6-3* ์‹คํŒจ - ๊ณจ๋ฃธ ํˆฌ๋‘ ์ถ”๊ฐ€์‹œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *6-4* ์‹คํŒจ - ๊ณจ๋ฃธ ํˆฌ๋‘ ์ถ”๊ฐ€์‹œ ์ด๋ฏธ ์ข…๋ฃŒ๋œ ๊ณจ๋ฃธ์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์ด๋ฏธ_์ข…๋ฃŒ๋œ_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *6-5* ์‹คํŒจ - ๊ณจ๋ฃธ ํˆฌ๋‘ ์ถ”๊ฐ€์‹œ ๋ฆฌ๋”๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_๋ฆฌ๋”๊ฐ€_์•„๋‹Œ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *6-6* ์‹คํŒจ - ๊ณจ๋ฃธ ํˆฌ๋‘ ์ถ”๊ฐ€์‹œ ์ปจํ…์ธ ๊ฐ€ 250๊ธ€์ž๊ฐ€ ๋„˜์„ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์ปจํ…์ธ ๊ฐ€_250๊ธ€์ž๊ฐ€_๋„˜์„_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ์ธ์ฆํ”ผ๋“œ์ถ”๊ฐ€-API]] +== *7. ์ธ์ฆ ํ”ผ๋“œ ์ถ”๊ฐ€ API* + +=== *7-1* ์„ฑ๊ณต + +operation::goal-room-create-api-test/์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ์„_๋ณด๋‚ธ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response,response-headers'] + +=== *7-2* ์‹คํŒจ - ์ธ์ฆ ํ”ผ๋“œ ์š”์ฒญ ์‹œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์‚ฌ์šฉ์ž ์•„์ด๋””์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ์‹œ_๋ฉค๋ฒ„๊ฐ€_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *7-3* ์‹คํŒจ - ์ธ์ฆ ํ”ผ๋“œ ์š”์ฒญ ์‹œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ผ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ์‹œ_๋กœ๋“œ๋งต์ด_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response,response-fields'] + +=== *7-4* ์‹คํŒจ - ์ธ์ฆ ํ”ผ๋“œ ์š”์ฒญ ์‹œ ๋…ธ๋“œ ๊ธฐ๊ฐ„์„ ๋ฒ—์–ด๋‚œ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์‹œ_๋…ธ๋“œ_๊ธฐ๊ฐ„์—_ํ•ด๋‹นํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +[[์‚ฌ์šฉ์ž๊ณจ๋ฃธ๋‹จ์ผ์กฐํšŒ-API]] +== *8. ์‚ฌ์šฉ์ž ๊ณจ๋ฃธ ๋‹จ์ผ ์กฐํšŒ* + +=== *8-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,response-fields,http-response'] + +=== *8-2* ์‹คํŒจ - ์กฐํšŒ ์š”์ฒญ ์‹œ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ณจ๋ฃธ ์•„์ด๋””๊ฐ€ ๋“ค์–ด์˜ฌ ๋•Œ + +operation::goal-room-read-api-test/์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์กฐํšŒ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ_์•„์ด๋””๋ฅผ_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +[[์‚ฌ์šฉ์ž๊ณจ๋ฃธ๋ชฉ๋ก์กฐํšŒ-API]] +== *9. ์‚ฌ์šฉ์ž ๊ณจ๋ฃธ ๋ชฉ๋ก ์กฐํšŒ* + +=== *9-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/์‚ฌ์šฉ์ž_์ฐธ๊ฐ€_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค[snippets='http-request,request-headers,query-parameters,http-response,response-fields'] + +[[๊ณจ๋ฃธํˆฌ๋‘์ฒดํฌ-API]] +== *10. ๊ณจ๋ฃธ ํˆฌ๋‘ ์ฒดํฌ API* + +=== *10-1* ์„ฑ๊ณต - ์ฒดํฌ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ์—_๋Œ€ํ•ด_์ฒดํฌํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response,response-fields'] + +=== *10-2* ์„ฑ๊ณต - ์ฒดํฌ ํ•ด์ œ (๊ธฐ์กด์— ์ฒดํฌํ•œ ์ด๋ ฅ์ด ์žˆ๋Š” ๊ฒฝ์šฐ) + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_์ฒดํฌ_์ด๋ ฅ์ด_์žˆ์œผ๋ฉด_์ œ๊ฑฐํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response,response-fields'] + +=== *10-3* ์‹คํŒจ - ๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_๊ณจ๋ฃธ์ด_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *10-4* ์‹คํŒจ - ๊ณจ๋ฃธ์— ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_์‚ฌ์šฉ์ž๊ฐ€_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *10-5* ์‹คํŒจ - ํˆฌ๋‘๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_ํ•ด๋‹น_ํˆฌ๋‘๊ฐ€_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธํˆฌ๋‘๋ฆฌ์ŠคํŠธ์กฐํšŒ-API]] +== *11. ๊ณจ๋ฃธ ํˆฌ๋‘ ๋ฆฌ์ŠคํŠธ ์กฐํšŒ API* + +=== *11-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/๊ณจ๋ฃธ์˜_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response,response-fields'] + +=== *11-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š์€ ๊ณจ๋ฃธ์ผ ๊ฒฝ์šฐ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *11-3* ์‹คํŒจ - ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ๋‚˜๊ฐ€๊ธฐ-API]] +== *12. ๊ณจ๋ฃธ ๋‚˜๊ฐ€๊ธฐ API* + +=== *12-1* ์„ฑ๊ณต + +operation::goal-room-create-api-test/์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์„_๋‚˜๊ฐ„๋‹ค[snippets='http-request,request-headers,path-parameters,http-response'] + +=== *12-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์‹คํŒจํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *12-3* ์‹คํŒจ - ๊ณจ๋ฃธ์˜ ์•„์ด๋””๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์‹คํŒจํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *12-4* ์‹คํŒจ - ์ง„ํ–‰์ค‘์ธ ๊ณจ๋ฃธ์ธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์ง„ํ–‰์ค‘์ธ_๊ณจ๋ฃธ์ด๋ฉด_์‹คํŒจํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *12-5* ์‹คํŒจ - ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ๊ณจ๋ฃธ์ธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ด๋ฉด_์‹คํŒจํ•œ๋‹ค[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ๋…ธ๋“œ์กฐํšŒ-API]] +== *13. ๊ณจ๋ฃธ ๋…ธ๋“œ ๋ฆฌ์ŠคํŠธ ์กฐํšŒ API* + +=== *13-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/๊ณจ๋ฃธ์˜_๋…ธ๋“œ๋ฅผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,request-headers,path-parameters,http-response,response-fields'] + +=== *13-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š์€ ๊ณจ๋ฃธ์ผ ๊ฒฝ์šฐ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +=== *13-3* ์‹คํŒจ - ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ์ธ์ฆํ”ผ๋“œ์ „์ฒด์กฐํšŒ-API]] +== *14. ๊ณจ๋ฃธ ์ธ์ฆ ํ”ผ๋“œ ์ „์ฒด ์กฐํšŒ API* + +=== *14-1* ์„ฑ๊ณต + +operation::goal-room-read-api-test/๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒํ•œ๋‹ค[snippets='http-request,path-parameters,request-headers,http-response,response-fields'] + +=== *14-2* ์‹คํŒจ - ๊ณจ๋ฃธ ์ธ์ฆ ํ”ผ๋“œ ์ „์ฒด ์กฐํšŒ ์‹œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ธ ๊ฒฝ์šฐ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_์ธ์ฆํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *14-3* ์‹คํŒจ - ๊ณจ๋ฃธ ์ธ์ฆ ํ”ผ๋“œ ์ „์ฒด ์กฐํšŒ ์‹œ ํ•ด๋‹น ๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ + +operation::goal-room-read-api-test/๊ณจ๋ฃธ_์ธ์ฆํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‹œ_๊ณจ๋ฃธ์—_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ_๋ฐœ์ƒ[snippets='http-request,http-response'] + +[[๊ณจ๋ฃธ์‹œ์ž‘-API]] +== *15. ๊ณจ๋ฃธ ์‹œ์ž‘ API* + +=== *15-1* ์„ฑ๊ณต + +operation::goal-room-create-api-test/๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค[snippets='http-request,path-parameters,http-response'] + +=== *15-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์‚ฌ์šฉ์ž์ธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_์‚ฌ์šฉ์ž๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *15-3* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *15-4* ์‹คํŒจ - ์š”์ฒญ์„ ๋ณด๋‚ธ ์‚ฌ์šฉ์ž๊ฐ€ ๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•˜๋Š”_์‚ฌ์šฉ์ž๊ฐ€_๊ณจ๋ฃธ์˜_๋ฆฌ๋”๊ฐ€_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *15-5* ์‹คํŒจ - ๊ณจ๋ฃธ์˜ ์‹œ์ž‘ ๋‚ ์งœ๊ฐ€ ๋ฏธ๋ž˜์ธ ๊ฒฝ์šฐ + +operation::goal-room-create-api-test/๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๊ฐ€_๋ฏธ๋ž˜๋ผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] diff --git a/backend/kirikiri/src/docs/asciidoc/index.adoc b/backend/kirikiri/src/docs/asciidoc/index.adoc new file mode 100644 index 000000000..d8a0ccfaf --- /dev/null +++ b/backend/kirikiri/src/docs/asciidoc/index.adoc @@ -0,0 +1,32 @@ += Co-KiriKiri API Docs +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toc-title: Co-Kirikiri API Docs +:toclevels: 2 +:sectlinks: +ifndef::snippets[] +:snippets: ../../../build/generated-snippets +endif::[] +ifndef::page[] +:page: src/docs/asciidoc +endif::[] + +include::overview.adoc[Overview] + +== *ํšŒ์› API* + +* link:member.html[Member API] + +== *์ธ์ฆ/์ธ๊ฐ€ API* + +* link:auth.html[Auth API] + +== *๋กœ๋“œ๋งต API* + +* link:roadmap.html[Roadmap API] + +== *๊ณจ๋ฃธ API* + +* link:goalroom.html[GoalRoom API] diff --git a/backend/kirikiri/src/docs/asciidoc/member.adoc b/backend/kirikiri/src/docs/asciidoc/member.adoc new file mode 100644 index 000000000..ddb45009e --- /dev/null +++ b/backend/kirikiri/src/docs/asciidoc/member.adoc @@ -0,0 +1,87 @@ += Member API +:toc-title: Member API Docs +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 2 +:sectlinks: +ifndef::snippets[] +:snippets: ../../../build/generated-snippets +endif::[] +ifndef::page[] +:page: src/docs/asciidoc +endif::[] + +[[ํšŒ์›๊ฐ€์ž…-API]] +== *1. ํšŒ์› ๊ฐ€์ž…* + +=== *1-1* ์„ฑ๊ณต + +operation::member-create-api-test/์ •์ƒ์ ์œผ๋กœ_ํšŒ์›๊ฐ€์ž…์—_์„ฑ๊ณตํ•œ๋‹ค[snippets='http-request,http-response,request-fields,response-headers'] + +=== *1-2* ์‹คํŒจ - ์•„์ด๋””๊ฐ€ ํ˜•์‹์— ๋งž์ง€ ์•Š์„ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_์•„์ด๋””๊ฐ€_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ[snippets='http-request,http-response'] + +=== *1-3* ์‹คํŒจ - ๋น„๋ฐ€๋ฒˆํ˜ธ ํ˜•์‹์— ๋งž์ง€ ์•Š์„ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ[snippets='http-request,http-response'] + +=== *1-4* ์‹คํŒจ - ๋‹‰๋„ค์ž„์ด ํ˜•์‹์— ๋งž์ง€ ์•Š์„ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_๋‹‰๋„ค์ž„์ด_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ[snippets='http-request,http-response'] + +=== *1-5* ์‹คํŒจ - ์ „ํ™”๋ฒˆํ˜ธ ํ˜•์‹์— ๋งž์ง€ ์•Š์„ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_์ „ํ™”๋ฒˆํ˜ธ_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ[snippets='http-request,http-response'] + +=== *1-6* ์‹คํŒจ - ์ค‘๋ณต๋œ ์•„์ด๋””์ผ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_์ค‘๋ณต๋œ_๋‹‰๋„ค์ž„์ผ_๋•Œ[snippets='http-request,http-response'] + +=== *1-7* ์‹คํŒจ - ์ค‘๋ณต๋œ ๋‹‰๋„ค์ž„์ผ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_์ค‘๋ณต๋œ_์•„์ด๋””์ผ_๋•Œ[snippets='http-request,http-response'] + +=== *1-8* ์‹คํŒจ - ํšŒ์›๊ฐ€์ž… ์‹œ ์•„์ด๋””์— ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_์•„์ด๋””์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ[snippets='http-request,http-response'] + +=== *1-9* ์‹คํŒจ - ํšŒ์›๊ฐ€์ž… ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ์— ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ[snippets='http-request,http-response'] + +=== *1-10* ์‹คํŒจ - ํšŒ์›๊ฐ€์ž… ํ•  ๋•Œ ๋‹‰๋„ค์ž„์— ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_๋‹‰๋„ค์ž„์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ[snippets='http-request,http-response'] + +=== *1-11* ์‹คํŒจ - ํšŒ์›๊ฐ€์ž… ์‹œ ์ „ํ™”๋ฒˆํ˜ธ์— ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_์ „ํ™”๋ฒˆํ˜ธ์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ[snippets='http-request,http-response'] + +=== *1-12* ์‹คํŒจ - ํšŒ์›๊ฐ€์ž… ์‹œ ์•„์ด๋”” ๋น„๋ฐ€๋ฒˆํ˜ธ ๋‹‰๋„ค์ž„ ์ „ํ™”๋ฒˆํ˜ธ ํ•„๋“œ์— ๋นˆ๊ฐ’์ด ๋“ค์–ด์˜ฌ ๋•Œ + +operation::member-create-api-test/ํšŒ์›๊ฐ€์ž…_์‹œ_์•„์ด๋””_๋น„๋ฐ€๋ฒˆํ˜ธ_๋‹‰๋„ค์ž„_์ „ํ™”๋ฒˆํ˜ธ_ํ•„๋“œ์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ[snippets='http-request,http-response'] + +[[์‚ฌ์šฉ์ž์ •๋ณด์กฐํšŒ-API]] +== *2. ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ* + +=== *2-1* ์„ฑ๊ณต + +operation::member-read-api-test/๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,http-response,response-fields'] + +=== *2-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š์€ ํšŒ์›์ผ ๋•Œ + +operation::member-read-api-test/๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ• ๋•Œ_์กด์žฌํ•˜์ง€_์•Š์€_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ[snippets='http-request,http-response'] + +[[ํŠน์ •์‚ฌ์šฉ์ž์ •๋ณด์กฐํšŒ-API]] +== *3. ํŠน์ • ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ* + +=== *3-1* ์„ฑ๊ณต + +operation::member-read-api-test/ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,http-response,response-fields'] + +=== *3-2* ์‹คํŒจ - ์กฐํšŒํ•  ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์€ ํšŒ์›์ผ ๋•Œ + +operation::member-read-api-test/ํŠน์ •_์‚ฌ์šฉ์ž_์ •๋ณด_์กฐํšŒ์‹œ_์กฐํšŒํ• _์‚ฌ์šฉ์ž๊ฐ€_์—†๋Š”_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ[snippets='http-request,http-response'] diff --git a/backend/kirikiri/src/docs/asciidoc/overview.adoc b/backend/kirikiri/src/docs/asciidoc/overview.adoc new file mode 100644 index 000000000..c78b3d840 --- /dev/null +++ b/backend/kirikiri/src/docs/asciidoc/overview.adoc @@ -0,0 +1,58 @@ +[[Overview]] += *Overview* + +== [[overview-error-message]] + +=== *ErrorMessage* + +|=== +| ErrorMessage | Description + +| ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +| ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์ง€ ์•Š์„ ๋•Œ + +| ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋‹‰๋„ค์ž„์ž…๋‹ˆ๋‹ค. +| ์ค‘๋ณต๋œ ๋‹‰๋„ค์ž„์ผ ๋•Œ + +| ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค. +| ์ค‘๋ณต๋œ ์•„์ด๋””์ผ ๋•Œ + +| ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. +| ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์„ ๋•Œ + +| ํ† ํฐ์ด ๋งŒ๋ฃŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. +| ํ† ํฐ์ด ๋งŒ๋ฃŒ ๋˜์—ˆ์„ ๋•Œ + +|=== + +[[overview-page-response]] +=== *Page Response Data* + +|=== +| Field Name | Type | Description + +| currentPage +| int +| ํ˜„์žฌ ํŽ˜์ด์ง€ ๊ฐ’ + +| totalPage +| int +| ์ด ํŽ˜์ด์ง€ ๊ฐ’ + +| data +| Object +| ๋ฐ์ดํ„ฐ ๋ฆฌ์ŠคํŠธ + +|=== + +[[overview-error-response]] +=== *Error Response Data* + +|=== +| Field Name | Type | Description + +| message +| String +| ์—๋Ÿฌ ๋ฉ”์‹œ์ง€ + +|=== diff --git a/backend/kirikiri/src/docs/asciidoc/roadmap.adoc b/backend/kirikiri/src/docs/asciidoc/roadmap.adoc new file mode 100644 index 000000000..32b684800 --- /dev/null +++ b/backend/kirikiri/src/docs/asciidoc/roadmap.adoc @@ -0,0 +1,221 @@ += Roadmap API +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toc-title: Roadmap API Docs +:toclevels: 2 +:sectlinks: +ifndef::snippets[] +:snippets: ../../../build/generated-snippets +endif::[] +ifndef::page[] +:page: src/docs/asciidoc +endif::[] + + +[[๋กœ๋“œ๋งต์ƒ์„ฑ-API]] +== *1. ๋กœ๋“œ๋งต ์ƒ์„ฑ API* + +=== *1-1* ์„ฑ๊ณต + +operation::roadmap-create-api-test/์ •์ƒ์ ์œผ๋กœ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค[snippets='http-request,request-headers,request-part-jsonData-fields,http-response,response-headers'] + +=== *1-2* ์‹คํŒจ - ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๋ฅผ_์ž…๋ ฅํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-3* ์‹คํŒจ - ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ž…๋ ฅํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๋ฅผ_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-4* ์‹คํŒจ - ๋กœ๋“œ๋งต ์ œ๋ชฉ์˜ ๊ธธ์ด๊ฐ€ 40๋ณด๋‹ค ํผ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_40๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-5* ์‹คํŒจ - ๋กœ๋“œ๋งต ์ œ๋ชฉ์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ œ๋ชฉ์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-6* ์‹คํŒจ - ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€์˜ ๊ธธ์ด๊ฐ€ 150๋ณด๋‹ค ํผ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€์˜_๊ธธ์ด๊ฐ€_150๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-7* ์‹คํŒจ - ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-8* ์‹คํŒจ - ๋กœ๋“œ๋งต ๋ณธ๋ฌธ์˜ ๊ธธ์ด๊ฐ€ 2000๋ณด๋‹ค ํผ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋ณธ๋ฌธ์˜_๊ธธ์ด๊ฐ€_2000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-9* ์‹คํŒจ - ๋กœ๋“œ๋งต ๋‚œ์ด๋„๋ฅผ ์ž…๋ ฅํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋‚œ์ด๋„๋ฅผ_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-10* ์‹คํŒจ - ๋กœ๋“œ๋งต ์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„์ด 0๋ณด๋‹ค ์ž‘๊ฑฐ๋‚˜ 1000๋ณด๋‹ค ํผ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ถ”์ฒœ_์†Œ์š”๊ธฐ๊ฐ„์ด_0๋ณด๋‹ค_์ž‘๊ฑฐ๋‚˜_1000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-11* ์‹คํŒจ - ๋กœ๋“œ๋งต ์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ถ”์ฒœ_์†Œ์š”๊ธฐ๊ฐ„์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-12* ์‹คํŒจ - ๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ์˜ ๊ธธ์ด๊ฐ€ 40๋ณด๋‹ค ํผ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_40๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-13* ์‹คํŒจ - ๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์ œ๋ชฉ์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-14* ์‹คํŒจ - ๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…์˜ ๊ธธ์ด๊ฐ€ 2000๋ณด๋‹ค ํผ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์„ค๋ช…์˜_๊ธธ์ด๊ฐ€_2000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-15* ์‹คํŒจ - ๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์„ค๋ช…์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-16* ์‹คํŒจ - ๋กœ๋“œ๋งต ํƒœ๊ทธ์˜ ์ด๋ฆ„์— ์ค‘๋ณต์ด ์žˆ์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์ค‘๋ณต๋œ_ํƒœ๊ทธ_์ด๋ฆ„์ด_์žˆ์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-17* ์‹คํŒจ - ๋กœ๋“œ๋งต ํƒœ๊ทธ์˜ ๊ฐœ์ˆ˜๊ฐ€ 5๊ฐœ ์ดˆ๊ณผ์ž„ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_ํƒœ๊ทธ_๊ฐœ์ˆ˜๊ฐ€_5๊ฐœ_์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-18* ์‹คํŒจ - ๋กœ๋“œ๋งต ํƒœ๊ทธ์˜ ์ด๋ฆ„์ด 1์ž ๋ฏธ๋งŒ 10์ž ์ดˆ๊ณผ์ž„ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_ํƒœ๊ทธ_์ด๋ฆ„์ด_1๋ฏธ๋งŒ_10์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *1-19* ์‹คํŒจ - ๋กœ๋“œ๋งต ์ƒ์„ฑ ์‹œ ํšŒ์›์ด ์กด์žฌํ•˜์ง€ ์•Š์Œ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +[[๋กœ๋“œ๋งต๋ชฉ๋ก์กฐํšŒ-API]] +== *2. ๋กœ๋“œ๋งต ๋ชฉ๋ก ์กฐํšŒ API* + +=== *2-1* ์„ฑ๊ณต + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์กฐ๊ฑด์—_๋”ฐ๋ผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,query-parameters,http-response,response-fields'] + +=== *2-2* ์‹คํŒจ - ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๋ฅผ_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *2-3* ์‹คํŒจ - ์‚ฌ์ด์ฆˆ ๊ฐ’์„ ์ „์†กํ•˜์ง€ ์•Š์Œ + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ์‹œ_์‚ฌ์ด์ฆˆ_๊ฐ’์„_์ „์†กํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +[[๋กœ๋“œ๋งต์นดํ…Œ๊ณ ๋ฆฌ๋ชฉ๋ก์กฐํšŒ-API]] +== *3. ๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ๋ชฉ๋ก ์กฐํšŒ API* + +=== *3-1* ์„ฑ๊ณต + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค[snippets='http-request,http-response,response-fields'] + +[[๋กœ๋“œ๋งต๋‹จ์ผ์กฐํšŒ-API]] +== *4. ๋กœ๋“œ๋งต ๋‹จ์ผ ์กฐํšŒ API* + +=== *4-1* ์„ฑ๊ณต + +operation::roadmap-read-api-test/๋‹จ์ผ_๋กœ๋“œ๋งต_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,path-parameters,http-response,response-fields'] + +=== *4-2* ์‹คํŒจ - ๋กœ๋“œ๋งต ์•„์ด๋””๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ + +operation::roadmap-read-api-test/์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_์š”์ฒญ_์‹œ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค[snippets='http-request,http-response'] + +[[๋กœ๋“œ๋งต๊ฒ€์ƒ‰-API]] +== *5. ๋กœ๋“œ๋งต ๊ฒ€์ƒ‰ + ํ•„ํ„ฐ๋ง API* + +=== *5-1* ์„ฑ๊ณต + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต์„_์กฐ๊ฑด๋ณ„๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค[snippets='http-request,query-parameters,http-response,response-fields'] + +=== *5-2* ์‹คํŒจ + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต_๊ฒ€์ƒ‰์‹œ_์‚ฌ์ด์ฆˆ_๊ฐ’์„_์ „์†กํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +[[๋กœ๋“œ๋งต๋ฆฌ๋ทฐ์ƒ์„ฑ-API]] +== *6. ๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ์ƒ์„ฑ API* + +=== *6-1* ์„ฑ๊ณต + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต์˜_๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค[snippets='http-request,path-parameters,request-headers,request-fields,http-response'] + +=== *6-2* ์‹คํŒจ - ์œ ํšจํ•˜์ง€ ์•Š์€ ๋กœ๋“œ๋งต ์•„์ด๋””์ธ ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *6-3* ์‹คํŒจ - ๋ณ„์ ์ด null์ธ ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋ณ„์ ์ด_null์ด๋ผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *6-4* ์‹คํŒจ - ๋ฆฌ๋ทฐ ๋‚ด์šฉ์ด 1000์ž๊ฐ€ ๋„˜๋Š” ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋‚ด์šฉ์ด_1000์ž๊ฐ€_๋„˜์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *6-5* ์‹คํŒจ - ๋ฆฌ๋ทฐ ๋ณ„์ ์ด 0~5 ์‚ฌ์ด์˜ 0.5์”ฉ ์ฆ๊ฐ€ํ•˜๋Š” ๊ฐ’์ด ์•„๋‹Œ ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋ณ„์ ์ด_์ž˜๋ชป๋œ_๊ฐ’์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *6-6* ์‹คํŒจ - ํ•ด๋‹น ๋กœ๋“œ๋งต์˜ ์ƒ์„ฑ์ž๊ฐ€ ๋ฆฌ๋ทฐ๋ฅผ ๋‹ฌ๋ ค๊ณ  ํ•˜๋Š” ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ƒ์„ฑ์ž๊ฐ€_๋ฆฌ๋ทฐ๋ฅผ_๋‹ฌ๋ ค๊ณ _ํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *6-7* ์‹คํŒจ - ๋กœ๋“œ๋งต์„ ์™„๋ฃŒํ•œ ๊ณจ๋ฃธ์ด ์—†๋Š” ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์ด_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +=== *6-8* ์‹คํŒจ - ํ•ด๋‹น ๋กœ๋“œ๋งต์— ์ด๋ฏธ ๋ฆฌ๋ทฐ๋ฅผ ๋‹จ ์ ์ด ์žˆ๋Š” ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์ด๋ฏธ_๋ฆฌ๋ทฐ๋ฅผ_๋‹จ์ ์ด_์žˆ์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response'] + +[[์‚ฌ์šฉ์ž๋กœ๋“œ๋งต์กฐํšŒ-API]] +== *7. ์‚ฌ์šฉ์ž ๋กœ๋“œ๋งต ์กฐํšŒ API* + +=== *7-1* ์„ฑ๊ณต + +operation::roadmap-read-api-test/์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค[snippets='http-request,request-headers,query-parameters,http-response,response-fields'] + +=== *7-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ธ ๊ฒฝ์šฐ + +operation::roadmap-read-api-test/์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ• _๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response,response-fields'] + +[[๋กœ๋“œ๋งต์˜๊ณจ๋ฃธ๋ชฉ๋ก์กฐํšŒ-API]] +== *8. ๋กœ๋“œ๋งต์˜ ๊ณจ๋ฃธ ๋ชฉ๋ก ์กฐํšŒ API* + +=== *8-1* ์„ฑ๊ณต + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐ๊ฑด์—_๋”ฐ๋ผ_์กฐํšŒํ•œ๋‹ค[snippets='http-request,query-parameters,http-response,response-fields'] + +=== *8-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ธ ๊ฒฝ์šฐ + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐ๊ฑด์—_๋”ฐ๋ผ_์กฐํšŒํ• _๋•Œ_๋กœ๋“œ๋งต์ด_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ[snippets='http-request,query-parameters,http-response,response-fields'] + +[[๋กœ๋“œ๋งต๋ฆฌ๋ทฐ์กฐํšŒ-API]] +== *9. ๋กœ๋“œ๋งต์˜ ๋ฆฌ๋ทฐ ๋ชฉ๋ก ์กฐํšŒ API* + +=== *9-1* ์„ฑ๊ณต + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต์˜_๋ฆฌ๋ทฐ๋“ค์„_์กฐํšŒํ•œ๋‹ค[snippets='http-request,http-response,path-parameters,query-parameters,response-fields'] + +=== *9-1* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ธ ๊ฒฝ์šฐ + +operation::roadmap-read-api-test/๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต_์•„์ด๋””์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค[snippets='http-request,http-response,path-parameters,query-parameters,response-fields'] + +[[๋กœ๋“œ๋งต์‚ญ์ œ-API]] +== *10. ๋กœ๋“œ๋งต ์‚ญ์ œ API* + +=== *10-1* ์„ฑ๊ณต + +operation::roadmap-create-api-test/์ •์ƒ์ ์œผ๋กœ_๋กœ๋“œ๋งต์„_์‚ญ์ œํ•œ๋‹ค[snippets='http-request,path-parameters,http-response'] + +=== *10-2* ์‹คํŒจ - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ธ ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต์ธ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response,response-fields'] + +=== *10-3* ์‹คํŒจ - ์ž์‹ ์ด ์ƒ์„ฑํ•œ ๋กœ๋“œ๋งต์ด ์•„๋‹Œ ๊ฒฝ์šฐ + +operation::roadmap-create-api-test/๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_์ž์‹ ์ด_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์ด_์•„๋‹Œ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค[snippets='http-request,http-response,response-fields'] diff --git a/backend/kirikiri/src/main/java/co/kirikiri/KirikiriApplication.java b/backend/kirikiri/src/main/java/co/kirikiri/KirikiriApplication.java new file mode 100644 index 000000000..e37a05aae --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/KirikiriApplication.java @@ -0,0 +1,12 @@ +package co.kirikiri; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class KirikiriApplication { + + public static void main(String[] args) { + SpringApplication.run(KirikiriApplication.class, args); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/config/AWSConfig.java b/backend/kirikiri/src/main/java/co/kirikiri/common/config/AWSConfig.java new file mode 100644 index 000000000..b084ee0eb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/config/AWSConfig.java @@ -0,0 +1,25 @@ +package co.kirikiri.common.config; + +import com.amazonaws.regions.Regions; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class AWSConfig { + + private final Regions region; + + public AWSConfig(@Value("${cloud.aws.region.static}") final String region) { + this.region = Regions.fromName(region); + } + + @Bean + public AmazonS3 amazonS3() { + return AmazonS3ClientBuilder.standard() + .withRegion(region) + .build(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/config/AsyncConfig.java b/backend/kirikiri/src/main/java/co/kirikiri/common/config/AsyncConfig.java new file mode 100644 index 000000000..e6f2a6a8c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/config/AsyncConfig.java @@ -0,0 +1,10 @@ +package co.kirikiri.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; + +@Configuration +@EnableAsync +public class AsyncConfig { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/config/JpaConfig.java b/backend/kirikiri/src/main/java/co/kirikiri/common/config/JpaConfig.java new file mode 100644 index 000000000..18158e4fb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/config/JpaConfig.java @@ -0,0 +1,10 @@ +package co.kirikiri.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +@Configuration +@EnableJpaAuditing +public class JpaConfig { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/config/SchedulerConfig.java b/backend/kirikiri/src/main/java/co/kirikiri/common/config/SchedulerConfig.java new file mode 100644 index 000000000..bc1c120a2 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/config/SchedulerConfig.java @@ -0,0 +1,10 @@ +package co.kirikiri.common.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class SchedulerConfig { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/config/WebConfig.java b/backend/kirikiri/src/main/java/co/kirikiri/common/config/WebConfig.java new file mode 100644 index 000000000..4b19bc9a9 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/config/WebConfig.java @@ -0,0 +1,31 @@ +package co.kirikiri.common.config; + +import co.kirikiri.common.interceptor.AuthInterceptor; +import co.kirikiri.common.resolver.MemberIdentifierArgumentResolver; +import co.kirikiri.common.resolver.RoadmapSaveArgumentResolver; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@RequiredArgsConstructor +public class WebConfig implements WebMvcConfigurer { + + private final AuthInterceptor authInterceptor; + private final MemberIdentifierArgumentResolver memberIdentifierArgumentResolver; + private final RoadmapSaveArgumentResolver roadmapSaveArgumentResolver; + + @Override + public void addInterceptors(final InterceptorRegistry interceptorRegistry) { + interceptorRegistry.addInterceptor(authInterceptor); + } + + @Override + public void addArgumentResolvers(final List argumentResolvers) { + argumentResolvers.add(roadmapSaveArgumentResolver); + argumentResolvers.add(memberIdentifierArgumentResolver); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/interceptor/AuthInterceptor.java b/backend/kirikiri/src/main/java/co/kirikiri/common/interceptor/AuthInterceptor.java new file mode 100644 index 000000000..a580a4897 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/interceptor/AuthInterceptor.java @@ -0,0 +1,47 @@ +package co.kirikiri.common.interceptor; + +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.service.AuthService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +@Component +@RequiredArgsConstructor +public class AuthInterceptor implements HandlerInterceptor { + + private static final String BEARER = "Bearer "; + + private final AuthService authService; + + @Override + public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, + final Object handler) { + if (!(handler instanceof final HandlerMethod handlerMethod)) { + return true; + } + if (handlerMethod.hasMethodAnnotation(Authenticated.class)) { + final String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION); + checkHeader(authorizationHeader); + final String token = authorizationHeader.substring(BEARER.length()); + checkTokenCertify(token); + } + return true; + } + + private void checkHeader(final String authorizationHeader) { + if (authorizationHeader == null || !authorizationHeader.startsWith(BEARER)) { + throw new AuthenticationException("์ธ์ฆ ํ—ค๋”๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + private void checkTokenCertify(final String token) { + if (!authService.isCertified(token)) { + throw new AuthenticationException("ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/interceptor/Authenticated.java b/backend/kirikiri/src/main/java/co/kirikiri/common/interceptor/Authenticated.java new file mode 100644 index 000000000..d0fe55404 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/interceptor/Authenticated.java @@ -0,0 +1,12 @@ +package co.kirikiri.common.interceptor; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Authenticated { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/MemberIdentifier.java b/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/MemberIdentifier.java new file mode 100644 index 000000000..cd61bcd1a --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/MemberIdentifier.java @@ -0,0 +1,12 @@ +package co.kirikiri.common.resolver; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface MemberIdentifier { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/MemberIdentifierArgumentResolver.java b/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/MemberIdentifierArgumentResolver.java new file mode 100644 index 000000000..26bb61ad4 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/MemberIdentifierArgumentResolver.java @@ -0,0 +1,42 @@ +package co.kirikiri.common.resolver; + +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.service.AuthService; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@Component +@RequiredArgsConstructor +public class MemberIdentifierArgumentResolver implements HandlerMethodArgumentResolver { + + private static final String BEARER = "Bearer "; + + private final AuthService authService; + + @Override + public boolean supportsParameter(final MethodParameter parameter) { + return parameter.getParameterType().equals(String.class) + && parameter.hasParameterAnnotation(MemberIdentifier.class); + } + + @Override + public String resolveArgument(final MethodParameter parameter, final ModelAndViewContainer mavContainer, + final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) { + final String authorizationHeader = webRequest.getHeader(HttpHeaders.AUTHORIZATION); + checkHeader(authorizationHeader); + final String token = authorizationHeader.substring(BEARER.length()); + return authService.findIdentifierByToken(token); + } + + private void checkHeader(final String authorizationHeader) { + if (authorizationHeader == null || !authorizationHeader.startsWith(BEARER)) { + throw new AuthenticationException("์ธ์ฆ ํ—ค๋”๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/RoadmapSaveArgumentResolver.java b/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/RoadmapSaveArgumentResolver.java new file mode 100644 index 000000000..168abc2f9 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/common/resolver/RoadmapSaveArgumentResolver.java @@ -0,0 +1,98 @@ +package co.kirikiri.common.resolver; + +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.validation.DataBinder; +import org.springframework.validation.Validator; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; +import org.springframework.web.multipart.MultipartResolver; +import org.springframework.web.multipart.support.StandardServletMultipartResolver; + +@Component +@RequiredArgsConstructor +public class RoadmapSaveArgumentResolver implements HandlerMethodArgumentResolver { + + private final ObjectMapper objectMapper; + private final Validator validator; + + @Override + public boolean supportsParameter(final MethodParameter parameter) { + return parameter.getParameterType().equals(RoadmapSaveRequest.class); + } + + @Override + public Object resolveArgument(final MethodParameter parameter, final ModelAndViewContainer mavContainer, + final NativeWebRequest nativeWebRequest, final WebDataBinderFactory binderFactory) + throws MethodArgumentNotValidException { + final HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest(); + checkMultipart(request); + final MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; + final RoadmapSaveRequest roadmapSaveRequestNotIncludeImage = makeRoadmapSaveRequestNotIncludeImage( + multipartRequest); + validateRequest(parameter, roadmapSaveRequestNotIncludeImage); + return makeRoadmapSaveRequestIncludeImage(roadmapSaveRequestNotIncludeImage, multipartRequest); + } + + private void checkMultipart(final HttpServletRequest request) { + final MultipartResolver multipartResolver = new StandardServletMultipartResolver(); + if (!multipartResolver.isMultipart(request)) { + throw new BadRequestException("multipart/form-data ํ˜•์‹์œผ๋กœ ๋“ค์–ด์™€์•ผํ•ฉ๋‹ˆ๋‹ค."); + } + } + + private RoadmapSaveRequest makeRoadmapSaveRequestNotIncludeImage( + final MultipartHttpServletRequest multipartRequest) { + final String jsonData = getJsonData(multipartRequest); + return bindRoadmapSaveRequest(jsonData); + } + + private void validateRequest(final MethodParameter parameter, final RoadmapSaveRequest roadmapSaveRequest) + throws MethodArgumentNotValidException { + final DataBinder binder = new DataBinder(roadmapSaveRequest); + binder.setValidator(validator); + binder.validate(); + + if (binder.getBindingResult().hasErrors()) { + throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); + } + } + + private RoadmapSaveRequest makeRoadmapSaveRequestIncludeImage(final RoadmapSaveRequest roadmapSaveRequest, + final MultipartHttpServletRequest multipartRequest) { + for (final RoadmapNodeSaveRequest roadmapNode : roadmapSaveRequest.roadmapNodes()) { + final List images = multipartRequest.getFiles(roadmapNode.getTitle()); + roadmapNode.setImages(images); + } + return roadmapSaveRequest; + } + + private String getJsonData(final MultipartHttpServletRequest multipartRequest) { + final String jsonData = multipartRequest.getParameter("jsonData"); + if (jsonData == null) { + throw new BadRequestException("๋กœ๋“œ๋งต ์ƒ์„ฑ ์‹œ jsonData๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค."); + } + return multipartRequest.getParameter("jsonData"); + } + + private RoadmapSaveRequest bindRoadmapSaveRequest(final String jsonData) { + try { + return objectMapper.readValue(jsonData, RoadmapSaveRequest.class); + } catch (final JsonProcessingException exception) { + throw new BadRequestException("๋กœ๋“œ๋งต ์ƒ์„ฑ ์š”์ฒญ ํ˜•์‹์ด ํ‹€๋ ธ์Šต๋‹ˆ๋‹ค."); + } + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/controller/AuthController.java b/backend/kirikiri/src/main/java/co/kirikiri/controller/AuthController.java new file mode 100644 index 000000000..38f8c8bc4 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/controller/AuthController.java @@ -0,0 +1,34 @@ +package co.kirikiri.controller; + +import co.kirikiri.service.AuthService; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.auth.request.ReissueTokenRequest; +import co.kirikiri.service.dto.auth.response.AuthenticationResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/auth") +@RequiredArgsConstructor +public class AuthController { + + private final AuthService authService; + + @PostMapping("/login") + public ResponseEntity login(@RequestBody @Valid final LoginRequest request) { + final AuthenticationResponse response = authService.login(request); + return ResponseEntity.ok(response); + } + + @PostMapping("/reissue") + public ResponseEntity reissue(@RequestBody @Valid final ReissueTokenRequest request) { + final AuthenticationResponse response = authService.reissueToken(request); + return ResponseEntity.ok(response); + } + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/controller/GlobalExceptionHandler.java b/backend/kirikiri/src/main/java/co/kirikiri/controller/GlobalExceptionHandler.java new file mode 100644 index 000000000..bfa90d07d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/controller/GlobalExceptionHandler.java @@ -0,0 +1,95 @@ +package co.kirikiri.controller; + +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ConflictException; +import co.kirikiri.exception.ForbiddenException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.exception.ServerException; +import co.kirikiri.service.dto.ErrorResponse; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @ExceptionHandler(AuthenticationException.class) + public ResponseEntity handleAuthenticationException(final AuthenticationException exception) { + log.warn(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(errorResponse); + } + + @ExceptionHandler(ForbiddenException.class) + public ResponseEntity handleForbiddenException(final ForbiddenException exception) { + log.warn(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(errorResponse); + } + + @ExceptionHandler(ConflictException.class) + public ResponseEntity handleConflictException(final ConflictException exception) { + log.warn(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.status(HttpStatus.CONFLICT).body(errorResponse); + } + + @ExceptionHandler(BadRequestException.class) + public ResponseEntity handleBadRequestException(final BadRequestException exception) { + log.warn(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.badRequest().body(errorResponse); + } + + @ExceptionHandler(NotFoundException.class) + public ResponseEntity handleNotFoundException(final NotFoundException exception) { + log.warn(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleMethodArgumentNotValidException( + final MethodArgumentNotValidException exception) { + log.warn(exception.getMessage(), exception); + final List errorResponses = makeErrorResponses(exception); + return ResponseEntity.badRequest().body(errorResponses); + } + + @ExceptionHandler(InvalidFormatException.class) + public ResponseEntity handleInvalidFormatException(final InvalidFormatException exception) { + log.warn(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); + } + + @ExceptionHandler(ServerException.class) + public ResponseEntity handleServerException(final ServerException exception) { + log.error(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(final Exception exception) { + log.error(exception.getMessage(), exception); + final ErrorResponse errorResponse = new ErrorResponse(exception.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + } + + private List makeErrorResponses(final MethodArgumentNotValidException exception) { + return exception.getFieldErrors() + .stream() + .map(it -> new ErrorResponse(it.getDefaultMessage())) + .toList(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/controller/GoalRoomController.java b/backend/kirikiri/src/main/java/co/kirikiri/controller/GoalRoomController.java new file mode 100644 index 000000000..6123024e3 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/controller/GoalRoomController.java @@ -0,0 +1,183 @@ +package co.kirikiri.controller; + +import co.kirikiri.common.interceptor.Authenticated; +import co.kirikiri.common.resolver.MemberIdentifier; +import co.kirikiri.service.GoalRoomCreateService; +import co.kirikiri.service.GoalRoomReadService; +import co.kirikiri.service.dto.goalroom.GoalRoomMemberSortTypeDto; +import co.kirikiri.service.dto.goalroom.request.CheckFeedRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomStatusTypeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCertifiedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomMemberResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodeResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomTodoResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomForListResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import jakarta.validation.Valid; +import java.net.URI; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +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.RestController; + +@RestController +@RequestMapping("/goal-rooms") +@RequiredArgsConstructor +public class GoalRoomController { + + private final GoalRoomCreateService goalRoomCreateService; + private final GoalRoomReadService goalRoomReadService; + + @PostMapping + @Authenticated + public ResponseEntity create(@RequestBody @Valid final GoalRoomCreateRequest request, + @MemberIdentifier final String identifier) { + final Long id = goalRoomCreateService.create(request, identifier); + return ResponseEntity.created(URI.create("/api/goal-rooms/" + id)).build(); + } + + @Authenticated + @PostMapping("/{goalRoomId}/join") + public ResponseEntity joinGoalRoom(@MemberIdentifier final String identifier, + @PathVariable final Long goalRoomId) { + goalRoomCreateService.join(identifier, goalRoomId); + return ResponseEntity.status(HttpStatus.OK).build(); + } + + @Authenticated + @PostMapping("/{goalRoomId}/todos") + public ResponseEntity addTodo(@RequestBody @Valid final GoalRoomTodoRequest goalRoomTodoRequest, + @PathVariable final Long goalRoomId, + @MemberIdentifier final String identifier) { + final Long id = goalRoomCreateService.addGoalRoomTodo(goalRoomId, identifier, goalRoomTodoRequest); + return ResponseEntity.created(URI.create("/api/goal-rooms/" + goalRoomId + "/todos/" + id)).build(); + } + + @Authenticated + @PostMapping("/{goalRoomId}/todos/{todoId}") + public ResponseEntity checkTodo(@PathVariable final Long goalRoomId, + @PathVariable final Long todoId, + @MemberIdentifier final String identifier) { + final GoalRoomToDoCheckResponse checkResponse = goalRoomCreateService.checkGoalRoomTodo(goalRoomId, todoId, + identifier); + return ResponseEntity.ok(checkResponse); + } + + @Authenticated + @PostMapping(value = "/{goalRoomId}/checkFeeds", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + public ResponseEntity createCheckFeed(@MemberIdentifier final String identifier, + @PathVariable("goalRoomId") final Long goalRoomId, + @ModelAttribute final CheckFeedRequest checkFeedRequest) { + final String imageUrl = goalRoomCreateService.createCheckFeed(identifier, goalRoomId, checkFeedRequest); + return ResponseEntity.created(URI.create(imageUrl)).build(); + } + + @PostMapping("/{goalRoomId}/leave") + @Authenticated + public ResponseEntity leave(@MemberIdentifier final String identifier, + @PathVariable("goalRoomId") final Long goalRoomId) { + goalRoomCreateService.leave(identifier, goalRoomId); + return ResponseEntity.noContent().build(); + } + + @PostMapping("/{goalRoomId}/start") + @Authenticated + public ResponseEntity start(@MemberIdentifier final String identifier, + @PathVariable("goalRoomId") final Long goalRoomId) { + goalRoomCreateService.startGoalRoom(identifier, goalRoomId); + return ResponseEntity.noContent().build(); + } + + @GetMapping(value = "/{goalRoomId}", headers = "Authorization") + @Authenticated + public ResponseEntity findGoalRoom(@MemberIdentifier final String identifier, + @PathVariable("goalRoomId") final Long goalRoomId) { + final GoalRoomCertifiedResponse goalRoomResponse = goalRoomReadService.findGoalRoom(identifier, goalRoomId); + return ResponseEntity.ok(goalRoomResponse); + } + + @GetMapping("/{goalRoomId}") + public ResponseEntity findGoalRoom(@PathVariable("goalRoomId") final Long goalRoomId) { + final GoalRoomResponse goalRoomResponse = goalRoomReadService.findGoalRoom(goalRoomId); + return ResponseEntity.ok(goalRoomResponse); + } + + @Authenticated + @GetMapping("/{goalRoomId}/members") + public ResponseEntity> findGoalRoomMembers( + @PathVariable final Long goalRoomId, + @RequestParam(value = "sortCond", required = false) final GoalRoomMemberSortTypeDto sortType) { + final List goalRoomMembers = goalRoomReadService.findGoalRoomMembers(goalRoomId, + sortType); + return ResponseEntity.ok(goalRoomMembers); + } + + @Authenticated + @GetMapping("/{goalRoomId}/me") + public ResponseEntity findMemberGoalRoom( + @MemberIdentifier final String identifier, @PathVariable final Long goalRoomId) { + final MemberGoalRoomResponse memberGoalRoomResponse = goalRoomReadService.findMemberGoalRoom(identifier, + goalRoomId); + return ResponseEntity.ok(memberGoalRoomResponse); + } + + @Authenticated + @GetMapping("/me") + public ResponseEntity> findMemberGoalRoomsByStatus( + @MemberIdentifier final String identifier, + @RequestParam(value = "statusCond", required = false) final GoalRoomStatusTypeRequest goalRoomStatusTypeRequest) { + if (goalRoomStatusTypeRequest == null) { + final List memberGoalRoomForListResponses = + goalRoomReadService.findMemberGoalRooms(identifier); + return ResponseEntity.ok(memberGoalRoomForListResponses); + } + final List memberGoalRoomForListResponses = + goalRoomReadService.findMemberGoalRoomsByStatusType(identifier, goalRoomStatusTypeRequest); + return ResponseEntity.ok(memberGoalRoomForListResponses); + } + + @Authenticated + @GetMapping("/{goalRoomId}/todos") + public ResponseEntity> findAllTodos( + @PathVariable final Long goalRoomId, + @MemberIdentifier final String identifier) { + final List todoResponses = goalRoomReadService.findAllGoalRoomTodo(goalRoomId, + identifier); + return ResponseEntity.ok(todoResponses); + } + + @Authenticated + @GetMapping("/{goalRoomId}/nodes") + public ResponseEntity> findAllNodes( + @PathVariable final Long goalRoomId, + @MemberIdentifier final String identifier + ) { + final List nodeResponses = goalRoomReadService.findAllGoalRoomNodes(goalRoomId, + identifier); + return ResponseEntity.ok(nodeResponses); + } + + @Authenticated + @GetMapping("/{goalRoomId}/checkFeeds") + public ResponseEntity> findGoalRoomCheckFeeds( + @MemberIdentifier final String identifier, + @PathVariable("goalRoomId") final Long goalRoomId) { + final List response = goalRoomReadService.findGoalRoomCheckFeeds(identifier, + goalRoomId); + return ResponseEntity.ok(response); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/controller/MemberController.java b/backend/kirikiri/src/main/java/co/kirikiri/controller/MemberController.java new file mode 100644 index 000000000..ff0089974 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/controller/MemberController.java @@ -0,0 +1,46 @@ +package co.kirikiri.controller; + +import co.kirikiri.common.interceptor.Authenticated; +import co.kirikiri.common.resolver.MemberIdentifier; +import co.kirikiri.service.MemberService; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberInformationForPublicResponse; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import jakarta.validation.Valid; +import java.net.URI; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/members") +@RequiredArgsConstructor +public class MemberController { + + private final MemberService memberService; + + @PostMapping("/join") + public ResponseEntity join(@RequestBody @Valid final MemberJoinRequest request) { + final Long memberId = memberService.join(request); + return ResponseEntity.created(URI.create("/api/members/" + memberId)).build(); + } + + @GetMapping("/me") + @Authenticated + public ResponseEntity findMemberInformation(@MemberIdentifier final String identifier) { + final MemberInformationResponse response = memberService.findMemberInformation(identifier); + return ResponseEntity.ok(response); + } + + @GetMapping("/{memberId}") + @Authenticated + public ResponseEntity findMemberInfo(@PathVariable final Long memberId) { + final MemberInformationForPublicResponse response = memberService.findMemberInformationForPublic(memberId); + return ResponseEntity.ok(response); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/controller/RoadmapController.java b/backend/kirikiri/src/main/java/co/kirikiri/controller/RoadmapController.java new file mode 100644 index 000000000..531859b09 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/controller/RoadmapController.java @@ -0,0 +1,129 @@ +package co.kirikiri.controller; + +import co.kirikiri.common.interceptor.Authenticated; +import co.kirikiri.common.resolver.MemberIdentifier; +import co.kirikiri.service.RoadmapCreateService; +import co.kirikiri.service.RoadmapReadService; +import co.kirikiri.service.dto.CustomScrollRequest; +import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomsOrderTypeDto; +import co.kirikiri.service.dto.roadmap.request.RoadmapOrderTypeRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSearchRequest; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapCategoryResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse; +import jakarta.validation.Valid; +import java.net.URI; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +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.RestController; + +@RestController +@RequestMapping("/roadmaps") +@RequiredArgsConstructor +public class RoadmapController { + + private final RoadmapCreateService roadmapCreateService; + private final RoadmapReadService roadmapReadService; + + @Authenticated + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity create(final RoadmapSaveRequest request, @MemberIdentifier final String identifier) { + final Long roadmapId = roadmapCreateService.create(request, identifier); + return ResponseEntity.created(URI.create("/api/roadmaps/" + roadmapId)).build(); + } + + @PostMapping("/{roadmapId}/reviews") + public ResponseEntity createReview( + @PathVariable("roadmapId") final Long roadmapId, + @MemberIdentifier final String identifier, + @RequestBody @Valid final RoadmapReviewSaveRequest request) { + roadmapCreateService.createReview(roadmapId, identifier, request); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } + + @GetMapping("/{roadmapId}") + public ResponseEntity findRoadmap(@PathVariable final Long roadmapId) { + final RoadmapResponse response = roadmapReadService.findRoadmap(roadmapId); + return ResponseEntity.ok(response); + } + + @GetMapping + public ResponseEntity findRoadmapsByOrderType( + @RequestParam(value = "categoryId", required = false) final Long categoryId, + @RequestParam(value = "filterCond", required = false) final RoadmapOrderTypeRequest orderTypeRequest, + @ModelAttribute @Valid final CustomScrollRequest scrollRequest + ) { + final RoadmapForListResponses roadmapResponses = roadmapReadService.findRoadmapsByOrderType( + categoryId, orderTypeRequest, scrollRequest); + return ResponseEntity.ok(roadmapResponses); + } + + @GetMapping("/search") + public ResponseEntity search( + @RequestParam(value = "filterCond", required = false) final RoadmapOrderTypeRequest orderTypeRequest, + @ModelAttribute final RoadmapSearchRequest searchRequest, + @ModelAttribute @Valid final CustomScrollRequest scrollRequest + ) { + final RoadmapForListResponses roadmapResponses = roadmapReadService.search( + orderTypeRequest, searchRequest, scrollRequest); + return ResponseEntity.ok(roadmapResponses); + } + + @GetMapping("/categories") + public ResponseEntity> findAllRoadmapCategories() { + final List roadmapCategoryResponses = roadmapReadService.findAllRoadmapCategories(); + return ResponseEntity.ok(roadmapCategoryResponses); + } + + @GetMapping("/me") + @Authenticated + public ResponseEntity findAllMyRoadmaps(@MemberIdentifier final String identifier, + @ModelAttribute final CustomScrollRequest scrollRequest) { + final MemberRoadmapResponses responses = roadmapReadService.findAllMemberRoadmaps(identifier, scrollRequest); + return ResponseEntity.ok(responses); + } + + @GetMapping("/{roadmapId}/goal-rooms") + public ResponseEntity findGoalRoomsByOrderType( + @PathVariable final Long roadmapId, + @RequestParam(value = "filterCond", required = false) final RoadmapGoalRoomsOrderTypeDto roadmapGoalRoomsOrderTypeDto, + @ModelAttribute final CustomScrollRequest scrollRequest + ) { + final RoadmapGoalRoomResponses responses = roadmapReadService.findRoadmapGoalRoomsByOrderType( + roadmapId, roadmapGoalRoomsOrderTypeDto, scrollRequest); + return ResponseEntity.ok(responses); + } + + @GetMapping("/{roadmapId}/reviews") + public ResponseEntity> findRoadmapReviews( + @PathVariable final Long roadmapId, + @ModelAttribute final CustomScrollRequest scrollRequest + ) { + final List responses = roadmapReadService.findRoadmapReviews(roadmapId, scrollRequest); + return ResponseEntity.ok(responses); + } + + @DeleteMapping("/{roadmapId}") + @Authenticated + public ResponseEntity deleteRoadmap(@MemberIdentifier final String identifier, + @PathVariable("roadmapId") final Long roadmapId) { + roadmapCreateService.deleteRoadmap(identifier, roadmapId); + return ResponseEntity.noContent().build(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseCreatedTimeEntity.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseCreatedTimeEntity.java new file mode 100644 index 000000000..2a32dad7f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseCreatedTimeEntity.java @@ -0,0 +1,32 @@ +package co.kirikiri.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.PrePersist; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class BaseCreatedTimeEntity extends BaseEntity { + + private static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSSSSS"; + + @CreatedDate + @Column(nullable = false, updatable = false) + protected LocalDateTime createdAt; + + @PrePersist + public void prePersist() { + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(TIME_FORMAT); + final String formattedTime = createdAt.format(formatter); + createdAt = LocalDateTime.parse(formattedTime, formatter); + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseEntity.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseEntity.java new file mode 100644 index 000000000..e9cb9a77d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseEntity.java @@ -0,0 +1,39 @@ +package co.kirikiri.domain; + +import jakarta.persistence.EntityListeners; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.MappedSuperclass; +import java.util.Objects; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + protected Long id; + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final BaseEntity that = (BaseEntity) o; + return Objects.equals(id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + public Long getId() { + return id; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseUpdatedTimeEntity.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseUpdatedTimeEntity.java new file mode 100644 index 000000000..ac22c2f3d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/BaseUpdatedTimeEntity.java @@ -0,0 +1,17 @@ +package co.kirikiri.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class BaseUpdatedTimeEntity extends BaseCreatedTimeEntity { + + @LastModifiedDate + @Column(nullable = false) + private LocalDateTime updatedAt; +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/ImageContentType.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/ImageContentType.java new file mode 100644 index 000000000..681e49136 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/ImageContentType.java @@ -0,0 +1,26 @@ +package co.kirikiri.domain; + +import co.kirikiri.exception.BadRequestException; +import java.util.Arrays; + +public enum ImageContentType { + + JPG("image/jpg"), + JPEG("image/jpeg"), + PNG("image/png"), + WEBP("image/webp"), + ; + + private final String extension; + + ImageContentType(final String extension) { + this.extension = extension; + } + + public static ImageContentType findImageContentType(final String imageContentType) { + return Arrays.stream(values()) + .filter(it -> it.extension.equals(imageContentType)) + .findAny() + .orElseThrow(() -> new BadRequestException("ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ํ™•์žฅ์ž์ž…๋‹ˆ๋‹ค.")); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/auth/EncryptedToken.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/auth/EncryptedToken.java new file mode 100644 index 000000000..35670fa55 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/auth/EncryptedToken.java @@ -0,0 +1,57 @@ +package co.kirikiri.domain.auth; + +import co.kirikiri.exception.ServerException; +import jakarta.persistence.Column; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class EncryptedToken { + + private static final String ALGORITHM = "SHA-256"; + + @Column(name = "token", nullable = false) + private String value; + + public EncryptedToken(final String rawToken) { + this.value = encrypt(rawToken); + } + + private String encrypt(final String rawToken) { + final MessageDigest messageDigest = findMessageDigest(); + messageDigest.update(rawToken.getBytes()); + final byte[] hashedToken = messageDigest.digest(); + return Base64.getEncoder().encodeToString(hashedToken); + } + + private MessageDigest findMessageDigest() { + try { + return MessageDigest.getInstance(ALGORITHM); + } catch (final NoSuchAlgorithmException exception) { + throw new ServerException(exception.getMessage()); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final EncryptedToken that = (EncryptedToken) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/auth/RefreshToken.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/auth/RefreshToken.java new file mode 100644 index 000000000..537187f9b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/auth/RefreshToken.java @@ -0,0 +1,55 @@ +package co.kirikiri.domain.auth; + +import co.kirikiri.domain.member.Member; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RefreshToken { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Embedded + private EncryptedToken token; + + @Column(nullable = false) + private LocalDateTime expiredAt; + + @Column(nullable = false) + private final boolean isRevoked = false; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + private Member member; + + public RefreshToken(final EncryptedToken token, final LocalDateTime expiredAt, final Member member) { + this.token = token; + this.expiredAt = expiredAt; + this.member = member; + } + + public boolean isExpired() { + return expiredAt.isBefore(LocalDateTime.now()); + } + + public EncryptedToken getToken() { + return token; + } + + public Member getMember() { + return member; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/BaseGoalRoomMember.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/BaseGoalRoomMember.java new file mode 100644 index 000000000..603c6a6b5 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/BaseGoalRoomMember.java @@ -0,0 +1,102 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.BaseEntity; +import co.kirikiri.domain.member.Member; +import com.querydsl.core.annotations.QueryInit; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class BaseGoalRoomMember extends BaseEntity { + + @Enumerated(value = EnumType.STRING) + protected GoalRoomRole role; + + @CreatedDate + protected LocalDateTime joinedAt; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "goal_room_id", nullable = false) + @QueryInit(value = {"roadmapContent.roadmap"}) + protected GoalRoom goalRoom; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + @QueryInit(value = {"identifier"}) + protected Member member; + + public BaseGoalRoomMember(final GoalRoomRole role, final LocalDateTime joinedAt, + final GoalRoom goalRoom, final Member member) { + this(null, role, joinedAt, goalRoom, member); + } + + public BaseGoalRoomMember(final Long id, final GoalRoomRole role, final LocalDateTime joinedAt, + final GoalRoom goalRoom, final Member member) { + this.id = id; + this.role = role; + this.joinedAt = joinedAt; + this.goalRoom = goalRoom; + this.member = member; + } + + public boolean isLeader() { + return role == GoalRoomRole.LEADER; + } + + public boolean isSameMember(final Member member) { + return this.member.equals(member); + } + + public void becomeLeader() { + this.role = GoalRoomRole.LEADER; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + final BaseGoalRoomMember that = (BaseGoalRoomMember) o; + return Objects.equals(goalRoom, that.goalRoom) && Objects.equals(member, that.member); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), goalRoom, member); + } + + public GoalRoomRole getRole() { + return role; + } + + public LocalDateTime getJoinedAt() { + return joinedAt; + } + + public GoalRoom getGoalRoom() { + return goalRoom; + } + + public Member getMember() { + return member; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/CheckFeed.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/CheckFeed.java new file mode 100644 index 000000000..15c696158 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/CheckFeed.java @@ -0,0 +1,72 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.BaseCreatedTimeEntity; +import co.kirikiri.domain.ImageContentType; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class CheckFeed extends BaseCreatedTimeEntity { + + @Column(nullable = false) + private String serverFilePath; + + @Enumerated(value = EnumType.STRING) + @Column(nullable = false) + private ImageContentType imageContentType; + + @Column(nullable = false) + private String originalFileName; + + private String description; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "goal_room_roadmap_node_id", nullable = false) + private GoalRoomRoadmapNode goalRoomRoadmapNode; + + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + @JoinColumn(name = "goal_room_member_id", nullable = false) + private GoalRoomMember goalRoomMember; + + public CheckFeed(final String serverFilePath, final ImageContentType imageContentType, + final String originalFileName, final String description, + final GoalRoomRoadmapNode goalRoomRoadmapNode, final GoalRoomMember goalRoomMember) { + this(serverFilePath, imageContentType, originalFileName, description, goalRoomRoadmapNode, goalRoomMember, + null); + } + + public CheckFeed(final String serverFilePath, final ImageContentType imageContentType, + final String originalFileName, final String description, + final GoalRoomRoadmapNode goalRoomRoadmapNode, final GoalRoomMember goalRoomMember, final + LocalDateTime createdAt) { + this.serverFilePath = serverFilePath; + this.imageContentType = imageContentType; + this.originalFileName = originalFileName; + this.description = description; + this.goalRoomRoadmapNode = goalRoomRoadmapNode; + this.goalRoomMember = goalRoomMember; + this.createdAt = createdAt; + } + + public String getServerFilePath() { + return serverFilePath; + } + + public String getDescription() { + return description; + } + + public GoalRoomMember getGoalRoomMember() { + return goalRoomMember; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoom.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoom.java new file mode 100644 index 000000000..2921e0a7c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoom.java @@ -0,0 +1,293 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.BaseUpdatedTimeEntity; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoom extends BaseUpdatedTimeEntity { + + private static final int DATE_OFFSET = 1; + + @Embedded + private GoalRoomName name; + + @Embedded + private LimitedMemberCount limitedMemberCount; + + @Enumerated(value = EnumType.STRING) + private GoalRoomStatus status = GoalRoomStatus.RECRUITING; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "roadmap_content_id", nullable = false) + private RoadmapContent roadmapContent; + + @Column(nullable = false) + private LocalDate startDate; + + @Column(nullable = false) + private LocalDate endDate; + + @Embedded + private final GoalRoomPendingMembers goalRoomPendingMembers = new GoalRoomPendingMembers(); + + @Embedded + private final GoalRoomMembers goalRoomMembers = new GoalRoomMembers(); + + @Embedded + private final GoalRoomToDos goalRoomToDos = new GoalRoomToDos(); + + @Embedded + private final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes(); + + public GoalRoom(final GoalRoomName name, final LimitedMemberCount limitedMemberCount, + final RoadmapContent roadmapContent, final Member member) { + this(null, name, limitedMemberCount, roadmapContent, member); + } + + public GoalRoom(final Long id, final GoalRoomName name, final LimitedMemberCount limitedMemberCount, + final RoadmapContent roadmapContent, final Member member) { + this.id = id; + this.name = name; + this.limitedMemberCount = limitedMemberCount; + this.roadmapContent = roadmapContent; + updateLeader(member); + } + + private void updateLeader(final Member member) { + final GoalRoomPendingMember leader = new GoalRoomPendingMember(GoalRoomRole.LEADER, member); + leader.updateGoalRoom(this); + goalRoomPendingMembers.add(leader); + } + + public void join(final Member member) { + final GoalRoomPendingMember newMember = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, member); + newMember.updateGoalRoom(this); + validateJoinGoalRoom(newMember); + goalRoomPendingMembers.add(newMember); + } + + private void validateJoinGoalRoom(final GoalRoomPendingMember member) { + validateMemberCount(); + validateStatus(); + validateAlreadyParticipated(member); + } + + private void validateMemberCount() { + if (getCurrentMemberCount() >= limitedMemberCount.getValue()) { + throw new BadRequestException("์ œํ•œ ์ธ์›์ด ๊ฝ‰ ์ฐฌ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + private void validateStatus() { + if (status != GoalRoomStatus.RECRUITING) { + throw new BadRequestException("๋ชจ์ง‘ ์ค‘์ด์ง€ ์•Š์€ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + private void validateAlreadyParticipated(final GoalRoomPendingMember member) { + if (goalRoomPendingMembers.containGoalRoomPendingMember(member)) { + throw new BadRequestException("์ด๋ฏธ ์ฐธ์—ฌํ•œ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + public void start() { + this.status = GoalRoomStatus.RUNNING; + } + + public void complete() { + this.status = GoalRoomStatus.COMPLETED; + } + + public int calculateTotalPeriod() { + return (int) ChronoUnit.DAYS.between(startDate, endDate) + DATE_OFFSET; + } + + public int getAllCheckCount() { + return goalRoomRoadmapNodes.calculateAllCheckCount(); + } + + public boolean isRecruiting() { + return status == GoalRoomStatus.RECRUITING; + } + + public boolean isRunning() { + return status == GoalRoomStatus.RUNNING; + } + + public void addAllGoalRoomRoadmapNodes(final GoalRoomRoadmapNodes goalRoomRoadmapNodes) { + checkTotalSize(goalRoomRoadmapNodes.size() + this.goalRoomRoadmapNodes.size()); + this.goalRoomRoadmapNodes.addAll(goalRoomRoadmapNodes); + this.startDate = goalRoomRoadmapNodes.getGoalRoomStartDate(); + this.endDate = goalRoomRoadmapNodes.getGoalRoomEndDate(); + } + + private void checkTotalSize(final int totalSize) { + if (totalSize > roadmapContent.nodesSize()) { + throw new BadRequestException("๋กœ๋“œ๋งต์˜ ๋…ธ๋“œ ์ˆ˜๋ณด๋‹ค ๊ณจ๋ฃธ์˜ ๋…ธ๋“œ ์ˆ˜๊ฐ€ ํฝ๋‹ˆ๋‹ค."); + } + } + + public void addGoalRoomTodo(final GoalRoomToDo goalRoomToDo) { + goalRoomToDos.add(goalRoomToDo); + } + + public Member findGoalRoomLeader() { + if (status == GoalRoomStatus.RECRUITING) { + return goalRoomPendingMembers.findGoalRoomLeader(); + } + return goalRoomMembers.findGoalRoomLeader(); + } + + public boolean isNotLeader(final Member member) { + if (status == GoalRoomStatus.RECRUITING) { + return goalRoomPendingMembers.isNotLeader(member); + } + return goalRoomMembers.isNotLeader(member); + } + + public boolean isCompleted() { + return this.status == GoalRoomStatus.COMPLETED; + } + + public GoalRoomToDo findLastGoalRoomTodo() { + return goalRoomToDos.findLast(); + } + + public Optional findNodeByDate(final LocalDate date) { + return goalRoomRoadmapNodes.getNodeByDate(date); + } + + public Integer getCurrentMemberCount() { + if (status == GoalRoomStatus.RECRUITING) { + return goalRoomPendingMembers.size(); + } + return goalRoomMembers.size(); + } + + // FIXME ํ…Œ์ŠคํŠธ์šฉ ๋ฉ”์„œ๋“œ + public void addAllGoalRoomMembers(final List members) { + this.goalRoomMembers.addAll(new ArrayList<>(members)); + } + + public boolean isGoalRoomMember(final Member member) { + if (status == GoalRoomStatus.RECRUITING) { + return goalRoomPendingMembers.isMember(member); + } + return goalRoomMembers.isMember(member); + } + + public void leave(final Member member) { + if (status == GoalRoomStatus.RECRUITING) { + final GoalRoomPendingMember goalRoomPendingMember = findGoalRoomPendingMemberByMember(member); + changeRoleIfLeaderLeave(goalRoomPendingMembers, goalRoomPendingMember); + goalRoomPendingMembers.remove(goalRoomPendingMember); + return; + } + final GoalRoomMember goalRoomMember = findGoalRoomMemberByMember(member); + changeRoleIfLeaderLeave(goalRoomMembers, goalRoomMember); + goalRoomMembers.remove(goalRoomMember); + } + + public boolean cannotStart() { + return startDate.isAfter(LocalDate.now()); + } + + private GoalRoomPendingMember findGoalRoomPendingMemberByMember(final Member member) { + return goalRoomPendingMembers.findByMember(member) + .orElseThrow(() -> new BadRequestException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. memberId = " + member.getId())); + } + + private void changeRoleIfLeaderLeave(final GoalRoomPendingMembers goalRoomPendingMembers, + final GoalRoomPendingMember goalRoomPendingMember) { + if (goalRoomPendingMember.isLeader()) { + goalRoomPendingMembers.findNextLeader() + .ifPresent(GoalRoomPendingMember::becomeLeader); + } + } + + private GoalRoomMember findGoalRoomMemberByMember(final Member member) { + return goalRoomMembers.findByMember(member) + .orElseThrow(() -> new BadRequestException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. memberId = " + member.getId())); + } + + private void changeRoleIfLeaderLeave(final GoalRoomMembers goalRoomMembers, + final GoalRoomMember goalRoomMember) { + if (goalRoomMember.isLeader()) { + goalRoomMembers.findNextLeader() + .ifPresent(GoalRoomMember::becomeLeader); + } + } + + public boolean isEmptyGoalRoom() { + return goalRoomPendingMembers.isEmpty() && goalRoomMembers.isEmpty(); + } + + public Optional findGoalRoomTodoByTodoId(final Long todoId) { + return goalRoomToDos.findById(todoId); + } + + public void deleteAllPendingMembers() { + goalRoomPendingMembers.deleteAll(); + } + + public boolean isCompletedAfterMonths(final long numberOfMonth) { + final LocalDate currentDate = LocalDate.now(); + return currentDate.isAfter(endDate.plusMonths(numberOfMonth)); + } + + public GoalRoomName getName() { + return name; + } + + public LimitedMemberCount getLimitedMemberCount() { + return limitedMemberCount; + } + + public LocalDate getStartDate() { + return startDate; + } + + public LocalDate getEndDate() { + return endDate; + } + + public GoalRoomStatus getStatus() { + return status; + } + + public RoadmapContent getRoadmapContent() { + return roadmapContent; + } + + public GoalRoomRoadmapNodes getGoalRoomRoadmapNodes() { + return goalRoomRoadmapNodes; + } + + public GoalRoomToDos getGoalRoomToDos() { + return goalRoomToDos; + } + + public GoalRoomPendingMembers getGoalRoomPendingMembers() { + return goalRoomPendingMembers; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomMember.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomMember.java new file mode 100644 index 000000000..964584840 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomMember.java @@ -0,0 +1,29 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.member.Member; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomMember extends BaseGoalRoomMember { + + @Column + private Double accomplishmentRate = 0.0; + + public GoalRoomMember(final GoalRoomRole role, final LocalDateTime joinedAt, + final GoalRoom goalRoom, final Member member) { + super(role, joinedAt, goalRoom, member); + } + + public void updateAccomplishmentRate(final Double rate) { + this.accomplishmentRate = rate; + } + + public Double getAccomplishmentRate() { + return accomplishmentRate; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomMembers.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomMembers.java new file mode 100644 index 000000000..45525d93c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomMembers.java @@ -0,0 +1,86 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.exception.NotFoundException; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomMembers { + + private static final int MIN_SIZE_TO_FIND_NEXT_LEADER = 1; + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true, mappedBy = "goalRoom") + private final List values = new ArrayList<>(); + + public GoalRoomMembers(final List values) { + this.values.addAll(new ArrayList<>(values)); + } + + public void add(final GoalRoomMember goalRoomMember) { + this.values.add(goalRoomMember); + } + + public void addAll(final List goalRoomMembers) { + this.values.addAll(new ArrayList<>(goalRoomMembers)); + } + + public Optional findByMember(final Member member) { + return values.stream() + .filter(value -> value.isSameMember(member)) + .findFirst(); + } + + public Optional findNextLeader() { + if (size() <= MIN_SIZE_TO_FIND_NEXT_LEADER) { + return Optional.empty(); + } + values.sort(Comparator.comparing(GoalRoomMember::getJoinedAt)); + return Optional.of(values.get(1)); + } + + public boolean isMember(final Member member) { + return values.stream() + .anyMatch(value -> value.isSameMember(member)); + } + + public boolean isNotLeader(final Member member) { + final Member goalRoomLeader = findGoalRoomLeader(); + return !goalRoomLeader.equals(member); + } + + public Member findGoalRoomLeader() { + return values.stream() + .filter(GoalRoomMember::isLeader) + .findFirst() + .map(GoalRoomMember::getMember) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")); + } + + public int size() { + return values.size(); + } + + public void remove(final GoalRoomMember goalRoomMember) { + values.remove(goalRoomMember); + } + + public boolean isEmpty() { + return values.isEmpty(); + } + + public List getValues() { + return values; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomPendingMember.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomPendingMember.java new file mode 100644 index 000000000..f23b7dc6d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomPendingMember.java @@ -0,0 +1,42 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.exception.ServerException; +import jakarta.persistence.Entity; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomPendingMember extends BaseGoalRoomMember { + + public GoalRoomPendingMember(final GoalRoomRole role, final Member member) { + super(role, null, null, member); + } + + public GoalRoomPendingMember(final GoalRoomRole role, final GoalRoom goalRoom, final Member member) { + super(role, null, goalRoom, member); + } + + public GoalRoomPendingMember(final GoalRoomRole role, final LocalDateTime joinedAt, + final GoalRoom goalRoom, final Member member) { + super(role, joinedAt, goalRoom, member); + } + + public GoalRoomPendingMember(final Long id, final GoalRoomRole role, final LocalDateTime joinedAt, + final GoalRoom goalRoom, final Member member) { + super(id, role, joinedAt, goalRoom, member); + } + + public void updateGoalRoom(final GoalRoom goalRoom) { + if (this.goalRoom == null) { + this.goalRoom = goalRoom; + return; + } + if (this.goalRoom.equals(goalRoom)) { + return; + } + throw new ServerException("๊ณจ๋ฃธ์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomPendingMembers.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomPendingMembers.java new file mode 100644 index 000000000..4ce31d0b3 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomPendingMembers.java @@ -0,0 +1,91 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.exception.NotFoundException; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomPendingMembers { + + private static final int MIN_SIZE_TO_FIND_NEXT_LEADER = 1; + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true, mappedBy = "goalRoom") + private final List values = new ArrayList<>(); + + public GoalRoomPendingMembers(final List values) { + this.values.addAll(new ArrayList<>(values)); + } + + public void add(final GoalRoomPendingMember goalRoomPendingMember) { + values.add(goalRoomPendingMember); + } + + public boolean containGoalRoomPendingMember(final GoalRoomPendingMember goalRoomPendingMember) { + return values.stream() + .anyMatch(value -> value.isSameMember(goalRoomPendingMember.getMember())); + } + + public boolean isMember(final Member member) { + return values.stream() + .anyMatch(value -> value.isSameMember(member)); + } + + public int size() { + return values.size(); + } + + public Member findGoalRoomLeader() { + return values.stream() + .filter(GoalRoomPendingMember::isLeader) + .findFirst() + .map(GoalRoomPendingMember::getMember) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.")); + } + + public boolean isNotLeader(final Member member) { + final Member goalRoomLeader = findGoalRoomLeader(); + return !goalRoomLeader.equals(member); + } + + public Optional findByMember(final Member member) { + return values.stream() + .filter(value -> value.isSameMember(member)) + .findFirst(); + } + + public Optional findNextLeader() { + if (size() <= MIN_SIZE_TO_FIND_NEXT_LEADER) { + return Optional.empty(); + } + values.sort(Comparator.comparing(GoalRoomPendingMember::getJoinedAt)); + return Optional.of(values.get(1)); + } + + public void remove(final GoalRoomPendingMember goalRoomPendingMember) { + values.remove(goalRoomPendingMember); + } + + public boolean isEmpty() { + return values.isEmpty(); + } + + public void deleteAll() { + this.values.clear(); + } + + public List getValues() { + return new ArrayList<>(values); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNode.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNode.java new file mode 100644 index 000000000..72fd1a89b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNode.java @@ -0,0 +1,84 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.BaseEntity; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.time.LocalDate; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomRoadmapNode extends BaseEntity { + + private static final int MIN_CHECK_COUNT = 0; + + @Embedded + private Period period; + + private Integer checkCount; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "roadmap_node_id", nullable = false) + private RoadmapNode roadmapNode; + + public GoalRoomRoadmapNode(final Period period, final Integer checkCount, final RoadmapNode roadmapNode) { + this(null, period, checkCount, roadmapNode); + } + + public GoalRoomRoadmapNode(final Long id, final Period period, final Integer checkCount, + final RoadmapNode roadmapNode) { + validate(period, checkCount); + this.id = id; + this.period = period; + this.checkCount = checkCount; + this.roadmapNode = roadmapNode; + } + + private void validate(final Period period, final Integer checkCount) { + validateCheckCountPositive(checkCount); + validateCheckCountWithDaysBetween(period, checkCount); + } + + private void validateCheckCountPositive(final Integer checkCount) { + if (checkCount < MIN_CHECK_COUNT) { + throw new BadRequestException("๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๋Š” 0๋ณด๋‹ค ์ปค์•ผํ•ฉ๋‹ˆ๋‹ค."); + } + } + + private void validateCheckCountWithDaysBetween(final Period period, final int checkCount) { + if (checkCount > period.getDayCount()) { + throw new BadRequestException("๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๊ฐ€ ์„ค์ • ๊ธฐ๊ฐ„๋ณด๋‹ค ํด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + public boolean isEndDateEqualOrAfterOtherStartDate(final GoalRoomRoadmapNode other) { + return this.period.isEndDateEqualOrAfterOtherStartDate(other.period); + } + + public boolean isDayOfNode(final LocalDate date) { + return period.contains(date); + } + + public LocalDate getStartDate() { + return period.getStartDate(); + } + + public LocalDate getEndDate() { + return period.getEndDate(); + } + + public RoadmapNode getRoadmapNode() { + return roadmapNode; + } + + public int getCheckCount() { + return checkCount; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodes.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodes.java new file mode 100644 index 000000000..0e452b625 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodes.java @@ -0,0 +1,115 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.NotFoundException; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.stream.IntStream; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomRoadmapNodes { + + private static final int DATE_OFFSET = 1; + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true) + @JoinColumn(name = "goal_room_id", nullable = false, updatable = false) + private final List values = new ArrayList<>(); + + public GoalRoomRoadmapNodes(final List values) { + final List copiedValues = new ArrayList<>(values); + validatePeriodNoOverlap(copiedValues); + this.values.addAll(copiedValues); + } + + public void validatePeriodNoOverlap(final List nodes) { + sortByStartDateAsc(nodes); + + IntStream.range(0, nodes.size() - 1) + .filter(index -> nodes.get(index).isEndDateEqualOrAfterOtherStartDate(nodes.get(index + 1))) + .findAny() + .ifPresent(it -> { + throw new BadRequestException("๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ๊ธฐ๊ฐ„์ด ๊ฒน์น  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + }); + } + + private void sortByStartDateAsc(final List nodes) { + nodes.sort(Comparator.comparing(GoalRoomRoadmapNode::getStartDate)); + } + + public void addAll(final GoalRoomRoadmapNodes goalRoomRoadmapNodes) { + this.values.addAll(new ArrayList<>(goalRoomRoadmapNodes.values)); + } + + public LocalDate getGoalRoomStartDate() { + return values.stream() + .min(Comparator.comparing(GoalRoomRoadmapNode::getStartDate)) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ์— ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")) + .getStartDate(); + } + + public LocalDate getGoalRoomEndDate() { + return values.stream() + .max(Comparator.comparing(GoalRoomRoadmapNode::getEndDate)) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ์— ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")) + .getEndDate(); + } + + public int addTotalPeriod() { + return (int) ChronoUnit.DAYS.between(getGoalRoomStartDate(), getGoalRoomEndDate()) + DATE_OFFSET; + } + + public Optional getNodeByDate(final LocalDate date) { + sortByStartDateAsc(values); + + return values.stream() + .filter(node -> node.isDayOfNode(date)) + .findFirst(); + } + + public int size() { + return values.size(); + } + + public boolean hasFrontNode(final GoalRoomRoadmapNode node) { + sortByStartDateAsc(values); + return values.indexOf(node) != 0; + } + + public boolean hasBackNode(final GoalRoomRoadmapNode node) { + sortByStartDateAsc(values); + return values.indexOf(node) != (size() - 1); + } + + public Optional nextNode(final GoalRoomRoadmapNode roadmapNode) { + sortByStartDateAsc(values); + + if (hasBackNode(roadmapNode)) { + return Optional.of(values.get(values.indexOf(roadmapNode) + 1)); + } + return Optional.empty(); + } + + public int calculateAllCheckCount() { + return values.stream() + .mapToInt(GoalRoomRoadmapNode::getCheckCount) + .sum(); + } + + public List getValues() { + return new ArrayList<>(values); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRole.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRole.java new file mode 100644 index 000000000..1fec95ac2 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomRole.java @@ -0,0 +1,5 @@ +package co.kirikiri.domain.goalroom; + +public enum GoalRoomRole { + LEADER, FOLLOWER +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomStatus.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomStatus.java new file mode 100644 index 000000000..91e0916ef --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomStatus.java @@ -0,0 +1,5 @@ +package co.kirikiri.domain.goalroom; + +public enum GoalRoomStatus { + RECRUITING, RUNNING, COMPLETED +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDo.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDo.java new file mode 100644 index 000000000..c8852ff13 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDo.java @@ -0,0 +1,47 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.BaseUpdatedTimeEntity; +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.Period; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import java.time.LocalDate; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomToDo extends BaseUpdatedTimeEntity { + + @Embedded + private GoalRoomTodoContent content; + + @Embedded + private Period period; + + public GoalRoomToDo(final GoalRoomTodoContent content, final Period period) { + this(null, content, period); + } + + public GoalRoomToDo(final Long id, final GoalRoomTodoContent content, final Period period) { + this.id = id; + this.content = content; + this.period = period; + } + + public boolean isSameId(final Long todoId) { + return this.id.equals(todoId); + } + + public String getContent() { + return content.getValue(); + } + + public LocalDate getStartDate() { + return period.getStartDate(); + } + + public LocalDate getEndDate() { + return period.getEndDate(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDoCheck.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDoCheck.java new file mode 100644 index 000000000..a52ee1812 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDoCheck.java @@ -0,0 +1,31 @@ +package co.kirikiri.domain.goalroom; + +import co.kirikiri.domain.BaseEntity; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomToDoCheck extends BaseEntity { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "goal_room_member_id", nullable = false) + private GoalRoomMember goalRoomMember; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "goal_room_to_do_id", nullable = false) + private GoalRoomToDo goalRoomToDo; + + public GoalRoomToDoCheck(final GoalRoomMember goalRoomMember, final GoalRoomToDo goalRoomToDo) { + this.goalRoomMember = goalRoomMember; + this.goalRoomToDo = goalRoomToDo; + } + + public GoalRoomToDo getGoalRoomToDo() { + return goalRoomToDo; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDos.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDos.java new file mode 100644 index 000000000..e939c0536 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/GoalRoomToDos.java @@ -0,0 +1,45 @@ +package co.kirikiri.domain.goalroom; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomToDos { + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true) + @JoinColumn(name = "goal_room_id", updatable = false, nullable = false) + private final List values = new ArrayList<>(); + + public GoalRoomToDos(final List values) { + this.values.addAll(new ArrayList<>(values)); + } + + public void add(final GoalRoomToDo goalRoomToDo) { + values.add(goalRoomToDo); + } + + public GoalRoomToDo findLast() { + return values.get(values.size() - 1); + } + + public Optional findById(final Long todoId) { + return values.stream() + .filter(goalRoomToDo -> goalRoomToDo.isSameId(todoId)) + .findFirst(); + } + + public List getValues() { + return new ArrayList<>(values); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/GoalRoomName.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/GoalRoomName.java new file mode 100644 index 000000000..1e6922195 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/GoalRoomName.java @@ -0,0 +1,33 @@ +package co.kirikiri.domain.goalroom.vo; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomName { + + private static final int MIN_LENGTH = 1; + private static final int MAX_LENGTH = 40; + + @Column(nullable = false, length = 50, name = "name") + private String value; + + public GoalRoomName(final String value) { + validate(value); + this.value = value; + } + + private void validate(final String value) { + if (value.length() < MIN_LENGTH || value.length() > MAX_LENGTH) { + throw new BadRequestException("๊ณจ๋ฃธ ์ด๋ฆ„์˜ ๊ธธ์ด๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + public String getValue() { + return value; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/GoalRoomTodoContent.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/GoalRoomTodoContent.java new file mode 100644 index 000000000..485e07e70 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/GoalRoomTodoContent.java @@ -0,0 +1,33 @@ +package co.kirikiri.domain.goalroom.vo; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class GoalRoomTodoContent { + + private static final int MIN_LENGTH = 1; + private static final int MAX_LENGTH = 250; + + @Column(name = "content", nullable = false, length = 300) + private String value; + + public GoalRoomTodoContent(final String value) { + validate(value); + this.value = value; + } + + private void validate(final String value) { + if (value.length() < MIN_LENGTH || value.length() > MAX_LENGTH) { + throw new BadRequestException("ํˆฌ๋‘ ์ปจํ…์ธ ์˜ ๊ธธ์ด๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + public String getValue() { + return value; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/LimitedMemberCount.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/LimitedMemberCount.java new file mode 100644 index 000000000..2c9e74844 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/LimitedMemberCount.java @@ -0,0 +1,33 @@ +package co.kirikiri.domain.goalroom.vo; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class LimitedMemberCount { + + private static final int MIN = 1; + private static final int MAX = 20; + + @Column(name = "limited_member_count") + private int value; + + public LimitedMemberCount(final int value) { + validate(value); + this.value = value; + } + + private void validate(final int value) { + if (value < MIN || value > MAX) { + throw new BadRequestException("์ œํ•œ ์ธ์› ์ˆ˜๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + public int getValue() { + return value; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/Period.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/Period.java new file mode 100644 index 000000000..73370f8ba --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/goalroom/vo/Period.java @@ -0,0 +1,66 @@ +package co.kirikiri.domain.goalroom.vo; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Period { + + @Column(nullable = false) + private LocalDate startDate; + + @Column(nullable = false) + private LocalDate endDate; + + public Period(final LocalDate startDate, final LocalDate endDate) { + validate(startDate, endDate); + this.startDate = startDate; + this.endDate = endDate; + } + + private void validate(final LocalDate startDate, final LocalDate endDate) { + validateStartDateAfterNow(startDate); + validateStartDateBeforeOrEqualEndDate(startDate, endDate); + } + + private void validateStartDateAfterNow(final LocalDate startDate) { + if (startDate.isBefore(LocalDate.now())) { + throw new BadRequestException("์‹œ์ž‘์ผ์€ ์˜ค๋Š˜๋ณด๋‹ค ์ „์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + private void validateStartDateBeforeOrEqualEndDate(final LocalDate startDate, final LocalDate endDate) { + if (startDate.isAfter(endDate)) { + throw new BadRequestException("์‹œ์ž‘์ผ์€ ์ข…๋ฃŒ์ผ๋ณด๋‹ค ํ›„์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + public boolean isEndDateEqualOrAfterOtherStartDate(final Period other) { + return this.endDate.isEqual(other.startDate) + || this.endDate.isAfter(other.startDate); + } + + public boolean contains(final LocalDate date) { + return (startDate.isBefore(date) && endDate.isAfter(date)) + || startDate.isEqual(date) + || endDate.isEqual(date); + } + + public long getDayCount() { + return ChronoUnit.DAYS.between(startDate, endDate) + 1; + } + + public LocalDate getStartDate() { + return startDate; + } + + public LocalDate getEndDate() { + return endDate; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/EncryptedPassword.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/EncryptedPassword.java new file mode 100644 index 000000000..70e5cfbef --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/EncryptedPassword.java @@ -0,0 +1,74 @@ +package co.kirikiri.domain.member; + +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.exception.ServerException; +import jakarta.persistence.Column; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Base64; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class EncryptedPassword { + + private static final String ALGORITHM = "SHA-256"; + + @Column(nullable = false) + private String password; + + @Column(nullable = false) + private String salt; + + public EncryptedPassword(final Password unencryptedPassword) { + this.salt = generateSalt(unencryptedPassword.length()); + this.password = encrypt(unencryptedPassword, salt); + } + + private String generateSalt(final int length) { + final SecureRandom secureRandom = new SecureRandom(); + final byte[] value = new byte[length]; + secureRandom.nextBytes(value); + return Base64.getEncoder().encodeToString(value); + } + + private String encrypt(final Password unencryptedPassword, final String salt) { + final MessageDigest messageDigest = findMessageDigest(); + messageDigest.update(salt.getBytes()); + messageDigest.update(unencryptedPassword.getBytes()); + final byte[] hashedPassword = messageDigest.digest(); + return Base64.getEncoder().encodeToString(hashedPassword); + } + + private MessageDigest findMessageDigest() { + try { + return MessageDigest.getInstance(ALGORITHM); + } catch (final NoSuchAlgorithmException exception) { + throw new ServerException(exception.getMessage()); + } + } + + public boolean isMismatch(final Password password) { + final String encrypted = encrypt(password, this.salt); + return !encrypted.equals(this.password); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final EncryptedPassword that = (EncryptedPassword) o; + return Objects.equals(password, that.password); + } + + @Override + public int hashCode() { + return Objects.hash(password); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/Gender.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/Gender.java new file mode 100644 index 000000000..40827a664 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/Gender.java @@ -0,0 +1,7 @@ +package co.kirikiri.domain.member; + +public enum Gender { + + MALE, + FEMALE, +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/Member.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/Member.java new file mode 100644 index 000000000..222005d1d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/Member.java @@ -0,0 +1,75 @@ +package co.kirikiri.domain.member; + +import co.kirikiri.domain.BaseUpdatedTimeEntity; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Member extends BaseUpdatedTimeEntity { + + @Embedded + private Identifier identifier; + + @Embedded + private EncryptedPassword encryptedPassword; + + @Embedded + private Nickname nickname; + + @OneToOne(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true) + @JoinColumn(name = "member_image_id") + private MemberImage image; + + @OneToOne(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true) + @JoinColumn(name = "member_profile_id", nullable = false, unique = true) + private MemberProfile memberProfile; + + public Member(final Identifier identifier, final EncryptedPassword encryptedPassword, final Nickname nickname, + final MemberImage image, final MemberProfile memberProfile) { + this(null, identifier, encryptedPassword, nickname, image, memberProfile); + } + + public Member(final Long id, final Identifier identifier, final EncryptedPassword encryptedPassword, + final Nickname nickname, final MemberImage image, final MemberProfile memberProfile) { + this.id = id; + this.identifier = identifier; + this.encryptedPassword = encryptedPassword; + this.nickname = nickname; + this.image = image; + this.memberProfile = memberProfile; + } + + public boolean isPasswordMismatch(final Password password) { + return this.encryptedPassword.isMismatch(password); + } + + public Identifier getIdentifier() { + return identifier; + } + + public Nickname getNickname() { + return nickname; + } + + public MemberImage getImage() { + return image; + } + + public MemberProfile getMemberProfile() { + return memberProfile; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/MemberImage.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/MemberImage.java new file mode 100644 index 000000000..519ab7e5a --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/MemberImage.java @@ -0,0 +1,31 @@ +package co.kirikiri.domain.member; + +import co.kirikiri.domain.BaseEntity; +import co.kirikiri.domain.ImageContentType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class MemberImage extends BaseEntity { + + @Column(length = 100, nullable = false) + private String originalFileName; + + @Column(nullable = false) + private String serverFilePath; + + @Enumerated(value = EnumType.STRING) + @Column(length = 10, nullable = false) + private ImageContentType imageContentType; + + public String getServerFilePath() { + return serverFilePath; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/MemberProfile.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/MemberProfile.java new file mode 100644 index 000000000..afe56e7d7 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/MemberProfile.java @@ -0,0 +1,43 @@ +package co.kirikiri.domain.member; + +import co.kirikiri.domain.BaseUpdatedTimeEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import java.time.LocalDate; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class MemberProfile extends BaseUpdatedTimeEntity { + + @Enumerated(value = EnumType.STRING) + @Column(length = 10, nullable = false) + private Gender gender; + + @Column(nullable = false) + private LocalDate birthday; + + @Column(length = 20, nullable = false) + private String phoneNumber; + + public MemberProfile(final Gender gender, final LocalDate birthday, final String phoneNumber) { + this.gender = gender; + this.birthday = birthday; + this.phoneNumber = phoneNumber; + } + + public Gender getGender() { + return gender; + } + + public LocalDate getBirthday() { + return birthday; + } + + public String getPhoneNumber() { + return phoneNumber; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Identifier.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Identifier.java new file mode 100644 index 000000000..394509bdc --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Identifier.java @@ -0,0 +1,58 @@ +package co.kirikiri.domain.member.vo; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Identifier { + + private static final int MIN_LENGTH = 4; + private static final int MAX_LENGTH = 20; + private static final String REGEX = "^[a-z0-9]+$"; + + @Column(name = "identifier", length = 50, unique = true, nullable = false) + private String value; + + public Identifier(final String value) { + validate(value); + this.value = value; + } + + private void validate(final String value) { + if (isNotValidLength(value) || isNotValidPattern(value)) { + throw new BadRequestException("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค."); + } + } + + private boolean isNotValidLength(final String value) { + return value.length() < MIN_LENGTH || value.length() > MAX_LENGTH; + } + + private boolean isNotValidPattern(final String value) { + return !value.matches(REGEX); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final Identifier that = (Identifier) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + public String getValue() { + return value; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Nickname.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Nickname.java new file mode 100644 index 000000000..db51fdedd --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Nickname.java @@ -0,0 +1,52 @@ +package co.kirikiri.domain.member.vo; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import java.util.Objects; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +public class Nickname { + + private static final int MIN_LENGTH = 2; + private static final int MAX_LENGTH = 8; + + @Column(name = "nickname", length = 15, unique = true, nullable = false) + private String value; + + public Nickname(final String value) { + validate(value); + this.value = value; + } + + private void validate(final String value) { + if (isNotValidLength(value)) { + throw new BadRequestException("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋‹‰๋„ค์ž„์ž…๋‹ˆ๋‹ค."); + } + } + + private boolean isNotValidLength(final String value) { + return value.length() < MIN_LENGTH || value.length() > MAX_LENGTH; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final Nickname nickname = (Nickname) o; + return Objects.equals(value, nickname.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + public String getValue() { + return value; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Password.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Password.java new file mode 100644 index 000000000..54c63c621 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/member/vo/Password.java @@ -0,0 +1,41 @@ +package co.kirikiri.domain.member.vo; + +import co.kirikiri.exception.BadRequestException; +import lombok.Getter; + +@Getter +public class Password { + + private static final int MIN_LENGTH = 8; + private static final int MAX_LENGTH = 15; + private static final String REGEX = "^(?=.*[a-z])(?=.*\\d)[a-z\\d!@#\\$%\\^&\\*\\(\\)~]+$"; + + private final String value; + + public Password(final String value) { + validate(value); + this.value = value; + } + + private void validate(final String value) { + if (isNotValidLength(value) || isNotValidPattern(value)) { + throw new BadRequestException("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค."); + } + } + + private boolean isNotValidLength(final String value) { + return value.length() < MIN_LENGTH || value.length() > MAX_LENGTH; + } + + private boolean isNotValidPattern(final String value) { + return !value.matches(REGEX); + } + + public int length() { + return value.length(); + } + + public byte[] getBytes() { + return value.getBytes(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/Roadmap.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/Roadmap.java new file mode 100644 index 000000000..95b6fbc7f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/Roadmap.java @@ -0,0 +1,193 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.BaseCreatedTimeEntity; +import co.kirikiri.domain.member.Member; +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.util.Objects; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Roadmap extends BaseCreatedTimeEntity { + + private static final int TITLE_MIN_LENGTH = 1; + private static final int TITLE_MAX_LENGTH = 40; + private static final int INTRODUCTION_MIN_LENGTH = 1; + private static final int INTRODUCTION_MAX_LENGTH = 150; + private static final int REQUIRED_MIN_PERIOD = 0; + private static final int REQUIRED_MAX_PERIOD = 1000; + + @Column(length = 50, nullable = false) + private String title; + + @Column(length = 200, nullable = false) + private String introduction; + + @Column(nullable = false) + private Integer requiredPeriod; + + @Enumerated(value = EnumType.STRING) + @Column(length = 20, nullable = false) + private RoadmapDifficulty difficulty; + + @Enumerated(value = EnumType.STRING) + @Column(length = 10, nullable = false) + private RoadmapStatus status = RoadmapStatus.CREATED; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false, updatable = false) + private Member creator; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id", nullable = false) + private RoadmapCategory category; + + @Embedded + private RoadmapContents contents = new RoadmapContents(); + + @Embedded + private RoadmapTags tags = new RoadmapTags(); + + @Embedded + private RoadmapReviews reviews = new RoadmapReviews(); + + public Roadmap(final String title, final String introduction, final int requiredPeriod, + final RoadmapDifficulty difficulty, final Member creator, final RoadmapCategory category) { + this(null, title, introduction, requiredPeriod, difficulty, RoadmapStatus.CREATED, creator, category); + } + + public Roadmap(final String title, final String introduction, final Integer requiredPeriod, + final RoadmapDifficulty difficulty, final RoadmapStatus status, final Member creator, + final RoadmapCategory category) { + this(null, title, introduction, requiredPeriod, difficulty, status, creator, category); + } + + public Roadmap(final Long id, final String title, final String introduction, final Integer requiredPeriod, + final RoadmapDifficulty difficulty, final Member creator, final RoadmapCategory category) { + this(id, title, introduction, requiredPeriod, difficulty, RoadmapStatus.CREATED, creator, category); + } + + public Roadmap(final Long id, final String title, final String introduction, final Integer requiredPeriod, + final RoadmapDifficulty difficulty, final RoadmapStatus status, final Member creator, + final RoadmapCategory category) { + validate(title, introduction, requiredPeriod); + this.id = id; + this.title = title; + this.introduction = introduction; + this.requiredPeriod = requiredPeriod; + this.difficulty = difficulty; + this.status = status; + this.creator = creator; + this.category = category; + } + + private void validate(final String title, final String introduction, final int requiredPeriod) { + validateTitleLength(title); + validateIntroductionLength(introduction); + validateRequiredPeriod(requiredPeriod); + } + + private void validateTitleLength(final String title) { + if (title.length() < TITLE_MIN_LENGTH || title.length() > TITLE_MAX_LENGTH) { + throw new BadRequestException( + String.format("๋กœ๋“œ๋งต ์ œ๋ชฉ์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ %d๊ธ€์ž, ์ตœ๋Œ€ %d๊ธ€์ž์ž…๋‹ˆ๋‹ค.", TITLE_MIN_LENGTH, TITLE_MAX_LENGTH) + ); + } + } + + private void validateIntroductionLength(final String introduction) { + if (introduction.length() < INTRODUCTION_MIN_LENGTH || introduction.length() > INTRODUCTION_MAX_LENGTH) { + throw new BadRequestException( + String.format("๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ %d๊ธ€์ž, ์ตœ๋Œ€ %d๊ธ€์ž์ž…๋‹ˆ๋‹ค.", + INTRODUCTION_MIN_LENGTH, INTRODUCTION_MAX_LENGTH + ) + ); + } + } + + private void validateRequiredPeriod(final int requiredPeriod) { + if (requiredPeriod < REQUIRED_MIN_PERIOD || requiredPeriod > REQUIRED_MAX_PERIOD) { + throw new BadRequestException( + String.format("๋กœ๋“œ๋งต ์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„์€ ์ตœ์†Œ %d์ผ, ์ตœ๋Œ€ %d์ผ์ž…๋‹ˆ๋‹ค.", REQUIRED_MIN_PERIOD, REQUIRED_MAX_PERIOD) + ); + } + } + + public void addContent(final RoadmapContent content) { + contents.add(content); + if (content.isNotSameRoadmap(this)) { + content.updateRoadmap(this); + } + } + + public void addTags(final RoadmapTags tags) { + this.tags.addAll(tags); + } + + public boolean isCreator(final Member member) { + return Objects.equals(creator.getId(), member.getId()); + } + + public void addReview(final RoadmapReview review) { + reviews.add(review); + if (review.isNotSameRoadmap(this)) { + review.updateRoadmap(this); + } + } + + public void delete() { + this.status = RoadmapStatus.DELETED; + } + + public Optional findLastRoadmapContent() { + return this.contents.findLastRoadmapContent(); + } + + public boolean isDeleted() { + return status == RoadmapStatus.DELETED; + } + + public Member getCreator() { + return creator; + } + + public String getTitle() { + return title; + } + + public RoadmapCategory getCategory() { + return category; + } + + public RoadmapContents getContents() { + return contents; + } + + public String getIntroduction() { + return introduction; + } + + public Integer getRequiredPeriod() { + return requiredPeriod; + } + + public RoadmapDifficulty getDifficulty() { + return difficulty; + } + + public RoadmapTags getTags() { + return tags; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapCategory.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapCategory.java new file mode 100644 index 000000000..a983dce16 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapCategory.java @@ -0,0 +1,30 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.BaseEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class RoadmapCategory extends BaseEntity { + + @Column(length = 15, nullable = false) + private String name; + + public RoadmapCategory(final String name) { + this(null, name); + } + + public RoadmapCategory(final Long id, final String name) { + super.id = id; + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapContent.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapContent.java new file mode 100644 index 000000000..65d649d13 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapContent.java @@ -0,0 +1,94 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.BaseUpdatedTimeEntity; +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter +public class RoadmapContent extends BaseUpdatedTimeEntity { + + private static final int CONTENT_MAX_LENGTH = 2000; + + @Column(length = 2200) + private String content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "roadmap_id", nullable = false) + private Roadmap roadmap; + + @Embedded + private final RoadmapNodes nodes = new RoadmapNodes(); + + public RoadmapContent(final String content) { + this(null, content); + } + + public RoadmapContent(final Long id, final String content) { + validate(content); + this.id = id; + this.content = content; + } + + private void validate(final String content) { + if (content == null) { + return; + } + validateContentLength(content); + } + + private void validateContentLength(final String content) { + if (content.length() > CONTENT_MAX_LENGTH) { + throw new BadRequestException(String.format("๋กœ๋“œ๋งต ๋ณธ๋ฌธ์˜ ๊ธธ์ด๋Š” ์ตœ๋Œ€ %d๊ธ€์ž์ž…๋‹ˆ๋‹ค.", CONTENT_MAX_LENGTH)); + } + } + + public void addNodes(final RoadmapNodes nodes) { + this.nodes.addAll(nodes); + nodes.updateAllRoadmapContent(this); + } + + public boolean isNotSameRoadmap(final Roadmap roadmap) { + return this.roadmap == null || !this.roadmap.equals(roadmap); + } + + public void updateRoadmap(final Roadmap roadmap) { + if (this.roadmap == null) { + this.roadmap = roadmap; + } + } + + public int nodesSize() { + return nodes.size(); + } + + public Optional findRoadmapNodeById(final Long id) { + return nodes.findById(id); + } + + public Optional findRoadmapNodeByTitle(final String title) { + return nodes.findByTitle(title); + } + + public String getContent() { + return content; + } + + public RoadmapNodes getNodes() { + return nodes; + } + + public Roadmap getRoadmap() { + return roadmap; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapContents.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapContents.java new file mode 100644 index 000000000..7266f63e4 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapContents.java @@ -0,0 +1,42 @@ +package co.kirikiri.domain.roadmap; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapContents { + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + mappedBy = "roadmap") + @Column(nullable = false) + private final List values = new ArrayList<>(); + + public RoadmapContents(final List contents) { + this.values.addAll(contents); + } + + public void add(final RoadmapContent content) { + this.values.add(content); + } + + public Optional findLastRoadmapContent() { + if (values.isEmpty()) { + return Optional.empty(); + } + return Optional.of(values.get(values.size() - 1)); + } + + public List getValues() { + return values; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapDifficulty.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapDifficulty.java new file mode 100644 index 000000000..f8379da50 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapDifficulty.java @@ -0,0 +1,10 @@ +package co.kirikiri.domain.roadmap; + +public enum RoadmapDifficulty { + + VERY_EASY, + EASY, + NORMAL, + DIFFICULT, + VERY_DIFFICULT +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNode.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNode.java new file mode 100644 index 000000000..67f00b154 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNode.java @@ -0,0 +1,95 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.BaseEntity; +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapNode extends BaseEntity { + + private static final int TITLE_MIN_LENGTH = 1; + private static final int TITLE_MAX_LENGTH = 40; + private static final int CONTENT_MIN_LENGTH = 1; + private static final int CONTENT_MAX_LENGTH = 2000; + + @Column(length = 50, nullable = false) + private String title; + + @Column(length = 2200, nullable = false) + private String content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "roadmap_content_id", nullable = false) + private RoadmapContent roadmapContent; + + @Embedded + private final RoadmapNodeImages roadmapNodeImages = new RoadmapNodeImages(); + + public RoadmapNode(final String title, final String content) { + this(null, title, content); + } + + public RoadmapNode(final Long id, final String title, final String content) { + validate(title, content); + this.id = id; + this.title = title; + this.content = content; + } + + private void validate(final String title, final String content) { + validateTitleLength(title); + validateContentLength(content); + } + + private void validateTitleLength(final String title) { + if (title.length() < TITLE_MIN_LENGTH || title.length() > TITLE_MAX_LENGTH) { + throw new BadRequestException( + String.format("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ %d๊ธ€์ž, ์ตœ๋Œ€ %d๊ธ€์ž์ž…๋‹ˆ๋‹ค.", TITLE_MIN_LENGTH, TITLE_MAX_LENGTH)); + } + } + + private void validateContentLength(final String content) { + if (content.length() < CONTENT_MIN_LENGTH || content.length() > CONTENT_MAX_LENGTH) { + throw new BadRequestException( + String.format("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ %d๊ธ€์ž, ์ตœ๋Œ€ %d๊ธ€์ž์ž…๋‹ˆ๋‹ค.", CONTENT_MIN_LENGTH, CONTENT_MAX_LENGTH)); + } + } + + public void addImages(final RoadmapNodeImages roadmapNodeImages) { + this.roadmapNodeImages.addAll(roadmapNodeImages); + } + + public boolean isNotSameRoadmapContent(final RoadmapContent roadmapContent) { + return this.roadmapContent == null || !this.roadmapContent.equals(roadmapContent); + } + + public void updateRoadmapContent(final RoadmapContent roadmapContent) { + if (this.roadmapContent == null) { + this.roadmapContent = roadmapContent; + } + } + + public String getTitle() { + return title; + } + + public String getContent() { + return content; + } + + public RoadmapContent getRoadmapContent() { + return roadmapContent; + } + + public RoadmapNodeImages getRoadmapNodeImages() { + return roadmapNodeImages; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodeImage.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodeImage.java new file mode 100644 index 000000000..47f3b1a1d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodeImage.java @@ -0,0 +1,42 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.BaseEntity; +import co.kirikiri.domain.ImageContentType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapNodeImage extends BaseEntity { + + @Column(length = 100, nullable = false) + private String originalFileName; + + @Column(nullable = false) + private String serverFilePath; + + @Enumerated(value = EnumType.STRING) + @Column(length = 10, nullable = false) + private ImageContentType imageContentType; + + public RoadmapNodeImage(final String originalFileName, final String serverFilePath, + final ImageContentType imageContentType) { + this(null, originalFileName, serverFilePath, imageContentType); + } + + public RoadmapNodeImage(final Long id, final String originalFileName, final String serverFilePath, + final ImageContentType imageContentType) { + this.id = id; + this.originalFileName = originalFileName; + this.serverFilePath = serverFilePath; + this.imageContentType = imageContentType; + } + + public String getServerFilePath() { + return serverFilePath; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodeImages.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodeImages.java new file mode 100644 index 000000000..160eb73b6 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodeImages.java @@ -0,0 +1,47 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor +public class RoadmapNodeImages { + + private static final int MAX_SIZE = 2; + + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}) + @JoinColumn(name = "roadmap_node_id", nullable = false, updatable = false) + private final List values = new ArrayList<>(); + + public RoadmapNodeImages(final List images) { + validateSize(images); + this.values.addAll(new ArrayList<>(images)); + } + + private void validateSize(final List images) { + if (images.size() > MAX_SIZE) { + throw new BadRequestException("ํ•œ ๋กœ๋“œ๋งต ๋…ธ๋“œ์— ์‚ฌ์ง„์€ ์ตœ๋Œ€ 2๊ฐœ๊นŒ์ง€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."); + } + } + + public void addAll(final RoadmapNodeImages images) { + this.values.addAll(new ArrayList<>(images.values)); + validateSize(this.values); + } + + public void add(final RoadmapNodeImage roadmapNodeImage) { + this.values.add(roadmapNodeImage); + validateSize(this.values); + } + + public List getValues() { + return new ArrayList<>(values); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodes.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodes.java new file mode 100644 index 000000000..bf9af9556 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapNodes.java @@ -0,0 +1,80 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapNodes { + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + mappedBy = "roadmapContent") + private final List values = new ArrayList<>(); + + public RoadmapNodes(final List roadmapNodes) { + validateTitleDistinct(roadmapNodes); + this.values.addAll(new ArrayList<>(roadmapNodes)); + } + + private void validateTitleDistinct(final List roadmapNodes) { + final int distinctNameCount = roadmapNodes.stream() + .map(RoadmapNode::getTitle) + .collect(Collectors.toSet()) + .size(); + if (roadmapNodes.size() != distinctNameCount) { + throw new BadRequestException("ํ•œ ๋กœ๋“œ๋งต์— ๊ฐ™์€ ์ด๋ฆ„์˜ ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + public void add(final RoadmapNode roadmapNode) { + this.values.add(roadmapNode); + validateTitleDistinct(values); + } + + public void addAll(final RoadmapNodes roadmapNodes) { + this.values.addAll(new ArrayList<>(roadmapNodes.values)); + validateTitleDistinct(values); + } + + public void updateAllRoadmapContent(final RoadmapContent content) { + for (final RoadmapNode roadmapNode : values) { + updateRoadmapContent(roadmapNode, content); + } + } + + private void updateRoadmapContent(final RoadmapNode roadmapNode, final RoadmapContent content) { + if (roadmapNode.isNotSameRoadmapContent(content)) { + roadmapNode.updateRoadmapContent(content); + } + } + + public Optional findById(final Long roadmapNodeId) { + return values.stream() + .filter(it -> it.getId().equals(roadmapNodeId)) + .findAny(); + } + + public Optional findByTitle(final String title) { + return values.stream() + .filter(it -> it.getTitle().equals(title)) + .findAny(); + } + + public int size() { + return values.size(); + } + + public List getValues() { + return new ArrayList<>(values); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapReview.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapReview.java new file mode 100644 index 000000000..f38b30b25 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapReview.java @@ -0,0 +1,88 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.BaseUpdatedTimeEntity; +import co.kirikiri.domain.member.Member; +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapReview extends BaseUpdatedTimeEntity { + + private static final int MIN_RATE = 0; + private static final int MAX_RATE = 5; + private static final int RATE_UNIT = 5; + private static final String RATE_FORMAT = String.format("(%d(\\.%d)?|[%d-%d](\\.0|\\.%d)?)", MAX_RATE, MIN_RATE, + MIN_RATE, MAX_RATE - 1, RATE_UNIT); + private static final int CONTENT_MAX_LENGTH = 1000; + + @Column(length = 1200) + private String content; + + @Column(nullable = false) + private Double rate = 0.0; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "roadmap_id") + private Roadmap roadmap; + + public RoadmapReview(final String content, final Double rate, final Member member) { + if (content != null) { + validate(content, rate); + } + this.content = content; + this.rate = rate; + this.member = member; + } + + private void validate(final String content, final Double rate) { + validateContentLength(content); + validateRate(rate); + } + + private void validateContentLength(final String content) { + if (content.length() > CONTENT_MAX_LENGTH) { + throw new BadRequestException(String.format("๋ฆฌ๋ทฐ๋Š” ์ตœ๋Œ€ %d๊ธ€์ž๊นŒ์ง€ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.", CONTENT_MAX_LENGTH)); + } + } + + private void validateRate(final Double rate) { + if (!Pattern.matches(RATE_FORMAT, String.valueOf(rate))) { + throw new BadRequestException(String.format("๋ณ„์ ์€ %d๋ถ€ํ„ฐ %d๊นŒ์ง€ 0.%d ๋‹จ์œ„๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.", + MIN_RATE, MAX_RATE, RATE_UNIT)); + } + } + + public void updateRoadmap(final Roadmap roadmap) { + if (this.roadmap == null) { + this.roadmap = roadmap; + } + } + + public boolean isNotSameRoadmap(final Roadmap roadmap) { + return this.roadmap == null || !this.roadmap.equals(roadmap); + } + + public String getContent() { + return content; + } + + public Double getRate() { + return rate; + } + + public Member getMember() { + return member; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapReviews.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapReviews.java new file mode 100644 index 000000000..b006fcbcb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapReviews.java @@ -0,0 +1,24 @@ +package co.kirikiri.domain.roadmap; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapReviews { + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true, mappedBy = "roadmap") + private List values = new ArrayList<>(); + + public void add(final RoadmapReview review) { + this.values.add(review); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapStatus.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapStatus.java new file mode 100644 index 000000000..2e24fc540 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapStatus.java @@ -0,0 +1,7 @@ +package co.kirikiri.domain.roadmap; + +public enum RoadmapStatus { + + CREATED, + DELETED, +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapTag.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapTag.java new file mode 100644 index 000000000..416be4829 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapTag.java @@ -0,0 +1,33 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.BaseEntity; +import co.kirikiri.domain.roadmap.vo.RoadmapTagName; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapTag extends BaseEntity { + + @Embedded + private RoadmapTagName name; + + public RoadmapTag(final RoadmapTagName name) { + this.name = name; + } + + public RoadmapTag(final Long id, final RoadmapTagName name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public RoadmapTagName getName() { + return name; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapTags.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapTags.java new file mode 100644 index 000000000..8fdbdb5be --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/RoadmapTags.java @@ -0,0 +1,62 @@ +package co.kirikiri.domain.roadmap; + +import co.kirikiri.domain.roadmap.vo.RoadmapTagName; +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToMany; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapTags { + + private static final int MAX_COUNT = 5; + + @OneToMany(fetch = FetchType.LAZY, + cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, + orphanRemoval = true) + @JoinColumn(name = "roadmap_id", updatable = false, nullable = false) + private final Set values = new HashSet<>(); + + public RoadmapTags(final List roadmapTags) { + validate(roadmapTags); + values.addAll(new HashSet<>(roadmapTags)); + } + + private void validate(final List roadmapTags) { + validateCount(roadmapTags); + validateDuplicatedName(roadmapTags); + } + + private void validateCount(final List roadmapTags) { + if (roadmapTags.size() > MAX_COUNT) { + throw new BadRequestException( + String.format("ํƒœ๊ทธ์˜ ๊ฐœ์ˆ˜๋Š” ์ตœ๋Œ€ %d๊ฐœ๊นŒ์ง€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.", MAX_COUNT)); + } + } + + private void validateDuplicatedName(final List roadmapTags) { + final Set nonDuplicatedNames = roadmapTags.stream() + .map(RoadmapTag::getName) + .collect(Collectors.toSet()); + if (roadmapTags.size() != nonDuplicatedNames.size()) { + throw new BadRequestException("ํƒœ๊ทธ ์ด๋ฆ„์€ ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + public void addAll(final RoadmapTags tags) { + this.values.addAll(new HashSet<>(tags.values)); + } + + public Set getValues() { + return new HashSet<>(values); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/vo/RoadmapTagName.java b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/vo/RoadmapTagName.java new file mode 100644 index 000000000..d4929c78f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/domain/roadmap/vo/RoadmapTagName.java @@ -0,0 +1,51 @@ +package co.kirikiri.domain.roadmap.vo; + +import co.kirikiri.exception.BadRequestException; +import jakarta.persistence.Column; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class RoadmapTagName { + + private static final int MIN_LENGTH = 1; + private static final int MAX_LENGTH = 10; + + @Column(name = "name", length = 15) + private String value; + + public RoadmapTagName(final String value) { + final String removedSpaceValue = value.replaceAll(" ", ""); + validate(removedSpaceValue); + this.value = removedSpaceValue; + } + + private void validate(final String name) { + if (name.length() < MIN_LENGTH || name.length() > MAX_LENGTH) { + throw new BadRequestException( + String.format("ํƒœ๊ทธ ์ด๋ฆ„์€ ์ตœ์†Œ %d์ž๋ถ€ํ„ฐ ์ตœ๋Œ€ %d์ž๊นŒ์ง€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.", MIN_LENGTH, MAX_LENGTH)); + } + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final RoadmapTagName that = (RoadmapTagName) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + public String getValue() { + return value; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/exception/AuthenticationException.java b/backend/kirikiri/src/main/java/co/kirikiri/exception/AuthenticationException.java new file mode 100644 index 000000000..303cb5908 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/exception/AuthenticationException.java @@ -0,0 +1,8 @@ +package co.kirikiri.exception; + +public class AuthenticationException extends BusinessException { + + public AuthenticationException(final String message) { + super(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/exception/BadRequestException.java b/backend/kirikiri/src/main/java/co/kirikiri/exception/BadRequestException.java new file mode 100644 index 000000000..e88a97266 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/exception/BadRequestException.java @@ -0,0 +1,8 @@ +package co.kirikiri.exception; + +public class BadRequestException extends BusinessException { + + public BadRequestException(final String message) { + super(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/exception/BusinessException.java b/backend/kirikiri/src/main/java/co/kirikiri/exception/BusinessException.java new file mode 100644 index 000000000..32c3e413d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/exception/BusinessException.java @@ -0,0 +1,8 @@ +package co.kirikiri.exception; + +public class BusinessException extends RuntimeException { + + public BusinessException(final String message) { + super(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/exception/ConflictException.java b/backend/kirikiri/src/main/java/co/kirikiri/exception/ConflictException.java new file mode 100644 index 000000000..e40e602dc --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/exception/ConflictException.java @@ -0,0 +1,8 @@ +package co.kirikiri.exception; + +public class ConflictException extends BusinessException { + + public ConflictException(final String message) { + super(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/exception/ForbiddenException.java b/backend/kirikiri/src/main/java/co/kirikiri/exception/ForbiddenException.java new file mode 100644 index 000000000..11c23e4ac --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/exception/ForbiddenException.java @@ -0,0 +1,8 @@ +package co.kirikiri.exception; + +public class ForbiddenException extends RuntimeException { + + public ForbiddenException(final String message) { + super(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/exception/NotFoundException.java b/backend/kirikiri/src/main/java/co/kirikiri/exception/NotFoundException.java new file mode 100644 index 000000000..ae007e40e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/exception/NotFoundException.java @@ -0,0 +1,8 @@ +package co.kirikiri.exception; + +public class NotFoundException extends BusinessException { + + public NotFoundException(final String message) { + super(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/exception/ServerException.java b/backend/kirikiri/src/main/java/co/kirikiri/exception/ServerException.java new file mode 100644 index 000000000..aa1a6efad --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/exception/ServerException.java @@ -0,0 +1,8 @@ +package co.kirikiri.exception; + +public class ServerException extends RuntimeException { + + public ServerException(final String message) { + super(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/infra/AmazonS3FileService.java b/backend/kirikiri/src/main/java/co/kirikiri/infra/AmazonS3FileService.java new file mode 100644 index 000000000..2516a0dba --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/infra/AmazonS3FileService.java @@ -0,0 +1,84 @@ +package co.kirikiri.infra; + +import co.kirikiri.exception.ServerException; +import co.kirikiri.service.FileService; +import co.kirikiri.service.dto.FileInformation; +import com.amazonaws.SdkClientException; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest; +import com.amazonaws.services.s3.model.ObjectMetadata; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import java.io.InputStream; +import java.net.URL; +import java.util.Date; + +@Service +public class AmazonS3FileService implements FileService { + + private static final String ROOT_DIRECTORY_PROPERTY = "cloud.aws.s3.root-directory"; + private static final String SUB_DIRECTORY_PROPERTY = "cloud.aws.s3.sub-directory"; + private static final String BUCKET_PROPERTY = "cloud.aws.s3.bucket"; + private static final String EXPIRATION_PROPERTY = "cloud.aws.s3.url-expiration"; + private static final String DIRECTORY_SEPARATOR = "/"; + + private final AmazonS3 amazonS3; + private final Environment environment; + + public AmazonS3FileService(final AmazonS3 amazonS3, final Environment environment) { + this.amazonS3 = amazonS3; + this.environment = environment; + } + + @Override + public void save(final String path, final FileInformation fileInformation) { + final String key = makeKey(path); + final ObjectMetadata objectMetadata = makeObjectMetadata(fileInformation); + putObjectToS3(key, fileInformation.inputStream(), objectMetadata); + } + + private String makeKey(final String path) { + return findProperty(ROOT_DIRECTORY_PROPERTY) + DIRECTORY_SEPARATOR + + findProperty(SUB_DIRECTORY_PROPERTY) + path; + } + + private String findProperty(final String property) { + return environment.getProperty(property); + } + + private ObjectMetadata makeObjectMetadata(final FileInformation fileInformation) { + final ObjectMetadata objectMetadata = new ObjectMetadata(); + objectMetadata.setContentLength(fileInformation.size()); + objectMetadata.setContentType(fileInformation.contentType()); + return objectMetadata; + } + + private void putObjectToS3(final String key, final InputStream inputStream, final ObjectMetadata objectMetadata) { + try { + amazonS3.putObject(getBucketName(), key, inputStream, objectMetadata); + } catch (final SdkClientException sdkClientException) { + throw new ServerException(sdkClientException.getMessage()); + } + } + + private String getBucketName() { + return findProperty(BUCKET_PROPERTY); + } + + @Override + public URL generateUrl(final String path, final HttpMethod httpMethod) { + final String key = makeKey(path); + final Date expiration = createExpiration(Long.parseLong(findProperty(EXPIRATION_PROPERTY))); + final GeneratePresignedUrlRequest generatePresignedUrlRequest = + new GeneratePresignedUrlRequest(getBucketName(), key) + .withMethod(com.amazonaws.HttpMethod.valueOf(httpMethod.name())) + .withExpiration(expiration); + return amazonS3.generatePresignedUrl(generatePresignedUrlRequest); + } + + private Date createExpiration(final Long validity) { + final long now = new Date().getTime(); + return new Date(now + validity); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/QuerydslRepositorySupporter.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/QuerydslRepositorySupporter.java new file mode 100644 index 000000000..2f9f79d55 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/QuerydslRepositorySupporter.java @@ -0,0 +1,83 @@ +package co.kirikiri.persistence; + +import co.kirikiri.exception.ServerException; +import com.querydsl.core.types.EntityPath; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.dsl.PathBuilder; +import com.querydsl.core.types.dsl.PathBuilderFactory; +import com.querydsl.jpa.impl.JPAQuery; +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.annotation.PostConstruct; +import jakarta.persistence.EntityManager; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cglib.core.internal.Function; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.support.Querydsl; +import org.springframework.data.support.PageableExecutionUtils; +import org.springframework.stereotype.Repository; + +@Repository +public abstract class QuerydslRepositorySupporter { + + private final PathBuilder builder; + private Querydsl querydsl; + private EntityManager entityManager; + private JPAQueryFactory queryFactory; + + public QuerydslRepositorySupporter(final Class domainClass) { + if (domainClass == null) { + throw new ServerException("Domain class must not be null!"); + } + this.builder = new PathBuilderFactory().create(domainClass); + } + + @Autowired + public void setEntityManager(final EntityManager entityManager) { + if (entityManager == null) { + throw new ServerException("EntityManager must not be null!"); + } + this.entityManager = entityManager; + this.querydsl = new Querydsl(entityManager, builder); + this.queryFactory = new JPAQueryFactory(entityManager); + } + + @PostConstruct + public void validate() { + if (entityManager == null) { + throw new ServerException("EntityManager must not be null!"); + } + if (querydsl == null) { + throw new ServerException("Querydsl must not be null!"); + } + if (queryFactory == null) { + throw new ServerException("QueryFactory must not be null!"); + } + } + + protected JPAQuery select(final Expression expr) { + return getQueryFactory().select(expr); + } + + protected JPAQuery selectFrom(final EntityPath from) { + return getQueryFactory().selectFrom(from); + } + + protected Page applyPagination(final Pageable pageable, + final Function> contentQuery, + final Function> countQuery) { + final JPAQuery jpaContentQuery = contentQuery.apply(getQueryFactory()); + final JPAQuery jpaCountQuery = countQuery.apply(getQueryFactory()); + final List content = getQuerydsl().applyPagination(pageable, jpaContentQuery).fetch(); + return PageableExecutionUtils.getPage(content, pageable, jpaCountQuery::fetchOne); + } + + protected JPAQueryFactory getQueryFactory() { + return queryFactory; + } + + protected Querydsl getQuerydsl() { + return querydsl; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenQueryRepository.java new file mode 100644 index 000000000..771f49681 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenQueryRepository.java @@ -0,0 +1,10 @@ +package co.kirikiri.persistence.auth; + +import co.kirikiri.domain.auth.EncryptedToken; +import co.kirikiri.domain.auth.RefreshToken; +import java.util.Optional; + +public interface RefreshTokenQueryRepository { + + Optional findByTokenAndIsRevokedFalse(final EncryptedToken token); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenQueryRepositoryImpl.java new file mode 100644 index 000000000..31672da4b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenQueryRepositoryImpl.java @@ -0,0 +1,28 @@ +package co.kirikiri.persistence.auth; + +import static co.kirikiri.domain.auth.QRefreshToken.refreshToken; +import static co.kirikiri.domain.member.QMember.member; + +import co.kirikiri.domain.auth.EncryptedToken; +import co.kirikiri.domain.auth.RefreshToken; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import java.util.Optional; + +public class RefreshTokenQueryRepositoryImpl extends QuerydslRepositorySupporter implements + RefreshTokenQueryRepository { + + public RefreshTokenQueryRepositoryImpl() { + super(RefreshToken.class); + } + + @Override + public Optional findByTokenAndIsRevokedFalse(final EncryptedToken token) { + + return Optional.ofNullable(selectFrom(refreshToken) + .join(refreshToken.member, member) + .fetchJoin() + .where(refreshToken.token.eq(token)) + .where(refreshToken.isRevoked.isFalse()) + .fetchOne()); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenRepository.java new file mode 100644 index 000000000..bf457b877 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/auth/RefreshTokenRepository.java @@ -0,0 +1,8 @@ +package co.kirikiri.persistence.auth; + +import co.kirikiri.domain.auth.RefreshToken; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RefreshTokenRepository extends JpaRepository, RefreshTokenQueryRepository { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapOrderType.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapOrderType.java new file mode 100644 index 000000000..fb4ccb0b6 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapOrderType.java @@ -0,0 +1,5 @@ +package co.kirikiri.persistence.dto; + +public enum RoadmapOrderType { + LATEST, GOAL_ROOM_COUNT, PARTICIPANT_COUNT, REVIEW_RATE +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchCreatorNickname.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchCreatorNickname.java new file mode 100644 index 000000000..70ab96d1d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchCreatorNickname.java @@ -0,0 +1,14 @@ +package co.kirikiri.persistence.dto; + +public record RoadmapSearchCreatorNickname( + String value +) { + + public RoadmapSearchCreatorNickname(final String value) { + this.value = trim(value); + } + + private String trim(final String nickname) { + return nickname.trim(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchDto.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchDto.java new file mode 100644 index 000000000..adde60018 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchDto.java @@ -0,0 +1,27 @@ +package co.kirikiri.persistence.dto; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Getter +public class RoadmapSearchDto { + + private final RoadmapSearchCreatorNickname creatorName; + private final RoadmapSearchTitle title; + private final RoadmapSearchTagName tagName; + + public static RoadmapSearchDto create(final String creatorName, final String title, final String tagName) { + if (creatorName != null) { + return new RoadmapSearchDto(new RoadmapSearchCreatorNickname(creatorName), null, null); + } + if (title != null) { + return new RoadmapSearchDto(null, new RoadmapSearchTitle(title), null); + } + if (tagName != null) { + return new RoadmapSearchDto(null, null, new RoadmapSearchTagName(tagName)); + } + return new RoadmapSearchDto(null, null, null); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchTagName.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchTagName.java new file mode 100644 index 000000000..d059b45f5 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchTagName.java @@ -0,0 +1,27 @@ +package co.kirikiri.persistence.dto; + +import co.kirikiri.exception.BadRequestException; + +public record RoadmapSearchTagName( + String value +) { + + private static final int MIN_LENGTH = 1; + + public RoadmapSearchTagName(final String value) { + final String removedBlankName = removeBlank(value); + validateLength(removedBlankName); + this.value = removedBlankName; + } + + private String removeBlank(final String name) { + return name.replaceAll(" ", ""); + } + + private void validateLength(final String name) { + if (name.length() < MIN_LENGTH) { + throw new BadRequestException( + String.format("๊ฒ€์ƒ‰์–ด๋Š” ์ตœ์†Œ %d์ž๋ถ€ํ„ฐ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.", MIN_LENGTH)); + } + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchTitle.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchTitle.java new file mode 100644 index 000000000..35291df93 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/dto/RoadmapSearchTitle.java @@ -0,0 +1,27 @@ +package co.kirikiri.persistence.dto; + +import co.kirikiri.exception.BadRequestException; + +public record RoadmapSearchTitle( + String value +) { + + private static final int MIN_LENGTH = 1; + + public RoadmapSearchTitle(final String value) { + final String removedBlankTitle = removeBlank(value); + validateLength(removedBlankTitle); + this.value = removedBlankTitle; + } + + private String removeBlank(final String title) { + return title.replaceAll(" ", ""); + } + + private void validateLength(final String title) { + if (title.length() < MIN_LENGTH) { + throw new BadRequestException( + String.format("๊ฒ€์ƒ‰์–ด๋Š” ์ตœ์†Œ %d์ž๋ถ€ํ„ฐ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.", MIN_LENGTH)); + } + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedQueryRepository.java new file mode 100644 index 000000000..5cb828965 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedQueryRepository.java @@ -0,0 +1,15 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import java.util.List; + +public interface CheckFeedQueryRepository { + + List findByRunningGoalRoomRoadmapNodeWithMemberAndMemberImage(final GoalRoomRoadmapNode goalRoomRoadmapNode); + + List findByRunningGoalRoomRoadmapNode(final GoalRoomRoadmapNode currentGoalRoomRoadmapNode); + + List findByGoalRoomWithMemberAndMemberImage(final GoalRoom goalRoom); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedQueryRepositoryImpl.java new file mode 100644 index 000000000..be35407bd --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedQueryRepositoryImpl.java @@ -0,0 +1,70 @@ +package co.kirikiri.persistence.goalroom; + +import static co.kirikiri.domain.goalroom.QCheckFeed.checkFeed; +import static co.kirikiri.domain.goalroom.QGoalRoomMember.goalRoomMember; +import static co.kirikiri.domain.member.QMember.member; +import static co.kirikiri.domain.member.QMemberImage.memberImage; + +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import com.querydsl.core.types.dsl.BooleanExpression; +import java.util.List; + +public class CheckFeedQueryRepositoryImpl extends QuerydslRepositorySupporter implements CheckFeedQueryRepository { + + public CheckFeedQueryRepositoryImpl() { + super(CheckFeed.class); + } + + @Override + public List findByRunningGoalRoomRoadmapNodeWithMemberAndMemberImage( + final GoalRoomRoadmapNode goalRoomRoadmapNode) { + return selectFrom(checkFeed) + .innerJoin(checkFeed.goalRoomMember, goalRoomMember) + .fetchJoin() + .innerJoin(goalRoomMember.member, member) + .fetchJoin() + .innerJoin(member.image, memberImage) + .fetchJoin() + .where(nodeCond(goalRoomRoadmapNode)) + .orderBy(checkFeed.createdAt.desc()) + .fetch(); + } + + @Override + public List findByRunningGoalRoomRoadmapNode( + final GoalRoomRoadmapNode currentGoalRoomRoadmapNode) { + return selectFrom(checkFeed) + .innerJoin(checkFeed.goalRoomMember, goalRoomMember) + .fetchJoin() + .innerJoin(goalRoomMember.member, member) + .fetchJoin() + .where(nodeCond(currentGoalRoomRoadmapNode)) + .orderBy(checkFeed.createdAt.desc()) + .fetch(); + } + + @Override + public List findByGoalRoomWithMemberAndMemberImage(final GoalRoom goalRoom) { + return selectFrom(checkFeed) + .innerJoin(checkFeed.goalRoomMember, goalRoomMember) + .fetchJoin() + .innerJoin(goalRoomMember.member, member) + .fetchJoin() + .innerJoin(member.image, memberImage) + .fetchJoin() + .where(goalRoomCond(goalRoom)) + .orderBy(checkFeed.createdAt.desc()) + .fetch(); + } + + private BooleanExpression nodeCond(final GoalRoomRoadmapNode node) { + return checkFeed.goalRoomRoadmapNode.eq(node); + } + + private BooleanExpression goalRoomCond(final GoalRoom goalRoom) { + return goalRoomMember.goalRoom.eq(goalRoom); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedRepository.java new file mode 100644 index 000000000..1440fb02b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/CheckFeedRepository.java @@ -0,0 +1,42 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; + +public interface CheckFeedRepository extends JpaRepository, CheckFeedQueryRepository { + + @Query("SELECT cf" + + " FROM CheckFeed cf" + + " WHERE cf.goalRoomMember = :goalRoomMember" + + " AND cf.createdAt >= :start" + + " AND cf.createdAt < :end") + Optional findByGoalRoomMemberAndDateTime(final GoalRoomMember goalRoomMember, final LocalDateTime start, + final LocalDateTime end); + + @Query("SELECT COUNT(cf)" + + " FROM CheckFeed cf" + + " WHERE cf.goalRoomMember = :goalRoomMember") + int countByGoalRoomMember(final GoalRoomMember goalRoomMember); + + @Query("SELECT COUNT(cf)" + + " FROM CheckFeed cf" + + " WHERE cf.goalRoomMember = :goalRoomMember" + + " AND cf.goalRoomRoadmapNode = :goalRoomRoadmapNode") + int countByGoalRoomMemberAndGoalRoomRoadmapNode(final GoalRoomMember goalRoomMember, + final GoalRoomRoadmapNode goalRoomRoadmapNode); + + @Query("SELECT cf" + + " FROM CheckFeed cf" + + " WHERE cf.goalRoomMember.goalRoom =:goalRoom" + + " ORDER BY cf.createdAt DESC") + List findByGoalRoom(final GoalRoom goalRoom); + + List findByGoalRoomRoadmapNode(final GoalRoomRoadmapNode goalRoomRoadmapNode); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberQueryRepository.java new file mode 100644 index 000000000..33428b2b1 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberQueryRepository.java @@ -0,0 +1,22 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import java.util.List; +import java.util.Optional; +import org.springframework.data.repository.query.Param; + +public interface GoalRoomMemberQueryRepository { + + Optional findByRoadmapIdAndMemberIdentifierAndGoalRoomStatus( + @Param("roadmapId") final Long roadmapId, + @Param("identifier") final Identifier identifier, + @Param("status") final GoalRoomStatus status); + + List findByGoalRoomIdOrderedBySortType(final Long goalRoomId, + final GoalRoomMemberSortType sortType); + + Optional findGoalRoomMember(final Long goalRoomId, final Identifier memberIdentifier); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberQueryRepositoryImpl.java new file mode 100644 index 000000000..5f83611bb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberQueryRepositoryImpl.java @@ -0,0 +1,87 @@ +package co.kirikiri.persistence.goalroom; + +import static co.kirikiri.domain.goalroom.QGoalRoom.goalRoom; +import static co.kirikiri.domain.goalroom.QGoalRoomMember.goalRoomMember; +import static co.kirikiri.domain.member.QMember.member; +import static co.kirikiri.domain.member.QMemberImage.memberImage; +import static co.kirikiri.domain.roadmap.QRoadmapContent.roadmapContent; +import static co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType.ACCOMPLISHMENT_RATE; +import static co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType.JOINED_ASC; + +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; +import java.util.List; +import java.util.Optional; + +public class GoalRoomMemberQueryRepositoryImpl extends QuerydslRepositorySupporter implements + GoalRoomMemberQueryRepository { + + public GoalRoomMemberQueryRepositoryImpl() { + super(GoalRoomMember.class); + } + + @Override + public Optional findByRoadmapIdAndMemberIdentifierAndGoalRoomStatus(final Long roadmapId, + final Identifier identifier, + final GoalRoomStatus status) { + return Optional.ofNullable(selectFrom(goalRoomMember) + .innerJoin(goalRoomMember.goalRoom, goalRoom) + .fetchJoin() + .innerJoin(goalRoom.roadmapContent, roadmapContent) + .fetchJoin() + .innerJoin(goalRoomMember.member, member) + .fetchJoin() + .where( + goalRoom.roadmapContent.roadmap.id.eq(roadmapId), + member.identifier.eq(identifier), + goalRoom.status.eq(status)) + .fetchOne()); + } + + @Override + public List findByGoalRoomIdOrderedBySortType(final Long goalRoomId, + final GoalRoomMemberSortType sortType) { + return selectFrom(goalRoomMember) + .innerJoin(goalRoomMember.member, member) + .fetchJoin() + .innerJoin(member.image, memberImage) + .fetchJoin() + .where(goalRoomMember.goalRoom.id.eq(goalRoomId)) + .orderBy(sortCond(sortType)) + .fetch(); + } + + private OrderSpecifier sortCond(final GoalRoomMemberSortType sortType) { + if (sortType == null || sortType == ACCOMPLISHMENT_RATE) { + return goalRoomMember.accomplishmentRate.desc(); + } + if (sortType == JOINED_ASC) { + return goalRoomMember.joinedAt.asc(); + } + return goalRoomMember.joinedAt.desc(); + } + + @Override + public Optional findGoalRoomMember(final Long goalRoomId, final Identifier memberIdentifier) { + return Optional.ofNullable(selectFrom(goalRoomMember) + .innerJoin(goalRoomMember.goalRoom, goalRoom) + .where( + goalRoomIdCond(goalRoomId), + memberIdentifierCond(memberIdentifier)) + .fetchJoin() + .fetchFirst()); + } + + private BooleanExpression goalRoomIdCond(final Long goalRoomId) { + return goalRoom.id.eq(goalRoomId); + } + + private BooleanExpression memberIdentifierCond(final Identifier memberIdentifier) { + return goalRoomMember.member.identifier.eq(memberIdentifier); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberRepository.java new file mode 100644 index 000000000..22c1e050b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomMemberRepository.java @@ -0,0 +1,28 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.member.vo.Identifier; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface GoalRoomMemberRepository extends JpaRepository, GoalRoomMemberQueryRepository { + + @Query("select gm from GoalRoomMember gm " + + "inner join fetch gm.goalRoom g " + + "inner join fetch gm.member m " + + "where g=:goalRoom " + + "and m.identifier =:identifier") + Optional findByGoalRoomAndMemberIdentifier( + @Param("goalRoom") final GoalRoom goalRoom, @Param("identifier") final Identifier identifier); + + @Query("select gm from GoalRoomMember gm " + + "join fetch gm.goalRoom g " + + "join fetch gm.member m " + + "where g=:goalRoom " + + "and gm.member = m") + List findAllByGoalRoom(@Param("goalRoom") final GoalRoom goalRoom); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberQueryRepository.java new file mode 100644 index 000000000..ab5d88527 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberQueryRepository.java @@ -0,0 +1,11 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import java.util.List; + +public interface GoalRoomPendingMemberQueryRepository { + + List findByGoalRoomIdOrderedBySortType(final Long goalRoomId, + final GoalRoomMemberSortType sortType); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberQueryRepositoryImpl.java new file mode 100644 index 000000000..036c074d8 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberQueryRepositoryImpl.java @@ -0,0 +1,40 @@ +package co.kirikiri.persistence.goalroom; + +import static co.kirikiri.domain.goalroom.QGoalRoomPendingMember.goalRoomPendingMember; +import static co.kirikiri.domain.member.QMember.member; +import static co.kirikiri.domain.member.QMemberImage.memberImage; +import static co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType.JOINED_DESC; + +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import com.querydsl.core.types.OrderSpecifier; +import java.util.List; + +public class GoalRoomPendingMemberQueryRepositoryImpl extends QuerydslRepositorySupporter + implements GoalRoomPendingMemberQueryRepository { + + public GoalRoomPendingMemberQueryRepositoryImpl() { + super(GoalRoomPendingMember.class); + } + + @Override + public List findByGoalRoomIdOrderedBySortType(final Long goalRoomId, + final GoalRoomMemberSortType sortType) { + return selectFrom(goalRoomPendingMember) + .innerJoin(goalRoomPendingMember.member, member) + .fetchJoin() + .innerJoin(member.image, memberImage) + .fetchJoin() + .where(goalRoomPendingMember.goalRoom.id.eq(goalRoomId)) + .orderBy(sortCond(sortType)) + .fetch(); + } + + private OrderSpecifier sortCond(final GoalRoomMemberSortType sortType) { + if (sortType == JOINED_DESC) { + return goalRoomPendingMember.joinedAt.desc(); + } + return goalRoomPendingMember.joinedAt.asc(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberRepository.java new file mode 100644 index 000000000..a72f9397c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberRepository.java @@ -0,0 +1,31 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.domain.member.vo.Identifier; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface GoalRoomPendingMemberRepository extends JpaRepository, + GoalRoomPendingMemberQueryRepository { + + @Query("select gp from GoalRoomPendingMember gp " + + "inner join fetch gp.goalRoom g " + + "inner join fetch gp.member m " + + "where g=:goalRoom " + + "and m.identifier =:identifier") + Optional findByGoalRoomAndMemberIdentifier( + @Param("goalRoom") final GoalRoom goalRoom, @Param("identifier") final Identifier identifier); + + List findByGoalRoom(final GoalRoom goalRoom); + + @Query("select gp from GoalRoomPendingMember gp " + + "join fetch gp.goalRoom g " + + "join fetch gp.member m " + + "where g=:goalRoom " + + "and gp.member = m") + List findAllByGoalRoom(@Param("goalRoom") final GoalRoom goalRoom); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomQueryRepository.java new file mode 100644 index 000000000..3892d3985 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomQueryRepository.java @@ -0,0 +1,31 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsOrderType; +import java.util.List; +import java.util.Optional; + +public interface GoalRoomQueryRepository { + + Optional findByIdWithRoadmapContent(final Long goalRoomId); + + Optional findByIdWithContentAndTodos(final Long goalRoomId); + + List findGoalRoomsWithPendingMembersByRoadmapAndCond(final Roadmap roadmap, + final RoadmapGoalRoomsOrderType filterType, + final Long lastId, + final int pageSize); + + Optional findByIdWithTodos(final Long goalRoomId); + + List findByMember(final Member member); + + List findByMemberAndStatus(final Member member, final GoalRoomStatus goalRoomStatus); + + Optional findByIdWithNodes(final Long goalRoomId); + + List findByRoadmap(final Roadmap roadmap); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomQueryRepositoryImpl.java new file mode 100644 index 000000000..4beabc68b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomQueryRepositoryImpl.java @@ -0,0 +1,156 @@ +package co.kirikiri.persistence.goalroom; + +import static co.kirikiri.domain.goalroom.QGoalRoom.goalRoom; +import static co.kirikiri.domain.goalroom.QGoalRoomMember.goalRoomMember; +import static co.kirikiri.domain.goalroom.QGoalRoomPendingMember.goalRoomPendingMember; +import static co.kirikiri.domain.goalroom.QGoalRoomRoadmapNode.goalRoomRoadmapNode; +import static co.kirikiri.domain.goalroom.QGoalRoomToDo.goalRoomToDo; +import static co.kirikiri.domain.member.QMember.member; +import static co.kirikiri.domain.member.QMemberProfile.memberProfile; +import static co.kirikiri.domain.roadmap.QRoadmapContent.roadmapContent; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsOrderType; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; +import java.util.List; +import java.util.Optional; + +public class GoalRoomQueryRepositoryImpl extends QuerydslRepositorySupporter implements GoalRoomQueryRepository { + + private static final int LIMIT_OFFSET = 1; + + public GoalRoomQueryRepositoryImpl() { + super(GoalRoom.class); + } + + @Override + public Optional findByIdWithRoadmapContent(final Long goalRoomId) { + return Optional.ofNullable(selectFrom(goalRoom) + .innerJoin(goalRoom.roadmapContent, roadmapContent) + .fetchJoin() + .where(goalRoomIdCond(goalRoomId)) + .fetchFirst()); + } + + @Override + public Optional findByIdWithContentAndTodos(final Long goalRoomId) { + return Optional.ofNullable(selectFrom(goalRoom) + .innerJoin(goalRoom.roadmapContent, roadmapContent) + .fetchJoin() + .innerJoin(goalRoom.goalRoomToDos.values, goalRoomToDo) + .fetchJoin() + .where(goalRoomIdCond(goalRoomId)) + .fetchOne()); + } + + @Override + public List findGoalRoomsWithPendingMembersByRoadmapAndCond(final Roadmap roadmap, + final RoadmapGoalRoomsOrderType orderType, + final Long lastId, + final int pageSize) { + return selectFrom(goalRoom) + .innerJoin(goalRoom.roadmapContent, roadmapContent) + .on(roadmapContent.roadmap.eq(roadmap)) + .innerJoin(goalRoom.goalRoomPendingMembers.values, goalRoomPendingMember) + .fetchJoin() + .innerJoin(goalRoomPendingMember.member, member) + .fetchJoin() + .innerJoin(member.memberProfile, memberProfile) + .fetchJoin() + .where( + statusCond(GoalRoomStatus.RECRUITING), + lessThanLastId(lastId, orderType), + roadmapCond(roadmap)) + .limit(pageSize + LIMIT_OFFSET) + .orderBy(sortCond(orderType)) + .fetch(); + } + + @Override + public Optional findByIdWithTodos(final Long goalRoomId) { + return Optional.ofNullable(selectFrom(goalRoom) + .leftJoin(goalRoom.goalRoomToDos.values, goalRoomToDo) + .fetchJoin() + .where(goalRoomIdCond(goalRoomId)) + .fetchFirst()); + } + + @Override + public List findByMember(final Member member) { + return selectFrom(goalRoom) + .leftJoin(goalRoom.goalRoomPendingMembers.values, goalRoomPendingMember) + .leftJoin(goalRoom.goalRoomMembers.values, goalRoomMember) + .where(goalRoomPendingMember.member.eq(member) + .or(goalRoomMember.member.eq(member))) + .fetch(); + } + + @Override + public List findByMemberAndStatus(final Member member, final GoalRoomStatus goalRoomStatus) { + return selectFrom(goalRoom) + .leftJoin(goalRoom.goalRoomPendingMembers.values, goalRoomPendingMember) + .leftJoin(goalRoom.goalRoomMembers.values, goalRoomMember) + .where(goalRoomPendingMember.member.eq(member) + .or(goalRoomMember.member.eq(member))) + .where(statusCond(goalRoomStatus)) + .fetch(); + } + + @Override + public Optional findByIdWithNodes(final Long goalRoomId) { + return Optional.ofNullable(selectFrom(goalRoom) + .innerJoin(goalRoom.goalRoomRoadmapNodes.values, goalRoomRoadmapNode) + .fetchJoin() + .where(goalRoomIdCond(goalRoomId)) + .fetchOne()); + } + + @Override + public List findByRoadmap(final Roadmap roadmap) { + return selectFrom(goalRoom) + .innerJoin(goalRoom.roadmapContent, roadmapContent) + .where(roadmapContent.roadmap.eq(roadmap)) + .fetch(); + } + + private BooleanExpression goalRoomIdCond(final Long goalRoomId) { + return goalRoom.id.eq(goalRoomId); + } + + private BooleanExpression statusCond(final GoalRoomStatus status) { + return goalRoom.status.eq(status); + } + + private OrderSpecifier sortCond(final RoadmapGoalRoomsOrderType orderType) { + if (orderType == RoadmapGoalRoomsOrderType.CLOSE_TO_DEADLINE) { + return goalRoom.startDate.asc(); + } + return goalRoom.createdAt.desc(); + } + + private BooleanExpression lessThanLastId(final Long lastId, final RoadmapGoalRoomsOrderType orderType) { + if (lastId == null) { + return null; + } + if (orderType == RoadmapGoalRoomsOrderType.CLOSE_TO_DEADLINE) { + return select(goalRoom.startDate) + .from(goalRoom) + .where(goalRoom.id.eq(lastId)) + .lt(goalRoom.startDate); + } + return goalRoom.createdAt.lt( + select(goalRoom.createdAt) + .from(goalRoom) + .where(goalRoom.id.eq(lastId)) + ); + } + + private BooleanExpression roadmapCond(final Roadmap roadmap) { + return goalRoom.roadmapContent.roadmap.eq(roadmap); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomRepository.java new file mode 100644 index 000000000..ebcc375b1 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomRepository.java @@ -0,0 +1,16 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoom; +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface GoalRoomRepository extends JpaRepository, GoalRoomQueryRepository { + + @Override + Optional findById(final Long goalRoomId); + + List findAllByStartDate(final LocalDate startDate); + List findAllByEndDate(final LocalDate endDate); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomToDoCheckRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomToDoCheckRepository.java new file mode 100644 index 000000000..5b8ec6464 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/GoalRoomToDoCheckRepository.java @@ -0,0 +1,44 @@ +package co.kirikiri.persistence.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.GoalRoomToDoCheck; +import co.kirikiri.domain.member.vo.Identifier; +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface GoalRoomToDoCheckRepository extends JpaRepository { + + @Query("select gc from GoalRoomToDoCheck gc " + + "inner join fetch gc.goalRoomMember gcm " + + "inner join fetch gcm.member m " + + "inner join fetch gcm.goalRoom g " + + "where m.identifier = :identifier " + + "and gc.goalRoomToDo = :goalRoomTodo " + + "and g.id = :goalRoomId") + Optional findByGoalRoomIdAndTodoAndMemberIdentifier( + @Param("goalRoomId") final Long goalRoomId, + @Param("goalRoomTodo") final GoalRoomToDo goalRoomToDo, + @Param("identifier") final Identifier identifier); + + @Query("select gc from GoalRoomToDoCheck gc " + + "inner join fetch gc.goalRoomMember gcm " + + "inner join fetch gcm.member m " + + "inner join fetch gcm.goalRoom g " + + "where m.identifier = :identifier " + + "and g.id = :goalRoomId ") + List findByGoalRoomIdAndMemberIdentifier( + @Param("goalRoomId") final Long goalRoomId, + @Param("identifier") final Identifier identifier); + + @Modifying + @Query("delete from GoalRoomToDoCheck gc " + + "where gc.goalRoomMember = :goalRoomMember " + + "and gc.goalRoomToDo.id = :todoId") + void deleteByGoalRoomMemberAndToDoId(@Param("goalRoomMember") final GoalRoomMember goalRoomMember, + @Param("todoId") final Long todoId); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/GoalRoomFilterType.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/GoalRoomFilterType.java new file mode 100644 index 000000000..a102fa9eb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/GoalRoomFilterType.java @@ -0,0 +1,5 @@ +package co.kirikiri.persistence.goalroom.dto; + +public enum GoalRoomFilterType { + LATEST, PARTICIPATION_RATE +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/GoalRoomMemberSortType.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/GoalRoomMemberSortType.java new file mode 100644 index 000000000..417a74f29 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/GoalRoomMemberSortType.java @@ -0,0 +1,14 @@ +package co.kirikiri.persistence.goalroom.dto; + +public enum GoalRoomMemberSortType { + + JOINED_ASC("๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์˜ค๋ž˜๋œ ์ˆœ)"), + JOINED_DESC("๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์ตœ์‹ ์ˆœ)"), + ACCOMPLISHMENT_RATE("๋‹ฌ์„ฑ๋ฅ  ์ˆœ"); + + private final String description; + + GoalRoomMemberSortType(final String description) { + this.description = description; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/RoadmapGoalRoomsOrderType.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/RoadmapGoalRoomsOrderType.java new file mode 100644 index 000000000..17a5256d3 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/goalroom/dto/RoadmapGoalRoomsOrderType.java @@ -0,0 +1,5 @@ +package co.kirikiri.persistence.goalroom.dto; + +public enum RoadmapGoalRoomsOrderType { + LATEST, CLOSE_TO_DEADLINE +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberQueryRepository.java new file mode 100644 index 000000000..8a11d80b8 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberQueryRepository.java @@ -0,0 +1,11 @@ +package co.kirikiri.persistence.member; + +import co.kirikiri.domain.member.Member; +import java.util.Optional; + +public interface MemberQueryRepository { + + Optional findWithMemberProfileAndImageByIdentifier(final String identifier); + + Optional findWithMemberProfileAndImageById(final Long memberId); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberQueryRepositoryImpl.java new file mode 100644 index 000000000..9d725af72 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberQueryRepositoryImpl.java @@ -0,0 +1,38 @@ +package co.kirikiri.persistence.member; + +import static co.kirikiri.domain.member.QMember.member; +import static co.kirikiri.domain.member.QMemberImage.memberImage; +import static co.kirikiri.domain.member.QMemberProfile.memberProfile; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import java.util.Optional; + +public class MemberQueryRepositoryImpl extends QuerydslRepositorySupporter implements MemberQueryRepository { + + public MemberQueryRepositoryImpl() { + super(Member.class); + } + + @Override + public Optional findWithMemberProfileAndImageByIdentifier(final String identifier) { + return Optional.ofNullable(selectFrom(member) + .innerJoin(member.memberProfile, memberProfile) + .fetchJoin() + .innerJoin(member.image, memberImage) + .fetchJoin() + .where(member.identifier.value.eq(identifier)) + .fetchOne()); + } + + @Override + public Optional findWithMemberProfileAndImageById(final Long memberId) { + return Optional.ofNullable(selectFrom(member) + .innerJoin(member.memberProfile, memberProfile) + .fetchJoin() + .innerJoin(member.image, memberImage) + .fetchJoin() + .where(member.id.eq(memberId)) + .fetchOne()); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberRepository.java new file mode 100644 index 000000000..e09aad8ea --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/member/MemberRepository.java @@ -0,0 +1,14 @@ +package co.kirikiri.persistence.member; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MemberRepository extends JpaRepository, MemberQueryRepository { + + Optional findByIdentifier(final Identifier identifier); + + Optional findByNickname(final Nickname nickname); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapCategoryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapCategoryRepository.java new file mode 100644 index 000000000..5d1596636 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapCategoryRepository.java @@ -0,0 +1,8 @@ +package co.kirikiri.persistence.roadmap; + +import co.kirikiri.domain.roadmap.RoadmapCategory; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoadmapCategoryRepository extends JpaRepository { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapContentRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapContentRepository.java new file mode 100644 index 000000000..f7c20aaa9 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapContentRepository.java @@ -0,0 +1,18 @@ +package co.kirikiri.persistence.roadmap; + +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapContent; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface RoadmapContentRepository extends JpaRepository { + + Optional findFirstByRoadmapOrderByCreatedAtDesc(final Roadmap roadmap); + + @Query("select rc from RoadmapContent rc " + + "join fetch rc.roadmap r " + + "where rc.id = :roadmapContentId") + Optional findByIdWithRoadmap(@Param("roadmapContentId") final Long roadmapContentId); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapNodeRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapNodeRepository.java new file mode 100644 index 000000000..674c23bfe --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapNodeRepository.java @@ -0,0 +1,11 @@ +package co.kirikiri.persistence.roadmap; + +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapNode; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoadmapNodeRepository extends JpaRepository { + + List findAllByRoadmapContent(final RoadmapContent roadmapContent); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapQueryRepository.java new file mode 100644 index 000000000..05a9d838e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapQueryRepository.java @@ -0,0 +1,33 @@ +package co.kirikiri.persistence.roadmap; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapStatus; +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.persistence.dto.RoadmapSearchDto; +import java.util.List; +import java.util.Optional; + +public interface RoadmapQueryRepository { + + Optional findRoadmapById(final Long roadmapId); + + List findRoadmapsByCategory(final RoadmapCategory category, + final RoadmapOrderType orderType, + final Long lastId, + final int pageSize); + + List findRoadmapsByCond(final RoadmapSearchDto searchRequest, + final RoadmapOrderType orderType, + final Long lastId, + final int pageSize); + + List findRoadmapsWithCategoryByMemberOrderByLatest(final Member member, + final Long lastId, + final int pageSize); + + Optional findByIdAndMemberIdentifier(final Long roadmapId, final String identifier); + + List findWithRoadmapContentByStatus(final RoadmapStatus status); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapQueryRepositoryImpl.java new file mode 100644 index 000000000..a2105efc0 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapQueryRepositoryImpl.java @@ -0,0 +1,245 @@ +package co.kirikiri.persistence.roadmap; + +import static co.kirikiri.domain.goalroom.QGoalRoom.goalRoom; +import static co.kirikiri.domain.goalroom.QGoalRoomMember.goalRoomMember; +import static co.kirikiri.domain.member.QMember.member; +import static co.kirikiri.domain.roadmap.QRoadmap.roadmap; +import static co.kirikiri.domain.roadmap.QRoadmapCategory.roadmapCategory; +import static co.kirikiri.domain.roadmap.QRoadmapContent.roadmapContent; +import static co.kirikiri.domain.roadmap.QRoadmapReview.roadmapReview; +import static co.kirikiri.domain.roadmap.QRoadmapTag.roadmapTag; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapStatus; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.persistence.dto.RoadmapSearchCreatorNickname; +import co.kirikiri.persistence.dto.RoadmapSearchDto; +import co.kirikiri.persistence.dto.RoadmapSearchTagName; +import co.kirikiri.persistence.dto.RoadmapSearchTitle; +import com.querydsl.core.types.Order; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.core.types.dsl.NumberPath; +import com.querydsl.core.types.dsl.StringExpression; +import com.querydsl.jpa.impl.JPAQuery; +import java.util.List; +import java.util.Optional; + +public class RoadmapQueryRepositoryImpl extends QuerydslRepositorySupporter implements RoadmapQueryRepository { + + private static final int LIMIT_OFFSET = 1; + + public RoadmapQueryRepositoryImpl() { + super(Roadmap.class); + } + + @Override + public Optional findRoadmapById(final Long roadmapId) { + return Optional.ofNullable(selectFrom(roadmap) + .innerJoin(roadmap.creator, member) + .fetchJoin() + .innerJoin(roadmap.category, roadmapCategory) + .fetchJoin() + .leftJoin(roadmap.tags.values, roadmapTag) + .where(roadmapCond(roadmapId)) + .fetchOne()); + } + + @Override + public List findRoadmapsByCategory(final RoadmapCategory category, final RoadmapOrderType orderType, + final Long lastId, final int pageSize) { + + return selectFrom(roadmap) + .innerJoin(roadmap.category, roadmapCategory) + .fetchJoin() + .innerJoin(roadmap.creator, member) + .fetchJoin() + .leftJoin(roadmap.tags.values, roadmapTag) + .where( + lessThanLastId(lastId, orderType), + statusCond(RoadmapStatus.CREATED), + categoryCond(category)) + .limit(pageSize + LIMIT_OFFSET) + .orderBy(sortCond(orderType)) + .fetch(); + } + + @Override + public List findRoadmapsByCond(final RoadmapSearchDto searchRequest, final RoadmapOrderType orderType, + final Long lastId, final int pageSize) { + return selectFrom(roadmap) + .innerJoin(roadmap.category, roadmapCategory) + .fetchJoin() + .innerJoin(roadmap.creator, member) + .fetchJoin() + .leftJoin(roadmap.tags.values, roadmapTag) + .where( + lessThanLastId(lastId, orderType), + statusCond(RoadmapStatus.CREATED), + titleCond(searchRequest.getTitle()), + creatorNicknameCond(searchRequest.getCreatorName()), + tagCond(searchRequest.getTagName())) + .limit(pageSize + LIMIT_OFFSET) + .orderBy(sortCond(orderType)) + .fetch(); + } + + @Override + public List findRoadmapsWithCategoryByMemberOrderByLatest(final Member member, + final Long lastId, + final int pageSize) { + final RoadmapOrderType orderType = RoadmapOrderType.LATEST; + return selectFrom(roadmap) + .innerJoin(roadmap.category, roadmapCategory) + .fetchJoin() + .where( + creatorIdCond(member.getId()), + lessThanLastId(lastId, orderType)) + .limit(pageSize + LIMIT_OFFSET) + .orderBy(sortCond(orderType)) + .fetch(); + } + + @Override + public Optional findByIdAndMemberIdentifier(final Long roadmapId, final String identifier) { + return Optional.ofNullable(selectFrom(roadmap) + .where(creatorIdentifierCond(identifier), + roadmapCond(roadmapId)) + .fetchOne()); + } + + @Override + public List findWithRoadmapContentByStatus(final RoadmapStatus status) { + return selectFrom(roadmap) + .innerJoin(roadmap.contents.values, roadmapContent) + .fetchJoin() + .where(statusCond(status)) + .fetch(); + } + + private BooleanExpression roadmapCond(final Long roadmapId) { + return roadmap.id.eq(roadmapId); + } + + private BooleanExpression categoryCond(final RoadmapCategory category) { + if (category == null) { + return null; + } + return roadmap.category.eq(category); + } + + private BooleanExpression statusCond(final RoadmapStatus status) { + return roadmap.status.eq(status); + } + + private BooleanExpression titleCond(final RoadmapSearchTitle title) { + if (title == null) { + return null; + } + return removeBlank(roadmap.title).containsIgnoreCase(title.value()); + } + + private StringExpression removeBlank(final StringExpression field) { + return Expressions.stringTemplate("REPLACE({0}, ' ', '')", field); + } + + private BooleanExpression creatorIdCond(final Long creatorId) { + if (creatorId == null) { + return null; + } + return roadmap.creator.id.eq(creatorId); + } + + private BooleanExpression creatorNicknameCond(final RoadmapSearchCreatorNickname creatorName) { + if (creatorName == null) { + return null; + } + return roadmap.creator.nickname.value.eq(creatorName.value()); + } + + private BooleanExpression tagCond(final RoadmapSearchTagName tagName) { + if (tagName == null) { + return null; + } + return roadmap.tags.values + .any() + .name.value + .equalsIgnoreCase(tagName.value()); + } + + private OrderSpecifier sortCond(final RoadmapOrderType orderType) { + if (orderType == RoadmapOrderType.GOAL_ROOM_COUNT) { + return new OrderSpecifier<>( + Order.DESC, + goalRoomCountCond(goalRoom.roadmapContent.roadmap.eq(roadmap)) + ); + } + if (orderType == RoadmapOrderType.PARTICIPANT_COUNT) { + return new OrderSpecifier<>( + Order.DESC, + participantCountCond(goalRoomMember.goalRoom.roadmapContent.roadmap.eq(roadmap)) + ); + } + if (orderType == RoadmapOrderType.REVIEW_RATE) { + return new OrderSpecifier<>( + Order.DESC, + reviewRateCond(roadmapReview.roadmap.eq(roadmap)) + ); + } + return roadmap.createdAt.desc(); + } + + private JPAQuery goalRoomCountCond(final BooleanExpression isSatisfiedRoadmap) { + return select(goalRoom.count()) + .from(goalRoom) + .where(isSatisfiedRoadmap); + } + + private JPAQuery participantCountCond(final BooleanExpression isSatisfiedRoadmap) { + return select(goalRoomMember.count()) + .from(goalRoomMember) + .where(isSatisfiedRoadmap); + } + + private JPAQuery reviewRateCond(final BooleanExpression isSatisfiedRoadmap) { + return select(roadmapReview.rate.avg()) + .from(roadmapReview) + .where(isSatisfiedRoadmap); + } + + private BooleanExpression lessThanLastId(final Long lastId, final RoadmapOrderType orderType) { + if (lastId == null) { + return null; + } + if (orderType == RoadmapOrderType.GOAL_ROOM_COUNT) { + final NumberPath goalRoomRoadmapId = goalRoom.roadmapContent.roadmap.id; + return goalRoomCountCond(goalRoomRoadmapId.eq(roadmap.id)) + .lt(goalRoomCountCond(goalRoomRoadmapId.eq(lastId))); + } + if (orderType == RoadmapOrderType.PARTICIPANT_COUNT) { + final NumberPath goalRoomMemberRoadmapId = goalRoomMember.goalRoom.roadmapContent.roadmap.id; + return participantCountCond(goalRoomMemberRoadmapId.eq(roadmap.id)) + .lt(participantCountCond(goalRoomMemberRoadmapId.eq(lastId))); + } + if (orderType == RoadmapOrderType.REVIEW_RATE) { + final NumberPath roadmapReviewRoadmapId = roadmapReview.roadmap.id; + return reviewRateCond(roadmapReviewRoadmapId.eq(roadmap.id)) + .lt(reviewRateCond(roadmapReviewRoadmapId.eq(lastId))); + } + return roadmap.createdAt.lt( + select(roadmap.createdAt) + .from(roadmap) + .where(roadmap.id.eq(lastId)) + ); + } + + private BooleanExpression creatorIdentifierCond(final String identifier) { + final Identifier creatorIdentifier = new Identifier(identifier); + return roadmap.creator.identifier.eq(creatorIdentifier); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapRepository.java new file mode 100644 index 000000000..6df4b1ba4 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapRepository.java @@ -0,0 +1,8 @@ +package co.kirikiri.persistence.roadmap; + +import co.kirikiri.domain.roadmap.Roadmap; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoadmapRepository extends JpaRepository, RoadmapQueryRepository { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewQueryRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewQueryRepository.java new file mode 100644 index 000000000..84a779636 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewQueryRepository.java @@ -0,0 +1,12 @@ +package co.kirikiri.persistence.roadmap; + +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapReview; +import java.util.List; + +public interface RoadmapReviewQueryRepository { + + List findRoadmapReviewWithMemberByRoadmapOrderByLatest(final Roadmap roadmap, + final Long lastId, + final int pageSize); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewQueryRepositoryImpl.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewQueryRepositoryImpl.java new file mode 100644 index 000000000..a0dc47a56 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewQueryRepositoryImpl.java @@ -0,0 +1,50 @@ +package co.kirikiri.persistence.roadmap; + +import static co.kirikiri.domain.member.QMember.member; +import static co.kirikiri.domain.roadmap.QRoadmapReview.roadmapReview; + +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapReview; +import co.kirikiri.persistence.QuerydslRepositorySupporter; +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; +import java.time.LocalDateTime; +import java.util.List; + +public class RoadmapReviewQueryRepositoryImpl extends QuerydslRepositorySupporter implements + RoadmapReviewQueryRepository { + + public RoadmapReviewQueryRepositoryImpl() { + super(RoadmapReview.class); + } + + @Override + public List findRoadmapReviewWithMemberByRoadmapOrderByLatest(final Roadmap roadmap, + final Long lastId, + final int pageSize) { + return selectFrom(roadmapReview) + .innerJoin(roadmapReview.member, member) + .fetchJoin() + .where(roadmapCond(roadmap), lessThanLastId(lastId)) + .limit(pageSize) + .orderBy(orderByCreatedAtDesc()) + .fetch(); + } + + private BooleanExpression roadmapCond(final Roadmap roadmap) { + return roadmapReview.roadmap.eq(roadmap); + } + + private BooleanExpression lessThanLastId(final Long lastId) { + if (lastId == null) { + return null; + } + return roadmapReview.createdAt.lt( + select(roadmapReview.createdAt).from(roadmapReview).where(roadmapReview.id.eq(lastId)) + ); + } + + private OrderSpecifier orderByCreatedAtDesc() { + return roadmapReview.createdAt.desc(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewRepository.java b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewRepository.java new file mode 100644 index 000000000..729324c74 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/persistence/roadmap/RoadmapReviewRepository.java @@ -0,0 +1,12 @@ +package co.kirikiri.persistence.roadmap; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapReview; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoadmapReviewRepository extends JpaRepository, RoadmapReviewQueryRepository { + + Optional findByRoadmapAndMember(final Roadmap roadmap, final Member member); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/AuthService.java b/backend/kirikiri/src/main/java/co/kirikiri/service/AuthService.java new file mode 100644 index 000000000..34becf89a --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/AuthService.java @@ -0,0 +1,98 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.auth.EncryptedToken; +import co.kirikiri.domain.auth.RefreshToken; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.persistence.auth.RefreshTokenRepository; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.service.dto.auth.LoginDto; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.auth.request.ReissueTokenRequest; +import co.kirikiri.service.dto.auth.response.AuthenticationResponse; +import co.kirikiri.service.mapper.AuthMapper; +import java.time.LocalDateTime; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class AuthService { + + private final RefreshTokenRepository refreshTokenRepository; + private final MemberRepository memberRepository; + private final TokenProvider tokenProvider; + + @Transactional + public AuthenticationResponse login(final LoginRequest loginRequest) { + final LoginDto loginDto = AuthMapper.convertToLoginDto(loginRequest); + final Member member = findMember(loginDto); + checkPassword(loginDto.password(), member); + return makeAuthenticationResponse(member); + } + + private Member findMember(final LoginDto loginDto) { + return memberRepository.findByIdentifier(loginDto.identifier()) + .orElseThrow(() -> new AuthenticationException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค.")); + } + + private void checkPassword(final Password password, final Member member) { + if (member.isPasswordMismatch(password)) { + throw new AuthenticationException("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + private AuthenticationResponse makeAuthenticationResponse(final Member member) { + final String refreshToken = tokenProvider.createRefreshToken(member.getIdentifier().getValue(), Map.of()); + saveRefreshToken(member, refreshToken); + final String accessToken = tokenProvider.createAccessToken(member.getIdentifier().getValue(), Map.of()); + return AuthMapper.convertToAuthenticationResponse(refreshToken, accessToken); + } + + private void saveRefreshToken(final Member member, final String rawRefreshToken) { + final EncryptedToken encryptedToken = new EncryptedToken(rawRefreshToken); + final LocalDateTime expiredAt = tokenProvider.findTokenExpiredAt(rawRefreshToken); + final RefreshToken refreshToken = new RefreshToken(encryptedToken, expiredAt, member); + refreshTokenRepository.save(refreshToken); + } + + public boolean isCertified(final String token) { + return tokenProvider.isValidToken(token); + } + + @Transactional + public AuthenticationResponse reissueToken(final ReissueTokenRequest reissueTokenRequest) { + checkTokenValid(reissueTokenRequest.refreshToken()); + final EncryptedToken clientRefreshToken = AuthMapper.convertToEncryptedToken(reissueTokenRequest); + final RefreshToken refreshToken = findSavedRefreshToken(clientRefreshToken); + checkTokenExpired(refreshToken); + refreshTokenRepository.delete(refreshToken); + final Member member = refreshToken.getMember(); + return makeAuthenticationResponse(member); + } + + private void checkTokenValid(final String token) { + if (!isCertified(token)) { + throw new AuthenticationException("ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + private RefreshToken findSavedRefreshToken(final EncryptedToken clientRefreshToken) { + return refreshTokenRepository.findByTokenAndIsRevokedFalse(clientRefreshToken) + .orElseThrow(() -> new AuthenticationException("ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")); + } + + private void checkTokenExpired(final RefreshToken refreshToken) { + if (refreshToken.isExpired()) { + throw new AuthenticationException("ํ† ํฐ์ด ๋งŒ๋ฃŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); + } + } + + public String findIdentifierByToken(final String token) { + return tokenProvider.findSubject(token); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/FilePathGenerator.java b/backend/kirikiri/src/main/java/co/kirikiri/service/FilePathGenerator.java new file mode 100644 index 000000000..80bcb2120 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/FilePathGenerator.java @@ -0,0 +1,6 @@ +package co.kirikiri.service; + +public interface FilePathGenerator { + + String makeFilePath(final ImageDirType dirType, String originalFileName); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/FileService.java b/backend/kirikiri/src/main/java/co/kirikiri/service/FileService.java new file mode 100644 index 000000000..74aa91ac8 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/FileService.java @@ -0,0 +1,12 @@ +package co.kirikiri.service; + +import co.kirikiri.service.dto.FileInformation; +import org.springframework.http.HttpMethod; +import java.net.URL; + +public interface FileService { + + void save(final String path, final FileInformation fileInformation); + + URL generateUrl(final String path, final HttpMethod httpMethod); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomCreateService.java b/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomCreateService.java new file mode 100644 index 000000000..63eec340a --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomCreateService.java @@ -0,0 +1,318 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.GoalRoomToDoCheck; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.goalroom.CheckFeedRepository; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomPendingMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.goalroom.GoalRoomToDoCheckRepository; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapContentRepository; +import co.kirikiri.service.dto.FileInformation; +import co.kirikiri.service.dto.goalroom.GoalRoomCreateDto; +import co.kirikiri.service.dto.goalroom.GoalRoomRoadmapNodeDto; +import co.kirikiri.service.dto.goalroom.request.CheckFeedRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import co.kirikiri.service.mapper.GoalRoomMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class GoalRoomCreateService { + + private final FileService fileService; + private final FilePathGenerator filePathGenerator; + private final MemberRepository memberRepository; + private final GoalRoomRepository goalRoomRepository; + private final RoadmapContentRepository roadmapContentRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + private final GoalRoomToDoCheckRepository goalRoomToDoCheckRepository; + private final GoalRoomPendingMemberRepository goalRoomPendingMemberRepository; + private final CheckFeedRepository checkFeedRepository; + + public Long create(final GoalRoomCreateRequest goalRoomCreateRequest, final String memberIdentifier) { + final GoalRoomCreateDto goalRoomCreateDto = GoalRoomMapper.convertToGoalRoomCreateDto(goalRoomCreateRequest); + final RoadmapContent roadmapContent = findRoadmapContentById(goalRoomCreateDto.roadmapContentId()); + validateDeletedRoadmap(roadmapContent); + validateNodeSizeEqual(roadmapContent.nodesSize(), goalRoomCreateDto.goalRoomRoadmapNodeDtosSize()); + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = makeGoalRoomRoadmapNodes( + goalRoomCreateDto.goalRoomRoadmapNodeDtos(), roadmapContent); + final Member leader = findMemberByIdentifier(memberIdentifier); + + final GoalRoom goalRoom = new GoalRoom(goalRoomCreateDto.goalRoomName(), goalRoomCreateDto.limitedMemberCount(), + roadmapContent, leader); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + goalRoom.addGoalRoomTodo(goalRoomCreateDto.goalRoomToDo()); + return goalRoomRepository.save(goalRoom).getId(); + } + + private RoadmapContent findRoadmapContentById(final Long roadmapContentId) { + return roadmapContentRepository.findByIdWithRoadmap(roadmapContentId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค.")); + } + + private void validateDeletedRoadmap(final RoadmapContent roadmapContent) { + final Roadmap roadmap = roadmapContent.getRoadmap(); + if (roadmap.isDeleted()) { + throw new BadRequestException("์‚ญ์ œ๋œ ๋กœ๋“œ๋งต์— ๋Œ€ํ•ด ๊ณจ๋ฃธ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } + + private void validateNodeSizeEqual(final int roadmapNodesSize, final int goalRoomRoadmapNodeDtosSize) { + if (roadmapNodesSize != goalRoomRoadmapNodeDtosSize) { + throw new BadRequestException("๋ชจ๋“  ๋…ธ๋“œ์— ๋Œ€ํ•ด ๊ธฐ๊ฐ„์ด ์„ค์ •๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + private GoalRoomRoadmapNodes makeGoalRoomRoadmapNodes(final List goalRoomRoadmapNodeDtos, + final RoadmapContent roadmapContent) { + final List goalRoomRoadmapNodes = goalRoomRoadmapNodeDtos.stream() + .map(it -> makeGoalRoomRoadmapNode(roadmapContent, it)) + .toList(); + return new GoalRoomRoadmapNodes(goalRoomRoadmapNodes); + } + + private GoalRoomRoadmapNode makeGoalRoomRoadmapNode(final RoadmapContent roadmapContent, + final GoalRoomRoadmapNodeDto it) { + return new GoalRoomRoadmapNode(new Period(it.startDate(), it.endDate()), it.checkCount(), + findRoadmapNode(roadmapContent, it.roadmapNodeId())); + } + + private RoadmapNode findRoadmapNode(final RoadmapContent roadmapContent, final Long roadmapNodeId) { + return roadmapContent.findRoadmapNodeById(roadmapNodeId) + .orElseThrow(() -> new NotFoundException("๋กœ๋“œ๋งต์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค.")); + } + + private Member findMemberByIdentifier(final String memberIdentifier) { + return memberRepository.findByIdentifier(new Identifier(memberIdentifier)) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + public void join(final String identifier, final Long goalRoomId) { + final Member member = findMemberByIdentifier(identifier); + final GoalRoom goalRoom = findGoalRoomById(goalRoomId); + goalRoom.join(member); + } + + private GoalRoom findGoalRoomById(final Long goalRoomId) { + return goalRoomRepository.findById(goalRoomId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)); + } + + public Long addGoalRoomTodo(final Long goalRoomId, final String identifier, + final GoalRoomTodoRequest goalRoomTodoRequest) { + final Member member = findMemberByIdentifier(identifier); + final GoalRoom goalRoom = findGoalRoomById(goalRoomId); + checkGoalRoomCompleted(goalRoom); + checkGoalRoomLeader(member, goalRoom, "๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + final GoalRoomToDo goalRoomToDo = GoalRoomMapper.convertToGoalRoomTodo(goalRoomTodoRequest); + goalRoom.addGoalRoomTodo(goalRoomToDo); + goalRoomRepository.save(goalRoom); + return goalRoom.findLastGoalRoomTodo().getId(); + } + + private void checkGoalRoomCompleted(final GoalRoom goalRoom) { + if (goalRoom.isCompleted()) { + throw new BadRequestException("์ด๋ฏธ ์ข…๋ฃŒ๋œ ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค."); + } + } + + private void checkGoalRoomLeader(final Member member, final GoalRoom goalRoom, final String errorMessage) { + if (goalRoom.isNotLeader(member)) { + throw new BadRequestException(errorMessage); + } + } + + public GoalRoomToDoCheckResponse checkGoalRoomTodo(final Long goalRoomId, final Long todoId, + final String identifier) { + final Identifier memberIdentifier = new Identifier(identifier); + final GoalRoom goalRoom = findGoalRoomWithTodos(goalRoomId); + final GoalRoomToDo goalRoomToDo = findGoalRoomTodoById(todoId, goalRoom); + final GoalRoomMember goalRoomMember = findGoalRoomMember(memberIdentifier, goalRoom); + + final boolean isAlreadyChecked = goalRoomToDoCheckRepository.findByGoalRoomIdAndTodoAndMemberIdentifier( + goalRoomId, goalRoomToDo, memberIdentifier).isPresent(); + if (isAlreadyChecked) { + goalRoomToDoCheckRepository.deleteByGoalRoomMemberAndToDoId(goalRoomMember, todoId); + return new GoalRoomToDoCheckResponse(false); + } + final GoalRoomToDoCheck goalRoomToDoCheck = new GoalRoomToDoCheck(goalRoomMember, goalRoomToDo); + goalRoomToDoCheckRepository.save(goalRoomToDoCheck); + return new GoalRoomToDoCheckResponse(true); + } + + private GoalRoom findGoalRoomWithTodos(final Long goalRoomId) { + return goalRoomRepository.findByIdWithTodos(goalRoomId) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)); + } + + private GoalRoomToDo findGoalRoomTodoById(final Long todoId, final GoalRoom goalRoom) { + return goalRoom.findGoalRoomTodoByTodoId(todoId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํˆฌ๋‘์ž…๋‹ˆ๋‹ค. todoId = " + todoId)); + } + + private GoalRoomMember findGoalRoomMember(final Identifier memberIdentifier, final GoalRoom goalRoom) { + return goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(goalRoom, memberIdentifier) + .orElseThrow(() -> new NotFoundException( + "๊ณจ๋ฃธ์— ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = " + goalRoom.getId() + " memberIdentifier = " + + memberIdentifier.getValue())); + } + + public String createCheckFeed(final String identifier, final Long goalRoomId, + final CheckFeedRequest checkFeedRequest) { + final MultipartFile checkFeedImage = checkFeedRequest.image(); + validateEmptyImage(checkFeedImage); + final FileInformation fileInformation = GoalRoomMapper.convertToFileInformation(checkFeedImage); + + final GoalRoom goalRoom = findGoalRoomById(goalRoomId); + final GoalRoomMember goalRoomMember = findGoalRoomMemberByGoalRoomAndIdentifier(goalRoom, identifier); + final GoalRoomRoadmapNode currentNode = getNodeByDate(goalRoom); + final int currentMemberCheckCount = checkFeedRepository.countByGoalRoomMemberAndGoalRoomRoadmapNode( + goalRoomMember, currentNode); + validateCheckCount(currentMemberCheckCount, goalRoomMember, currentNode); + updateAccomplishmentRate(goalRoom, goalRoomMember, currentMemberCheckCount); + + final String path = filePathGenerator.makeFilePath(ImageDirType.CHECK_FEED, + fileInformation.originalFileName()); + saveCheckFeed(checkFeedRequest, checkFeedImage, goalRoomMember, currentNode, path); + fileService.save(path, fileInformation); + return fileService.generateUrl(path, HttpMethod.GET).toExternalForm(); + } + + private void validateEmptyImage(final MultipartFile image) { + if (image.isEmpty()) { + throw new BadRequestException("์ธ์ฆ ํ”ผ๋“œ ๋“ฑ๋ก ์‹œ ์ด๋ฏธ์ง€๊ฐ€ ๋ฐ˜๋“œ์‹œ ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + if (image.getOriginalFilename() == null) { + throw new BadRequestException("ํŒŒ์ผ ์ด๋ฆ„์€ ๋ฐ˜๋“œ์‹œ ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + private GoalRoomMember findGoalRoomMemberByGoalRoomAndIdentifier(final GoalRoom goalRoom, final String identifier) { + return goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(goalRoom, new Identifier(identifier)) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ์— ํ•ด๋‹น ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์•„์ด๋”” = " + identifier)); + } + + private GoalRoomRoadmapNode getNodeByDate(final GoalRoom goalRoom) { + return goalRoom.findNodeByDate(LocalDate.now()) + .orElseThrow(() -> new BadRequestException("์ธ์ฆ ํ”ผ๋“œ๋Š” ๋…ธ๋“œ ๊ธฐ๊ฐ„ ๋‚ด์—๋งŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")); + } + + private void validateCheckCount(final int memberCheckCount, final GoalRoomMember member, + final GoalRoomRoadmapNode goalRoomRoadmapNode) { + validateNodeCheckCount(memberCheckCount, goalRoomRoadmapNode); + validateTodayCheckCount(member); + } + + private void validateNodeCheckCount(final int memberCheckCount, + final GoalRoomRoadmapNode goalRoomRoadmapNode) { + if (memberCheckCount >= goalRoomRoadmapNode.getCheckCount()) { + throw new BadRequestException( + "์ด๋ฒˆ ๋…ธ๋“œ์—๋Š” ์ตœ๋Œ€ " + goalRoomRoadmapNode.getCheckCount() + "๋ฒˆ๋งŒ ์ธ์ฆ ํ”ผ๋“œ๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + } + } + + private void validateTodayCheckCount(final GoalRoomMember member) { + final LocalDate today = LocalDate.now(); + final LocalDateTime todayStart = today.atStartOfDay(); + final LocalDateTime todayEnd = today.plusDays(1).atStartOfDay(); + if (checkFeedRepository.findByGoalRoomMemberAndDateTime(member, todayStart, todayEnd).isPresent()) { + throw new BadRequestException("์ด๋ฏธ ์˜ค๋Š˜ ์ธ์ฆ ํ”ผ๋“œ๋ฅผ ๋“ฑ๋กํ•˜์˜€์Šต๋‹ˆ๋‹ค."); + } + } + + private void updateAccomplishmentRate(final GoalRoom goalRoom, final GoalRoomMember goalRoomMember, + final int pastCheckCount) { + final int wholeCheckCount = goalRoom.getAllCheckCount(); + final int memberCheckCount = pastCheckCount + 1; + final Double accomplishmentRate = 100 * memberCheckCount / (double) wholeCheckCount; + goalRoomMember.updateAccomplishmentRate(accomplishmentRate); + } + + private void saveCheckFeed(final CheckFeedRequest checkFeedRequest, final MultipartFile checkFeedImage, + final GoalRoomMember goalRoomMember, final GoalRoomRoadmapNode currentNode, + final String path) { + checkFeedRepository.save( + new CheckFeed(path, ImageContentType.findImageContentType(checkFeedImage.getContentType()), + checkFeedImage.getOriginalFilename(), + checkFeedRequest.description(), currentNode, goalRoomMember)); + } + + public void startGoalRoom(final String memberIdentifier, final Long goalRoomId) { + final Member member = findMemberByIdentifier(memberIdentifier); + final GoalRoom goalRoom = findGoalRoomById(goalRoomId); + checkGoalRoomLeader(member, goalRoom, "๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ๊ณจ๋ฃธ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + validateGoalRoomStart(goalRoom); + final List goalRoomPendingMembers = goalRoom.getGoalRoomPendingMembers().getValues(); + saveGoalRoomMemberFromPendingMembers(goalRoomPendingMembers, goalRoom); + goalRoom.start(); + } + + private void validateGoalRoomStart(final GoalRoom goalRoom) { + if (goalRoom.cannotStart()) { + throw new BadRequestException("๊ณจ๋ฃธ์˜ ์‹œ์ž‘ ๋‚ ์งœ๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค."); + } + } + + private void saveGoalRoomMemberFromPendingMembers(final List goalRoomPendingMembers, + final GoalRoom goalRoom) { + final List goalRoomMembers = makeGoalRoomMembers(goalRoomPendingMembers); + goalRoom.addAllGoalRoomMembers(goalRoomMembers); + goalRoom.deleteAllPendingMembers(); + } + + private List makeGoalRoomMembers(final List goalRoomPendingMembers) { + return goalRoomPendingMembers.stream() + .map(this::makeGoalRoomMember) + .toList(); + } + + private GoalRoomMember makeGoalRoomMember(final GoalRoomPendingMember goalRoomPendingMember) { + return new GoalRoomMember(goalRoomPendingMember.getRole(), + goalRoomPendingMember.getJoinedAt(), goalRoomPendingMember.getGoalRoom(), + goalRoomPendingMember.getMember()); + } + + public void leave(final String identifier, final Long goalRoomId) { + final Member member = findMemberByIdentifier(identifier); + final GoalRoom goalRoom = findGoalRoomById(goalRoomId); + validateStatus(goalRoom); + goalRoom.leave(member); + if (goalRoom.isEmptyGoalRoom()) { + goalRoomRepository.delete(goalRoom); + } + } + + private void validateStatus(final GoalRoom goalRoom) { + if (goalRoom.isRunning()) { + throw new BadRequestException("์ง„ํ–‰์ค‘์ธ ๊ณจ๋ฃธ์—์„œ๋Š” ๋‚˜๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomReadService.java b/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomReadService.java new file mode 100644 index 000000000..312a109a1 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomReadService.java @@ -0,0 +1,310 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.goalroom.GoalRoomToDoCheck; +import co.kirikiri.domain.goalroom.GoalRoomToDos; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.exception.ForbiddenException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.goalroom.CheckFeedRepository; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomPendingMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.goalroom.GoalRoomToDoCheckRepository; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.service.dto.goalroom.CheckFeedDto; +import co.kirikiri.service.dto.goalroom.GoalRoomCheckFeedDto; +import co.kirikiri.service.dto.goalroom.GoalRoomMemberDto; +import co.kirikiri.service.dto.goalroom.GoalRoomMemberSortTypeDto; +import co.kirikiri.service.dto.goalroom.MemberGoalRoomForListDto; +import co.kirikiri.service.dto.goalroom.request.GoalRoomStatusTypeRequest; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCertifiedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomMemberResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodeResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomTodoResponse; +import co.kirikiri.service.dto.member.MemberDto; +import co.kirikiri.service.dto.member.response.MemberGoalRoomForListResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.mapper.GoalRoomMapper; +import java.net.URL; +import java.time.LocalDate; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class GoalRoomReadService { + + private final MemberRepository memberRepository; + private final GoalRoomRepository goalRoomRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + private final GoalRoomToDoCheckRepository goalRoomToDoCheckRepository; + private final GoalRoomPendingMemberRepository goalRoomPendingMemberRepository; + private final CheckFeedRepository checkFeedRepository; + private final FileService fileService; + + public GoalRoomResponse findGoalRoom(final Long goalRoomId) { + final GoalRoom goalRoom = findGoalRoomWithRoadmapContentById(goalRoomId); + return GoalRoomMapper.convertGoalRoomResponse(goalRoom); + } + + private GoalRoom findGoalRoomWithRoadmapContentById(final Long goalRoomId) { + return goalRoomRepository.findByIdWithRoadmapContent(goalRoomId) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)); + } + + public GoalRoomCertifiedResponse findGoalRoom(final String identifier, final Long goalRoomId) { + final GoalRoom goalRoom = findGoalRoomWithRoadmapContentById(goalRoomId); + final boolean isJoined = isMemberGoalRoomJoin(new Identifier(identifier), goalRoom); + return GoalRoomMapper.convertGoalRoomCertifiedResponse(goalRoom, isJoined); + } + + private boolean isMemberGoalRoomJoin(final Identifier identifier, final GoalRoom goalRoom) { + if (goalRoom.isRecruiting()) { + return goalRoomPendingMemberRepository.findByGoalRoomAndMemberIdentifier(goalRoom, identifier).isPresent(); + } + return goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(goalRoom, identifier).isPresent(); + } + + public List findGoalRoomMembers(final Long goalRoomId, + final GoalRoomMemberSortTypeDto sortType) { + final GoalRoom goalRoom = findGoalRoomById(goalRoomId); + final GoalRoomMemberSortType goalRoomMemberSortType = GoalRoomMapper.convertGoalRoomMemberSortType(sortType); + if (goalRoom.isRecruiting()) { + final List goalRoomPendingMembers = goalRoomPendingMemberRepository.findByGoalRoomIdOrderedBySortType( + goalRoomId, goalRoomMemberSortType); + final List goalRoomMemberDtos = makeGoalRoomMemberDtosWithAccomplishmentRateZero( + goalRoomPendingMembers); + return GoalRoomMapper.convertToGoalRoomMemberResponses(goalRoomMemberDtos); + } + final List goalRoomMembers = goalRoomMemberRepository.findByGoalRoomIdOrderedBySortType( + goalRoomId, goalRoomMemberSortType); + final List goalRoomMemberDtos = makeGoalRoomMemberDtos(goalRoomMembers); + return GoalRoomMapper.convertToGoalRoomMemberResponses(goalRoomMemberDtos); + } + + private GoalRoom findGoalRoomById(final Long goalRoomId) { + return goalRoomRepository.findById(goalRoomId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)); + } + + private List makeGoalRoomMemberDtosWithAccomplishmentRateZero( + final List goalRoomPendingMembers) { + return goalRoomPendingMembers.stream() + .map(this::makeGoalRoomMemberDtoWithAccomplishmentRateZero) + .toList(); + } + + private GoalRoomMemberDto makeGoalRoomMemberDtoWithAccomplishmentRateZero( + final GoalRoomPendingMember goalRoomPendingMember) { + final Member member = goalRoomPendingMember.getMember(); + final URL memberImageUrl = fileService.generateUrl(member.getImage().getServerFilePath(), HttpMethod.GET); + return new GoalRoomMemberDto(member.getId(), member.getNickname().getValue(), + memberImageUrl.toExternalForm(), 0D); + } + + private List makeGoalRoomMemberDtos( + final List goalRoomPendingMembers) { + return goalRoomPendingMembers.stream() + .map(this::makeGoalRoomMemberDto) + .toList(); + } + + private GoalRoomMemberDto makeGoalRoomMemberDto(final GoalRoomMember goalRoomMember) { + final Member member = goalRoomMember.getMember(); + final URL memberImageUrl = fileService.generateUrl(member.getImage().getServerFilePath(), HttpMethod.GET); + return new GoalRoomMemberDto(member.getId(), member.getNickname().getValue(), + memberImageUrl.toExternalForm(), goalRoomMember.getAccomplishmentRate()); + } + + public List findAllGoalRoomTodo(final Long goalRoomId, final String identifier) { + final GoalRoomToDos goalRoomToDos = findGoalRoomTodosByGoalRoomId(goalRoomId); + validateGoalRoomMember(goalRoomId, identifier); + final List checkedTodos = findMemberCheckedGoalRoomToDoIds(goalRoomId, identifier); + return GoalRoomMapper.convertGoalRoomTodoResponses(goalRoomToDos, checkedTodos); + } + + private void validateGoalRoomMember(final Long goalRoomId, final String identifier) { + if (goalRoomMemberRepository.findGoalRoomMember(goalRoomId, new Identifier(identifier)).isEmpty()) { + throw new ForbiddenException( + "๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId + " memberIdentifier = " + identifier); + } + } + + private GoalRoomToDos findGoalRoomTodosByGoalRoomId(final Long goalRoomId) { + return goalRoomRepository.findByIdWithTodos(goalRoomId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)) + .getGoalRoomToDos(); + } + + private List findMemberCheckedGoalRoomToDoIds(final Long goalRoomId, final String identifier) { + return goalRoomToDoCheckRepository.findByGoalRoomIdAndMemberIdentifier(goalRoomId, new Identifier(identifier)); + } + + public MemberGoalRoomResponse findMemberGoalRoom(final String identifier, final Long goalRoomId) { + final GoalRoom goalRoom = findMemberGoalRoomById(goalRoomId); + final Member member = findMemberByIdentifier(new Identifier(identifier)); + validateMemberInGoalRoom(goalRoom, member); + + final Optional currentGoalRoomRoadmapNode = findCurrentGoalRoomNode(goalRoom); + final List checkFeeds = findCheckFeedsByNodeAndGoalRoomStatus(goalRoom, currentGoalRoomRoadmapNode); + final List checkedTodos = findMemberCheckedGoalRoomToDoIds(goalRoomId, identifier); + final List checkFeedDtos = makeCheckFeedDtos(checkFeeds); + return GoalRoomMapper.convertToMemberGoalRoomResponse(goalRoom, checkFeedDtos, checkedTodos); + } + + private List makeCheckFeedDtos(final List checkFeeds) { + return checkFeeds.stream() + .map(this::makeCheckFeedDto) + .collect(Collectors.toList()); + } + + private CheckFeedDto makeCheckFeedDto(final CheckFeed checkFeed) { + final URL checkFeedImageUrl = fileService.generateUrl(checkFeed.getServerFilePath(), HttpMethod.GET); + return new CheckFeedDto(checkFeed.getId(), checkFeedImageUrl.toExternalForm(), + checkFeed.getDescription(), checkFeed.getCreatedAt()); + } + + private GoalRoom findMemberGoalRoomById(final Long goalRoomId) { + return goalRoomRepository.findByIdWithContentAndTodos(goalRoomId) + .orElseThrow(() -> new NotFoundException("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)); + } + + private Member findMemberByIdentifier(final Identifier identifier) { + return memberRepository.findByIdentifier(identifier) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + private void validateMemberInGoalRoom(final GoalRoom goalRoom, final Member member) { + if (!goalRoom.isGoalRoomMember(member)) { + throw new ForbiddenException("ํ•ด๋‹น ๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค."); + } + } + + private Optional findCurrentGoalRoomNode(final GoalRoom goalRoom) { + return goalRoom.findNodeByDate(LocalDate.now()); + } + + private List findCheckFeedsByNodeAndGoalRoomStatus(final GoalRoom goalRoom, + final Optional currentGoalRoomRoadmapNode) { + if (goalRoom.isCompleted()) { + return checkFeedRepository.findByGoalRoom(goalRoom); + } + if (goalRoom.isRunning() && currentGoalRoomRoadmapNode.isPresent()) { + return checkFeedRepository.findByRunningGoalRoomRoadmapNode(currentGoalRoomRoadmapNode.get()); + } + return Collections.emptyList(); + } + + public List findMemberGoalRooms(final String identifier) { + final Member member = findMemberByIdentifier(new Identifier(identifier)); + final List memberGoalRooms = goalRoomRepository.findByMember(member); + final List memberGoalRoomForListDtos = makeMemberGoalRoomForListDto(memberGoalRooms); + return GoalRoomMapper.convertToMemberGoalRoomForListResponses(memberGoalRoomForListDtos); + } + + private List makeMemberGoalRoomForListDto(final List memberGoalRooms) { + return memberGoalRooms.stream() + .map(this::makeMemberGoalRoomForListDto) + .toList(); + } + + private MemberGoalRoomForListDto makeMemberGoalRoomForListDto(final GoalRoom goalRoom) { + final Member leader = goalRoom.findGoalRoomLeader(); + final URL leaderImageUrl = fileService.generateUrl(leader.getImage().getServerFilePath(), HttpMethod.GET); + return new MemberGoalRoomForListDto(goalRoom.getId(), goalRoom.getName().getValue(), + goalRoom.getStatus().name(), goalRoom.getCurrentMemberCount(), + goalRoom.getLimitedMemberCount().getValue(), + goalRoom.getCreatedAt(), goalRoom.getStartDate(), goalRoom.getEndDate(), + new MemberDto(leader.getId(), leader.getNickname().getValue(), leaderImageUrl.toExternalForm())); + } + + public List findMemberGoalRoomsByStatusType(final String identifier, + final GoalRoomStatusTypeRequest goalRoomStatusTypeRequest) { + final Member member = findMemberByIdentifier(new Identifier(identifier)); + final GoalRoomStatus goalRoomStatus = GoalRoomMapper.convertToGoalRoomStatus(goalRoomStatusTypeRequest); + final List memberGoalRooms = goalRoomRepository.findByMemberAndStatus(member, goalRoomStatus); + final List memberGoalRoomForListDtos = makeMemberGoalRoomForListDto(memberGoalRooms); + return GoalRoomMapper.convertToMemberGoalRoomForListResponses(memberGoalRoomForListDtos); + } + + public List findAllGoalRoomNodes(final Long goalRoomId, final String identifier) { + final GoalRoomRoadmapNodes goalRoomNodes = findGoalRoomNodesByGoalRoomId(goalRoomId); + validateGoalRoomMember(goalRoomId, identifier); + return GoalRoomMapper.convertGoalRoomNodeResponses(goalRoomNodes); + } + + private GoalRoomRoadmapNodes findGoalRoomNodesByGoalRoomId(final Long goalRoomId) { + return goalRoomRepository.findByIdWithNodes(goalRoomId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)) + .getGoalRoomRoadmapNodes(); + } + + public List findGoalRoomCheckFeeds(final String identifier, final Long goalRoomId) { + final GoalRoom goalRoom = findGoalRoomWithNodesById(goalRoomId); + validateJoinedMemberInRunningGoalRoom(goalRoom, identifier); + final Optional currentGoalRoomRoadmapNode = findCurrentGoalRoomNode(goalRoom); + final List checkFeeds = findCheckFeedsByNodeAndGoalRoomStatusWithMember(goalRoom, + currentGoalRoomRoadmapNode); + final List goalRoomCheckFeedDtos = makeGoalRoomCheckFeedDtos(checkFeeds); + return GoalRoomMapper.convertToGoalRoomCheckFeedResponses(goalRoomCheckFeedDtos); + } + + private GoalRoom findGoalRoomWithNodesById(final Long goalRoomId) { + return goalRoomRepository.findByIdWithNodes(goalRoomId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = " + goalRoomId)); + } + + private void validateJoinedMemberInRunningGoalRoom(final GoalRoom goalRoom, final String identifier) { + if (goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(goalRoom, new Identifier(identifier)) + .isEmpty()) { + throw new ForbiddenException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ํšŒ์›์ž…๋‹ˆ๋‹ค."); + } + } + + private List findCheckFeedsByNodeAndGoalRoomStatusWithMember(final GoalRoom goalRoom, + final Optional currentGoalRoomRoadmapNode) { + if (goalRoom.isCompleted()) { + return checkFeedRepository.findByGoalRoomWithMemberAndMemberImage(goalRoom); + } + if (goalRoom.isRunning() && currentGoalRoomRoadmapNode.isPresent()) { + return checkFeedRepository.findByRunningGoalRoomRoadmapNodeWithMemberAndMemberImage( + currentGoalRoomRoadmapNode.get()); + } + return Collections.emptyList(); + } + + public List makeGoalRoomCheckFeedDtos( + final List checkFeeds) { + return checkFeeds.stream() + .map(this::makeGoalRoomCheckFeedDto) + .toList(); + } + + private GoalRoomCheckFeedDto makeGoalRoomCheckFeedDto(final CheckFeed checkFeed) { + final GoalRoomMember goalRoomMember = checkFeed.getGoalRoomMember(); + final Member member = goalRoomMember.getMember(); + + final URL memberImageUrl = fileService.generateUrl(member.getImage().getServerFilePath(), HttpMethod.GET); + + return new GoalRoomCheckFeedDto(new MemberDto(member.getId(), member.getNickname().getValue(), + memberImageUrl.toExternalForm()), makeCheckFeedDto(checkFeed)); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomScheduler.java b/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomScheduler.java new file mode 100644 index 000000000..66bb9eed2 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/GoalRoomScheduler.java @@ -0,0 +1,55 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import java.time.LocalDate; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Transactional +@RequiredArgsConstructor +public class GoalRoomScheduler { + + private final GoalRoomRepository goalRoomRepository; + + @Scheduled(cron = "0 0 0 * * *") + public void startGoalRooms() { + final List goalRoomsToStart = goalRoomRepository.findAllByStartDate(LocalDate.now()); + for (final GoalRoom goalRoom : goalRoomsToStart) { + final List goalRoomPendingMembers = goalRoom.getGoalRoomPendingMembers().getValues(); + saveGoalRoomMemberFromPendingMembers(goalRoomPendingMembers, goalRoom); + goalRoom.start(); + } + } + + private void saveGoalRoomMemberFromPendingMembers(final List goalRoomPendingMembers, + final GoalRoom goalRoom) { + final List goalRoomMembers = makeGoalRoomMembers(goalRoomPendingMembers); + goalRoom.addAllGoalRoomMembers(goalRoomMembers); + goalRoom.deleteAllPendingMembers(); + } + + private List makeGoalRoomMembers(final List goalRoomPendingMembers) { + return goalRoomPendingMembers.stream() + .map(this::makeGoalRoomMember) + .toList(); + } + + private GoalRoomMember makeGoalRoomMember(final GoalRoomPendingMember goalRoomPendingMember) { + return new GoalRoomMember(goalRoomPendingMember.getRole(), + goalRoomPendingMember.getJoinedAt(), goalRoomPendingMember.getGoalRoom(), + goalRoomPendingMember.getMember()); + } + + @Scheduled(cron = "0 0 4 * * *") + public void endGoalRooms() { + final List goalRoomsToEnd = goalRoomRepository.findAllByEndDate(LocalDate.now().minusDays(1)); + goalRoomsToEnd.forEach(GoalRoom::complete); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/ImageDirType.java b/backend/kirikiri/src/main/java/co/kirikiri/service/ImageDirType.java new file mode 100644 index 000000000..87f99dfe2 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/ImageDirType.java @@ -0,0 +1,17 @@ +package co.kirikiri.service; + +public enum ImageDirType { + CHECK_FEED("goalroom/checkfeed"), + ROADMAP_NODE("roadmap"), + USER_PROFILE("member/profile"); + + private final String dirName; + + ImageDirType(final String dirName) { + this.dirName = dirName; + } + + public String getDirName() { + return dirName; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/JwtTokenProvider.java b/backend/kirikiri/src/main/java/co/kirikiri/service/JwtTokenProvider.java new file mode 100644 index 000000000..4dc82f64e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/JwtTokenProvider.java @@ -0,0 +1,117 @@ +package co.kirikiri.service; + +import co.kirikiri.exception.AuthenticationException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import javax.crypto.SecretKey; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class JwtTokenProvider implements TokenProvider { + + private static final String TYPE_CLAIM_KEY = "type"; + private static final String UUID_CLAIM_KEY = "UUID"; + + private final String secretKey; + private final Long accessTokenValidityInSeconds; + private final Long refreshTokenValidityInSeconds; + + public JwtTokenProvider(@Value("${jwt.secret-key}") final String secretKey, + @Value("#{T(Long).parseLong('${jwt.access-token-validity-in-seconds}')}") final Long accessTokenValidityInSeconds, + @Value("#{T(Long).parseLong('${jwt.refresh-token-validity-in-seconds}')}") final Long refreshTokenValidityInSeconds) { + this.secretKey = secretKey; + this.accessTokenValidityInSeconds = accessTokenValidityInSeconds; + this.refreshTokenValidityInSeconds = refreshTokenValidityInSeconds; + } + + @Override + public String createAccessToken(final String subject, final Map claims) { + final Map copiedClaims = new HashMap<>(claims); + copiedClaims.put(TYPE_CLAIM_KEY, "Access"); + copiedClaims.put(UUID_CLAIM_KEY, generateUUID()); + return createToken(accessTokenValidityInSeconds, subject, copiedClaims); + } + + @Override + public String createRefreshToken(final String subject, final Map claims) { + final Map copiedClaims = new HashMap<>(claims); + copiedClaims.put(TYPE_CLAIM_KEY, "Refresh"); + copiedClaims.put(UUID_CLAIM_KEY, generateUUID()); + return createToken(refreshTokenValidityInSeconds, subject, copiedClaims); + } + + private String generateUUID() { + return UUID.randomUUID().toString(); + } + + private String createToken(final Long tokenValidityInSeconds, final String subject, + final Map claims) { + final SecretKey signingKey = createKey(); + final Date expiration = createExpiration(tokenValidityInSeconds); + return Jwts.builder() + .signWith(signingKey) + .setClaims(claims) + .setSubject(subject) + .setExpiration(expiration) + .compact(); + } + + private SecretKey createKey() { + final byte[] secretKeyBytes = secretKey.getBytes(StandardCharsets.UTF_8); + return Keys.hmacShaKeyFor(secretKeyBytes); + } + + private Date createExpiration(final Long validity) { + final long now = new Date().getTime(); + return new Date(now + validity); + } + + @Override + public boolean isValidToken(final String token) { + try { + parseToClaimsJws(token); + } catch (final ExpiredJwtException expiredJwtException) { + throw new AuthenticationException("Expired Token"); + } catch (final JwtException jwtException) { + throw new AuthenticationException("Invalid Token"); + } + return true; + } + + private Jws parseToClaimsJws(final String token) { + final SecretKey signingKey = createKey(); + return Jwts.parserBuilder() + .setSigningKey(signingKey) + .build() + .parseClaimsJws(token); + } + + @Override + public LocalDateTime findTokenExpiredAt(final String token) { + final Jws claimsJws = parseToClaimsJws(token); + final Date expiration = claimsJws.getBody() + .getExpiration(); + return expiration.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime(); + } + + @Override + public String findSubject(final String token) { + final Jws claimsJws = parseToClaimsJws(token); + return claimsJws.getBody() + .getSubject(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/MemberService.java b/backend/kirikiri/src/main/java/co/kirikiri/service/MemberService.java new file mode 100644 index 000000000..de5f7246b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/MemberService.java @@ -0,0 +1,114 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.exception.ConflictException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.service.dto.member.MemberInformationDto; +import co.kirikiri.service.dto.member.MemberInformationForPublicDto; +import co.kirikiri.service.dto.member.MemberJoinDto; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberInformationForPublicResponse; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import co.kirikiri.service.mapper.MemberMapper; +import java.net.URL; +import lombok.RequiredArgsConstructor; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class MemberService { + + private static final String DEFAULT_ORIGINAL_FILE_NAME_PROPERTY = "image.default.originalFileName"; + private static final String DEFAULT_SERVER_FILE_PATH_PROPERTY = "image.default.serverFilePath"; + private static final String DEFAULT_IMAGE_CONTENT_TYPE_PROPERTY = "image.default.imageContentType"; + private static final String DEFAULT_EXTENSION = "image.default.extension"; + + private final MemberRepository memberRepository; + private final Environment environment; + private final NumberGenerator numberGenerator; + private final FileService fileService; + + @Transactional + public Long join(final MemberJoinRequest memberJoinRequest) { + final MemberJoinDto memberJoinDto = MemberMapper.convertToMemberJoinDto(memberJoinRequest); + checkIdentifierDuplicate(memberJoinDto.identifier()); + checkNicknameDuplicate(memberJoinDto.nickname()); + + final EncryptedPassword encryptedPassword = new EncryptedPassword(memberJoinDto.password()); + final MemberProfile memberProfile = new MemberProfile(memberJoinDto.gender(), + memberJoinDto.birthday(), memberJoinDto.phoneNumber()); + final Member member = new Member(memberJoinDto.identifier(), encryptedPassword, + memberJoinDto.nickname(), findDefaultMemberImage(), memberProfile); + return memberRepository.save(member).getId(); + } + + private void checkNicknameDuplicate(final Nickname nickname) { + if (memberRepository.findByNickname(nickname).isPresent()) { + throw new ConflictException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋‹‰๋„ค์ž„์ž…๋‹ˆ๋‹ค."); + } + } + + private void checkIdentifierDuplicate(final Identifier identifier) { + if (memberRepository.findByIdentifier(identifier).isPresent()) { + throw new ConflictException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค."); + } + } + + private MemberImage findDefaultMemberImage() { + final String defaultOriginalFileName = environment.getProperty(DEFAULT_ORIGINAL_FILE_NAME_PROPERTY); + final String defaultServerFilePath = environment.getProperty(DEFAULT_SERVER_FILE_PATH_PROPERTY); + final String defaultImageContentType = environment.getProperty(DEFAULT_IMAGE_CONTENT_TYPE_PROPERTY); + final String defaultExtension = environment.getProperty(DEFAULT_EXTENSION); + final int randomImageNumber = numberGenerator.generate(); + return new MemberImage(defaultOriginalFileName + randomImageNumber, + defaultServerFilePath + randomImageNumber + defaultExtension, + ImageContentType.valueOf(defaultImageContentType)); + } + + public MemberInformationResponse findMemberInformation(final String identifier) { + final Member memberWithInfo = findMemberInformationByIdentifier(identifier); + final MemberInformationDto memberInformationDto = makeMemberInformationDto(memberWithInfo); + return MemberMapper.convertToMemberInformationResponse(memberInformationDto); + } + + public MemberInformationDto makeMemberInformationDto(final Member member) { + final MemberImage memberImage = member.getImage(); + final MemberProfile memberProfile = member.getMemberProfile(); + final URL imageUrl = fileService.generateUrl(memberImage.getServerFilePath(), HttpMethod.GET); + return new MemberInformationDto(member.getId(), member.getNickname().getValue(), + imageUrl.toExternalForm(), memberProfile.getGender().name(), member.getIdentifier().getValue(), + memberProfile.getPhoneNumber(), memberProfile.getBirthday()); + } + + private Member findMemberInformationByIdentifier(final String identifier) { + return memberRepository.findWithMemberProfileAndImageByIdentifier(identifier) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + public MemberInformationForPublicResponse findMemberInformationForPublic(final Long memberId) { + final Member memberWithPublicInfo = findMemberInformationByMemberId(memberId); + final URL memberimageURl = fileService.generateUrl(memberWithPublicInfo.getImage().getServerFilePath(), + HttpMethod.GET); + final MemberInformationForPublicDto memberInformationForPublicDto = + new MemberInformationForPublicDto(memberWithPublicInfo.getNickname().getValue(), + memberimageURl.toExternalForm(), + memberWithPublicInfo.getMemberProfile().getGender().name()); + return MemberMapper.convertToMemberInformationForPublicResponse(memberInformationForPublicDto); + } + + private Member findMemberInformationByMemberId(final Long memberId) { + return memberRepository.findWithMemberProfileAndImageById(memberId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค. memberId = " + memberId)); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/NumberGenerator.java b/backend/kirikiri/src/main/java/co/kirikiri/service/NumberGenerator.java new file mode 100644 index 000000000..2c289f458 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/NumberGenerator.java @@ -0,0 +1,6 @@ +package co.kirikiri.service; + +public interface NumberGenerator { + + int generate(); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/RandomNumberGenerator.java b/backend/kirikiri/src/main/java/co/kirikiri/service/RandomNumberGenerator.java new file mode 100644 index 000000000..b4997b01f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/RandomNumberGenerator.java @@ -0,0 +1,17 @@ +package co.kirikiri.service; + +import java.util.Random; +import org.springframework.stereotype.Component; + +@Component +public class RandomNumberGenerator implements NumberGenerator { + + private static final int OFFSET = 1; + private static final int MAX_NUMBER = 7; + private static final Random random = new Random(); + + @Override + public int generate() { + return random.nextInt(MAX_NUMBER) + OFFSET; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapCreateEventListener.java b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapCreateEventListener.java new file mode 100644 index 000000000..8c22e011e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapCreateEventListener.java @@ -0,0 +1,86 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImage; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ServerException; +import co.kirikiri.persistence.roadmap.RoadmapContentRepository; +import co.kirikiri.service.dto.FileInformation; +import co.kirikiri.service.dto.roadmap.RoadmapNodeSaveDto; +import co.kirikiri.service.event.RoadmapCreateEvent; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.event.TransactionalEventListener; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class RoadmapCreateEventListener { + + private final RoadmapContentRepository roadmapContentRepository; + private final FileService fileService; + private final FilePathGenerator filePathGenerator; + + @Async + @TransactionalEventListener + @Transactional + public void handleRoadmapCreate(final RoadmapCreateEvent roadmapCreateEvent) { + saveRoadmapNodeImage(roadmapCreateEvent); + } + + private void saveRoadmapNodeImage(final RoadmapCreateEvent roadmapCreateEvent) { + final RoadmapContent lastRoadmapContent = findLastRoadmapContent(roadmapCreateEvent.roadmap()); + for (final RoadmapNodeSaveDto roadmapNodeSaveDto : roadmapCreateEvent.roadmapSaveDto().roadmapNodes()) { + final RoadmapNode roadmapNode = findRoadmapNodeByTitle(lastRoadmapContent, roadmapNodeSaveDto); + final RoadmapNodeImages roadmapNodeImages = makeRoadmapNodeImages(roadmapNodeSaveDto, roadmapNode); + roadmapNode.addImages(roadmapNodeImages); + } + roadmapContentRepository.save(lastRoadmapContent); + } + + private RoadmapContent findLastRoadmapContent(final Roadmap roadmap) { + return roadmap.findLastRoadmapContent() + .orElseThrow(() -> new ServerException("๋กœ๋“œ๋งต ์ปจํ…์ธ ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")); + } + + private RoadmapNode findRoadmapNodeByTitle(final RoadmapContent lastRoadmapContent, + final RoadmapNodeSaveDto roadmapNodeSaveDto) { + return lastRoadmapContent.findRoadmapNodeByTitle(roadmapNodeSaveDto.title()) + .orElseThrow(() -> new BadRequestException( + "ํ•ด๋‹น ์ œ๋ชฉ์„ ๊ฐ€์ง€๊ณ ์žˆ๋Š” ๋กœ๋“œ๋งต ๋…ธ๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. title = " + roadmapNodeSaveDto.title())); + } + + private RoadmapNodeImages makeRoadmapNodeImages(final RoadmapNodeSaveDto roadmapNodeSaveDto, + final RoadmapNode roadmapNode) { + final List fileInformations = roadmapNodeSaveDto.fileInformations(); + final RoadmapNodeImages roadmapNodeImages = new RoadmapNodeImages(); + for (final FileInformation fileInformation : fileInformations) { + final RoadmapNodeImage roadmapNodeImage = makeRoadmapNodeImage(fileInformation); + roadmapNodeImages.add(roadmapNodeImage); + fileService.save(roadmapNodeImage.getServerFilePath(), fileInformation); + } + roadmapNode.addImages(roadmapNodeImages); + return roadmapNodeImages; + } + + private RoadmapNodeImage makeRoadmapNodeImage(final FileInformation fileInformation) { + final String originalFileName = findOriginalFileName(fileInformation); + final ImageContentType imageContentType = ImageContentType.findImageContentType(fileInformation.contentType()); + final String serverFIlePath = filePathGenerator.makeFilePath(ImageDirType.ROADMAP_NODE, originalFileName); + return new RoadmapNodeImage(originalFileName, serverFIlePath, imageContentType); + } + + private String findOriginalFileName(final FileInformation fileInformation) { + final String originalFilename = fileInformation.originalFileName(); + if (originalFilename == null) { + throw new BadRequestException("์›๋ณธ ํŒŒ์ผ์˜ ์ด๋ฆ„์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + return originalFilename; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapCreateService.java b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapCreateService.java new file mode 100644 index 000000000..348b45f38 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapCreateService.java @@ -0,0 +1,170 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.domain.roadmap.RoadmapReview; +import co.kirikiri.domain.roadmap.RoadmapTag; +import co.kirikiri.domain.roadmap.RoadmapTags; +import co.kirikiri.domain.roadmap.vo.RoadmapTagName; +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ForbiddenException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import co.kirikiri.persistence.roadmap.RoadmapReviewRepository; +import co.kirikiri.service.dto.roadmap.RoadmapNodeSaveDto; +import co.kirikiri.service.dto.roadmap.RoadmapReviewDto; +import co.kirikiri.service.dto.roadmap.RoadmapSaveDto; +import co.kirikiri.service.dto.roadmap.RoadmapTagSaveDto; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.event.RoadmapCreateEvent; +import co.kirikiri.service.mapper.RoadmapMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class RoadmapCreateService { + + private final MemberRepository memberRepository; + private final RoadmapRepository roadmapRepository; + private final RoadmapReviewRepository roadmapReviewRepository; + private final GoalRoomRepository goalRoomRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final ApplicationEventPublisher applicationEventPublisher; + + public Long create(final RoadmapSaveRequest request, final String identifier) { + final Member member = findMemberByIdentifier(identifier); + final RoadmapCategory roadmapCategory = findRoadmapCategoryById(request.categoryId()); + final RoadmapSaveDto roadmapSaveDto = RoadmapMapper.convertToRoadmapSaveDto(request); + final Roadmap roadmap = createRoadmap(member, roadmapSaveDto, roadmapCategory); + final Roadmap savedRoadmap = roadmapRepository.save(roadmap); + + applicationEventPublisher.publishEvent(new RoadmapCreateEvent(savedRoadmap, roadmapSaveDto)); + + return savedRoadmap.getId(); + } + + private Member findMemberByIdentifier(final String identifier) { + return memberRepository.findByIdentifier(new Identifier(identifier)) + .orElseThrow(() -> new AuthenticationException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + private RoadmapCategory findRoadmapCategoryById(final Long categoryId) { + return roadmapCategoryRepository.findById(categoryId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค. categoryId = " + categoryId)); + } + + private Roadmap createRoadmap(final Member member, final RoadmapSaveDto roadmapSaveDto, + final RoadmapCategory roadmapCategory) { + final RoadmapNodes roadmapNodes = makeRoadmapNodes(roadmapSaveDto.roadmapNodes()); + final RoadmapContent roadmapContent = makeRoadmapContent(roadmapSaveDto, roadmapNodes); + final RoadmapTags roadmapTags = makeRoadmapTags(roadmapSaveDto.tags()); + final Roadmap roadmap = makeRoadmap(member, roadmapSaveDto, roadmapCategory); + roadmap.addContent(roadmapContent); + roadmap.addTags(roadmapTags); + return roadmap; + } + + private RoadmapNodes makeRoadmapNodes(final List roadmapNodeSaveDtos) { + return new RoadmapNodes( + roadmapNodeSaveDtos.stream() + .map(node -> new RoadmapNode(node.title(), node.content())) + .toList() + ); + } + + private RoadmapContent makeRoadmapContent(final RoadmapSaveDto roadmapSaveDto, final RoadmapNodes roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent(roadmapSaveDto.content()); + roadmapContent.addNodes(roadmapNodes); + return roadmapContent; + } + + private RoadmapTags makeRoadmapTags(final List roadmapTagSaveDto) { + return new RoadmapTags( + roadmapTagSaveDto.stream() + .map(tag -> new RoadmapTag(new RoadmapTagName(tag.name()))) + .toList() + ); + } + + private Roadmap makeRoadmap(final Member member, final RoadmapSaveDto roadmapSaveDto, + final RoadmapCategory roadmapCategory) { + return new Roadmap(roadmapSaveDto.title(), roadmapSaveDto.introduction(), + roadmapSaveDto.requiredPeriod(), RoadmapDifficulty.valueOf(roadmapSaveDto.difficulty().name()), member, + roadmapCategory); + } + + public void createReview(final Long roadmapId, final String identifier, final RoadmapReviewSaveRequest request) { + final Roadmap roadmap = findRoadmapById(roadmapId); + final GoalRoomMember goalRoomMember = findCompletedGoalRoomMember(roadmapId, identifier); + final Member member = goalRoomMember.getMember(); + final RoadmapReviewDto roadmapReviewDto = RoadmapMapper.convertRoadmapReviewDto(request, member); + validateReviewQualification(roadmap, member); + validateReviewCount(roadmap, member); + final RoadmapReview roadmapReview = new RoadmapReview(roadmapReviewDto.content(), roadmapReviewDto.rate(), + roadmapReviewDto.member()); + roadmap.addReview(roadmapReview); + } + + private Roadmap findRoadmapById(final Long id) { + return roadmapRepository.findById(id) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = " + id)); + } + + private GoalRoomMember findCompletedGoalRoomMember(final Long roadmapId, final String identifier) { + return goalRoomMemberRepository.findByRoadmapIdAndMemberIdentifierAndGoalRoomStatus(roadmapId, + new Identifier(identifier), GoalRoomStatus.COMPLETED) + .orElseThrow(() -> new BadRequestException( + "๋กœ๋“œ๋งต์— ๋Œ€ํ•ด์„œ ์™„๋ฃŒ๋œ ๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. roadmapId = " + roadmapId + " memberIdentifier = " + identifier)); + } + + private void validateReviewQualification(final Roadmap roadmap, final Member member) { + if (roadmap.isCreator(member)) { + throw new BadRequestException( + "๋กœ๋“œ๋งต ์ƒ์„ฑ์ž๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๋‹ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. roadmapId = " + roadmap.getId() + " memberId = " + member.getId()); + } + } + + private void validateReviewCount(final Roadmap roadmap, final Member member) { + if (roadmapReviewRepository.findByRoadmapAndMember(roadmap, member).isPresent()) { + throw new BadRequestException( + "์ด๋ฏธ ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. roadmapId = " + roadmap.getId() + " memberId = " + member.getId()); + } + } + + public void deleteRoadmap(final String identifier, final Long roadmapId) { + final Roadmap roadmap = findRoadmapById(roadmapId); + validateRoadmapCreator(roadmapId, identifier); + final List goalRooms = goalRoomRepository.findByRoadmap(roadmap); + if (goalRooms.isEmpty()) { + roadmapRepository.delete(roadmap); + return; + } + roadmap.delete(); + } + + private void validateRoadmapCreator(final Long roadmapId, final String identifier) { + roadmapRepository.findByIdAndMemberIdentifier(roadmapId, identifier) + .orElseThrow(() -> new ForbiddenException("ํ•ด๋‹น ๋กœ๋“œ๋งต์„ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.")); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapReadService.java b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapReadService.java new file mode 100644 index 000000000..8b117639f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapReadService.java @@ -0,0 +1,270 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.domain.roadmap.RoadmapReview; +import co.kirikiri.domain.roadmap.RoadmapTags; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.persistence.dto.RoadmapSearchDto; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsOrderType; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapContentRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import co.kirikiri.persistence.roadmap.RoadmapReviewRepository; +import co.kirikiri.service.dto.CustomScrollRequest; +import co.kirikiri.service.dto.goalroom.RoadmapGoalRoomDto; +import co.kirikiri.service.dto.goalroom.RoadmapGoalRoomScrollDto; +import co.kirikiri.service.dto.member.MemberDto; +import co.kirikiri.service.dto.roadmap.RoadmapCategoryDto; +import co.kirikiri.service.dto.roadmap.RoadmapContentDto; +import co.kirikiri.service.dto.roadmap.RoadmapDto; +import co.kirikiri.service.dto.roadmap.RoadmapForListDto; +import co.kirikiri.service.dto.roadmap.RoadmapForListScrollDto; +import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomNumberDto; +import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomsOrderTypeDto; +import co.kirikiri.service.dto.roadmap.RoadmapNodeDto; +import co.kirikiri.service.dto.roadmap.RoadmapReviewReadDto; +import co.kirikiri.service.dto.roadmap.RoadmapTagDto; +import co.kirikiri.service.dto.roadmap.request.RoadmapOrderTypeRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSearchRequest; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapCategoryResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse; +import co.kirikiri.service.mapper.GoalRoomMapper; +import co.kirikiri.service.mapper.RoadmapMapper; +import co.kirikiri.service.mapper.ScrollResponseMapper; +import java.net.URL; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class RoadmapReadService { + + private final RoadmapRepository roadmapRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final RoadmapContentRepository roadmapContentRepository; + private final RoadmapReviewRepository roadmapReviewRepository; + private final GoalRoomRepository goalRoomRepository; + private final MemberRepository memberRepository; + private final FileService fileService; + + public RoadmapResponse findRoadmap(final Long id) { + final Roadmap roadmap = findRoadmapById(id); + final RoadmapContent recentRoadmapContent = findRecentContent(roadmap); + final List goalRooms = goalRoomRepository.findByRoadmap(roadmap); + final RoadmapGoalRoomNumberDto roadmapGoalRoomNumberDto = GoalRoomMapper.convertRoadmapGoalRoomDto(goalRooms); + final RoadmapDto roadmapDto = makeRoadmapDto(roadmap, recentRoadmapContent); + return RoadmapMapper.convertToRoadmapResponse(roadmapDto, roadmapGoalRoomNumberDto); + } + + private RoadmapDto makeRoadmapDto(final Roadmap roadmap, final RoadmapContent roadmapContent) { + final RoadmapCategory category = roadmap.getCategory(); + final Member creator = roadmap.getCreator(); + final RoadmapContentDto roadmapContentDto = new RoadmapContentDto( + roadmapContent.getId(), + roadmapContent.getContent(), + makeRoadmapNodeDtos(roadmapContent.getNodes())); + return new RoadmapDto(roadmap.getId(), new RoadmapCategoryDto(category.getId(), category.getName()), + roadmap.getTitle(), roadmap.getIntroduction(), makeMemberDto(creator), + roadmapContentDto, roadmap.getDifficulty().name(), roadmap.getRequiredPeriod(), + roadmap.getCreatedAt(), makeRoadmapTagDtos(roadmap.getTags())); + } + + private MemberDto makeMemberDto(final Member creator) { + final URL url = fileService.generateUrl(creator.getImage().getServerFilePath(), HttpMethod.GET); + return new MemberDto(creator.getId(), creator.getNickname().getValue(), url.toExternalForm()); + } + + private List makeRoadmapNodeDtos(final RoadmapNodes nodes) { + return nodes.getValues() + .stream() + .map(this::makeRoadmapNodeDto) + .toList(); + } + + private RoadmapNodeDto makeRoadmapNodeDto(final RoadmapNode roadmapNode) { + final List imageUrls = roadmapNode.getRoadmapNodeImages() + .getValues() + .stream() + .map(it -> fileService.generateUrl(it.getServerFilePath(), HttpMethod.GET).toExternalForm()) + .toList(); + return new RoadmapNodeDto(roadmapNode.getId(), roadmapNode.getTitle(), roadmapNode.getContent(), imageUrls); + } + + private List makeRoadmapTagDtos(final RoadmapTags roadmapTags) { + return roadmapTags.getValues() + .stream() + .map(it -> new RoadmapTagDto(it.getId(), it.getName().getValue())) + .toList(); + } + + private Roadmap findRoadmapById(final Long id) { + return roadmapRepository.findRoadmapById(id) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = " + id)); + } + + private RoadmapContent findRecentContent(final Roadmap roadmap) { + return roadmapContentRepository.findFirstByRoadmapOrderByCreatedAtDesc(roadmap) + .orElseThrow(() -> new NotFoundException("๋กœ๋“œ๋งต์— ์ปจํ…์ธ ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")); + } + + public RoadmapForListResponses findRoadmapsByOrderType(final Long categoryId, + final RoadmapOrderTypeRequest orderTypeRequest, + final CustomScrollRequest scrollRequest) { + final RoadmapCategory category = findCategoryById(categoryId); + final RoadmapOrderType orderType = RoadmapMapper.convertRoadmapOrderType(orderTypeRequest); + final List roadmaps = roadmapRepository.findRoadmapsByCategory(category, orderType, + scrollRequest.lastId(), scrollRequest.size()); + final RoadmapForListScrollDto roadmapForListScrollDto = makeRoadmapForListScrollDto(roadmaps, + scrollRequest.size()); + return RoadmapMapper.convertRoadmapResponses(roadmapForListScrollDto); + } + + private RoadmapCategory findCategoryById(final Long categoryId) { + if (categoryId == null) { + return null; + } + return roadmapCategoryRepository.findById(categoryId) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค. categoryId = " + categoryId)); + } + + public RoadmapForListScrollDto makeRoadmapForListScrollDto(final List roadmaps, final int requestSize) { + final List roadmapForListDtos = roadmaps.stream() + .map(this::makeRoadmapForListDto) + .toList(); + final List subDtos = ScrollResponseMapper.getSubResponses(roadmapForListDtos, requestSize); + final boolean hasNext = ScrollResponseMapper.hasNext(roadmapForListDtos.size(), requestSize); + return new RoadmapForListScrollDto(subDtos, hasNext); + } + + private RoadmapForListDto makeRoadmapForListDto(final Roadmap roadmap) { + final RoadmapCategory category = roadmap.getCategory(); + final RoadmapCategoryDto roadmapCategoryDto = new RoadmapCategoryDto(category.getId(), + category.getName()); + final Member creator = roadmap.getCreator(); + final URL creatorImageUrl = fileService.generateUrl(creator.getImage().getServerFilePath(), HttpMethod.GET); + final MemberDto memberDto = new MemberDto(creator.getId(), creator.getNickname().getValue(), + creatorImageUrl.toExternalForm()); + final List roadmapTagDtos = makeRoadmapTagDto(roadmap.getTags()); + + return new RoadmapForListDto( + roadmap.getId(), + roadmap.getTitle(), + roadmap.getIntroduction(), + roadmap.getDifficulty().name(), + roadmap.getRequiredPeriod(), + roadmap.getCreatedAt(), + memberDto, + roadmapCategoryDto, + roadmapTagDtos + ); + } + + private List makeRoadmapTagDto(final RoadmapTags roadmapTags) { + return roadmapTags.getValues() + .stream() + .map(tag -> new RoadmapTagDto(tag.getId(), tag.getName().getValue())) + .toList(); + } + + public RoadmapForListResponses search(final RoadmapOrderTypeRequest orderTypeRequest, + final RoadmapSearchRequest searchRequest, + final CustomScrollRequest scrollRequest) { + final RoadmapOrderType orderType = RoadmapMapper.convertRoadmapOrderType(orderTypeRequest); + final RoadmapSearchDto roadmapSearchDto = RoadmapSearchDto.create( + searchRequest.creatorName(), searchRequest.roadmapTitle(), searchRequest.tagName()); + final List roadmaps = roadmapRepository.findRoadmapsByCond(roadmapSearchDto, orderType, + scrollRequest.lastId(), scrollRequest.size()); + final RoadmapForListScrollDto roadmapForListScrollDto = makeRoadmapForListScrollDto(roadmaps, + scrollRequest.size()); + return RoadmapMapper.convertRoadmapResponses(roadmapForListScrollDto); + } + + public List findAllRoadmapCategories() { + final List roadmapCategories = roadmapCategoryRepository.findAll(); + return RoadmapMapper.convertRoadmapCategoryResponses(roadmapCategories); + } + + public MemberRoadmapResponses findAllMemberRoadmaps(final String identifier, + final CustomScrollRequest scrollRequest) { + final Member member = findMemberByIdentifier(identifier); + final List roadmaps = roadmapRepository.findRoadmapsWithCategoryByMemberOrderByLatest(member, + scrollRequest.lastId(), scrollRequest.size()); + return RoadmapMapper.convertMemberRoadmapResponses(roadmaps, scrollRequest.size()); + } + + private Member findMemberByIdentifier(final String identifier) { + return memberRepository.findByIdentifier(new Identifier(identifier)) + .orElseThrow(() -> new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + public RoadmapGoalRoomResponses findRoadmapGoalRoomsByOrderType(final Long roadmapId, + final RoadmapGoalRoomsOrderTypeDto orderTypeDto, + final CustomScrollRequest scrollRequest) { + final Roadmap roadmap = findRoadmapById(roadmapId); + final RoadmapGoalRoomsOrderType orderType = GoalRoomMapper.convertToGoalRoomOrderType(orderTypeDto); + final List goalRoomsWithPendingMembers = goalRoomRepository.findGoalRoomsWithPendingMembersByRoadmapAndCond( + roadmap, orderType, scrollRequest.lastId(), scrollRequest.size()); + final RoadmapGoalRoomScrollDto roadmapGoalRoomScrollDto = makeGoalRoomDtos(goalRoomsWithPendingMembers, + scrollRequest.size()); + return GoalRoomMapper.convertToRoadmapGoalRoomResponses(roadmapGoalRoomScrollDto); + } + + public RoadmapGoalRoomScrollDto makeGoalRoomDtos(final List goalRooms, + final int requestSize) { + final List roadmapGoalRoomDtos = goalRooms.stream() + .map(this::makeGoalRoomDto) + .toList(); + final List subDtos = ScrollResponseMapper.getSubResponses(roadmapGoalRoomDtos, requestSize); + final boolean hasNext = ScrollResponseMapper.hasNext(roadmapGoalRoomDtos.size(), requestSize); + return new RoadmapGoalRoomScrollDto(subDtos, hasNext); + } + + private RoadmapGoalRoomDto makeGoalRoomDto(final GoalRoom goalRoom) { + final Member goalRoomLeader = goalRoom.findGoalRoomLeader(); + return new RoadmapGoalRoomDto(goalRoom.getId(), goalRoom.getName().getValue(), + goalRoom.getCurrentMemberCount(), goalRoom.getLimitedMemberCount().getValue(), + goalRoom.getCreatedAt(), goalRoom.getStartDate(), + goalRoom.getEndDate(), makeMemberDto(goalRoomLeader)); + } + + public List findRoadmapReviews(final Long roadmapId, + final CustomScrollRequest scrollRequest) { + final Roadmap roadmap = findRoadmapById(roadmapId); + final List roadmapReviews = roadmapReviewRepository.findRoadmapReviewWithMemberByRoadmapOrderByLatest( + roadmap, scrollRequest.lastId(), scrollRequest.size()); + final List roadmapReviewReadDtos = makeRoadmapReviewReadDtos(roadmapReviews); + return RoadmapMapper.convertToRoadmapReviewResponses(roadmapReviewReadDtos); + } + + public List makeRoadmapReviewReadDtos(final List roadmapReviews) { + return roadmapReviews.stream() + .map(this::makeRoadmapReviewReadDto) + .toList(); + } + + private RoadmapReviewReadDto makeRoadmapReviewReadDto(final RoadmapReview review) { + final Member member = review.getMember(); + final URL memberImageURl = fileService.generateUrl(member.getImage().getServerFilePath(), HttpMethod.GET); + return new RoadmapReviewReadDto(review.getId(), + new MemberDto(member.getId(), member.getNickname().getValue(), memberImageURl.toExternalForm()), + review.getCreatedAt(), review.getContent(), review.getRate()); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapScheduler.java b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapScheduler.java new file mode 100644 index 000000000..2d58282be --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/RoadmapScheduler.java @@ -0,0 +1,54 @@ +package co.kirikiri.service; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapStatus; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Transactional +@RequiredArgsConstructor +public class RoadmapScheduler { + + private static final int DELETE_AFTER_MONTH = 3; + + private final RoadmapRepository roadmapRepository; + private final GoalRoomRepository goalRoomRepository; + + @Scheduled(cron = "0 0 4 * * *") + public void deleteRoadmaps() { + final RoadmapStatus status = RoadmapStatus.DELETED; + final List deletedStatusRoadmaps = roadmapRepository.findWithRoadmapContentByStatus(status); + for (final Roadmap roadmap : deletedStatusRoadmaps) { + delete(roadmap); + } + } + + private void delete(final Roadmap roadmap) { + final List goalRooms = goalRoomRepository.findByRoadmap(roadmap); + final boolean canDelete = canDeleteRoadmapBasedOnGoalRooms(goalRooms); + if (canDelete) { + deleteGoalRooms(goalRooms); + deleteRoadmap(roadmap); + } + } + + private boolean canDeleteRoadmapBasedOnGoalRooms(final List goalRooms) { + return goalRooms.stream() + .allMatch(goalRoom -> goalRoom.isCompleted() && goalRoom.isCompletedAfterMonths(DELETE_AFTER_MONTH)); + } + + private void deleteGoalRooms(final List goalRooms) { + goalRoomRepository.deleteAll(goalRooms); + } + + private void deleteRoadmap(final Roadmap roadmap) { + roadmapRepository.delete(roadmap); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/TokenProvider.java b/backend/kirikiri/src/main/java/co/kirikiri/service/TokenProvider.java new file mode 100644 index 000000000..f1d44c998 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/TokenProvider.java @@ -0,0 +1,17 @@ +package co.kirikiri.service; + +import java.time.LocalDateTime; +import java.util.Map; + +public interface TokenProvider { + + String createAccessToken(final String subject, final Map claims); + + String createRefreshToken(final String subject, final Map claims); + + boolean isValidToken(final String token); + + LocalDateTime findTokenExpiredAt(final String token); + + String findSubject(final String token); +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/UUIDFilePathGenerator.java b/backend/kirikiri/src/main/java/co/kirikiri/service/UUIDFilePathGenerator.java new file mode 100644 index 000000000..9fa83e2ed --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/UUIDFilePathGenerator.java @@ -0,0 +1,24 @@ +package co.kirikiri.service; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.UUID; +import org.springframework.stereotype.Component; + +@Component +public class UUIDFilePathGenerator implements FilePathGenerator { + + private static final String DIRECTORY_SEPARATOR = "/"; + private static final String UUID_ORIGINAL_FILE_NAME_SEPARATOR = "_"; + + @Override + public String makeFilePath(final ImageDirType dirType, final String originalFileName) { + final LocalDate currentDate = LocalDate.now(); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern( + String.format("yyyy%sMMdd", DIRECTORY_SEPARATOR)); + final String dateString = currentDate.format(formatter); + + return DIRECTORY_SEPARATOR + dateString + DIRECTORY_SEPARATOR + dirType.getDirName() + + DIRECTORY_SEPARATOR + UUID.randomUUID() + UUID_ORIGINAL_FILE_NAME_SEPARATOR + originalFileName; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/CustomScrollRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/CustomScrollRequest.java new file mode 100644 index 000000000..f76ab1dd8 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/CustomScrollRequest.java @@ -0,0 +1,11 @@ +package co.kirikiri.service.dto; + +import jakarta.validation.constraints.NotNull; + +public record CustomScrollRequest( + Long lastId, + @NotNull(message = "์‚ฌ์ด์ฆˆ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.") + Integer size +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/ErrorResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/ErrorResponse.java new file mode 100644 index 000000000..789d0f211 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/ErrorResponse.java @@ -0,0 +1,25 @@ +package co.kirikiri.service.dto; + +import java.util.Objects; + +public record ErrorResponse( + String message +) { + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ErrorResponse that = (ErrorResponse) o; + return Objects.equals(message, that.message); + } + + @Override + public int hashCode() { + return Objects.hash(message); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/FileInformation.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/FileInformation.java new file mode 100644 index 000000000..0c1fc17b7 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/FileInformation.java @@ -0,0 +1,12 @@ +package co.kirikiri.service.dto; + +import java.io.InputStream; + +public record FileInformation( + String originalFileName, + long size, + String contentType, + InputStream inputStream +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/LoginDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/LoginDto.java new file mode 100644 index 000000000..1224c1d5c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/LoginDto.java @@ -0,0 +1,11 @@ +package co.kirikiri.service.dto.auth; + +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Password; + +public record LoginDto( + Identifier identifier, + Password password +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/request/LoginRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/request/LoginRequest.java new file mode 100644 index 000000000..cc901cbdf --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/request/LoginRequest.java @@ -0,0 +1,14 @@ +package co.kirikiri.service.dto.auth.request; + +import jakarta.validation.constraints.NotBlank; + +public record LoginRequest( + + @NotBlank(message = "์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String identifier, + + @NotBlank(message = "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String password +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/request/ReissueTokenRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/request/ReissueTokenRequest.java new file mode 100644 index 000000000..68c220de0 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/request/ReissueTokenRequest.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.auth.request; + +import jakarta.validation.constraints.NotBlank; + +public record ReissueTokenRequest( + @NotBlank(message = "๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String refreshToken +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/response/AuthenticationResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/response/AuthenticationResponse.java new file mode 100644 index 000000000..5c71cf9d1 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/auth/response/AuthenticationResponse.java @@ -0,0 +1,8 @@ +package co.kirikiri.service.dto.auth.response; + +public record AuthenticationResponse( + String refreshToken, + String accessToken +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/CheckFeedDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/CheckFeedDto.java new file mode 100644 index 000000000..a1a3279eb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/CheckFeedDto.java @@ -0,0 +1,12 @@ +package co.kirikiri.service.dto.goalroom; + +import java.time.LocalDateTime; + +public record CheckFeedDto( + Long id, + String imageUrl, + String description, + LocalDateTime createdAt +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomCheckFeedDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomCheckFeedDto.java new file mode 100644 index 000000000..06e0d4323 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomCheckFeedDto.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.goalroom; + +import co.kirikiri.service.dto.member.MemberDto; + +public record GoalRoomCheckFeedDto( + MemberDto memberDto, + CheckFeedDto checkFeedDto +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomCreateDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomCreateDto.java new file mode 100644 index 000000000..28f4583cd --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomCreateDto.java @@ -0,0 +1,19 @@ +package co.kirikiri.service.dto.goalroom; + +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import java.util.List; + +public record GoalRoomCreateDto( + Long roadmapContentId, + GoalRoomName goalRoomName, + LimitedMemberCount limitedMemberCount, + GoalRoomToDo goalRoomToDo, + List goalRoomRoadmapNodeDtos +) { + + public int goalRoomRoadmapNodeDtosSize() { + return goalRoomRoadmapNodeDtos.size(); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomFilterTypeDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomFilterTypeDto.java new file mode 100644 index 000000000..596ecde51 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomFilterTypeDto.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.goalroom; + +public enum GoalRoomFilterTypeDto { + + LATEST("์ตœ์‹ ์ˆœ"), + PARTICIPATION_RATE("์ฐธ๊ฐ€์œจ ์ˆœ"); + + private final String description; + + GoalRoomFilterTypeDto(final String description) { + this.description = description; + } +} \ No newline at end of file diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomMemberDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomMemberDto.java new file mode 100644 index 000000000..01363bc1e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomMemberDto.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.goalroom; + +public record GoalRoomMemberDto( + Long memberId, + String nickname, + String imagePath, + Double accomplishmentRate +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomMemberSortTypeDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomMemberSortTypeDto.java new file mode 100644 index 000000000..a7f816eea --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomMemberSortTypeDto.java @@ -0,0 +1,14 @@ +package co.kirikiri.service.dto.goalroom; + +public enum GoalRoomMemberSortTypeDto { + + JOINED_ASC("๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์˜ค๋ž˜๋œ ์ˆœ)"), + JOINED_DESC("๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์ตœ์‹ ์ˆœ)"), + ACCOMPLISHMENT_RATE("๋‹ฌ์„ฑ๋ฅ  ์ˆœ"); + + private final String description; + + GoalRoomMemberSortTypeDto(final String description) { + this.description = description; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomRoadmapNodeDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomRoadmapNodeDto.java new file mode 100644 index 000000000..a456a23d4 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomRoadmapNodeDto.java @@ -0,0 +1,12 @@ +package co.kirikiri.service.dto.goalroom; + +import java.time.LocalDate; + +public record GoalRoomRoadmapNodeDto( + Long roadmapNodeId, + int checkCount, + LocalDate startDate, + LocalDate endDate +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomStatusTypeDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomStatusTypeDto.java new file mode 100644 index 000000000..4f59aced8 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/GoalRoomStatusTypeDto.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.goalroom; + +public enum GoalRoomStatusTypeDto { + RECRUITING("๋ชจ์ง‘ ์ค‘"), + RUNNING("์ง„ํ–‰ ์ค‘"), + COMPLETED("์™„๋ฃŒ"); + + private final String description; + + GoalRoomStatusTypeDto(final String description) { + this.description = description; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/MemberGoalRoomForListDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/MemberGoalRoomForListDto.java new file mode 100644 index 000000000..6ee615c46 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/MemberGoalRoomForListDto.java @@ -0,0 +1,19 @@ +package co.kirikiri.service.dto.goalroom; + +import co.kirikiri.service.dto.member.MemberDto; +import java.time.LocalDate; +import java.time.LocalDateTime; + +public record MemberGoalRoomForListDto( + Long goalRoomId, + String name, + String goalRoomStatus, + Integer currentMemberCount, + Integer limitedMemberCount, + LocalDateTime createdAt, + LocalDate startDate, + LocalDate endDate, + MemberDto goalRoomLeader +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/RoadmapGoalRoomDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/RoadmapGoalRoomDto.java new file mode 100644 index 000000000..0954a480c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/RoadmapGoalRoomDto.java @@ -0,0 +1,18 @@ +package co.kirikiri.service.dto.goalroom; + +import co.kirikiri.service.dto.member.MemberDto; +import java.time.LocalDate; +import java.time.LocalDateTime; + +public record RoadmapGoalRoomDto( + Long goalRoomId, + String name, + Integer currentMemberCount, + Integer limitedMemberCount, + LocalDateTime createdAt, + LocalDate startDate, + LocalDate endDate, + MemberDto goalRoomLeader +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/RoadmapGoalRoomScrollDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/RoadmapGoalRoomScrollDto.java new file mode 100644 index 000000000..59937fe0e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/RoadmapGoalRoomScrollDto.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.goalroom; + +import java.util.List; + +public record RoadmapGoalRoomScrollDto( + List roadmapGoalRoomDtos, + boolean hasNext +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/CheckFeedRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/CheckFeedRequest.java new file mode 100644 index 000000000..439284a88 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/CheckFeedRequest.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.goalroom.request; + +import org.springframework.web.multipart.MultipartFile; + +public record CheckFeedRequest( + MultipartFile image, + String description +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomCreateRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomCreateRequest.java new file mode 100644 index 000000000..e5c1e43b0 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomCreateRequest.java @@ -0,0 +1,26 @@ +package co.kirikiri.service.dto.goalroom.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.util.List; + +public record GoalRoomCreateRequest( + + @NotNull(message = "๋กœ๋“œ๋งต ์ปจํ…์ธ  ์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + Long roadmapContentId, + + @NotBlank(message = "๊ณจ๋ฃธ ์ด๋ฆ„์„ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String name, + + @NotNull(message = "๊ณจ๋ฃธ ์ œํ•œ ์ธ์›์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + Integer limitedMemberCount, + + @Valid + GoalRoomTodoRequest goalRoomTodo, + + @Valid + List goalRoomRoadmapNodeRequests +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomRoadmapNodeRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomRoadmapNodeRequest.java new file mode 100644 index 000000000..91582039e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomRoadmapNodeRequest.java @@ -0,0 +1,23 @@ +package co.kirikiri.service.dto.goalroom.request; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDate; + +public record GoalRoomRoadmapNodeRequest( + @NotNull(message = "๋กœ๋“œ๋งต ๋…ธ๋“œ ์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + Long roadmapNodeId, + + @NotNull(message = "์ธ์ฆ ํšŸ์ˆ˜๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + Integer checkCount, + + @NotNull(message = "๋กœ๋“œ๋งต ๋…ธ๋“œ ์‹œ์ž‘ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + @JsonFormat(pattern = "yyyyMMdd") + LocalDate startDate, + + @NotNull(message = "๋กœ๋“œ๋งต ๋…ธ๋“œ ์ข…๋ฃŒ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + @JsonFormat(pattern = "yyyyMMdd") + LocalDate endDate +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomStatusTypeRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomStatusTypeRequest.java new file mode 100644 index 000000000..53fd85154 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomStatusTypeRequest.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.goalroom.request; + +public enum GoalRoomStatusTypeRequest { + RECRUITING("๋ชจ์ง‘ ์ค‘"), + RUNNING("์ง„ํ–‰ ์ค‘"), + COMPLETED("์™„๋ฃŒ"); + + private final String description; + + GoalRoomStatusTypeRequest(final String description) { + this.description = description; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomTodoRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomTodoRequest.java new file mode 100644 index 000000000..8f7da0ce8 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/request/GoalRoomTodoRequest.java @@ -0,0 +1,21 @@ +package co.kirikiri.service.dto.goalroom.request; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDate; + +public record GoalRoomTodoRequest( + @NotBlank(message = "ํˆฌ๋‘์˜ ์ปจํ…์ธ ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String content, + + @NotNull(message = "๊ณจ๋ฃธ ํˆฌ๋‘ ์‹œ์ž‘ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + @JsonFormat(pattern = "yyyyMMdd") + LocalDate startDate, + + @NotNull(message = "๊ณจ๋ฃธ ํˆฌ๋‘ ์ข…๋ฃŒ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + @JsonFormat(pattern = "yyyyMMdd") + LocalDate endDate +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/CheckFeedResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/CheckFeedResponse.java new file mode 100644 index 000000000..0b2fa2869 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/CheckFeedResponse.java @@ -0,0 +1,12 @@ +package co.kirikiri.service.dto.goalroom.response; + +import java.time.LocalDate; + +public record CheckFeedResponse( + Long id, + String imageUrl, + String description, + LocalDate createdAt +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomCertifiedResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomCertifiedResponse.java new file mode 100644 index 000000000..253bb6b21 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomCertifiedResponse.java @@ -0,0 +1,14 @@ +package co.kirikiri.service.dto.goalroom.response; + +import java.util.List; + +public record GoalRoomCertifiedResponse( + String name, + Integer currentMemberCount, + Integer limitedMemberCount, + List goalRoomNodes, + int period, + boolean isJoined +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomCheckFeedResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomCheckFeedResponse.java new file mode 100644 index 000000000..011b2d38d --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomCheckFeedResponse.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.goalroom.response; + +import co.kirikiri.service.dto.member.response.MemberResponse; + +public record GoalRoomCheckFeedResponse( + MemberResponse member, + CheckFeedResponse checkFeed +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomMemberResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomMemberResponse.java new file mode 100644 index 000000000..11ef4b04f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomMemberResponse.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.goalroom.response; + +public record GoalRoomMemberResponse( + Long memberId, + String nickname, + String imagePath, + Double accomplishmentRate +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomResponse.java new file mode 100644 index 000000000..15f9df8be --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomResponse.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.goalroom.response; + +import java.util.List; + +public record GoalRoomResponse( + String name, + Integer currentMemberCount, + Integer limitedMemberCount, + List goalRoomNodes, + int period +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomRoadmapNodeResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomRoadmapNodeResponse.java new file mode 100644 index 000000000..c89b8b1a5 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomRoadmapNodeResponse.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.goalroom.response; + +import java.time.LocalDate; + +public record GoalRoomRoadmapNodeResponse( + Long id, + String title, + LocalDate startDate, + LocalDate endDate, + Integer checkCount +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomRoadmapNodesResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomRoadmapNodesResponse.java new file mode 100644 index 000000000..000dad727 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomRoadmapNodesResponse.java @@ -0,0 +1,11 @@ +package co.kirikiri.service.dto.goalroom.response; + +import java.util.List; + +public record GoalRoomRoadmapNodesResponse( + boolean hasFrontNode, + boolean hasBackNode, + List nodes +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomToDoCheckResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomToDoCheckResponse.java new file mode 100644 index 000000000..5da8c9c95 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomToDoCheckResponse.java @@ -0,0 +1,7 @@ +package co.kirikiri.service.dto.goalroom.response; + +public record GoalRoomToDoCheckResponse( + boolean isChecked +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomTodoResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomTodoResponse.java new file mode 100644 index 000000000..be7247689 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/goalroom/response/GoalRoomTodoResponse.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.goalroom.response; + +import java.time.LocalDate; + +public record GoalRoomTodoResponse( + Long id, + String content, + LocalDate startDate, + LocalDate endDate, + GoalRoomToDoCheckResponse check +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberDto.java new file mode 100644 index 000000000..e687b3c6a --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberDto.java @@ -0,0 +1,9 @@ +package co.kirikiri.service.dto.member; + +public record MemberDto( + long id, + String name, + String imageUrl +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberInformationDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberInformationDto.java new file mode 100644 index 000000000..68e0d8c03 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberInformationDto.java @@ -0,0 +1,15 @@ +package co.kirikiri.service.dto.member; + +import java.time.LocalDate; + +public record MemberInformationDto( + Long id, + String nickname, + String profileImageUrl, + String gender, + String identifier, + String phoneNumber, + LocalDate birthday +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberInformationForPublicDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberInformationForPublicDto.java new file mode 100644 index 000000000..d5438e4cb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberInformationForPublicDto.java @@ -0,0 +1,9 @@ +package co.kirikiri.service.dto.member; + +public record MemberInformationForPublicDto( + String nickname, + String profileImageUrl, + String gender +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberJoinDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberJoinDto.java new file mode 100644 index 000000000..a88b08868 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/MemberJoinDto.java @@ -0,0 +1,18 @@ +package co.kirikiri.service.dto.member; + +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import java.time.LocalDate; + +public record MemberJoinDto( + Identifier identifier, + Password password, + Nickname nickname, + String phoneNumber, + Gender gender, + LocalDate birthday +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/request/GenderType.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/request/GenderType.java new file mode 100644 index 000000000..eb9ff514c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/request/GenderType.java @@ -0,0 +1,5 @@ +package co.kirikiri.service.dto.member.request; + +public enum GenderType { + MALE, FEMALE +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/request/MemberJoinRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/request/MemberJoinRequest.java new file mode 100644 index 000000000..cfbd230cd --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/request/MemberJoinRequest.java @@ -0,0 +1,31 @@ +package co.kirikiri.service.dto.member.request; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import java.time.LocalDate; + +public record MemberJoinRequest( + @NotBlank(message = "์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String identifier, + + @NotBlank(message = "๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String password, + + @NotBlank(message = "๋‹‰๋„ค์ž„์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + String nickname, + + @NotBlank(message = "์ „ํ™”๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + @Pattern(regexp = "^010-\\d{4}-\\d{4}$", message = "์ „ํ™”๋ฒˆํ˜ธ ํ˜•์‹์ด ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.") + String phoneNumber, + + @NotNull(message = "์„ฑ๋ณ„์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + GenderType genderType, + + @NotNull(message = "์ƒ์ผ์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + @JsonFormat(pattern = "yyyyMMdd") + LocalDate birthday +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberGoalRoomForListResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberGoalRoomForListResponse.java new file mode 100644 index 000000000..dc30e5e21 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberGoalRoomForListResponse.java @@ -0,0 +1,18 @@ +package co.kirikiri.service.dto.member.response; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +public record MemberGoalRoomForListResponse( + Long goalRoomId, + String name, + String goalRoomStatus, + Integer currentMemberCount, + Integer limitedMemberCount, + LocalDateTime createdAt, + LocalDate startDate, + LocalDate endDate, + MemberResponse goalRoomLeader +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberGoalRoomResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberGoalRoomResponse.java new file mode 100644 index 000000000..1204d182c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberGoalRoomResponse.java @@ -0,0 +1,23 @@ +package co.kirikiri.service.dto.member.response; + +import co.kirikiri.service.dto.goalroom.response.CheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodesResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomTodoResponse; +import java.time.LocalDate; +import java.util.List; + +public record MemberGoalRoomResponse( + String name, + String status, + Long leaderId, + Integer currentMemberCount, + Integer limitedMemberCount, + LocalDate startDate, + LocalDate endDate, + Long roadmapContentId, + GoalRoomRoadmapNodesResponse goalRoomRoadmapNodes, + List goalRoomTodos, + List checkFeeds +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberInformationForPublicResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberInformationForPublicResponse.java new file mode 100644 index 000000000..b533d7e73 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberInformationForPublicResponse.java @@ -0,0 +1,9 @@ +package co.kirikiri.service.dto.member.response; + +public record MemberInformationForPublicResponse( + String nickname, + String profileImageUrl, + String gender +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberInformationResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberInformationResponse.java new file mode 100644 index 000000000..9ad52eb8f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberInformationResponse.java @@ -0,0 +1,15 @@ +package co.kirikiri.service.dto.member.response; + +import java.time.LocalDate; + +public record MemberInformationResponse( + Long id, + String nickname, + String profileImageUrl, + String gender, + String identifier, + String phoneNumber, + LocalDate birthday +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberResponse.java new file mode 100644 index 000000000..26b1e7b23 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/member/response/MemberResponse.java @@ -0,0 +1,9 @@ +package co.kirikiri.service.dto.member.response; + +public record MemberResponse( + long id, + String name, + String imageUrl +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapCategoryDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapCategoryDto.java new file mode 100644 index 000000000..591ab9e85 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapCategoryDto.java @@ -0,0 +1,8 @@ +package co.kirikiri.service.dto.roadmap; + +public record RoadmapCategoryDto( + long id, + String name +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapContentDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapContentDto.java new file mode 100644 index 000000000..c568a32e6 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapContentDto.java @@ -0,0 +1,11 @@ +package co.kirikiri.service.dto.roadmap; + +import java.util.List; + +public record RoadmapContentDto( + Long id, + String content, + List nodes +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapDto.java new file mode 100644 index 000000000..a85cd7915 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapDto.java @@ -0,0 +1,20 @@ +package co.kirikiri.service.dto.roadmap; + +import co.kirikiri.service.dto.member.MemberDto; +import java.time.LocalDateTime; +import java.util.List; + +public record RoadmapDto( + Long roadmapId, + RoadmapCategoryDto category, + String roadmapTitle, + String introduction, + MemberDto creator, + RoadmapContentDto content, + String difficulty, + int recommendedRoadmapPeriod, + LocalDateTime createdAt, + List tags +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapForListDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapForListDto.java new file mode 100644 index 000000000..1b05ab352 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapForListDto.java @@ -0,0 +1,19 @@ +package co.kirikiri.service.dto.roadmap; + +import co.kirikiri.service.dto.member.MemberDto; +import java.time.LocalDateTime; +import java.util.List; + +public record RoadmapForListDto( + long roadmapId, + String roadmapTitle, + String introduction, + String difficulty, + int recommendedRoadmapPeriod, + LocalDateTime createdAt, + MemberDto creator, + RoadmapCategoryDto category, + List tags +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapForListScrollDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapForListScrollDto.java new file mode 100644 index 000000000..042c42c97 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapForListScrollDto.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.roadmap; + +import java.util.List; + +public record RoadmapForListScrollDto( + List dtos, + boolean hasNext +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapGoalRoomNumberDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapGoalRoomNumberDto.java new file mode 100644 index 000000000..da159eeb4 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapGoalRoomNumberDto.java @@ -0,0 +1,9 @@ +package co.kirikiri.service.dto.roadmap; + +public record RoadmapGoalRoomNumberDto( + long recruitedGoalRoomNumber, + long runningGoalRoomNumber, + long completedGoalRoomNumber +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapGoalRoomsOrderTypeDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapGoalRoomsOrderTypeDto.java new file mode 100644 index 000000000..f8688c26f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapGoalRoomsOrderTypeDto.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.roadmap; + +public enum RoadmapGoalRoomsOrderTypeDto { + + LATEST("์ตœ์‹ ์ˆœ"), + CLOSE_TO_DEADLINE("๋งˆ๊ฐ์ž„๋ฐ• ์ˆœ"); + + private final String description; + + RoadmapGoalRoomsOrderTypeDto(final String description) { + this.description = description; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapNodeDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapNodeDto.java new file mode 100644 index 000000000..c0d4cc164 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapNodeDto.java @@ -0,0 +1,12 @@ +package co.kirikiri.service.dto.roadmap; + +import java.util.List; + +public record RoadmapNodeDto( + Long id, + String title, + String description, + List imageUrls +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapNodeSaveDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapNodeSaveDto.java new file mode 100644 index 000000000..474aab738 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapNodeSaveDto.java @@ -0,0 +1,12 @@ +package co.kirikiri.service.dto.roadmap; + +import co.kirikiri.service.dto.FileInformation; +import java.util.List; + +public record RoadmapNodeSaveDto( + String title, + String content, + List fileInformations +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapReviewDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapReviewDto.java new file mode 100644 index 000000000..89ef43983 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapReviewDto.java @@ -0,0 +1,11 @@ +package co.kirikiri.service.dto.roadmap; + +import co.kirikiri.domain.member.Member; + +public record RoadmapReviewDto( + String content, + Double rate, + Member member +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapReviewReadDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapReviewReadDto.java new file mode 100644 index 000000000..40ac375eb --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapReviewReadDto.java @@ -0,0 +1,14 @@ +package co.kirikiri.service.dto.roadmap; + +import co.kirikiri.service.dto.member.MemberDto; +import java.time.LocalDateTime; + +public record RoadmapReviewReadDto( + Long id, + MemberDto member, + LocalDateTime createdAt, + String content, + Double rate +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapSaveDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapSaveDto.java new file mode 100644 index 000000000..448326df7 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapSaveDto.java @@ -0,0 +1,17 @@ +package co.kirikiri.service.dto.roadmap; + +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import java.util.List; + +public record RoadmapSaveDto( + Long categoryId, + String title, + String introduction, + String content, + RoadmapDifficultyType difficulty, + Integer requiredPeriod, + List roadmapNodes, + List tags +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapTagDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapTagDto.java new file mode 100644 index 000000000..bb3251790 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapTagDto.java @@ -0,0 +1,8 @@ +package co.kirikiri.service.dto.roadmap; + +public record RoadmapTagDto( + Long id, + String name +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapTagSaveDto.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapTagSaveDto.java new file mode 100644 index 000000000..fa8d75256 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/RoadmapTagSaveDto.java @@ -0,0 +1,7 @@ +package co.kirikiri.service.dto.roadmap; + +public record RoadmapTagSaveDto( + String name +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapDifficultyType.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapDifficultyType.java new file mode 100644 index 000000000..9a3ac701f --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapDifficultyType.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.roadmap.request; + +public enum RoadmapDifficultyType { + + VERY_EASY, + EASY, + NORMAL, + DIFFICULT, + VERY_DIFFICULT +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapNodeSaveRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapNodeSaveRequest.java new file mode 100644 index 000000000..e36754ec2 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapNodeSaveRequest.java @@ -0,0 +1,26 @@ +package co.kirikiri.service.dto.roadmap.request; + +import jakarta.validation.constraints.NotBlank; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +public class RoadmapNodeSaveRequest { + + @NotBlank(message = "๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + private String title; + + @NotBlank(message = "๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + private String content; + + private List images; + + public void setImages(final List images) { + this.images = images; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapOrderTypeRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapOrderTypeRequest.java new file mode 100644 index 000000000..d195dae6a --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapOrderTypeRequest.java @@ -0,0 +1,14 @@ +package co.kirikiri.service.dto.roadmap.request; + +public enum RoadmapOrderTypeRequest { + LATEST("์ตœ์‹ ์ˆœ"), + GOAL_ROOM_COUNT("์ƒ์„ฑ๋œ ๊ณจ๋ฃธ์ด ๋งŽ์€์ˆœ"), + PARTICIPANT_COUNT("์ฐธ์—ฌ ์ค‘์ธ ์ธ์›์ˆœ"), + REVIEW_RATE("ํ‰์ ์ˆœ"); + + private final String description; + + RoadmapOrderTypeRequest(final String description) { + this.description = description; + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapReviewSaveRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapReviewSaveRequest.java new file mode 100644 index 000000000..9d29c0337 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapReviewSaveRequest.java @@ -0,0 +1,14 @@ +package co.kirikiri.service.dto.roadmap.request; + +import jakarta.validation.constraints.NotNull; + +public record RoadmapReviewSaveRequest( + + String content, + + @NotNull(message = "๋ณ„์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.") + Double rate +) { + +} + diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapSaveRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapSaveRequest.java new file mode 100644 index 000000000..c58a272c0 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapSaveRequest.java @@ -0,0 +1,34 @@ +package co.kirikiri.service.dto.roadmap.request; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.List; + +public record RoadmapSaveRequest( + + @NotNull(message = "์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + Long categoryId, + + @NotBlank(message = "๋กœ๋“œ๋งต์˜ ์ œ๋ชฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + String title, + + @NotBlank(message = "๋กœ๋“œ๋งต์˜ ์†Œ๊ฐœ๊ธ€์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + String introduction, + + String content, + + @NotNull(message = "๋‚œ์ด๋„๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + RoadmapDifficultyType difficulty, + + @NotNull(message = "์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + Integer requiredPeriod, + + @NotEmpty(message = "๋กœ๋“œ๋งต์˜ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.") + List<@Valid RoadmapNodeSaveRequest> roadmapNodes, + + List roadmapTags +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapSearchRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapSearchRequest.java new file mode 100644 index 000000000..e19832c48 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapSearchRequest.java @@ -0,0 +1,9 @@ +package co.kirikiri.service.dto.roadmap.request; + +public record RoadmapSearchRequest( + String roadmapTitle, + String creatorName, + String tagName +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapTagSaveRequest.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapTagSaveRequest.java new file mode 100644 index 000000000..52be91ad0 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/request/RoadmapTagSaveRequest.java @@ -0,0 +1,7 @@ +package co.kirikiri.service.dto.roadmap.request; + +public record RoadmapTagSaveRequest( + String name +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/MemberRoadmapResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/MemberRoadmapResponse.java new file mode 100644 index 000000000..a8dc55c8b --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/MemberRoadmapResponse.java @@ -0,0 +1,13 @@ +package co.kirikiri.service.dto.roadmap.response; + +import java.time.LocalDateTime; + +public record MemberRoadmapResponse( + Long roadmapId, + String roadmapTitle, + String difficulty, + LocalDateTime createdAt, + RoadmapCategoryResponse category +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/MemberRoadmapResponses.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/MemberRoadmapResponses.java new file mode 100644 index 000000000..7c9620776 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/MemberRoadmapResponses.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.roadmap.response; + +import java.util.List; + +public record MemberRoadmapResponses( + List responses, + boolean hasNext +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapCategoryResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapCategoryResponse.java new file mode 100644 index 000000000..d2660dd97 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapCategoryResponse.java @@ -0,0 +1,8 @@ +package co.kirikiri.service.dto.roadmap.response; + +public record RoadmapCategoryResponse( + long id, + String name +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapContentResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapContentResponse.java new file mode 100644 index 000000000..41ca642cc --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapContentResponse.java @@ -0,0 +1,11 @@ +package co.kirikiri.service.dto.roadmap.response; + +import java.util.List; + +public record RoadmapContentResponse( + Long id, + String content, + List nodes +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapForListResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapForListResponse.java new file mode 100644 index 000000000..b0ad3d37e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapForListResponse.java @@ -0,0 +1,19 @@ +package co.kirikiri.service.dto.roadmap.response; + +import co.kirikiri.service.dto.member.response.MemberResponse; +import java.time.LocalDateTime; +import java.util.List; + +public record RoadmapForListResponse( + long roadmapId, + String roadmapTitle, + String introduction, + String difficulty, + int recommendedRoadmapPeriod, + LocalDateTime createdAt, + MemberResponse creator, + RoadmapCategoryResponse category, + List tags +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapForListResponses.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapForListResponses.java new file mode 100644 index 000000000..161eb8be6 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapForListResponses.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.roadmap.response; + +import java.util.List; + +public record RoadmapForListResponses( + List responses, + boolean hasNext +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapGoalRoomResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapGoalRoomResponse.java new file mode 100644 index 000000000..7ea65cffe --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapGoalRoomResponse.java @@ -0,0 +1,18 @@ +package co.kirikiri.service.dto.roadmap.response; + +import co.kirikiri.service.dto.member.response.MemberResponse; +import java.time.LocalDate; +import java.time.LocalDateTime; + +public record RoadmapGoalRoomResponse( + Long goalRoomId, + String name, + Integer currentMemberCount, + Integer limitedMemberCount, + LocalDateTime createdAt, + LocalDate startDate, + LocalDate endDate, + MemberResponse goalRoomLeader +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapGoalRoomResponses.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapGoalRoomResponses.java new file mode 100644 index 000000000..1bb5df0dd --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapGoalRoomResponses.java @@ -0,0 +1,10 @@ +package co.kirikiri.service.dto.roadmap.response; + +import java.util.List; + +public record RoadmapGoalRoomResponses( + List responses, + boolean hasNext +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapNodeResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapNodeResponse.java new file mode 100644 index 000000000..2fe654d34 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapNodeResponse.java @@ -0,0 +1,12 @@ +package co.kirikiri.service.dto.roadmap.response; + +import java.util.List; + +public record RoadmapNodeResponse( + Long id, + String title, + String description, + List imageUrls +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapResponse.java new file mode 100644 index 000000000..3286b0df2 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapResponse.java @@ -0,0 +1,23 @@ +package co.kirikiri.service.dto.roadmap.response; + +import co.kirikiri.service.dto.member.response.MemberResponse; +import java.time.LocalDateTime; +import java.util.List; + +public record RoadmapResponse( + Long roadmapId, + RoadmapCategoryResponse category, + String roadmapTitle, + String introduction, + MemberResponse creator, + RoadmapContentResponse content, + String difficulty, + int recommendedRoadmapPeriod, + LocalDateTime createdAt, + List tags, + Long recruitedGoalRoomNumber, + Long runningGoalRoomNumber, + Long completedGoalRoomNumber +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapReviewResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapReviewResponse.java new file mode 100644 index 000000000..956143b7c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapReviewResponse.java @@ -0,0 +1,14 @@ +package co.kirikiri.service.dto.roadmap.response; + +import co.kirikiri.service.dto.member.response.MemberResponse; +import java.time.LocalDateTime; + +public record RoadmapReviewResponse( + Long id, + MemberResponse member, + LocalDateTime createdAt, + String content, + Double rate +) { + +} \ No newline at end of file diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapTagResponse.java b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapTagResponse.java new file mode 100644 index 000000000..9fc072030 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/dto/roadmap/response/RoadmapTagResponse.java @@ -0,0 +1,8 @@ +package co.kirikiri.service.dto.roadmap.response; + +public record RoadmapTagResponse( + Long id, + String name +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/event/RoadmapCreateEvent.java b/backend/kirikiri/src/main/java/co/kirikiri/service/event/RoadmapCreateEvent.java new file mode 100644 index 000000000..d0e3d129c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/event/RoadmapCreateEvent.java @@ -0,0 +1,11 @@ +package co.kirikiri.service.event; + +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.service.dto.roadmap.RoadmapSaveDto; + +public record RoadmapCreateEvent( + Roadmap roadmap, + RoadmapSaveDto roadmapSaveDto +) { + +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/AuthMapper.java b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/AuthMapper.java new file mode 100644 index 000000000..ec3df85d4 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/AuthMapper.java @@ -0,0 +1,28 @@ +package co.kirikiri.service.mapper; + +import co.kirikiri.domain.auth.EncryptedToken; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.service.dto.auth.LoginDto; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.auth.request.ReissueTokenRequest; +import co.kirikiri.service.dto.auth.response.AuthenticationResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AuthMapper { + + public static LoginDto convertToLoginDto(final LoginRequest request) { + return new LoginDto(new Identifier(request.identifier()), new Password(request.password())); + } + + public static AuthenticationResponse convertToAuthenticationResponse(final String refreshToken, + final String accessToken) { + return new AuthenticationResponse(refreshToken, accessToken); + } + + public static EncryptedToken convertToEncryptedToken(final ReissueTokenRequest reissueTokenRequest) { + return new EncryptedToken(reissueTokenRequest.refreshToken()); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/GoalRoomMapper.java b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/GoalRoomMapper.java new file mode 100644 index 000000000..905f0f24c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/GoalRoomMapper.java @@ -0,0 +1,303 @@ +package co.kirikiri.service.mapper; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.GoalRoomToDoCheck; +import co.kirikiri.domain.goalroom.GoalRoomToDos; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.exception.ServerException; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsOrderType; +import co.kirikiri.service.dto.FileInformation; +import co.kirikiri.service.dto.goalroom.CheckFeedDto; +import co.kirikiri.service.dto.goalroom.GoalRoomCheckFeedDto; +import co.kirikiri.service.dto.goalroom.GoalRoomCreateDto; +import co.kirikiri.service.dto.goalroom.GoalRoomMemberDto; +import co.kirikiri.service.dto.goalroom.GoalRoomMemberSortTypeDto; +import co.kirikiri.service.dto.goalroom.GoalRoomRoadmapNodeDto; +import co.kirikiri.service.dto.goalroom.MemberGoalRoomForListDto; +import co.kirikiri.service.dto.goalroom.RoadmapGoalRoomDto; +import co.kirikiri.service.dto.goalroom.RoadmapGoalRoomScrollDto; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomStatusTypeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.goalroom.response.CheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCertifiedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomMemberResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodeResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodesResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomTodoResponse; +import co.kirikiri.service.dto.member.MemberDto; +import co.kirikiri.service.dto.member.response.MemberGoalRoomForListResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.dto.member.response.MemberResponse; +import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomNumberDto; +import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomsOrderTypeDto; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponses; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.time.LocalDate; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class GoalRoomMapper { + + private static final int MAX_MEMBER_GOAL_ROOM_TODO_NUMBER = 3; + private static final int MAX_MEMBER_GOAL_ROOM_CHECK_FEED_NUMBER = 4; + + public static GoalRoomCreateDto convertToGoalRoomCreateDto(final GoalRoomCreateRequest goalRoomCreateRequest) { + final GoalRoomTodoRequest goalRoomTodoRequest = goalRoomCreateRequest.goalRoomTodo(); + final GoalRoomToDo goalRoomToDo = convertToGoalRoomTodo(goalRoomTodoRequest); + final List goalRoomRoadmapNodeRequests = goalRoomCreateRequest.goalRoomRoadmapNodeRequests(); + final List goalRoomRoadmapNodeDtos = makeGoalRoomRoadmapNodeDtos( + goalRoomRoadmapNodeRequests); + + return new GoalRoomCreateDto( + goalRoomCreateRequest.roadmapContentId(), + new GoalRoomName(goalRoomCreateRequest.name()), + new LimitedMemberCount(goalRoomCreateRequest.limitedMemberCount()), + goalRoomToDo, goalRoomRoadmapNodeDtos); + } + + public static GoalRoomToDo convertToGoalRoomTodo(final GoalRoomTodoRequest goalRoomTodoRequest) { + return new GoalRoomToDo(new GoalRoomTodoContent(goalRoomTodoRequest.content()), + new Period(goalRoomTodoRequest.startDate(), goalRoomTodoRequest.endDate())); + } + + private static List makeGoalRoomRoadmapNodeDtos( + final List goalRoomRoadmapNodeRequests) { + return goalRoomRoadmapNodeRequests + .stream() + .map(it -> new GoalRoomRoadmapNodeDto(it.roadmapNodeId(), it.checkCount(), it.startDate(), + it.endDate())) + .toList(); + } + + public static GoalRoomResponse convertGoalRoomResponse(final GoalRoom goalRoom) { + final GoalRoomRoadmapNodes nodes = goalRoom.getGoalRoomRoadmapNodes(); + final List roadmapNodeResponses = convertGoalRoomNodeResponses(nodes); + final int period = goalRoom.calculateTotalPeriod(); + return new GoalRoomResponse(goalRoom.getName().getValue(), goalRoom.getCurrentMemberCount(), + goalRoom.getLimitedMemberCount().getValue(), roadmapNodeResponses, period); + } + + public static List convertGoalRoomNodeResponses(final GoalRoomRoadmapNodes nodes) { + return nodes.getValues().stream() + .map(GoalRoomMapper::convertGoalRoomNodeResponse) + .toList(); + } + + private static GoalRoomRoadmapNodeResponse convertGoalRoomNodeResponse(final GoalRoomRoadmapNode node) { + return new GoalRoomRoadmapNodeResponse(node.getId(), node.getRoadmapNode().getTitle(), node.getStartDate(), + node.getEndDate(), node.getCheckCount()); + } + + public static GoalRoomCertifiedResponse convertGoalRoomCertifiedResponse(final GoalRoom goalRoom, + final boolean isJoined) { + final GoalRoomRoadmapNodes nodes = goalRoom.getGoalRoomRoadmapNodes(); + final List roadmapNodeResponses = convertGoalRoomNodeResponses(nodes); + final int period = goalRoom.calculateTotalPeriod(); + return new GoalRoomCertifiedResponse(goalRoom.getName().getValue(), goalRoom.getCurrentMemberCount(), + goalRoom.getLimitedMemberCount().getValue(), roadmapNodeResponses, period, isJoined); + } + + public static RoadmapGoalRoomsOrderType convertToGoalRoomOrderType( + final RoadmapGoalRoomsOrderTypeDto orderType) { + if (orderType == null) { + return RoadmapGoalRoomsOrderType.LATEST; + } + return RoadmapGoalRoomsOrderType.valueOf(orderType.name()); + } + + public static RoadmapGoalRoomResponses convertToRoadmapGoalRoomResponses( + final RoadmapGoalRoomScrollDto roadmapGoalRoomScrollDto) { + final List responses = roadmapGoalRoomScrollDto.roadmapGoalRoomDtos() + .stream() + .map(GoalRoomMapper::convertToRoadmapGoalRoomResponse) + .toList(); + return new RoadmapGoalRoomResponses(responses, roadmapGoalRoomScrollDto.hasNext()); + } + + private static RoadmapGoalRoomResponse convertToRoadmapGoalRoomResponse( + final RoadmapGoalRoomDto roadmapGoalRoomDto) { + return new RoadmapGoalRoomResponse(roadmapGoalRoomDto.goalRoomId(), roadmapGoalRoomDto.name(), + roadmapGoalRoomDto.currentMemberCount(), roadmapGoalRoomDto.limitedMemberCount(), + roadmapGoalRoomDto.createdAt(), roadmapGoalRoomDto.startDate(), + roadmapGoalRoomDto.endDate(), convertToMemberResponse(roadmapGoalRoomDto.goalRoomLeader())); + } + + private static MemberResponse convertToMemberResponse(final MemberDto memberDto) { + return new MemberResponse(memberDto.id(), memberDto.name(), memberDto.imageUrl()); + } + + public static GoalRoomMemberSortType convertGoalRoomMemberSortType(final GoalRoomMemberSortTypeDto sortType) { + if (sortType == null) { + return null; + } + return GoalRoomMemberSortType.valueOf(sortType.name()); + } + + public static List convertToGoalRoomMemberResponses( + final List goalRoomMemberDtos) { + return goalRoomMemberDtos.stream() + .map(GoalRoomMapper::convertToGoalRoomMemberResponse) + .toList(); + } + + private static GoalRoomMemberResponse convertToGoalRoomMemberResponse(final GoalRoomMemberDto goalRoomMemberDto) { + return new GoalRoomMemberResponse(goalRoomMemberDto.memberId(), goalRoomMemberDto.nickname(), + goalRoomMemberDto.imagePath(), goalRoomMemberDto.accomplishmentRate()); + } + + public static List convertGoalRoomTodoResponses(final GoalRoomToDos goalRoomToDos, + final List checkedTodos) { + return goalRoomToDos.getValues().stream() + .map(goalRoomToDo -> convertGoalRoomTodoResponse(checkedTodos, goalRoomToDo)) + .toList(); + } + + private static GoalRoomTodoResponse convertGoalRoomTodoResponse(final List checkedTodos, + final GoalRoomToDo goalRoomToDo) { + final GoalRoomToDoCheckResponse checkResponse = new GoalRoomToDoCheckResponse( + isCheckedTodo(goalRoomToDo.getId(), checkedTodos)); + return new GoalRoomTodoResponse(goalRoomToDo.getId(), + goalRoomToDo.getContent(), + goalRoomToDo.getStartDate(), goalRoomToDo.getEndDate(), + checkResponse); + } + + private static boolean isCheckedTodo(final Long targetTodoId, final List checkedTodos) { + final List checkTodoIds = checkedTodos.stream() + .map(goalRoomToDoCheck -> goalRoomToDoCheck.getGoalRoomToDo().getId()) + .toList(); + return checkTodoIds.contains(targetTodoId); + } + + public static MemberGoalRoomResponse convertToMemberGoalRoomResponse(final GoalRoom goalRoom, + final List checkFeedDtos, + final List checkedTodos) { + final GoalRoomRoadmapNodesResponse nodeResponses = convertToGoalRoomRoadmapNodesResponse( + goalRoom.getGoalRoomRoadmapNodes()); + final List todoResponses = convertGoalRoomTodoResponsesLimit(goalRoom.getGoalRoomToDos(), + checkedTodos); + final List checkFeedResponses = convertToCheckFeedResponses(checkFeedDtos); + + return new MemberGoalRoomResponse(goalRoom.getName().getValue(), goalRoom.getStatus().name(), + goalRoom.findGoalRoomLeader().getId(), goalRoom.getCurrentMemberCount(), + goalRoom.getLimitedMemberCount().getValue(), goalRoom.getStartDate(), goalRoom.getEndDate(), + goalRoom.getRoadmapContent().getId(), nodeResponses, todoResponses, checkFeedResponses); + } + + private static GoalRoomRoadmapNodesResponse convertToGoalRoomRoadmapNodesResponse( + final GoalRoomRoadmapNodes nodes) { + final GoalRoomRoadmapNode currentNode = nodes.getNodeByDate(LocalDate.now()) + .orElse(nodes.getNodeByDate(nodes.getGoalRoomStartDate()).get()); + + if (!nodes.hasBackNode(currentNode)) { + return new GoalRoomRoadmapNodesResponse( + nodes.hasFrontNode(currentNode), + nodes.hasBackNode(currentNode), + List.of(convertGoalRoomNodeResponse(currentNode)) + ); + } + + final GoalRoomRoadmapNode nextNode = nodes.nextNode(currentNode).get(); + return new GoalRoomRoadmapNodesResponse(nodes.hasFrontNode(currentNode), nodes.hasBackNode(nextNode), + List.of(convertGoalRoomNodeResponse(currentNode), convertGoalRoomNodeResponse(nextNode))); + } + + private static List convertGoalRoomTodoResponsesLimit(final GoalRoomToDos goalRoomToDos, + final List checkedTodos) { + return goalRoomToDos.getValues() + .stream() + .map(goalRoomToDo -> convertGoalRoomTodoResponse(checkedTodos, goalRoomToDo)) + .limit(MAX_MEMBER_GOAL_ROOM_TODO_NUMBER) + .toList(); + } + + private static List convertToCheckFeedResponses(final List checkFeedDtos) { + return checkFeedDtos.stream() + .map(checkFeed -> new CheckFeedResponse(checkFeed.id(), checkFeed.imageUrl(), + checkFeed.description(), checkFeed.createdAt().toLocalDate())) + .limit(MAX_MEMBER_GOAL_ROOM_CHECK_FEED_NUMBER) + .toList(); + } + + public static GoalRoomStatus convertToGoalRoomStatus(final GoalRoomStatusTypeRequest statusType) { + return GoalRoomStatus.valueOf(statusType.name()); + } + + public static List convertToMemberGoalRoomForListResponses( + final List memberGoalRoomForListDtos) { + return memberGoalRoomForListDtos.stream() + .map(GoalRoomMapper::convertToMemberGoalRoomForListResponse) + .toList(); + } + + private static MemberGoalRoomForListResponse convertToMemberGoalRoomForListResponse( + final MemberGoalRoomForListDto memberGoalRoomForListDto) { + final MemberDto memberDto = memberGoalRoomForListDto.goalRoomLeader(); + return new MemberGoalRoomForListResponse(memberGoalRoomForListDto.goalRoomId(), memberGoalRoomForListDto.name(), + memberGoalRoomForListDto.goalRoomStatus(), memberGoalRoomForListDto.currentMemberCount(), + memberGoalRoomForListDto.limitedMemberCount(), + memberGoalRoomForListDto.createdAt(), memberGoalRoomForListDto.startDate(), + memberGoalRoomForListDto.endDate(), + new MemberResponse(memberDto.id(), memberDto.name(), + memberDto.imageUrl())); + } + + public static List convertToGoalRoomCheckFeedResponses( + final List checkFeeds) { + return checkFeeds.stream() + .map(GoalRoomMapper::convertToGoalRoomCheckFeedResponse) + .toList(); + } + + private static GoalRoomCheckFeedResponse convertToGoalRoomCheckFeedResponse( + final GoalRoomCheckFeedDto goalRoomCheckFeedDto) { + final MemberDto memberDto = goalRoomCheckFeedDto.memberDto(); + final MemberResponse memberResponse = new MemberResponse(memberDto.id(), memberDto.name(), + memberDto.imageUrl()); + + final CheckFeedDto checkFeedDto = goalRoomCheckFeedDto.checkFeedDto(); + final CheckFeedResponse checkFeedResponse = new CheckFeedResponse(checkFeedDto.id(), checkFeedDto.imageUrl(), + checkFeedDto.description(), checkFeedDto.createdAt().toLocalDate()); + + return new GoalRoomCheckFeedResponse(memberResponse, checkFeedResponse); + } + + public static RoadmapGoalRoomNumberDto convertRoadmapGoalRoomDto(final List goalRooms) { + final Map> goalRoomsDividedByStatus = goalRooms.stream() + .collect(Collectors.groupingBy(GoalRoom::getStatus)); + return new RoadmapGoalRoomNumberDto( + goalRoomsDividedByStatus.getOrDefault(GoalRoomStatus.RECRUITING, Collections.emptyList()).size(), + goalRoomsDividedByStatus.getOrDefault(GoalRoomStatus.RUNNING, Collections.emptyList()).size(), + goalRoomsDividedByStatus.getOrDefault(GoalRoomStatus.COMPLETED, Collections.emptyList()).size() + ); + } + + public static FileInformation convertToFileInformation(final MultipartFile multipartFile) { + try { + return new FileInformation(multipartFile.getOriginalFilename(), + multipartFile.getSize(), multipartFile.getContentType(), multipartFile.getInputStream()); + } catch (final IOException exception) { + throw new ServerException(exception.getMessage()); + } + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/MemberMapper.java b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/MemberMapper.java new file mode 100644 index 000000000..dba8f260e --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/MemberMapper.java @@ -0,0 +1,41 @@ +package co.kirikiri.service.mapper; + +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.service.dto.member.MemberInformationDto; +import co.kirikiri.service.dto.member.MemberInformationForPublicDto; +import co.kirikiri.service.dto.member.MemberJoinDto; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberInformationForPublicResponse; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class MemberMapper { + + public static MemberJoinDto convertToMemberJoinDto(final MemberJoinRequest request) { + final Identifier identifier = new Identifier(request.identifier()); + final Password password = new Password(request.password()); + final Nickname nickname = new Nickname(request.nickname()); + final Gender gender = Gender.valueOf(request.genderType().name()); + return new MemberJoinDto(identifier, password, nickname, request.phoneNumber(), gender, request.birthday()); + } + + public static MemberInformationResponse convertToMemberInformationResponse( + final MemberInformationDto memberInformationDto) { + return new MemberInformationResponse(memberInformationDto.id(), memberInformationDto.nickname(), + memberInformationDto.profileImageUrl(), memberInformationDto.gender(), + memberInformationDto.identifier(), + memberInformationDto.phoneNumber(), memberInformationDto.birthday()); + } + + public static MemberInformationForPublicResponse convertToMemberInformationForPublicResponse( + final MemberInformationForPublicDto memberInformationForPublicDto) { + return new MemberInformationForPublicResponse(memberInformationForPublicDto.nickname(), + memberInformationForPublicDto.profileImageUrl(), + memberInformationForPublicDto.gender()); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/RoadmapMapper.java b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/RoadmapMapper.java new file mode 100644 index 000000000..e89811241 --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/RoadmapMapper.java @@ -0,0 +1,212 @@ +package co.kirikiri.service.mapper; + +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.exception.ServerException; +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.service.dto.FileInformation; +import co.kirikiri.service.dto.member.MemberDto; +import co.kirikiri.service.dto.member.response.MemberResponse; +import co.kirikiri.service.dto.roadmap.RoadmapCategoryDto; +import co.kirikiri.service.dto.roadmap.RoadmapContentDto; +import co.kirikiri.service.dto.roadmap.RoadmapDto; +import co.kirikiri.service.dto.roadmap.RoadmapForListDto; +import co.kirikiri.service.dto.roadmap.RoadmapForListScrollDto; +import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomNumberDto; +import co.kirikiri.service.dto.roadmap.RoadmapNodeDto; +import co.kirikiri.service.dto.roadmap.RoadmapNodeSaveDto; +import co.kirikiri.service.dto.roadmap.RoadmapReviewDto; +import co.kirikiri.service.dto.roadmap.RoadmapReviewReadDto; +import co.kirikiri.service.dto.roadmap.RoadmapSaveDto; +import co.kirikiri.service.dto.roadmap.RoadmapTagDto; +import co.kirikiri.service.dto.roadmap.RoadmapTagSaveDto; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapOrderTypeRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapCategoryResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapContentResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapNodeResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapTagResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class RoadmapMapper { + + public static RoadmapSaveDto convertToRoadmapSaveDto(final RoadmapSaveRequest request) { + final List roadmapNodes = request.roadmapNodes() + .stream() + .map(RoadmapMapper::convertToRoadmapNodesSaveDto) + .toList(); + final List roadmapTags = convertToRoadmapTagSaveDtos(request); + + return new RoadmapSaveDto(request.categoryId(), request.title(), request.introduction(), request.content(), + request.difficulty(), request.requiredPeriod(), roadmapNodes, roadmapTags); + } + + private static List convertToRoadmapTagSaveDtos(final RoadmapSaveRequest request) { + if (request.roadmapTags() == null) { + return Collections.emptyList(); + } + return request.roadmapTags() + .stream() + .map(RoadmapMapper::convertToRoadmapTagSaveDto) + .toList(); + } + + private static RoadmapNodeSaveDto convertToRoadmapNodesSaveDto(final RoadmapNodeSaveRequest request) { + final List fileInformations = request.getImages() + .stream() + .map(RoadmapMapper::converToRoadmapNodeImageDto) + .toList(); + return new RoadmapNodeSaveDto(request.getTitle(), request.getContent(), fileInformations); + } + + private static FileInformation converToRoadmapNodeImageDto(final MultipartFile it) { + try { + return new FileInformation(it.getOriginalFilename(), it.getSize(), it.getContentType(), it.getInputStream()); + } catch (final IOException exception) { + throw new ServerException(exception.getMessage()); + } + } + + private static RoadmapTagSaveDto convertToRoadmapTagSaveDto(final RoadmapTagSaveRequest request) { + return new RoadmapTagSaveDto(request.name()); + } + + public static RoadmapResponse convertToRoadmapResponse(final RoadmapDto roadmapDto, + final RoadmapGoalRoomNumberDto roadmapGoalRoomNumberDto) { + return new RoadmapResponse( + roadmapDto.roadmapId(), + new RoadmapCategoryResponse(roadmapDto.category().id(), roadmapDto.category().name()), + roadmapDto.roadmapTitle(), + roadmapDto.introduction(), + new MemberResponse(roadmapDto.creator().id(), roadmapDto.creator().name(), + roadmapDto.creator().imageUrl()), + convertToRoadmapContentResponse(roadmapDto.content()), + roadmapDto.difficulty(), + roadmapDto.recommendedRoadmapPeriod(), + roadmapDto.createdAt(), + convertRoadmapTagResponses(roadmapDto.tags()), + roadmapGoalRoomNumberDto.recruitedGoalRoomNumber(), + roadmapGoalRoomNumberDto.runningGoalRoomNumber(), + roadmapGoalRoomNumberDto.completedGoalRoomNumber() + ); + } + + private static RoadmapContentResponse convertToRoadmapContentResponse(final RoadmapContentDto roadmapContentDto) { + return new RoadmapContentResponse( + roadmapContentDto.id(), + roadmapContentDto.content(), + convertRoadmapNodeResponse(roadmapContentDto.nodes()) + ); + } + + private static List convertRoadmapNodeResponse(final List roadmapNodeDtos) { + return roadmapNodeDtos.stream() + .map(it -> new RoadmapNodeResponse(it.id(), it.title(), it.description(), it.imageUrls())) + .toList(); + } + + public static RoadmapOrderType convertRoadmapOrderType(final RoadmapOrderTypeRequest filterType) { + if (filterType == null) { + return RoadmapOrderType.LATEST; + } + return RoadmapOrderType.valueOf(filterType.name()); + } + + private static List convertRoadmapTagResponses(final List roadmapTagDtos) { + return roadmapTagDtos.stream() + .map(tag -> new RoadmapTagResponse(tag.id(), tag.name())) + .toList(); + } + + public static RoadmapForListResponses convertRoadmapResponses( + final RoadmapForListScrollDto roadmapForListScrollDto) { + final List responses = roadmapForListScrollDto.dtos() + .stream() + .map(RoadmapMapper::convertRoadmapResponse) + .toList(); + return new RoadmapForListResponses(responses, roadmapForListScrollDto.hasNext()); + } + + private static RoadmapForListResponse convertRoadmapResponse(final RoadmapForListDto roadmapForListDto) { + final RoadmapCategoryDto roadmapCategoryDto = roadmapForListDto.category(); + final RoadmapCategoryResponse categoryResponse = new RoadmapCategoryResponse(roadmapCategoryDto.id(), + roadmapCategoryDto.name()); + final MemberDto memberDto = roadmapForListDto.creator(); + final MemberResponse creatorResponse = new MemberResponse(memberDto.id(), memberDto.name(), + memberDto.imageUrl()); + final List roadmapTagResponses = convertRoadmapTagResponses(roadmapForListDto.tags()); + + return new RoadmapForListResponse( + roadmapForListDto.roadmapId(), + roadmapForListDto.roadmapTitle(), + roadmapForListDto.introduction(), + roadmapForListDto.difficulty(), + roadmapForListDto.recommendedRoadmapPeriod(), + roadmapForListDto.createdAt(), + creatorResponse, + categoryResponse, + roadmapTagResponses + ); + } + + public static List convertRoadmapCategoryResponses( + final List roadmapCategories) { + return roadmapCategories.stream() + .map(category -> new RoadmapCategoryResponse(category.getId(), category.getName())) + .toList(); + } + + public static RoadmapReviewDto convertRoadmapReviewDto(final RoadmapReviewSaveRequest request, + final Member member) { + return new RoadmapReviewDto(request.content(), request.rate(), member); + } + + public static MemberRoadmapResponses convertMemberRoadmapResponses(final List roadmaps, + final int requestSize) { + final List responses = roadmaps.stream() + .map(RoadmapMapper::convertMemberRoadmapResponse) + .toList(); + + final List subResponses = ScrollResponseMapper.getSubResponses(responses, requestSize); + final boolean hasNext = ScrollResponseMapper.hasNext(responses.size(), requestSize); + return new MemberRoadmapResponses(subResponses, hasNext); + } + + private static MemberRoadmapResponse convertMemberRoadmapResponse(final Roadmap roadmap) { + final RoadmapCategory category = roadmap.getCategory(); + return new MemberRoadmapResponse(roadmap.getId(), roadmap.getTitle(), + roadmap.getDifficulty().name(), roadmap.getCreatedAt(), + new RoadmapCategoryResponse(category.getId(), category.getName())); + } + + public static List convertToRoadmapReviewResponses( + final List roadmapReviewReadDtos) { + return roadmapReviewReadDtos.stream() + .map(RoadmapMapper::convertToRoadmapReviewResponse) + .toList(); + } + + private static RoadmapReviewResponse convertToRoadmapReviewResponse( + final RoadmapReviewReadDto roadmapReviewReadDto) { + final MemberDto memberDto = roadmapReviewReadDto.member(); + return new RoadmapReviewResponse(roadmapReviewReadDto.id(), + new MemberResponse(memberDto.id(), memberDto.name(), memberDto.imageUrl()), + roadmapReviewReadDto.createdAt(), roadmapReviewReadDto.content(), roadmapReviewReadDto.rate()); + } +} diff --git a/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/ScrollResponseMapper.java b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/ScrollResponseMapper.java new file mode 100644 index 000000000..198e55b7c --- /dev/null +++ b/backend/kirikiri/src/main/java/co/kirikiri/service/mapper/ScrollResponseMapper.java @@ -0,0 +1,18 @@ +package co.kirikiri.service.mapper; + +import java.util.List; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public final class ScrollResponseMapper { + + public static List getSubResponses(final List responses, final int requestSize) { + final int endIndex = Math.min(responses.size(), requestSize); + return responses.subList(0, endIndex); + } + + public static boolean hasNext(final int responseSize, final int requestSize) { + return responseSize > requestSize; + } +} diff --git a/backend/kirikiri/src/main/resources/application.yml b/backend/kirikiri/src/main/resources/application.yml new file mode 100644 index 000000000..7a6236a0f --- /dev/null +++ b/backend/kirikiri/src/main/resources/application.yml @@ -0,0 +1,13 @@ +spring: + config: + import: "classpath:properties/application-dev.yml" + activate: + on-profile: dev + +--- + +spring: + config: + import: "classpath:properties/application-prod.yml" + activate: + on-profile: prod \ No newline at end of file diff --git a/backend/kirikiri/src/main/resources/db/migration/V1__init.sql b/backend/kirikiri/src/main/resources/db/migration/V1__init.sql new file mode 100644 index 000000000..83727cbed --- /dev/null +++ b/backend/kirikiri/src/main/resources/db/migration/V1__init.sql @@ -0,0 +1,242 @@ +create table member_profile +( + id bigint not null auto_increment, + birthday date not null, + gender varchar(10) not null, + phone_number varchar(20) not null, + created_at datetime(6) not null, + updated_at datetime(6) not null, + primary key (id) +) engine=InnoDB; + +create table member_image +( + id bigint not null auto_increment, + image_content_type varchar(10) not null, + original_file_name varchar(100) not null, + server_file_path varchar(255) not null, + primary key (id) +) engine=InnoDB; + +create table member +( + id bigint not null auto_increment, + identifier varchar(50) not null, + password varchar(255) not null, + salt varchar(255) not null, + nickname varchar(15) not null, + created_at datetime(6) not null, + updated_at datetime(6) not null, + member_profile_id bigint not null, + member_image_id bigint not null, + primary key (id), + constraint UK_member_member_profile_id unique (member_profile_id), + constraint UK_member_identifier unique (identifier), + constraint UK_member_member_image_id unique (member_image_id), + constraint UK_member_nickname unique (nickname), + constraint FK_member_member_profile_id + foreign key (member_profile_id) references member_profile (id), + constraint FK_member_member_image_id + foreign key (member_image_id) references member_image (id) +) engine=InnoDB; + +create table refresh_token +( + id bigint not null auto_increment, + token varchar(255) not null, + expired_at datetime(6) not null, + is_revoked bit not null, + member_id bigint not null, + primary key (id), + constraint FK_refresh_token_member_id + foreign key (member_id) references member (id) +) engine=InnoDB; + +create table roadmap_category +( + id bigint not null auto_increment, + name varchar(15) not null, + primary key (id) +) engine=InnoDB; + +create table roadmap +( + id bigint not null auto_increment, + title varchar(50) not null, + introduction varchar(200) not null, + difficulty varchar(30) not null, + required_period integer not null, + status varchar(10) not null, + created_at datetime(6) not null, + category_id bigint not null, + member_id bigint not null, + primary key (id), + constraint FK_roadmap_roadmap_category_id + foreign key (category_id) references roadmap_category (id), + constraint FK_roadmap_member_id + foreign key (member_id) references member (id) +) engine=InnoDB; + +create table roadmap_content +( + id bigint not null auto_increment, + content varchar(2200), + created_at datetime(6) not null, + updated_at datetime(6) not null, + roadmap_id bigint not null, + primary key (id), + constraint FK_roadmap_content_roadmap_id + foreign key (roadmap_id) references roadmap (id) +) engine=InnoDB; + +create table roadmap_node +( + id bigint not null auto_increment, + title varchar(50) not null, + content varchar(2200) not null, + roadmap_content_id bigint not null, + primary key (id), + constraint FK_roadmap_node_roadmap_content_id + foreign key (roadmap_content_id) references roadmap_content (id) +) engine=InnoDB; + +create table roadmap_node_image +( + id bigint not null auto_increment, + image_content_type varchar(10) not null, + original_file_name varchar(100) not null, + server_file_path varchar(255) not null, + roadmap_node_id bigint not null, + primary key (id), + constraint FK_roadmap_node_image_roadmap_node_id + foreign key (roadmap_node_id) references roadmap_node (id) +) engine=InnoDB; + +create table goal_room +( + id bigint not null auto_increment, + name varchar(50) not null, + limited_member_count integer not null, + status varchar(30) not null, + start_date date not null, + end_date date not null, + created_at datetime(6) not null, + updated_at datetime(6) not null, + roadmap_content_id bigint not null, + primary key (id), + constraint FK_goal_room_roadmap_content_id + foreign key (roadmap_content_id) references roadmap_content (id) +) engine=InnoDB; + +create table goal_room_pending_member +( + id bigint not null auto_increment, + role varchar(15) not null, + joined_at datetime(6), + goal_room_id bigint not null, + member_id bigint not null, + primary key (id), + constraint FK_goal_room_pending_member_goal_room_id + foreign key (goal_room_id) references goal_room (id), + constraint FK_goal_room_pending_member_member_id + foreign key (member_id) references member (id) +) engine=InnoDB; + +create table goal_room_member +( + id bigint not null auto_increment, + accomplishment_rate float(53), + role varchar(15) not null, + joined_at datetime(6), + goal_room_id bigint not null, + member_id bigint not null, + primary key (id), + constraint FK_goal_room_member_goal_room_id + foreign key (goal_room_id) references goal_room (id), + constraint FK_goal_room_member_member_id + foreign key (member_id) references member (id) +) engine=InnoDB; + +create table goal_room_to_do +( + id bigint not null auto_increment, + content varchar(300) not null, + start_date date not null, + end_date date not null, + created_at datetime(6) not null, + updated_at datetime(6) not null, + goal_room_id bigint not null, + primary key (id), + constraint FK_goal_room_to_do_goal_room_id + foreign key (goal_room_id) references goal_room (id) +) engine=InnoDB; + +create table goal_room_roadmap_node +( + id bigint not null auto_increment, + start_date date not null, + end_date date not null, + check_count integer not null, + goal_room_id bigint not null, + roadmap_node_id bigint not null, + primary key (id), + constraint FK_goal_room_roadmap_node_roadmap_node_id + foreign key (roadmap_node_id) references roadmap_node (id), + constraint goal_room_roadmap_node_goal_room_id + foreign key (goal_room_id) references goal_room (id) +) engine=InnoDB; + +create table check_feed +( + id bigint not null auto_increment, + server_file_path varchar(255) not null, + image_content_type varchar(255) not null, + original_file_name varchar(255) not null, + description varchar(255), + created_at timestamp(6) not null, + goal_room_roadmap_node_id bigint not null, + goal_room_member_id bigint not null, + primary key (id), + constraint FK_check_feed_goal_room_roadmap_node_id + foreign key (goal_room_roadmap_node_id) references goal_room_roadmap_node (id), + constraint FK_check_feed_goal_room_member_id + foreign key (goal_room_member_id) references goal_room_member (id) +) engine=InnoDB; + +create table roadmap_review +( + id bigint not null auto_increment, + rate float(53) not null, + content varchar(1200), + created_at datetime(6) not null, + updated_at datetime(6) not null, + member_id bigint not null, + roadmap_id bigint not null, + primary key (id), + constraint FK_roadmap_review_roadmap_id + foreign key (roadmap_id) references roadmap (id), + constraint FK_roadmap_review_member_id + foreign key (member_id) references member (id) +) engine=InnoDB; + +create table roadmap_tag +( + id bigint not null auto_increment, + name varchar(15) not null, + roadmap_id bigint not null, + primary key (id), + constraint FK_roadmap_tag_roadmap_id + foreign key (roadmap_id) references roadmap (id) +) engine=InnoDB; + +create table goal_room_to_do_check +( + id bigint not null auto_increment, + goal_room_member_id bigint not null, + goal_room_to_do_id bigint not null, + primary key (id), + constraint FK_goal_room_to_do_check_goal_room_member_id + foreign key (goal_room_member_id) references goal_room_member (id), + constraint FK_goal_room_to_do_check_goal_room_to_do_id + foreign key (goal_room_to_do_id) references goal_room_to_do (id) +) engine=InnoDB; diff --git a/backend/kirikiri/src/main/resources/logback-spring.xml b/backend/kirikiri/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..af830e368 --- /dev/null +++ b/backend/kirikiri/src/main/resources/logback-spring.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + ${LOG_PATTERN} + + + + + + + WARN + ACCEPT + DENY + + + ${LOG_PATH}/${DateFormat}/${LOG_FILE_NAME}.log + + + ${LOG_PATH}/%d{yyyy-MM-dd}/${LOG_FILE_NAME}_%i.log + + 10MB + 30 + + + ${LOG_PATTERN} + + + + + ${SLACK_WEBHOOK_URI} + + ${LOG_PATTERN} + + + + + + + ERROR + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/backend/kirikiri/src/main/resources/properties b/backend/kirikiri/src/main/resources/properties new file mode 160000 index 000000000..41b18591e --- /dev/null +++ b/backend/kirikiri/src/main/resources/properties @@ -0,0 +1 @@ +Subproject commit 41b18591e522e5fb41069236a5fa7756997ef3a7 diff --git a/backend/kirikiri/src/test/java/co/kirikiri/KirikiriApplicationTests.java b/backend/kirikiri/src/test/java/co/kirikiri/KirikiriApplicationTests.java new file mode 100644 index 000000000..b6cd535b4 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/KirikiriApplicationTests.java @@ -0,0 +1,15 @@ +package co.kirikiri; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("test") +class KirikiriApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/common/interceptor/AuthInterceptorTest.java b/backend/kirikiri/src/test/java/co/kirikiri/common/interceptor/AuthInterceptorTest.java new file mode 100644 index 000000000..9c0889d96 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/common/interceptor/AuthInterceptorTest.java @@ -0,0 +1,94 @@ +package co.kirikiri.common.interceptor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.service.AuthService; +import org.junit.jupiter.api.BeforeEach; +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 org.springframework.http.HttpHeaders; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.method.HandlerMethod; + +@ExtendWith(MockitoExtension.class) +class AuthInterceptorTest { + + private MockHttpServletRequest request; + private MockHttpServletResponse response; + + @Mock + private AuthService authService; + + @Mock + private HandlerMethod handlerMethod; + + @InjectMocks + private AuthInterceptor authInterceptor; + + @BeforeEach + void setUp() { + request = new MockHttpServletRequest(); + response = new MockHttpServletResponse(); + } + + @Test + void ์ธ์ฆ์ด_ํ•„์š”ํ•œ_์š”์ฒญ์—์„œ_์ •์ƒ์ ์œผ๋กœ_์œ ํšจํ•œ_ํ† ํฐ์„_๊ฒ€์‚ฌํ•œ๋‹ค() { + //given + when(handlerMethod.hasMethodAnnotation(any())) + .thenReturn(true); + request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer test-token"); + when(authService.isCertified(anyString())).thenReturn(true); + + //when + final boolean result = authInterceptor.preHandle(request, response, handlerMethod); + + //then + assertThat(result).isTrue(); + } + + @Test + void ์ธ์ฆ์ด_ํ•„์š”ํ•œ_์š”์ฒญ์—์„œ_Authorization_ํ—ค๋”๊ฐ€_์—†์„๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + when(handlerMethod.hasMethodAnnotation(any())) + .thenReturn(true); + + //when + //then + assertThatThrownBy(() -> authInterceptor.preHandle(request, response, handlerMethod)) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ์ธ์ฆ์ด_ํ•„์š”ํ•œ_์š”์ฒญ์—์„œ_Authorization_ํ—ค๋”๊ฐ€_Bearer๊ฐ€_์—†์„๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + when(handlerMethod.hasMethodAnnotation(any())) + .thenReturn(true); + request.addHeader(HttpHeaders.AUTHORIZATION, "test-token"); + + //when + assertThatThrownBy(() -> authInterceptor.preHandle(request, response, handlerMethod)) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ์ธ์ฆ์ด_ํ•„์š”ํ•œ_์š”์ฒญ์—์„œ_ํ† ํฐ์ด_์œ ํšจํ•˜์ง€_์•Š์„๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + when(handlerMethod.hasMethodAnnotation(any())) + .thenReturn(true); + request.addHeader(HttpHeaders.AUTHORIZATION, "Bearer test-token"); + when(authService.isCertified(anyString())).thenReturn(false); + + //when + assertThatThrownBy(() -> authInterceptor.preHandle(request, response, handlerMethod)) + .isInstanceOf(AuthenticationException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/common/resolver/MemberIdentifierArgumentResolverTest.java b/backend/kirikiri/src/test/java/co/kirikiri/common/resolver/MemberIdentifierArgumentResolverTest.java new file mode 100644 index 000000000..dfe250b02 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/common/resolver/MemberIdentifierArgumentResolverTest.java @@ -0,0 +1,153 @@ +package co.kirikiri.common.resolver; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.service.AuthService; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.ModelAndViewContainer; + +@ExtendWith(MockitoExtension.class) +class MemberIdentifierArgumentResolverTest { + + private static final String BEARER = "Bearer "; + + @Mock + private AuthService authService; + + @Mock + private MethodParameter parameter; + + @Mock + private ModelAndViewContainer mavContainer; + + @Mock + private NativeWebRequest webRequest; + + @Mock + private WebDataBinderFactory binderFactory; + + @InjectMocks + private MemberIdentifierArgumentResolver memberIdentifierArgumentResolver; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_String_ํƒ€์ž…์ด๊ณ _MemberIdentifier์ด_๋ถ™์€_์ธ์ž์ธ_๊ฒฝ์šฐ() { + //given + Mockito.>when(parameter.getParameterType()) + .thenReturn(String.class); + when(parameter.hasParameterAnnotation(MemberIdentifier.class)) + .thenReturn(true); + + //when + final boolean result = memberIdentifierArgumentResolver.supportsParameter(parameter); + + //then + assertThat(result).isTrue(); + } + + @Test + void String_ํƒ€์ž…์ด_๋ถ™์ง€_์•Š์€_๊ฒฝ์šฐ() { + //given + Mockito.>when(parameter.getParameterType()) + .thenReturn(List.class); + + //when + final boolean result = memberIdentifierArgumentResolver.supportsParameter(parameter); + + //then + assertThat(result).isFalse(); + } + + @Test + void String_ํƒ€์ž…์ด๊ณ _MemberIdentifier์ด_๋ถ™์ง€_์•Š์€_์ธ์ž์ธ_๊ฒฝ์šฐ() { + //given + Mockito.>when(parameter.getParameterType()) + .thenReturn(String.class); + when(parameter.hasParameterAnnotation(MemberIdentifier.class)) + .thenReturn(false); + + //when + final boolean result = memberIdentifierArgumentResolver.supportsParameter(parameter); + + //then + assertThat(result).isFalse(); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํ† ํฐ์ด_๋“ค์–ด์˜จ_๊ฒฝ์šฐ_ํ† ํฐ์„_์ธ์ฆํ•œ๋‹ค() { + // given + final String expectedIdentifier = "test"; + final String token = "testToken"; + + when(webRequest.getHeader(HttpHeaders.AUTHORIZATION)) + .thenReturn(BEARER + token); + when(authService.findIdentifierByToken(anyString())) + .thenReturn(expectedIdentifier); + + // when + final String actualIdentifier = memberIdentifierArgumentResolver.resolveArgument(parameter, mavContainer, + webRequest, binderFactory); + + // then + assertThat(actualIdentifier).isEqualTo(expectedIdentifier); + } + + @Test + void AUTHORIZATION_HEADER์—_BEARER์ด_์•ˆ๋ถ™์€_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_ํ„ฐํŠธ๋ฆฐ๋‹ค() { + // given + final String token = "testToken"; + + when(webRequest.getHeader(HttpHeaders.AUTHORIZATION)) + .thenReturn(token); + + // when + // then + assertThatThrownBy(() -> memberIdentifierArgumentResolver.resolveArgument(parameter, mavContainer, webRequest, + binderFactory)) + .isInstanceOf(AuthenticationException.class); + + } + + @Test + void AUTHORIZATION_HEADER๊ฐ€_๋น„์–ด์žˆ์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_ํ„ฐํŠธ๋ฆฐ๋‹ค() { + // given + when(webRequest.getHeader(HttpHeaders.AUTHORIZATION)) + .thenReturn(null); + + // when + // then + assertThatThrownBy(() -> memberIdentifierArgumentResolver.resolveArgument(parameter, mavContainer, webRequest, + binderFactory)) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ์ ์ ˆํ•˜์ง€_์•Š์€_ํ† ํฐ์ด_๋“ค์–ด์˜ฌ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_ํ„ฐํŠธ๋ฆฐ๋‹ค() { + // given + final String token = "testToken"; + + when(webRequest.getHeader(HttpHeaders.AUTHORIZATION)) + .thenReturn(BEARER + token); + when(authService.findIdentifierByToken(anyString())) + .thenThrow(new AuthenticationException("ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")); + + // when + // then + assertThatThrownBy(() -> memberIdentifierArgumentResolver.resolveArgument(parameter, mavContainer, webRequest, + binderFactory)) + .isInstanceOf(AuthenticationException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/common/resolver/RoadmapSaveArgumentResolverTest.java b/backend/kirikiri/src/test/java/co/kirikiri/common/resolver/RoadmapSaveArgumentResolverTest.java new file mode 100644 index 000000000..757128140 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/common/resolver/RoadmapSaveArgumentResolverTest.java @@ -0,0 +1,117 @@ +package co.kirikiri.common.resolver; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.when; + +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import javax.xml.validation.Validator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.core.MethodParameter; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockMultipartHttpServletRequest; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.ModelAndViewContainer; + +@ExtendWith(MockitoExtension.class) +class RoadmapSaveArgumentResolverTest { + + @Mock + private ObjectMapper objectMapper; + + @Mock + private Validator validator; + + @Mock + private MethodParameter parameter; + + @Mock + private ModelAndViewContainer mavContainer; + + @Mock + private NativeWebRequest nativeWebRequest; + + @Mock + private WebDataBinderFactory binderFactory; + + @InjectMocks + private RoadmapSaveArgumentResolver resolver; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํ•ธ๋“ค๋Ÿฌ์˜_ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€_๊ฐ์ฒด๋ฅผ_ํƒ€๋„๋ก_ํ•œ๋‹ค() { + //given + Mockito.>when(parameter.getParameterType()) + .thenReturn(RoadmapSaveRequest.class); + + //when + final boolean result = resolver.supportsParameter(parameter); + + //then + assertThat(result).isTrue(); + } + + @Test + void ํ•ธ๋“ค๋Ÿฌ์˜_ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€_๊ฐ์ฒด๋ฅผ_ํƒ€์ง€_์•Š๋Š”๋‹ค() { + //given + Mockito.>when(parameter.getParameterType()) + .thenReturn(MemberJoinRequest.class); + + //when + final boolean result = resolver.supportsParameter(parameter); + + //then + assertThat(result).isFalse(); + } + + @Test + void ๋ฉ€ํ‹ฐํŒŒํŠธํผ_์š”์ฒญ์ด_์•„๋‹_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„() { + //given + when(nativeWebRequest.getNativeRequest()) + .thenReturn(new MockHttpServletRequest()); + + //when + //then + assertThatThrownBy(() -> resolver.resolveArgument(parameter, mavContainer, nativeWebRequest, binderFactory)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ์š”์ฒญ์—_jsonData๊ฐ€_ํฌํ•จ๋˜์–ด์žˆ์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final MockMultipartHttpServletRequest multipartRequest = new MockMultipartHttpServletRequest(); + + when(nativeWebRequest.getNativeRequest()).thenReturn(multipartRequest); + + //when + //then + assertThatThrownBy(() -> resolver.resolveArgument(parameter, mavContainer, nativeWebRequest, binderFactory)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void jsonData๊ฐ€_RoadmapSaveRequest_ํ˜•์‹์ด_์•„๋‹_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws JsonProcessingException { + //given + final MockMultipartHttpServletRequest multipartRequest = new MockMultipartHttpServletRequest(); + final String jsonData = "{\"key\":\"value\"}"; + multipartRequest.addParameter("jsonData", jsonData); + when(nativeWebRequest.getNativeRequest()).thenReturn(multipartRequest); + when(objectMapper.readValue(jsonData, RoadmapSaveRequest.class)) + .thenThrow(new JsonProcessingException("message") { + }); + + //when + //then + assertThatThrownBy(() -> resolver.resolveArgument(parameter, mavContainer, nativeWebRequest, binderFactory)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/AuthCreateApiTest.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/AuthCreateApiTest.java new file mode 100644 index 000000000..575a2aa23 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/AuthCreateApiTest.java @@ -0,0 +1,297 @@ +package co.kirikiri.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doThrow; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import co.kirikiri.controller.helper.ControllerTestHelper; +import co.kirikiri.controller.helper.FieldDescriptionHelper.FieldDescription; +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.service.AuthService; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.auth.request.ReissueTokenRequest; +import co.kirikiri.service.dto.auth.response.AuthenticationResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import java.util.List; +import org.junit.jupiter.api.Test; +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.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.ResultMatcher; + +@WebMvcTest(AuthController.class) +class AuthCreateApiTest extends ControllerTestHelper { + + private static final String IDENTIFIER = "identifier1"; + private static final String PASSWORD = "password1!"; + + @MockBean + private AuthService authService; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๊ทธ์ธ์—_์„ฑ๊ณตํ•œ๋‹ค() throws Exception { + //given + final LoginRequest request = new LoginRequest(IDENTIFIER, PASSWORD); + final AuthenticationResponse expectedResponse = new AuthenticationResponse("refreshToken", "accessToken"); + final String jsonRequest = objectMapper.writeValueAsString(request); + given(authService.login(request)) + .willReturn(expectedResponse); + + final List requestFieldDescription = makeSuccessRequestFieldDescription(); + final List responseFieldDescription = makeSuccessResponseFieldDescription(); + + //when + final MvcResult mvcResult = ๋กœ๊ทธ์ธ(jsonRequest, status().isOk()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(requestFieldDescription)), + responseFields(makeFieldDescriptor(responseFieldDescription))) + ) + .andReturn(); + + //then + final AuthenticationResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๋กœ๊ทธ์ธ_์‹œ_์•„์ด๋””์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final LoginRequest request = new LoginRequest("", PASSWORD); + final String jsonRequest = objectMapper.writeValueAsString(request); + + //when + final MvcResult mvcResult = ๋กœ๊ทธ์ธ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .isEqualTo(List.of(expectedResponse)); + } + + @Test + void ๋กœ๊ทธ์ธ_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final LoginRequest request = new LoginRequest(IDENTIFIER, ""); + final String jsonRequest = objectMapper.writeValueAsString(request); + + //when + final MvcResult mvcResult = ๋กœ๊ทธ์ธ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .isEqualTo(List.of(expectedResponse)); + } + + @Test + void ๋กœ๊ทธ์ธ_์‹œ_์•„์ด๋””์™€_๋น„๋ฐ€๋ฒˆํ˜ธ_๋ชจ๋‘_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final LoginRequest request = new LoginRequest("", ""); + final String jsonRequest = objectMapper.writeValueAsString(request); + + //when + final MvcResult mvcResult = ๋กœ๊ทธ์ธ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse passwordResponse = new ErrorResponse("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse identifierResponse = new ErrorResponse("์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(identifierResponse, passwordResponse)); + } + + @Test + void ๋กœ๊ทธ์ธ_์‹œ_์•„์ด๋””์—_ํ•ด๋‹นํ•˜๋Š”_ํšŒ์›์ด_์—†์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final LoginRequest request = new LoginRequest(IDENTIFIER, PASSWORD); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new AuthenticationException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค.")) + .when(authService) + .login(request); + + //when + final MvcResult mvcResult = ๋กœ๊ทธ์ธ(jsonRequest, status().isUnauthorized()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค."); + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .isEqualTo(expectedResponse); + } + + @Test + void ๋กœ๊ทธ์ธ_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€_๋งž์ง€_์•Š์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final LoginRequest request = new LoginRequest(IDENTIFIER, PASSWORD); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new AuthenticationException("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")) + .when(authService) + .login(request); + + //when + final MvcResult mvcResult = ๋กœ๊ทธ์ธ(jsonRequest, status().isUnauthorized()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .isEqualTo(expectedResponse); + } + + @Test + void ํ† ํฐ์„_์ •์ƒ์ ์œผ๋กœ_์žฌ๋ฐœํ–‰ํ•œ๋‹ค() throws Exception { + //given + final ReissueTokenRequest request = new ReissueTokenRequest("refreshToken"); + final AuthenticationResponse expectedResponse = new AuthenticationResponse("reIssuedRefreshToken", + "reIssuedAccessToken"); + final String jsonRequest = objectMapper.writeValueAsString(request); + given(authService.reissueToken(request)) + .willReturn(expectedResponse); + + //when + final MvcResult mvcResult = ํ† ํฐ_์žฌ๋ฐœํ–‰(jsonRequest, status().isOk()) + .andDo( + documentationResultHandler.document( + requestFields( + fieldWithPath("refreshToken").description("๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ") + ), + responseFields( + fieldWithPath("refreshToken").description("๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ"), + fieldWithPath("accessToken").description("์•ก์„ธ์Šค ํ† ํฐ") + ) + ) + ) + .andReturn(); + + //then + final AuthenticationResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_๋ฆฌํ”„๋ ˆ์‹œ_ํ† ํฐ์ด_๋นˆ๊ฐ’์ผ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final ReissueTokenRequest request = new ReissueTokenRequest(""); + final String jsonRequest = objectMapper.writeValueAsString(request); + + //when + final MvcResult mvcResult = ํ† ํฐ_์žฌ๋ฐœํ–‰(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse errorResponse = new ErrorResponse("๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).usingRecursiveComparison() + .isEqualTo(List.of(errorResponse)); + } + + @Test + void ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_ํ† ํฐ์ด_์œ ํšจํ•˜์ง€_์•Š์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final ReissueTokenRequest request = new ReissueTokenRequest("refreshToken"); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new AuthenticationException("Invalid Token")) + .when(authService) + .reissueToken(request); + + //when + final MvcResult mvcResult = ํ† ํฐ_์žฌ๋ฐœํ–‰(jsonRequest, status().isUnauthorized()) + .andReturn(); + + //then + final ErrorResponse errorResponse = new ErrorResponse("Invalid Token"); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).usingRecursiveComparison() + .isEqualTo(errorResponse); + } + + @Test + void ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_ํ† ํฐ์ด_๋งŒ๋ฃŒ_๋์„_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws Exception { + //given + final ReissueTokenRequest request = new ReissueTokenRequest("refreshToken"); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new AuthenticationException("Expired Token")) + .when(authService) + .reissueToken(request); + + //when + final MvcResult mvcResult = ํ† ํฐ_์žฌ๋ฐœํ–‰(jsonRequest, status().isUnauthorized()) + .andReturn(); + + //then + final ErrorResponse errorResponse = new ErrorResponse("Expired Token"); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).usingRecursiveComparison() + .isEqualTo(errorResponse); + } + + private ResultActions ๋กœ๊ทธ์ธ(final String jsonRequest, final ResultMatcher result) throws Exception { + return mockMvc.perform(post(API_PREFIX + "/auth/login") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(result) + .andDo(print()); + } + + private ResultActions ํ† ํฐ_์žฌ๋ฐœํ–‰(final String jsonRequest, final ResultMatcher result) throws Exception { + return mockMvc.perform(post(API_PREFIX + "/auth/reissue") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(result) + .andDo(print()); + } + + private List makeSuccessRequestFieldDescription() { + return List.of( + new FieldDescription("identifier", "์‚ฌ์šฉ์ž ์•„์ด๋””", + "- ๊ธธ์ด : 4 ~ 20 +" + "\n" + + "- ์˜์–ด ์†Œ๋ฌธ์ž, ์ˆซ์ž ๊ฐ€๋Šฅ"), + new FieldDescription("password", "์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ", + "- ๊ธธ์ด : 8 ~ 15 +" + "\n" + + "- ์˜์–ด ์†Œ๋ฌธ์ž, ์ˆซ์ž, ํŠน์ˆ˜๋ฌธ์ž +" + "\n" + + "- ํŠน์ˆ˜๋ฌธ์ž[!,@,#,$,%,^,&,*,(,),~] ์‚ฌ์šฉ ๊ฐ€๋Šฅ") + ); + } + + private List makeSuccessResponseFieldDescription() { + return List.of( + new FieldDescription("refreshToken", "๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ"), + new FieldDescription("accessToken", "์•ก์„ธ์Šค ํ† ํฐ") + ); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/GoalRoomCreateApiTest.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/GoalRoomCreateApiTest.java new file mode 100644 index 000000000..b49c2a716 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/GoalRoomCreateApiTest.java @@ -0,0 +1,1286 @@ +package co.kirikiri.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.partWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.requestParts; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import co.kirikiri.controller.helper.ControllerTestHelper; +import co.kirikiri.controller.helper.FieldDescriptionHelper.FieldDescription; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.service.GoalRoomCreateService; +import co.kirikiri.service.GoalRoomReadService; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.ResultMatcher; + +@WebMvcTest(GoalRoomController.class) +class GoalRoomCreateApiTest extends ControllerTestHelper { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + + @MockBean + private GoalRoomCreateService goalRoomCreateService; + + @MockBean + private GoalRoomReadService goalRoomReadService; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + + given(goalRoomCreateService.create(any(), any())) + .willReturn(1L); + final String jsonRequest = objectMapper.writeValueAsString(request); + + //when + final List requestFieldDescription = makeCreateGoalRoomSuccessRequestFieldDescription(); + + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isCreated()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(requestFieldDescription)), + requestHeaders(headerWithName(HttpHeaders.AUTHORIZATION).description("Access Token")), + responseHeaders(headerWithName(HttpHeaders.LOCATION).description("๊ณจ๋ฃธ ๋‹จ์ผ ์กฐํšŒ api ๊ฒฝ๋กœ")) + )) + .andReturn(); + + //then + assertThat(mvcResult.getResponse().getHeader("Location")).isEqualTo("/api/goal-rooms/" + 1); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์š”์ฒญ์—_๋นˆ๊ฐ’์ด_์žˆ์„_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(null, null, + null, new GoalRoomTodoRequest(null, null, null), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(null, null, null, null)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse roadmapCheckCountIdErrorResponse = new ErrorResponse("์ธ์ฆ ํšŸ์ˆ˜๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse roadmapNodeIdErrorResponse = new ErrorResponse("๋กœ๋“œ๋งต ๋…ธ๋“œ ์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse goalRoomTodoContentErrorResponse = new ErrorResponse("ํˆฌ๋‘์˜ ์ปจํ…์ธ ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse limitedMemberCountErrorResponse = new ErrorResponse("๊ณจ๋ฃธ ์ œํ•œ ์ธ์›์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse goalRoomNameErrorResponse = new ErrorResponse("๊ณจ๋ฃธ ์ด๋ฆ„์„ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse roadmapContentIdErrorResponse = new ErrorResponse("๋กœ๋“œ๋งต ์ปจํ…์ธ  ์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse goalRoomNodeStartDateErrorResponse = new ErrorResponse("๋กœ๋“œ๋งต ๋…ธ๋“œ ์‹œ์ž‘ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse goalRoomNodeEndDateErrorResponse = new ErrorResponse("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ข…๋ฃŒ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse goalRoomTodoStartDateErrorResponse = new ErrorResponse("๊ณจ๋ฃธ ํˆฌ๋‘ ์‹œ์ž‘ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse goalRoomTodoEndDateErrorResponse = new ErrorResponse("๊ณจ๋ฃธ ํˆฌ๋‘ ์ข…๋ฃŒ ๋‚ ์งœ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(roadmapCheckCountIdErrorResponse, roadmapNodeIdErrorResponse, + goalRoomTodoContentErrorResponse, limitedMemberCountErrorResponse, + goalRoomNameErrorResponse, roadmapContentIdErrorResponse, + goalRoomNodeStartDateErrorResponse, goalRoomNodeEndDateErrorResponse, + goalRoomTodoStartDateErrorResponse, goalRoomTodoEndDateErrorResponse + )); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต์ด_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isNotFound()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์‚ญ์ œ๋œ_๋กœ๋“œ๋งต_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("์‚ญ์ œ๋œ ๋กœ๋“œ๋งต์— ๋Œ€ํ•ด ๊ณจ๋ฃธ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์‚ญ์ œ๋œ ๋กœ๋“œ๋งต์— ๋Œ€ํ•ด ๊ณจ๋ฃธ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต์˜_๋…ธ๋“œ_ํฌ๊ธฐ์™€_์š”์ฒญ์˜_๋…ธ๋“œ_ํฌ๊ธฐ๊ฐ€_์ผ์น˜ํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("๋ชจ๋“  ๋…ธ๋“œ์— ๋Œ€ํ•ด ๊ธฐ๊ฐ„์ด ์„ค์ •๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("๋ชจ๋“  ๋…ธ๋“œ์— ๋Œ€ํ•ด ๊ธฐ๊ฐ„์ด ์„ค์ •๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต์—_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋…ธ๋“œ์ผ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new NotFoundException("๋กœ๋“œ๋งต์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isNotFound()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("๋กœ๋“œ๋งต์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋…ธ๋“œ์ž…๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ผ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isNotFound()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_ํˆฌ๋‘์˜_์‹œ์ž‘_๋‚ ์งœ๋ณด๋‹ค_์ข…๋ฃŒ_๋‚ ์งœ๊ฐ€_๋น ๋ฅธ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TEN_DAY_LATER, TODAY), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("์‹œ์ž‘์ผ์€ ์ข…๋ฃŒ์ผ๋ณด๋‹ค ํ›„์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์‹œ์ž‘์ผ์€ ์ข…๋ฃŒ์ผ๋ณด๋‹ค ํ›„์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_ํˆฌ๋‘์˜_์‹œ์ž‘_๋‚ ์งœ๊ฐ€_์˜ค๋Š˜๋ณด๋‹ค_์ „์ผ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY.minusDays(10), TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("์‹œ์ž‘์ผ์€ ์˜ค๋Š˜๋ณด๋‹ค ์ „์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์‹œ์ž‘์ผ์€ ์˜ค๋Š˜๋ณด๋‹ค ์ „์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์‹œ์ž‘_๋‚ ์งœ๋ณด๋‹ค_์ข…๋ฃŒ_๋‚ ์งœ๊ฐ€_๋น ๋ฅธ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TEN_DAY_LATER, TODAY)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("์‹œ์ž‘์ผ์€ ์ข…๋ฃŒ์ผ๋ณด๋‹ค ํ›„์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์‹œ์ž‘์ผ์€ ์ข…๋ฃŒ์ผ๋ณด๋‹ค ํ›„์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์‹œ์ž‘_๋‚ ์งœ๊ฐ€_์˜ค๋Š˜๋ณด๋‹ค_์ „์ผ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY.minusDays(10), TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("์‹œ์ž‘์ผ์€ ์˜ค๋Š˜๋ณด๋‹ค ์ „์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("์‹œ์ž‘์ผ์€ ์˜ค๋Š˜๋ณด๋‹ค ์ „์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์ธ์ฆ_ํšŸ์ˆ˜๊ฐ€_0๋ณด๋‹ค_์ž‘์„_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 0, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๋Š” 0๋ณด๋‹ค ์ปค์•ผํ•ฉ๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๋Š” 0๋ณด๋‹ค ์ปค์•ผํ•ฉ๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์ธ์ฆ_ํšŸ์ˆ˜๊ฐ€_๊ธฐ๊ฐ„๋ณด๋‹ค_ํด_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 11, TODAY, TEN_DAY_LATER)))); + final String jsonRequest = objectMapper.writeValueAsString(request); + doThrow(new BadRequestException("๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๊ฐ€ ์„ค์ • ๊ธฐ๊ฐ„๋ณด๋‹ค ํด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .create(any(), any()); + + //when + final MvcResult mvcResult = ๊ณจ๋ฃธ_์ƒ์„ฑ(jsonRequest, status().isBadRequest()) + .andReturn(); + + //then + final ErrorResponse expectedResponse = new ErrorResponse("๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜๊ฐ€ ์„ค์ • ๊ธฐ๊ฐ„๋ณด๋‹ค ํด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(expectedResponse); + } + + @Test + void ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ์„_์„ฑ๊ณตํ•œ๋‹ค() throws Exception { + //given + final Long goalRoomId = 1L; + doNothing().when(goalRoomCreateService) + .join(anyString(), anyLong()); + + //when + //then + mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/join", goalRoomId) + .header(AUTHORIZATION, "Bearer ") + .contextPath(API_PREFIX)) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")))) + .andExpect(status().isOk()); + } + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ๊ฐ€_์š”์ฒญ์€_์‹คํŒจํ•œ๋‹ค() throws Exception { + //given + final Long goalRoomId = 1L; + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. roadmapId = 1")) + .when(goalRoomCreateService) + .join(anyString(), anyLong()); + + //when + //given + mockMvc.perform( + post(API_PREFIX + "/goal-rooms/{goalRoomId}/join", goalRoomId) + .header("Authorization", "Bearer ") + .content(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. roadmapId = 1")) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))); + } + + @Test + void ์ด๋ฏธ_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ๊ฐ€_์š”์ฒญ์€_์‹คํŒจํ•œ๋‹ค() throws Exception { + //given + final Long goalRoomId = 1L; + doThrow(new BadRequestException("์ด๋ฏธ ์ฐธ๊ฐ€๋˜์–ด ์žˆ๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .join(anyString(), anyLong()); + + //when + //then + mockMvc.perform( + post(API_PREFIX + "/goal-rooms/{goalRoomId}/join", goalRoomId) + .header("Authorization", "Bearer ") + .content(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value("์ด๋ฏธ ์ฐธ๊ฐ€๋˜์–ด ์žˆ๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))); + } + + @Test + void ์ œํ•œ_์ธ์›์ด_๊ฐ€๋“_์ฐฌ_๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ๊ฐ€_์š”์ฒญ์€_์‹คํŒจํ•œ๋‹ค() throws Exception { + //given + final Long goalRoomId = 1L; + doThrow(new BadRequestException("์ œํ•œ ์ธ์›์ด ๊ฐ€๋“ ์ฐฌ ๊ณจ๋ฃธ์—๋Š” ์ฐธ๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .join(anyString(), anyLong()); + + //when + //then + mockMvc.perform( + post(API_PREFIX + "/goal-rooms/{goalRoomId}/join", goalRoomId) + .header("Authorization", "Bearer ") + .content(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value("์ œํ•œ ์ธ์›์ด ๊ฐ€๋“ ์ฐฌ ๊ณจ๋ฃธ์—๋Š” ์ฐธ๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค() throws Exception { + //given + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER); + final String jsonRequest = objectMapper.writeValueAsString(goalRoomTodoRequest); + given(goalRoomCreateService.addGoalRoomTodo(anyLong(), anyString(), any())) + .willReturn(1L); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1L) + .content(jsonRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isCreated()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(makeAddTodoSuccessRequestFieldDescription())), + requestHeaders(headerWithName(HttpHeaders.AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + responseHeaders(headerWithName(HttpHeaders.LOCATION).description("๊ณจ๋ฃธ ํˆฌ๋‘ ๋‹จ์ผ ์กฐํšŒ api ๊ฒฝ๋กœ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")))) + .andReturn(); + + //then + assertThat(mvcResult.getResponse().getHeader(HttpHeaders.LOCATION)).isEqualTo( + API_PREFIX + "/goal-rooms/1/todos/1"); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ผ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER); + final String jsonRequest = objectMapper.writeValueAsString(goalRoomTodoRequest); + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .addGoalRoomTodo(anyLong(), anyString(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1) + .content(jsonRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(makeAddTodoSuccessRequestFieldDescription())), + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER); + final String jsonRequest = objectMapper.writeValueAsString(goalRoomTodoRequest); + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomCreateService) + .addGoalRoomTodo(anyLong(), anyString(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1) + .content(jsonRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(makeAddTodoSuccessRequestFieldDescription())), + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์ด๋ฏธ_์ข…๋ฃŒ๋œ_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER); + final String jsonRequest = objectMapper.writeValueAsString(goalRoomTodoRequest); + doThrow(new BadRequestException("์ด๋ฏธ ์ข…๋ฃŒ๋œ ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .addGoalRoomTodo(anyLong(), anyString(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1L) + .content(jsonRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(makeAddTodoSuccessRequestFieldDescription())), + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("์ด๋ฏธ ์ข…๋ฃŒ๋œ ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_๋ฆฌ๋”๊ฐ€_์•„๋‹Œ_๊ฒฝ์šฐ() throws Exception { + //given + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER); + final String jsonRequest = objectMapper.writeValueAsString(goalRoomTodoRequest); + doThrow(new BadRequestException("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .addGoalRoomTodo(anyLong(), anyString(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1L) + .content(jsonRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(makeAddTodoSuccessRequestFieldDescription())), + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘_์ถ”๊ฐ€์‹œ_์ปจํ…์ธ ๊ฐ€_250๊ธ€์ž๊ฐ€_๋„˜์„_๊ฒฝ์šฐ() throws Exception { + //given + final String content = "a".repeat(251); + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest(content, TODAY, TEN_DAY_LATER); + final String jsonRequest = objectMapper.writeValueAsString(goalRoomTodoRequest); + doThrow(new BadRequestException("ํˆฌ๋‘ ์ปจํ…์ธ ์˜ ๊ธธ์ด๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .addGoalRoomTodo(anyLong(), anyString(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1L) + .content(jsonRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(makeAddTodoSuccessRequestFieldDescription())), + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("ํˆฌ๋‘ ์ปจํ…์ธ ์˜ ๊ธธ์ด๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ์—_๋Œ€ํ•ด_์ฒดํฌํ•œ๋‹ค() throws Exception { + // given + final GoalRoomToDoCheckResponse expected = new GoalRoomToDoCheckResponse(true); + when(goalRoomCreateService.checkGoalRoomTodo(anyLong(), anyLong(), anyString())) + .thenReturn(expected); + + // when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos/{todoId}", 1L, 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””"), + parameterWithName("todoId").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์•„์ด๋””")), + responseFields( + fieldWithPath("isChecked").description( + "ํˆฌ๋‘ ์ฒดํฌ ํ˜„ํ™ฉ (true: ์ฒดํฌ๋จ, false: ์ฒดํฌ๋˜์ง€ ์•Š์Œ)")))) + .andReturn(); + + // then + final GoalRoomToDoCheckResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_์ฒดํฌ_์ด๋ ฅ์ด_์žˆ์œผ๋ฉด_์ œ๊ฑฐํ•œ๋‹ค() throws Exception { + // given + final GoalRoomToDoCheckResponse expected = new GoalRoomToDoCheckResponse(false); + when(goalRoomCreateService.checkGoalRoomTodo(anyLong(), anyLong(), anyString())) + .thenReturn(expected); + + // when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos/{todoId}", 1L, 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””"), + parameterWithName("todoId").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์•„์ด๋””")), + responseFields( + fieldWithPath("isChecked").description( + "ํˆฌ๋‘ ์ฒดํฌ ํ˜„ํ™ฉ (true: ์ฒดํฌ๋จ, false: ์ฒดํฌ๋˜์ง€ ์•Š์Œ)")))) + .andReturn(); + + // then + final GoalRoomToDoCheckResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_๊ณจ๋ฃธ์ด_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + //given + doThrow(new NotFoundException("๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomCreateService) + .checkGoalRoomTodo(anyLong(), anyLong(), anyString()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos/{todoId}", 1L, 1L) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””"), + parameterWithName("todoId").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_ํ•ด๋‹น_ํˆฌ๋‘๊ฐ€_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + //given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํˆฌ๋‘์ž…๋‹ˆ๋‹ค. todoId = 1")) + .when(goalRoomCreateService) + .checkGoalRoomTodo(anyLong(), anyLong(), anyString()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos/{todoId}", 1L, 1L) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””"), + parameterWithName("todoId").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์•„์ด๋””")), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response) + .isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํˆฌ๋‘์ž…๋‹ˆ๋‹ค. todoId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_์‚ฌ์šฉ์ž๊ฐ€_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + //given + doThrow(new NotFoundException("๊ณจ๋ฃธ์— ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = cokirikiri")) + .when(goalRoomCreateService) + .checkGoalRoomTodo(anyLong(), anyLong(), anyString()); + + //when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos/{todoId}", 1L, 1L) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””"), + parameterWithName("todoId").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์•„์ด๋””")), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response) + .isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = cokirikiri")); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ์„_๋ณด๋‚ธ๋‹ค() throws Exception { + //given + final String imageName = "image"; + final String originalImageName = "originalImageName.jpeg"; + final String contentType = "image/jpeg"; + final String image = "ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€"; + final String description = "์ด๋ฏธ์ง€ ์„ค๋ช…"; + final String filePath = "path/to/directories/" + contentType; + final MockMultipartFile imageFile = new MockMultipartFile(imageName, originalImageName, + contentType, image.getBytes()); + + given(goalRoomCreateService.createCheckFeed(anyString(), anyLong(), any())) + .willReturn(filePath); + + //expect + mockMvc.perform( + RestDocumentationRequestBuilders + .multipart(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", 1L) + .file(imageFile) + .file("text", description.getBytes()) + .header("Authorization", "Bearer accessToken") + .contextPath(API_PREFIX) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE)) + .andExpect(status().isCreated()) + .andExpect(header().string("Location", filePath)) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName("Authorization").description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + requestParts( + partWithName("image").description("์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€"), + partWithName("text").description("์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ") + ), + responseHeaders( + headerWithName("Location").description("์ €์žฅ๋œ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ") + ))); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์‹œ_๋…ธ๋“œ_๊ธฐ๊ฐ„์—_ํ•ด๋‹นํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String imageName = "image"; + final String originalImageName = "originalImageName.jpeg"; + final String contentType = "image/jpeg"; + final String image = "ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€"; + final String description = "์ด๋ฏธ์ง€ ์„ค๋ช…"; + final MockMultipartFile imageFile = new MockMultipartFile(imageName, originalImageName, + contentType, image.getBytes()); + + doThrow(new BadRequestException("์ธ์ฆ ํ”ผ๋“œ๋Š” ๋…ธ๋“œ ๊ธฐ๊ฐ„ ๋‚ด์—๋งŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .createCheckFeed(anyString(), anyLong(), any()); + + //when + mockMvc.perform( + RestDocumentationRequestBuilders + .multipart(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", 1L) + .file(imageFile) + .param("description", description) + .header("Authorization", "Bearer accessToken") + .contextPath(API_PREFIX) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value("์ธ์ฆ ํ”ผ๋“œ๋Š” ๋…ธ๋“œ ๊ธฐ๊ฐ„ ๋‚ด์—๋งŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName("Authorization").description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + requestParts( + partWithName("image").description("์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ์‹œ_๋ฉค๋ฒ„๊ฐ€_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws Exception { + //given + final String imageName = "image"; + final String originalImageName = "originalImageName.jpeg"; + final String contentType = "image/jpeg"; + final String image = "ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€"; + final String description = "์ด๋ฏธ์ง€ ์„ค๋ช…"; + final MockMultipartFile imageFile = new MockMultipartFile(imageName, originalImageName, + contentType, image.getBytes()); + + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .createCheckFeed(anyString(), anyLong(), any()); + + //when + mockMvc.perform( + RestDocumentationRequestBuilders + .multipart(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", 1L) + .file(imageFile) + .file("text", description.getBytes()) + .header("Authorization", "Bearer accessToken") + .contextPath(API_PREFIX) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName("Authorization").description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + requestParts( + partWithName("image").description("์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€"), + partWithName("text").description("์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ์‹œ_๋กœ๋“œ๋งต์ด_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws Exception { + //given + final String imageName = "image"; + final String originalImageName = "originalImageName.jpeg"; + final String contentType = "image/jpeg"; + final String image = "ํ…Œ์ŠคํŠธ ์ด๋ฏธ์ง€"; + final String description = "์ด๋ฏธ์ง€ ์„ค๋ช…"; + final MockMultipartFile imageFile = new MockMultipartFile(imageName, originalImageName, + contentType, image.getBytes()); + + doThrow(new NotFoundException("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L")) + .when(goalRoomCreateService) + .createCheckFeed(anyString(), anyLong(), any()); + + //when + mockMvc.perform( + RestDocumentationRequestBuilders + .multipart(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", 1L) + .file(imageFile) + .file("text", description.getBytes()) + .header("Authorization", "Bearer accessToken") + .contextPath(API_PREFIX) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L")) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName("Authorization").description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + requestParts( + partWithName("image").description("์—…๋กœ๋“œํ•œ ์ด๋ฏธ์ง€"), + partWithName("text").description("์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์„_๋‚˜๊ฐ„๋‹ค() throws Exception { + // given + final Long goalRoomId = 1L; + doNothing().when(goalRoomCreateService) + .leave(anyString(), anyLong()); + + // when + // then + mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/leave", goalRoomId) + .header(AUTHORIZATION, "Bearer ") + .contextPath(API_PREFIX)) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””").optional() + ))) + .andExpect(status().isNoContent()); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์‹คํŒจํ•œ๋‹ค() throws Exception { + // given + final Long goalRoomId = 1L; + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .leave(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform( + post(API_PREFIX + "/goal-rooms/{goalRoomId}/leave", goalRoomId) + .header("Authorization", "Bearer ") + .content(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””").optional() + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse errorResponse = jsonToClass(mvcResult, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์‹คํŒจํ•œ๋‹ค() throws Exception { + // given + final Long goalRoomId = 1L; + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomCreateService) + .leave(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform( + post(API_PREFIX + "/goal-rooms/{goalRoomId}/leave", goalRoomId) + .header("Authorization", "Bearer ") + .content(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””").optional() + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse errorResponse = jsonToClass(mvcResult, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์ง„ํ–‰์ค‘์ธ_๊ณจ๋ฃธ์ด๋ฉด_์‹คํŒจํ•œ๋‹ค() throws Exception { + // given + final Long goalRoomId = 1L; + doThrow(new BadRequestException("์ง„ํ–‰์ค‘์ธ ๊ณจ๋ฃธ์—์„œ๋Š” ๋‚˜๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .leave(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform( + post(API_PREFIX + "/goal-rooms/{goalRoomId}/leave", goalRoomId) + .header("Authorization", "Bearer ") + .content(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value("์ง„ํ–‰์ค‘์ธ ๊ณจ๋ฃธ์—์„œ๋Š” ๋‚˜๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””").optional() + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse errorResponse = jsonToClass(mvcResult, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์ง„ํ–‰์ค‘์ธ ๊ณจ๋ฃธ์—์„œ๋Š” ๋‚˜๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ด๋ฉด_์‹คํŒจํ•œ๋‹ค() throws Exception { + // given + final Long goalRoomId = 1L; + doThrow(new BadRequestException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. memberId = 1")) + .when(goalRoomCreateService) + .leave(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform( + post(API_PREFIX + "/goal-rooms/{goalRoomId}/leave", goalRoomId) + .header("Authorization", "Bearer ") + .content(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.message").value("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. memberId = 1")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””").optional() + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse errorResponse = jsonToClass(mvcResult, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. memberId = 1"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค() throws Exception { + // given + doNothing().when(goalRoomCreateService) + .startGoalRoom(anyString(), anyLong()); + + // when + mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/start", 1L) + .header(AUTHORIZATION, "Bearer ") + .contextPath(API_PREFIX)) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””").optional() + ))) + .andExpect(status().isNoContent()); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_์‚ฌ์šฉ์ž๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .startGoalRoom(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/start", 1L) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomCreateService) + .startGoalRoom(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/start", 1L) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•˜๋Š”_์‚ฌ์šฉ์ž๊ฐ€_๊ณจ๋ฃธ์˜_๋ฆฌ๋”๊ฐ€_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new NotFoundException("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ๊ณจ๋ฃธ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .startGoalRoom(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/start", 1L) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ๊ณจ๋ฃธ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๊ฐ€_๋ฏธ๋ž˜๋ผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new NotFoundException("๊ณจ๋ฃธ์˜ ์‹œ์ž‘ ๋‚ ์งœ๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")) + .when(goalRoomCreateService) + .startGoalRoom(anyString(), anyLong()); + + // when + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/goal-rooms/{goalRoomId}/start", 1L) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(print()) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters(parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€")))) + .andReturn(); + + //then + final ErrorResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + assertThat(response).isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์˜ ์‹œ์ž‘ ๋‚ ์งœ๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")); + } + + private ResultActions ๊ณจ๋ฃธ_์ƒ์„ฑ(final String jsonRequest, final ResultMatcher result) throws Exception { + return mockMvc.perform(post(API_PREFIX + "/goal-rooms") + .content(jsonRequest) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(result) + .andDo(print()); + } + + private List makeCreateGoalRoomSuccessRequestFieldDescription() { + return List.of( + new FieldDescription("roadmapContentId", "๋กœ๋“œ๋งต ์ปจํ…์ธ  id"), + new FieldDescription("name", "๊ณจ๋ฃธ ์ด๋ฆ„", "- ๊ธธ์ด : 1 ~ 40"), + new FieldDescription("limitedMemberCount", "์ตœ๋Œ€ ์ œํ•œ ์ธ์›", "- ๊ธธ์ด : 1 ~ 20"), + new FieldDescription("goalRoomTodo", "์ตœ์ดˆ ๊ณจ๋ฃธ ํˆฌ๋‘"), + new FieldDescription("goalRoomTodo.content", "๊ณจ๋ฃธ ํˆฌ๋‘ ์ปจํ…์ธ ", "- ๊ธธ์ด : 1 ~ 250"), + new FieldDescription("goalRoomTodo.startDate", "๊ณจ๋ฃธ ํˆฌ๋‘ ์‹œ์ž‘์ผ", "- yyyyMMdd ํ˜•์‹"), + new FieldDescription("goalRoomTodo.endDate", "๊ณจ๋ฃธ ํˆฌ๋‘ ์ข…๋ฃŒ์ผ", "- yyyyMMdd ํ˜•์‹"), + new FieldDescription("goalRoomRoadmapNodeRequests", "๊ณจ๋ฃธ ๋…ธ๋“œ ์ •๋ณด"), + new FieldDescription("goalRoomRoadmapNodeRequests[].roadmapNodeId", "์„ค์ •ํ•  ๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ id"), + new FieldDescription("goalRoomRoadmapNodeRequests[].checkCount", "๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ธ์ฆ ํšŸ์ˆ˜"), + new FieldDescription("goalRoomRoadmapNodeRequests[].startDate", "๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์‹œ์ž‘์ผ", "- yyyyMMdd ํ˜•์‹"), + new FieldDescription("goalRoomRoadmapNodeRequests[].endDate", "๊ณจ๋ฃธ ๋…ธ๋“œ์˜ ์ข…๋ฃŒ์ผ", "- yyyyMMdd ํ˜•์‹") + ); + } + + private List makeAddTodoSuccessRequestFieldDescription() { + return List.of( + new FieldDescription("content", "๊ณจ๋ฃธ ํˆฌ๋‘ ์ปจํ…์ธ ", "- ๊ธธ์ด : 1 ~ 250"), + new FieldDescription("startDate", "๊ณจ๋ฃธ ํˆฌ๋‘ ์‹œ์ž‘์ผ", "- yyyyMMdd ํ˜•์‹"), + new FieldDescription("endDate", "๊ณจ๋ฃธ ํˆฌ๋‘ ์ข…๋ฃŒ์ผ", "- yyyyMMdd ํ˜•์‹") + ); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/GoalRoomReadApiTest.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/GoalRoomReadApiTest.java new file mode 100644 index 000000000..06c18fd8f --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/GoalRoomReadApiTest.java @@ -0,0 +1,790 @@ +package co.kirikiri.controller; + +import static co.kirikiri.service.dto.goalroom.GoalRoomMemberSortTypeDto.ACCOMPLISHMENT_RATE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import co.kirikiri.controller.helper.ControllerTestHelper; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ForbiddenException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.service.GoalRoomCreateService; +import co.kirikiri.service.GoalRoomReadService; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.goalroom.request.GoalRoomStatusTypeRequest; +import co.kirikiri.service.dto.goalroom.response.CheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCertifiedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomMemberResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodeResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodesResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomTodoResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomForListResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.dto.member.response.MemberResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MvcResult; + +@WebMvcTest(GoalRoomController.class) +class GoalRoomReadApiTest extends ControllerTestHelper { + + @MockBean + private GoalRoomReadService goalRoomReadService; + + @MockBean + private GoalRoomCreateService goalRoomCreateService; + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final GoalRoomResponse expected = ๊ณจ๋ฃธ_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(); + when(goalRoomReadService.findGoalRoom(any())) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/goal-rooms/{goalRoomId}", 1L) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("name").description("๊ณจ๋ฃธ ์ œ๋ชฉ"), + fieldWithPath("currentMemberCount").description("ํ˜„์žฌ ์ฐธ์—ฌ ์ธ์› ์ˆ˜"), + fieldWithPath("limitedMemberCount").description("๋ชจ์ง‘ ์ธ์› ์ˆ˜"), + fieldWithPath("goalRoomNodes[0].id").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์•„์ด๋””"), + fieldWithPath("goalRoomNodes[0].title").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ"), + fieldWithPath("goalRoomNodes[0].startDate").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์‹œ์ž‘ ๋‚ ์งœ"), + fieldWithPath("goalRoomNodes[0].endDate").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ข…๋ฃŒ ๋‚ ์งœ"), + fieldWithPath("goalRoomNodes[0].checkCount").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ธ์ฆ ํšŸ์ˆ˜"), + fieldWithPath("period").description("๊ณจ๋ฃธ ์ง„ํ–‰ ๊ธฐ๊ฐ„")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final GoalRoomResponse ๊ณจ๋ฃธ_๋‹จ์ผ_์กฐํšŒ_์‘๋‹ต = objectMapper.readValue(response, new TypeReference<>() { + }); + assertThat(๊ณจ๋ฃธ_๋‹จ์ผ_์กฐํšŒ_์‘๋‹ต) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์กฐํšŒ์‹œ_์•„์ด๋””๊ฐ€_์œ ํšจํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + when(goalRoomReadService.findGoalRoom(any())) + .thenThrow(new NotFoundException("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L")); + + // when + final String response = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}", 1L) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L")) + .andDo(documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final GoalRoomCertifiedResponse expected = ๋กœ๊ทธ์ธ์‹œ_๊ณจ๋ฃธ_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(true); + when(goalRoomReadService.findGoalRoom(any(), any())) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/goal-rooms/{goalRoomId}", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("name").description("๊ณจ๋ฃธ ์ œ๋ชฉ"), + fieldWithPath("currentMemberCount").description("ํ˜„์žฌ ์ฐธ์—ฌ ์ธ์› ์ˆ˜"), + fieldWithPath("limitedMemberCount").description("๋ชจ์ง‘ ์ธ์› ์ˆ˜"), + fieldWithPath("goalRoomNodes[0].id").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์•„์ด๋””"), + fieldWithPath("goalRoomNodes[0].title").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ"), + fieldWithPath("goalRoomNodes[0].startDate").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์‹œ์ž‘ ๋‚ ์งœ"), + fieldWithPath("goalRoomNodes[0].endDate").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ข…๋ฃŒ ๋‚ ์งœ"), + fieldWithPath("goalRoomNodes[0].checkCount").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ธ์ฆ ํšŸ์ˆ˜"), + fieldWithPath("period").description("๊ณจ๋ฃธ ์ง„ํ–‰ ๊ธฐ๊ฐ„"), + fieldWithPath("isJoined").description("๊ณจ๋ฃธ ์ฐธ์—ฌ ์—ฌ๋ถ€ (true / false)")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final GoalRoomCertifiedResponse ๊ณจ๋ฃธ_๋‹จ์ผ_์กฐํšŒ_์‘๋‹ต = objectMapper.readValue(response, new TypeReference<>() { + }); + assertThat(๊ณจ๋ฃธ_๋‹จ์ผ_์กฐํšŒ_์‘๋‹ต) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์กฐํšŒ์‹œ_๊ณจ๋ฃธ_์•„์ด๋””๊ฐ€_์œ ํšจํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ() throws Exception { + // given + when(goalRoomReadService.findGoalRoom(any(), any())) + .thenThrow(new NotFoundException("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L")); + + // when + final String response = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1L"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() throws Exception { + //given + final MemberGoalRoomResponse expected = ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(); + when(goalRoomReadService.findMemberGoalRoom(any(), any())) + .thenReturn(expected); + + //when + final String response = mockMvc.perform( + get(API_PREFIX + "/goal-rooms/{goalRoomId}/me", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "access-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("name").description("๊ณจ๋ฃธ ์ด๋ฆ„"), + fieldWithPath("status").description("๊ณจ๋ฃธ ์ƒํƒœ"), + fieldWithPath("leaderId").description("๊ณจ๋ฃธ ๋ฆฌ๋” ์•„์ด๋””"), + fieldWithPath("currentMemberCount").description("ํ˜„์žฌ ๊ณจ๋ฃธ ์ฐธ์—ฌ์ž ์ˆ˜"), + fieldWithPath("limitedMemberCount").description("๊ณจ๋ฃธ ์ฐธ์—ฌ ์ œํ•œ ์ธ์› ์ˆ˜"), + fieldWithPath("startDate").description("๊ณจ๋ฃธ ์‹œ์ž‘ ๋‚ ์งœ"), + fieldWithPath("endDate").description("๊ณจ๋ฃธ ์ข…๋ฃŒ ๋‚ ์งœ"), + fieldWithPath("roadmapContentId").description("๋กœ๋“œ๋งต ์ปจํ…์ธ  ์•„์ด๋””"), + fieldWithPath("goalRoomRoadmapNodes.hasFrontNode").description( + "๋Œ€์‹œ ๋ณด๋“œ์— ํ‘œ์‹œ๋œ ๊ณจ๋ฃธ ๋…ธ๋“œ ์•ž์˜ ๋…ธ๋“œ ์กด์žฌ ์—ฌ๋ถ€"), + fieldWithPath("goalRoomRoadmapNodes.hasBackNode").description( + "๋Œ€์‹œ ๋ณด๋“œ์— ํ‘œ์‹œ๋œ ๊ณจ๋ฃธ ๋…ธ๋“œ ์ดํ›„์˜ ๋…ธ๋“œ ์กด์žฌ ์—ฌ๋ถ€"), + fieldWithPath("goalRoomRoadmapNodes.nodes[0].id").description( + "๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์•„์ด๋””"), + fieldWithPath("goalRoomRoadmapNodes.nodes[0].title").description( + "๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ"), + fieldWithPath("goalRoomRoadmapNodes.nodes[0].startDate").description( + "๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์‹œ์ž‘์ผ"), + fieldWithPath("goalRoomRoadmapNodes.nodes[0].endDate").description( + "๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ข…๋ฃŒ์ผ"), + fieldWithPath("goalRoomRoadmapNodes.nodes[0].checkCount").description( + "๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์ตœ๋Œ€ ์ธ์ฆ ํšŸ์ˆ˜"), + fieldWithPath("goalRoomTodos[0].id").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์•„์ด๋””"), + fieldWithPath("goalRoomTodos[0].content").description("๊ณจ๋ฃธ ํˆฌ๋‘ ๋‚ด์šฉ"), + fieldWithPath("goalRoomTodos[0].startDate").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์‹œ์ž‘์ผ"), + fieldWithPath("goalRoomTodos[0].endDate").description("๊ณจ๋ฃธ ํˆฌ๋‘ ์ข…๋ฃŒ์ผ"), + fieldWithPath("goalRoomTodos[0].check.isChecked").description( + "๊ณจ๋ฃธ ํˆฌ๋‘ ์ฒดํฌ ์—ฌ๋ถ€(true/false)"), + fieldWithPath("checkFeeds[0].id").description("์ธ์ฆ ํ”ผ๋“œ ์•„์ด๋””"), + fieldWithPath("checkFeeds[0].imageUrl").description("์ธ์ฆ ํ”ผ๋“œ ์ด๋ฏธ์ง€ ์ €์žฅ๊ฒฝ๋กœ"), + fieldWithPath("checkFeeds[0].description").description("์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ"), + fieldWithPath("checkFeeds[0].createdAt").description("์ธ์ฆ ํ”ผ๋“œ ๋“ฑ๋ก ๋‚ ์งœ") + ))) + .andReturn().getResponse() + .getContentAsString(); + + //then + final MemberGoalRoomResponse memberGoalRoomResponses = objectMapper.readValue(response, + new TypeReference<>() { + }); + + assertThat(memberGoalRoomResponses) + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์กฐํšŒ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ_์•„์ด๋””๋ฅผ_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + //given + when(goalRoomReadService.findMemberGoalRoom(any(), any())) + .thenThrow(new ForbiddenException("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1")); + + //when + final String response = mockMvc.perform( + get(API_PREFIX + "/goal-rooms/{goalRoomId}/me", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "access-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isForbidden()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€") + ))) + .andReturn().getResponse() + .getContentAsString(); + + //then + final ErrorResponse errorResponse = objectMapper.readValue(response, new TypeReference<>() { + }); + + assertThat(errorResponse.message()).isEqualTo("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1"); + } + + @Test + void ์‚ฌ์šฉ์ž_์ฐธ๊ฐ€_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws Exception { + //given + final List expected = ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(); + when(goalRoomReadService.findMemberGoalRoomsByStatusType(any(), any())) + .thenReturn(expected); + + //when + final String response = mockMvc.perform( + get(API_PREFIX + "/goal-rooms/me") + .param("statusCond", GoalRoomStatusTypeRequest.RUNNING.name()) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "access-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + queryParameters( + parameterWithName("statusCond").description("๊ณจ๋ฃธ ์ƒํƒœ") + ), + responseFields( + fieldWithPath("[0].goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””"), + fieldWithPath("[0].name").description("๊ณจ๋ฃธ ์ด๋ฆ„"), + fieldWithPath("[0].goalRoomStatus").description("๊ณจ๋ฃธ ์ƒํƒœ"), + fieldWithPath("[0].currentMemberCount").description("ํ˜„์žฌ ๊ณจ๋ฃธ ์ฐธ์—ฌ์ž ์ˆ˜"), + fieldWithPath("[0].limitedMemberCount").description("๊ณจ๋ฃธ ์ฐธ์—ฌ ์ œํ•œ ์ธ์› ์ˆ˜"), + fieldWithPath("[0].createdAt").description("๊ณจ๋ฃธ ์ƒ์„ฑ ์‹œ๊ฐ„"), + fieldWithPath("[0].startDate").description("๊ณจ๋ฃธ ์‹œ์ž‘ ๋‚ ์งœ"), + fieldWithPath("[0].endDate").description("๊ณจ๋ฃธ ์ข…๋ฃŒ ๋‚ ์งœ"), + fieldWithPath("[0].goalRoomLeader.id").description("๊ณจ๋ฃธ ์ƒ์„ฑ ์‚ฌ์šฉ์ž ์•„์ด๋””"), + fieldWithPath("[0].goalRoomLeader.name").description("๊ณจ๋ฃธ ์ƒ์„ฑ ์‚ฌ์šฉ์ž ๋‹‰๋„ค์ž„"), + fieldWithPath("[0].goalRoomLeader.imageUrl").description("๊ณจ๋ฃธ ์ƒ์„ฑ ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ") + ))) + .andReturn().getResponse() + .getContentAsString(); + + //then + final List memberGoalRoomResponses = objectMapper.readValue(response, + new TypeReference<>() { + }); + + assertThat(memberGoalRoomResponses) + .isEqualTo(expected); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ_๋ฉค๋ฒ„๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final GoalRoomMemberResponse goalRoomMemberResponse1 = new GoalRoomMemberResponse(1L, "nickname1", "imagePath1", + 50D); + final GoalRoomMemberResponse goalRoomMemberResponse2 = new GoalRoomMemberResponse(2L, "nickname2", "imagePath2", + 40D); + given(goalRoomReadService.findGoalRoomMembers(anyLong(), any())) + .willReturn(List.of(goalRoomMemberResponse1, goalRoomMemberResponse2)); + + // when + final MvcResult mvcResult = mockMvc.perform( + get(API_PREFIX + "/goal-rooms/{goalRoomId}/members", 1L) + .param("sortCond", ACCOMPLISHMENT_RATE.name()) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("Bearer ์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + queryParameters( + parameterWithName("sortCond") + .description( + "์ •๋ ฌ ์กฐ๊ฑด (null์ผ ๊ฒฝ์šฐ: ๊ณจ๋ฃธ ๋ชจ์ง‘์ค‘ -> ๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ(์˜ค๋ž˜๋œ์ˆœ)/ ๊ณจ๋ฃธ ์ง„ํ–‰์ค‘, ์™„๋ฃŒ๋จ -> ๋‹ฌ์„ฑ๋ฅ  ์ˆœ์œผ๋กœ ๊ธฐ๋ณธ ์ •๋ ฌ) +" + + "\n" + + "ACCOMPLISHMENT_RATE : ๋‹ฌ์„ฑ๋ฅ  ์ˆœ +" + "\n" + + "JOINED_ASC : ๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์˜ค๋ž˜๋œ์ˆœ) +" + "\n" + + "JOINED_DESC : ๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์ตœ์‹ ์ˆœ) +" + "\n") + .optional() + ), + responseFields( + fieldWithPath("[0].memberId").description("ํšŒ์› id"), + fieldWithPath("[0].nickname").description("ํšŒ์› ๋‹‰๋„ค์ž„"), + fieldWithPath("[0].imagePath").description("ํšŒ์› ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ"), + fieldWithPath("[0].accomplishmentRate").description("ํšŒ์› ๋‹ฌ์„ฑ๋ฅ ")))) + .andReturn(); + + // then + final List response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response) + .isEqualTo(List.of(goalRoomMemberResponse1, goalRoomMemberResponse2)); + } + + @Test + void ๊ณจ๋ฃธ_๋ฉค๋ฒ„_์กฐํšŒ_์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ() throws Exception { + //given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomReadService) + .findGoalRoomMembers(anyLong(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/members", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .param("sortCond", ACCOMPLISHMENT_RATE.name()) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + queryParameters( + parameterWithName("sortCond") + .description( + "์ •๋ ฌ ์กฐ๊ฑด (null์ผ ๊ฒฝ์šฐ: ๊ณจ๋ฃธ ๋ชจ์ง‘์ค‘ -> ๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ(์˜ค๋ž˜๋œ์ˆœ)/ ๊ณจ๋ฃธ ์ง„ํ–‰์ค‘, ์™„๋ฃŒ๋จ -> ๋‹ฌ์„ฑ๋ฅ  ์ˆœ์œผ๋กœ ๊ธฐ๋ณธ ์ •๋ ฌ) +" + + "\n" + + "ACCOMPLISHMENT_RATE : ๋‹ฌ์„ฑ๋ฅ  ์ˆœ +" + "\n" + + "JOINED_ASC : ๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์˜ค๋ž˜๋œ์ˆœ) +" + "\n" + + "JOINED_DESC : ๊ณจ๋ฃธ ์ž…์žฅ ์ˆœ (์ตœ์‹ ์ˆœ) +" + "\n") + .optional() + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ์˜_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final LocalDate today = LocalDate.now(); + final List goalRoomTodoResponses = List.of( + new GoalRoomTodoResponse(1L, "ํˆฌ๋‘ 1", today, today.plusDays(10), new GoalRoomToDoCheckResponse(true)), + new GoalRoomTodoResponse(2L, "ํˆฌ๋‘ 2", today.plusDays(20), today.plusDays(30), + new GoalRoomToDoCheckResponse(false))); + + when(goalRoomReadService.findAllGoalRoomTodo(any(), any())) + .thenReturn(goalRoomTodoResponses); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("[0].id").description("ํˆฌ๋‘ ์•„์ด๋””"), + fieldWithPath("[0].content").description("ํˆฌ๋‘ ๋‚ด์šฉ"), + fieldWithPath("[0].startDate").description("ํˆฌ๋‘ ์‹œ์ž‘ ๋‚ ์งœ"), + fieldWithPath("[0].endDate").description("ํˆฌ๋‘ ์ข…๋ฃŒ ๋‚ ์งœ"), + fieldWithPath("[0].check.isChecked").description("ํˆฌ๋‘ ์ฒดํฌ ์—ฌ๋ถ€") + ))) + .andReturn(); + + // then + final List response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response) + .isEqualTo(goalRoomTodoResponses); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ() throws Exception { + // given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomReadService) + .findAllGoalRoomTodo(any(), any()); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses) + .isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ() throws Exception { + // given + doThrow(new ForbiddenException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = identifier")) + .when(goalRoomReadService) + .findAllGoalRoomTodo(any(), any()); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isForbidden()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses) + .isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = identifier")); + } + + @Test + void ๊ณจ๋ฃธ์˜_๋…ธ๋“œ๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final LocalDate today = LocalDate.now(); + final List goalRoomNodeResponses = List.of( + new GoalRoomRoadmapNodeResponse(1L, "๊ณจ๋ฃธ ๋…ธ๋“œ 1", today, today.plusDays(10), 10), + new GoalRoomRoadmapNodeResponse(2L, "๊ณจ๋ฃธ ๋…ธ๋“œ 2", today.plusDays(20), today.plusDays(30), 5)); + + when(goalRoomReadService.findAllGoalRoomNodes(any(), any())) + .thenReturn(goalRoomNodeResponses); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/nodes", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("[0].id").description("๊ณจ๋ฃธ ๋กœ๋“œ๋งต ๋…ธ๋“œ ์•„์ด๋””"), + fieldWithPath("[0].title").description("๋…ธ๋“œ ์ œ๋ชฉ"), + fieldWithPath("[0].startDate").description("๋…ธ๋“œ ์‹œ์ž‘ ๋‚ ์งœ"), + fieldWithPath("[0].endDate").description("๋…ธ๋“œ ์ข…๋ฃŒ ๋‚ ์งœ"), + fieldWithPath("[0].checkCount").description("์ธ์ฆ ํšŸ์ˆ˜") + ))) + .andReturn(); + + // then + final List response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response) + .isEqualTo(goalRoomNodeResponses); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ() throws Exception { + // given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomReadService) + .findAllGoalRoomNodes(any(), any()); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/nodes", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses) + .isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ() throws Exception { + // given + doThrow(new ForbiddenException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = identifier")) + .when(goalRoomReadService) + .findAllGoalRoomNodes(any(), any()); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/nodes", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isForbidden()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses) + .isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = identifier")); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse1 = new GoalRoomCheckFeedResponse( + new MemberResponse(1L, "name1", "imageUrl"), + new CheckFeedResponse(1L, "imageUrl", "image description1", LocalDate.now())); + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse2 = new GoalRoomCheckFeedResponse( + new MemberResponse(2L, "name2", "imageUrl"), + new CheckFeedResponse(2L, "imageUrl", "image description2", LocalDate.now())); + + final List expected = List.of(goalRoomCheckFeedResponse2, + goalRoomCheckFeedResponse1); + + when(goalRoomReadService.findGoalRoomCheckFeeds(any(), any())) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("[0].member.id").description("์‚ฌ์šฉ์ž ID"), + fieldWithPath("[0].member.name").description("์‚ฌ์šฉ์ž ๋‹‰๋„ค์ž„"), + fieldWithPath("[0].member.imageUrl").description("์‚ฌ์šฉ์ž ์ด๋ฏธ์ง€ Url"), + fieldWithPath("[0].checkFeed.id").description("์ธ์ฆ ํ”ผ๋“œ ID"), + fieldWithPath("[0].checkFeed.imageUrl").description("์ธ์ฆ ํ”ผ๋“œ ์ด๋ฏธ์ง€ Url"), + fieldWithPath("[0].checkFeed.description").description("์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…"), + fieldWithPath("[0].checkFeed.createdAt").description("์ธ์ฆ ํ”ผ๋“œ ๋“ฑ๋ก ๋‚ ์งœ")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final List ๊ณจ๋ฃธ_์ธ์ฆํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‘๋‹ต = objectMapper.readValue(response, + new TypeReference<>() { + }); + assertThat(๊ณจ๋ฃธ_์ธ์ฆํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‘๋‹ต) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์ธ์ฆํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + //given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")) + .when(goalRoomReadService) + .findGoalRoomCheckFeeds(any(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_์ธ์ฆํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‹œ_๊ณจ๋ฃธ์—_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ_๋ฐœ์ƒ() throws Exception { + //given + doThrow(new BadRequestException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .when(goalRoomReadService) + .findGoalRoomCheckFeeds(any(), any()); + + //when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))) + .andReturn(); + + // then + final ErrorResponse responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + private GoalRoomResponse ๊ณจ๋ฃธ_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค() { + final List goalRoomNodeResponses = List.of( + new GoalRoomRoadmapNodeResponse(1L, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ", LocalDate.of(2023, 7, 19), + LocalDate.of(2023, 7, 30), 10), + new GoalRoomRoadmapNodeResponse(2L, "๋กœ๋“œ๋งต 2์ฃผ์ฐจ", LocalDate.of(2023, 8, 1), + LocalDate.of(2023, 8, 5), 2)); + return new GoalRoomResponse("๊ณจ๋ฃธ", 1, 10, goalRoomNodeResponses, 17); + } + + private GoalRoomCertifiedResponse ๋กœ๊ทธ์ธ์‹œ_๊ณจ๋ฃธ_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(final boolean isJoined) { + final List goalRoomNodeResponses = List.of( + new GoalRoomRoadmapNodeResponse(1L, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ", LocalDate.of(2023, 7, 19), + LocalDate.of(2023, 7, 30), 10), + new GoalRoomRoadmapNodeResponse(2L, "๋กœ๋“œ๋งต 2์ฃผ์ฐจ", LocalDate.of(2023, 8, 1), + LocalDate.of(2023, 8, 5), 2)); + return new GoalRoomCertifiedResponse("๊ณจ๋ฃธ", 1, 10, goalRoomNodeResponses, 17, isJoined); + } + + private MemberGoalRoomResponse ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค() { + return new MemberGoalRoomResponse("๊ณจ๋ฃธ ์ด๋ฆ„", "RUNNING", 1L, + 15, 20, LocalDate.of(2023, 1, 1), + LocalDate.of(2023, 12, 31), 1L, + new GoalRoomRoadmapNodesResponse(false, true, List.of( + new GoalRoomRoadmapNodeResponse(1L, "์ฒซ๋ฒˆ์งธ ๊ณจ๋ฃธ ๋…ธ๋“œ ์ œ๋ชฉ", LocalDate.of(2023, 1, 1), + LocalDate.of(2023, 1, 31), 15), + new GoalRoomRoadmapNodeResponse(2L, "๋‘๋ฒˆ์งธ ๊ณจ๋ฃธ ๋…ธ๋“œ ์ œ๋ชฉ", LocalDate.of(2023, 2, 1), + LocalDate.of(2023, 2, 28), 14))), + List.of(new GoalRoomTodoResponse(1L, "์ฒซ ๋ฒˆ์งธ ํ• ์ผ", + LocalDate.of(2023, 1, 15), LocalDate.of(2023, 1, 31), + new GoalRoomToDoCheckResponse(false))), + List.of(new CheckFeedResponse(1L, "imageUrl1", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช… 1", LocalDate.now()), + new CheckFeedResponse(2L, "imageUrl2", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช… 2", LocalDate.now()), + new CheckFeedResponse(3L, "imageUrl3", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช… 3", LocalDate.now()), + new CheckFeedResponse(4L, "imageUrl4", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช… 4", LocalDate.now()))); + + } + + private List ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of(new MemberGoalRoomForListResponse(1L, "๊ณจ๋ฃธ ์ด๋ฆ„", GoalRoomStatus.RUNNING.name(), + 15, 20, LocalDateTime.of(2023, 7, 1, 0, 0), + LocalDate.of(2023, 7, 15), LocalDate.of(2023, 8, 15), + new MemberResponse(1L, "ํ™ฉ์‹œ์ง„", "default-member-image")), + new MemberGoalRoomForListResponse(2L, "๊ณจ๋ฃธ ์ด๋ฆ„", GoalRoomStatus.RUNNING.name(), + 15, 20, LocalDateTime.of(2023, 7, 5, 0, 0), + LocalDate.of(2023, 7, 8), LocalDate.of(2023, 8, 1), + new MemberResponse(2L, "์‹œ์ง„์ด", "default-member-image")) + ); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/MemberCreateApiTest.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/MemberCreateApiTest.java new file mode 100644 index 000000000..bd50249d1 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/MemberCreateApiTest.java @@ -0,0 +1,320 @@ +package co.kirikiri.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import co.kirikiri.controller.helper.ControllerTestHelper; +import co.kirikiri.controller.helper.FieldDescriptionHelper.FieldDescription; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ConflictException; +import co.kirikiri.service.MemberService; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import com.fasterxml.jackson.core.type.TypeReference; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.ResultMatcher; + +@WebMvcTest(MemberController.class) +class MemberCreateApiTest extends ControllerTestHelper { + + @MockBean + private MemberService memberService; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํšŒ์›๊ฐ€์ž…์—_์„ฑ๊ณตํ•œ๋‹ค() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier1", "password1!", + "nickname", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + //then + final List requestFieldDescription = makeSuccessRequestFieldDescription(); + + ํšŒ์›๊ฐ€์ž…(jsonRequest, status().isCreated()) + .andDo(documentationResultHandler.document( + requestFields(makeFieldDescriptor(requestFieldDescription)), + responseHeaders(headerWithName(HttpHeaders.LOCATION).description("ํšŒ์› ๋‹จ์ผ ์กฐํšŒ api ๊ฒฝ๋กœ")))); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์•„์ด๋””๊ฐ€_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier1@!#!@#", "password1!", + "nickname", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + doThrow(new BadRequestException("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค.")) + .when(memberService) + .join(any()); + + //then + ํšŒ์›๊ฐ€์ž…(jsonRequest, status().isBadRequest()); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier1", "password1!โ‚ฉ", + "nickname", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + doThrow(new BadRequestException("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค.")) + .when(memberService) + .join(any()); + + //then + ํšŒ์›๊ฐ€์ž…(jsonRequest, status().isBadRequest()); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_๋‹‰๋„ค์ž„์ด_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier1", "password1!", + "a", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + doThrow(new BadRequestException("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋‹‰๋„ค์ž„์ž…๋‹ˆ๋‹ค.")) + .when(memberService) + .join(any()); + + //then + ํšŒ์›๊ฐ€์ž…(jsonRequest, status().isBadRequest()); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์ „ํ™”๋ฒˆํ˜ธ_ํ˜•์‹์—_๋งž์ง€์•Š์„๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier1", "password1!", + "nickname", "010-1234-56789", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + //then + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/members/join") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andReturn(); + + final ErrorResponse expectedResponse = new ErrorResponse("์ „ํ™”๋ฒˆํ˜ธ ํ˜•์‹์ด ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison().isEqualTo(List.of(expectedResponse)); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์•„์ด๋””์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("", "password1!", + "nickname", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + //then + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/members/join") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andReturn(); + + final ErrorResponse expectedResponse = new ErrorResponse("์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison().isEqualTo(List.of(expectedResponse)); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_๋น„๋ฐ€๋ฒˆํ˜ธ์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier", "", + "nickname", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + //then + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/members/join") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andReturn(); + + final ErrorResponse expectedResponse = new ErrorResponse("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison().isEqualTo(List.of(expectedResponse)); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_๋‹‰๋„ค์ž„์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier", "identifier1!", + "", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + //then + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/members/join") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andReturn(); + + final ErrorResponse expectedResponse = new ErrorResponse("๋‹‰๋„ค์ž„์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison().isEqualTo(List.of(expectedResponse)); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์ „ํ™”๋ฒˆํ˜ธ์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier", "password1!", + "nickname", "", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + //then + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/members/join") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andReturn(); + + final ErrorResponse blankResponse = new ErrorResponse("์ „ํ™”๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse patternResponse = new ErrorResponse("์ „ํ™”๋ฒˆํ˜ธ ํ˜•์‹์ด ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(patternResponse, blankResponse)); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์•„์ด๋””_๋น„๋ฐ€๋ฒˆํ˜ธ_๋‹‰๋„ค์ž„_์ „ํ™”๋ฒˆํ˜ธ_ํ•„๋“œ์—_๋นˆ๊ฐ’์ด_๋“ค์–ด์˜ฌ_๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("", "", + "", "", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + //then + final MvcResult mvcResult = mockMvc.perform(post(API_PREFIX + "/members/join") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isBadRequest()) + .andDo(print()) + .andReturn(); + + final ErrorResponse identifierResponse = new ErrorResponse("์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse passwordResponse = new ErrorResponse("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse nicknameResponse = new ErrorResponse("๋‹‰๋„ค์ž„์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse phoneNumberBlankResponse = new ErrorResponse("์ „ํ™”๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse phoneNumberPatternResponse = new ErrorResponse("์ „ํ™”๋ฒˆํ˜ธ ํ˜•์‹์ด ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + final List responses = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(responses).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(identifierResponse, passwordResponse, nicknameResponse, phoneNumberBlankResponse, + phoneNumberPatternResponse)); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์ค‘๋ณต๋œ_์•„์ด๋””์ผ_๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier1", "password1!", + "nickname", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + doThrow(new ConflictException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค.")) + .when(memberService) + .join(any()); + + //then + ํšŒ์›๊ฐ€์ž…(jsonRequest, status().isConflict()); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์ค‘๋ณต๋œ_๋‹‰๋„ค์ž„์ผ_๋•Œ() throws Exception { + //given + final MemberJoinRequest memberJoinRequest = new MemberJoinRequest("identifier1", "password1!", + "nickname", "010-1234-5678", GenderType.MALE, LocalDate.now()); + final String jsonRequest = objectMapper.writeValueAsString(memberJoinRequest); + + //when + doThrow(new ConflictException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋‹‰๋„ค์ž„์ž…๋‹ˆ๋‹ค.")) + .when(memberService) + .join(any()); + + //then + ํšŒ์›๊ฐ€์ž…(jsonRequest, status().isConflict()); + } + + private ResultActions ํšŒ์›๊ฐ€์ž…(final String jsonRequest, final ResultMatcher result) throws Exception { + return mockMvc.perform(post(API_PREFIX + "/members/join") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(result) + .andDo(print()); + } + + private List makeSuccessRequestFieldDescription() { + return List.of( + new FieldDescription("identifier", "์‚ฌ์šฉ์ž ์•„์ด๋””", + "- ๊ธธ์ด : 4 ~ 20 +" + "\n" + + "- ์˜์–ด ์†Œ๋ฌธ์ž, ์ˆซ์ž ๊ฐ€๋Šฅ"), + new FieldDescription("password", "์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ", + "- ๊ธธ์ด : 8 ~ 15 +" + "\n" + + "- ์˜์–ด ์†Œ๋ฌธ์ž, ์ˆซ์ž, ํŠน์ˆ˜๋ฌธ์ž +" + "\n" + + "- ํŠน์ˆ˜๋ฌธ์ž[!,@,#,$,%,^,&,*,(,),~] ์‚ฌ์šฉ ๊ฐ€๋Šฅ"), + new FieldDescription("nickname", "ํšŒ์› ๋‹‰๋„ค์ž„", "- ๊ธธ์ด : 2 ~ 8"), + new FieldDescription("phoneNumber", "ํšŒ์› ํœด๋Œ€ํฐ ๋ฒˆํ˜ธ", + "- ๊ธธ์ด : 13 +" + "\n" + + "- ๋ฒˆํ˜ธ ํ˜•์‹ : 010-xxxx-xxxx"), + new FieldDescription("genderType", "ํšŒ์› ์„ฑ๋ณ„", + "- ๊ธธ์ด : 4 , 6 +" + "\n" + + "- MALE, FEMALE"), + new FieldDescription("birthday", "ํšŒ์› ์ƒ๋…„์›”์ผ", + "- ๊ธธ์ด : 6 +" + "\n" + + "- yyyyMMdd") + ); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/MemberReadApiTest.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/MemberReadApiTest.java new file mode 100644 index 000000000..e1c2e8836 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/MemberReadApiTest.java @@ -0,0 +1,162 @@ +package co.kirikiri.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import co.kirikiri.controller.helper.ControllerTestHelper; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.service.MemberService; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.member.response.MemberInformationForPublicResponse; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import java.time.LocalDate; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.web.servlet.MvcResult; + +@WebMvcTest(MemberController.class) +class MemberReadApiTest extends ControllerTestHelper { + + @MockBean + private MemberService memberService; + + @Test + void ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final MemberInformationResponse expected = new MemberInformationResponse(1L, "nickname", "serverFilePath", + Gender.MALE.name(), + "identifier1", "010-1234-5678", LocalDate.now()); + + given(memberService.findMemberInformation(any())) + .willReturn(expected); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/members/me") + .contextPath(API_PREFIX) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "access-token"))) + .andExpect(status().isOk()) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + responseFields( + fieldWithPath("id").description("์‚ฌ์šฉ์ž id (PK)"), + fieldWithPath("nickname").description("์‚ฌ์šฉ์ž ๋‹‰๋„ค์ž„"), + fieldWithPath("profileImageUrl").description("์‚ฌ์šฉ์ž ์ด๋ฏธ์ง€ Url"), + fieldWithPath("gender").description("์‚ฌ์šฉ์ž ์„ฑ๋ณ„"), + fieldWithPath("identifier").description("์‚ฌ์šฉ์ž ์•„์ด๋””"), + fieldWithPath("phoneNumber").description("์‚ฌ์šฉ์ž ์ „ํ™”๋ฒˆํ˜ธ"), + fieldWithPath("birthday").description("์‚ฌ์šฉ์ž ์ƒ๋…„์›”์ผ") + ))) + .andReturn(); + + // then + final MemberInformationResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response).isEqualTo(expected); + } + + @Test + void ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ• ๋•Œ_์กด์žฌํ•˜์ง€_์•Š์€_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ() throws Exception { + // given + when(memberService.findMemberInformation(any())) + .thenThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/members/me") + .contextPath(API_PREFIX) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "access-token"))) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn(); + + // then + final ErrorResponse errorResponse = jsonToClass(mvcResult, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final MemberInformationForPublicResponse expected = new MemberInformationForPublicResponse("nickname", + "serverFilePath", + Gender.MALE.name()); + + given(memberService.findMemberInformationForPublic(any())) + .willReturn(expected); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/members/{memberId}", 1L) + .contextPath(API_PREFIX) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "access-token"))) + .andExpect(status().isOk()) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + responseFields( + fieldWithPath("nickname").description("์‚ฌ์šฉ์ž ๋‹‰๋„ค์ž„"), + fieldWithPath("profileImageUrl").description("์‚ฌ์šฉ์ž ์ด๋ฏธ์ง€ Url"), + fieldWithPath("gender").description("์‚ฌ์šฉ์ž ์„ฑ๋ณ„") + ))) + .andReturn(); + + // then + final MemberInformationForPublicResponse response = jsonToClass(mvcResult, new TypeReference<>() { + }); + + assertThat(response).isEqualTo(expected); + } + + @Test + void ํŠน์ •_์‚ฌ์šฉ์ž_์ •๋ณด_์กฐํšŒ์‹œ_์กฐํšŒํ• _์‚ฌ์šฉ์ž๊ฐ€_์—†๋Š”_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ() throws Exception { + // given + when(memberService.findMemberInformationForPublic(any())) + .thenThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค. memberId = 2")); + + // when + final MvcResult mvcResult = mockMvc.perform(get(API_PREFIX + "/members/{memberId}", 2L) + .contextPath(API_PREFIX) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "access-token"))) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค. memberId = 2")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ") + ), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn(); + + // then + final ErrorResponse errorResponse = jsonToClass(mvcResult, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค. memberId = 2"); + + assertThat(errorResponse) + .isEqualTo(expected); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/RoadmapCreateApiTest.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/RoadmapCreateApiTest.java new file mode 100644 index 000000000..e81153962 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/RoadmapCreateApiTest.java @@ -0,0 +1,792 @@ +package co.kirikiri.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.headers.HeaderDocumentation.responseHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.multipart; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestPartFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.partWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.requestParts; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import co.kirikiri.controller.helper.ControllerTestHelper; +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ForbiddenException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.service.RoadmapCreateService; +import co.kirikiri.service.RoadmapReadService; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import com.fasterxml.jackson.core.type.TypeReference; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.restdocs.request.RequestPartDescriptor; +import org.springframework.restdocs.snippet.Attributes; +import org.springframework.restdocs.snippet.Attributes.Attribute; +import org.springframework.test.web.servlet.ResultMatcher; +import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; + +@WebMvcTest(RoadmapController.class) +class RoadmapCreateApiTest extends ControllerTestHelper { + + @MockBean + private RoadmapCreateService roadmapCreateService; + + @MockBean + private RoadmapReadService roadmapReadService; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค() throws Exception { + // given + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willReturn(1L); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isCreated()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new AuthenticationException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isUnauthorized()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๋ฅผ_์ž…๋ ฅํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final Long categoryId = 10L; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(categoryId, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค. categoryId = 10")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isNotFound()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๋ฅผ_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final Long categoryId = null; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(categoryId, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_40๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String title = "a".repeat(41); + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("๋กœ๋“œ๋งต ์ œ๋ชฉ์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 40๊ธ€์ž์ž…๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ œ๋ชฉ์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String title = null; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€์˜_๊ธธ์ด๊ฐ€_150๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String introduction = "a".repeat(151); + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", introduction, "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 150๊ธ€์ž์ž…๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String introduction = null; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", introduction, "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋ณธ๋ฌธ์˜_๊ธธ์ด๊ฐ€_2000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String content = "a".repeat(2001); + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", content, + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("๋กœ๋“œ๋งต ๋ณธ๋ฌธ์˜ ๊ธธ์ด๋Š” ์ตœ๋Œ€ 2000๊ธ€์ž์ž…๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋‚œ์ด๋„๋ฅผ_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final RoadmapDifficultyType difficulty = null; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + difficulty, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @ParameterizedTest + @ValueSource(ints = {-1, 1001}) + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ถ”์ฒœ_์†Œ์š”๊ธฐ๊ฐ„์ด_0๋ณด๋‹ค_์ž‘๊ฑฐ๋‚˜_1000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int requiredPeriod) throws Exception { + // given + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, requiredPeriod, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("๋กœ๋“œ๋งต ์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„์€ ์ตœ์†Œ 0์ผ, ์ตœ๋Œ€ 1000์ผ์ž…๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ถ”์ฒœ_์†Œ์š”๊ธฐ๊ฐ„์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final Integer requiredPeriod = null; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, requiredPeriod, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_40๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String nodeTitle = "a".repeat(41); + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest(nodeTitle, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 40๊ธ€์ž์ž…๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์„ค๋ช…์˜_๊ธธ์ด๊ฐ€_2000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String nodeContent = "a".repeat(2001); + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", nodeContent, null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 2000๊ธ€์ž์ž…๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์ œ๋ชฉ์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String nodeTitle = null; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest(nodeTitle, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ์—๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ฐฐ์šธ๊ฑฐ์—์š”.", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์„ค๋ช…์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final String nodeContent = null; + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", nodeContent, null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @ParameterizedTest + @ValueSource(ints = {0, 11}) + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_ํƒœ๊ทธ_์ด๋ฆ„์ด_1๋ฏธ๋งŒ_10์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int nameLength) throws Exception { + // given + final String tagName = "a".repeat(nameLength); + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest(tagName))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("ํƒœ๊ทธ ์ด๋ฆ„์€ ์ตœ์†Œ 1์ž๋ถ€ํ„ฐ ์ตœ๋Œ€ 10์ž๊นŒ์ง€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_ํƒœ๊ทธ_๊ฐœ์ˆ˜๊ฐ€_5๊ฐœ_์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"), new RoadmapTagSaveRequest("ํƒœ๊ทธ2"), + new RoadmapTagSaveRequest("ํƒœ๊ทธ3"), new RoadmapTagSaveRequest("ํƒœ๊ทธ4"), + new RoadmapTagSaveRequest("ํƒœ๊ทธ5"), new RoadmapTagSaveRequest("ํƒœ๊ทธ6"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("ํƒœ๊ทธ์˜ ๊ฐœ์ˆ˜๋Š” ์ตœ๋Œ€ 5๊ฐœ๊นŒ์ง€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์ค‘๋ณต๋œ_ํƒœ๊ทธ_์ด๋ฆ„์ด_์žˆ์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final RoadmapSaveRequest request = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"), new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + given(roadmapCreateService.create(any(), any())) + .willThrow(new BadRequestException("ํƒœ๊ทธ ์ด๋ฆ„์€ ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")); + + // expect + ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(request, status().isBadRequest()); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() throws Exception { + // given + doNothing().when(roadmapCreateService) + .createReview(any(), any(), any()); + + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isCreated()) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ") + .attributes(new Attribute(RESTRICT, "- ๊ธธ์ด : 0 ~ 1000")), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ") + .attributes(new Attribute(RESTRICT, "- 0.0๋ถ€ํ„ฐ 5.0๊นŒ์ง€, 0.5 ๋‹จ์œ„์˜ ๊ฐ’")) + .optional()), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋ณ„์ ์ด_null์ด๋ผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest(" ", null); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + final String response = mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$[0].message").value("๋ณ„์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final List errorResponses = objectMapper.readValue(response, new TypeReference<>() { + }); + final List expected = List.of(new ErrorResponse("๋ณ„์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.")); + assertThat(errorResponses) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋ณ„์ ์ด_์ž˜๋ชป๋œ_๊ฐ’์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new BadRequestException("๋ณ„์ ์€ 0๋ถ€ํ„ฐ 5๊นŒ์ง€ 0.5 ๋‹จ์œ„๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .when(roadmapCreateService) + .createReview(any(), any(), any()); + + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.5); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + final String response = mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("๋ณ„์ ์€ 0๋ถ€ํ„ฐ 5๊นŒ์ง€ 0.5 ๋‹จ์œ„๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("๋ณ„์ ์€ 0๋ถ€ํ„ฐ 5๊นŒ์ง€ 0.5 ๋‹จ์œ„๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋‚ด์šฉ์ด_1000์ž๊ฐ€_๋„˜์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new BadRequestException("๋ฆฌ๋ทฐ๋Š” ์ตœ๋Œ€ 1000๊ธ€์ž๊นŒ์ง€ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .when(roadmapCreateService) + .createReview(any(), any(), any()); + + final String content = "a".repeat(1001); + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest(content, 5.0); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + final String response = mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("๋ฆฌ๋ทฐ๋Š” ์ตœ๋Œ€ 1000๊ธ€์ž๊นŒ์ง€ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("๋ฆฌ๋ทฐ๋Š” ์ตœ๋Œ€ 1000๊ธ€์ž๊นŒ์ง€ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1L")) + .when(roadmapCreateService) + .createReview(any(), any(), any()); + + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + final String response = mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1L")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1L"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์ด_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new BadRequestException("๋กœ๋“œ๋งต์— ๋Œ€ํ•ด์„œ ์™„๋ฃŒ๋œ ๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. roadmapId = 1L memberIdentifier = cokirikiri")) + .when(roadmapCreateService) + .createReview(any(), any(), any()); + + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + final String response = mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message") + .value("๋กœ๋“œ๋งต์— ๋Œ€ํ•ด์„œ ์™„๋ฃŒ๋œ ๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. roadmapId = 1L memberIdentifier = cokirikiri")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse( + "๋กœ๋“œ๋งต์— ๋Œ€ํ•ด์„œ ์™„๋ฃŒ๋œ ๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. roadmapId = 1L memberIdentifier = cokirikiri"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ƒ์„ฑ์ž๊ฐ€_๋ฆฌ๋ทฐ๋ฅผ_๋‹ฌ๋ ค๊ณ _ํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new BadRequestException("๋กœ๋“œ๋งต ์ƒ์„ฑ์ž๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๋‹ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. roadmapId = 1L memberId = 1L")) + .when(roadmapCreateService) + .createReview(any(), any(), any()); + + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + final String response = mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message") + .value("๋กœ๋“œ๋งต ์ƒ์„ฑ์ž๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๋‹ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. roadmapId = 1L memberId = 1L")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse( + "๋กœ๋“œ๋งต ์ƒ์„ฑ์ž๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๋‹ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. roadmapId = 1L memberId = 1L"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์ด๋ฏธ_๋ฆฌ๋ทฐ๋ฅผ_๋‹จ์ ์ด_์žˆ์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new BadRequestException("์ด๋ฏธ ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. roadmapId = 1L memberId = 1L")) + .when(roadmapCreateService) + .createReview(any(), any(), any()); + + final RoadmapReviewSaveRequest request = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + final String jsonRequest = objectMapper.writeValueAsString(request); + + // when + final String response = mockMvc.perform(post(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message") + .value("์ด๋ฏธ ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. roadmapId = 1L memberId = 1L")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + requestFields( + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("rate").description("๋กœ๋“œ๋งต ๋ฆฌ๋ทฐ ๋ณ„์ ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse( + "์ด๋ฏธ ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. roadmapId = 1L memberId = 1L"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๋“œ๋งต์„_์‚ญ์ œํ•œ๋‹ค() throws Exception { + // given + doNothing() + .when(roadmapCreateService) + .deleteRoadmap(anyString(), anyLong()); + + // when + mockMvc.perform(delete(API_PREFIX + "/roadmaps/{roadmapId}", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpect(status().isNoContent()) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””").optional())) + ); + } + + @Test + void ๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต์ธ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")) + .when(roadmapCreateService) + .deleteRoadmap(anyString(), anyLong()); + + // when + final String response = mockMvc.perform(delete(API_PREFIX + "/roadmaps/{roadmapId}", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll(status().isNotFound(), + jsonPath("$.message") + .value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””").optional()), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_์ž์‹ ์ด_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์ด_์•„๋‹Œ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + doThrow(new ForbiddenException("ํ•ด๋‹น ๋กœ๋“œ๋งต์„ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.")) + .when(roadmapCreateService) + .deleteRoadmap(anyString(), anyLong()); + + // when + final String response = mockMvc.perform(delete(API_PREFIX + "/roadmaps/{roadmapId}", 1L) + .header(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, "test-token")) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .contextPath(API_PREFIX)) + .andExpectAll(status().isForbidden(), + jsonPath("$.message") + .value("ํ•ด๋‹น ๋กœ๋“œ๋งต์„ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.")) + .andDo(documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””").optional()), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("ํ•ด๋‹น ๋กœ๋“œ๋งต์„ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."); + assertThat(errorResponse) + .isEqualTo(expected); + } + + private RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ์„_์ƒ์„ฑํ•œ๋‹ค(final Long categoryId, final String roadmapTitle, + final String roadmapIntroduction, final String roadmapContent, + final RoadmapDifficultyType roadmapDifficulty, + final Integer requiredPeriod, + final List roadmapNodesSaveRequests, + final List roadmapTagSaveRequests) { + return new RoadmapSaveRequest(categoryId, roadmapTitle, roadmapIntroduction, roadmapContent, roadmapDifficulty, + requiredPeriod, roadmapNodesSaveRequests, roadmapTagSaveRequests); + } + + private void ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ(final RoadmapSaveRequest request, final ResultMatcher httpStatus) throws Exception { + final String jsonRequest = objectMapper.writeValueAsString(request); + final MockMultipartFile jsonDataFile = new MockMultipartFile("jsonData", "", "application/json", + objectMapper.writeValueAsBytes(request)); + + final List MULTIPART_FORM_๋ฐ์ดํ„ฐ_์„ค๋ช…_๋ฆฌ์ŠคํŠธ = new ArrayList<>(); + MULTIPART_FORM_๋ฐ์ดํ„ฐ_์„ค๋ช…_๋ฆฌ์ŠคํŠธ.add(partWithName("jsonData").description("๋กœ๋“œ๋งต ์ƒ์„ฑ ์š”์ฒญ json ๋ฐ์ดํ„ฐ")); + + MockMultipartHttpServletRequestBuilder httpServletRequestBuilder = multipart(API_PREFIX + "/roadmaps"); + + for (final RoadmapNodeSaveRequest roadmapNode : request.roadmapNodes()) { + final String ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ = roadmapNode.getTitle() != null ? roadmapNode.getTitle() : "name"; + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile(๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ, + "originalFileName.jpeg", "image/jpeg", "tempImage".getBytes()); + httpServletRequestBuilder = httpServletRequestBuilder.file(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด); + + MULTIPART_FORM_๋ฐ์ดํ„ฐ_์„ค๋ช…_๋ฆฌ์ŠคํŠธ.add( + partWithName(๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ).description("๋กœ๋“œ๋งต ๋…ธ๋“œ title") + ); + } + + mockMvc.perform(httpServletRequestBuilder + .file(jsonDataFile) + .param("jsonData", jsonRequest) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .header(HttpHeaders.AUTHORIZATION, "Bearer accessToken") + .contextPath(API_PREFIX)) + .andExpect(httpStatus) + .andDo(documentationResultHandler.document( + requestHeaders(headerWithName("Authorization").description("access token")), + requestParts(MULTIPART_FORM_๋ฐ์ดํ„ฐ_์„ค๋ช…_๋ฆฌ์ŠคํŠธ), + requestPartFields("jsonData", + fieldWithPath("categoryId").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””"), + fieldWithPath("title").description("๋กœ๋“œ๋งต ์ œ๋ชฉ") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด : 1-40")), + fieldWithPath("introduction").description("๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด : 1-150")), + fieldWithPath("content").description("๋กœ๋“œ๋งต ๋ณธ๋ฌธ ๋‚ด์šฉ").optional() + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด : 0-2000")), + fieldWithPath("difficulty").description( + "๋กœ๋“œ๋งต ๋‚œ์ด๋„(VERY_EASY, EASY, NORMAL, DIFFICULT, VERY_DIFFICULT)"), + fieldWithPath("requiredPeriod").description("๋กœ๋“œ๋งต ์ „์ฒด ์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด : 0-1000")), + fieldWithPath("roadmapNodes").description("๋กœ๋“œ๋งต ๋…ธ๋“œ๋“ค"), + fieldWithPath("roadmapNodes[0].title").description("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด : 1-40")), + fieldWithPath("roadmapNodes[0].content").description("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด : 1-2000")), + fieldWithPath("roadmapNodes[0].images").ignored(), + fieldWithPath("roadmapTags[0].name").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์ด๋ฆ„") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด : 1-10")) + .optional() + ), + responseHeaders( + headerWithName("Location").description("๋กœ๋“œ๋งต ์•„์ด๋””").optional() + ))); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/RoadmapReadApiTest.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/RoadmapReadApiTest.java new file mode 100644 index 000000000..b9a736f56 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/RoadmapReadApiTest.java @@ -0,0 +1,701 @@ +package co.kirikiri.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import co.kirikiri.controller.helper.ControllerTestHelper; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.service.RoadmapCreateService; +import co.kirikiri.service.RoadmapReadService; +import co.kirikiri.service.dto.CustomScrollRequest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.member.response.MemberResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapOrderTypeRequest; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapCategoryResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapContentResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapNodeResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapTagResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.restdocs.snippet.Attributes; +import org.springframework.test.web.servlet.MvcResult; + +@WebMvcTest(RoadmapController.class) +class RoadmapReadApiTest extends ControllerTestHelper { + + private final LocalDateTime ์˜ค๋Š˜ = LocalDateTime.now(); + + @MockBean + private RoadmapReadService roadmapReadService; + + @MockBean + private RoadmapCreateService roadmapCreateService; + + @Test + void ๋‹จ์ผ_๋กœ๋“œ๋งต_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + //given + final RoadmapResponse expectedResponse = ๋‹จ์ผ_๋กœ๋“œ๋งต_์กฐํšŒ์—_๋Œ€ํ•œ_์‘๋‹ต(); + when(roadmapReadService.findRoadmap(anyLong())) + .thenReturn(expectedResponse); + + //when + final MvcResult response = mockMvc.perform(get(API_PREFIX + "/roadmaps/{roadmapId}", 1L) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo(documentationResultHandler.document( + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””") + ), + responseFields( + fieldWithPath("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””"), + fieldWithPath("category.id").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””"), + fieldWithPath("category.name").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„"), + fieldWithPath("roadmapTitle").description("๋กœ๋“œ๋งต ์ œ๋ชฉ"), + fieldWithPath("introduction").description("๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€"), + fieldWithPath("difficulty").description("๋กœ๋“œ๋งต ๋‚œ์ด๋„"), + fieldWithPath("recommendedRoadmapPeriod").description("๋กœ๋“œ๋งต ์ถ”์ฒœ ๊ธฐ๊ฐ„"), + fieldWithPath("createdAt").description("๋กœ๋“œ๋งต ์ƒ์„ฑ ์‹œ๊ฐ„"), + fieldWithPath("creator.id").description("๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ์•„์ด๋””"), + fieldWithPath("creator.name").description("๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ๋‹‰๋„ค์ž„"), + fieldWithPath("creator.imageUrl").description("๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ"), + fieldWithPath("content.id").description("๋กœ๋“œ๋งต ์ปจํ…์ธ  ์•„์ด๋””"), + fieldWithPath("content.content").description("๋กœ๋“œ๋งต ์ปจํ…์ธ  ๋ณธ๋ฌธ"), + fieldWithPath("content.nodes[0].id").description("๋กœ๋“œ๋งต ๋…ธ๋“œ ์•„์ด๋””"), + fieldWithPath("content.nodes[0].title").description("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ"), + fieldWithPath("content.nodes[0].description").description("๋กœ๋“œ๋งต ๋…ธ๋“œ ๋ณธ๋ฌธ"), + fieldWithPath("content.nodes[0].imageUrls[0]").description("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ด๋ฏธ์ง€ ํŒŒ์ผ ๊ฒฝ๋กœ"), + fieldWithPath("tags[0].id").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์•„์ด๋””"), + fieldWithPath("tags[0].name").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์ด๋ฆ„"), + fieldWithPath("recruitedGoalRoomNumber").description("ํ•ด๋‹น ๋กœ๋“œ๋งต์—์„œ ๋ชจ์ง‘ ์ค‘์ธ ๊ณจ๋ฃธ ๊ฐœ์ˆ˜"), + fieldWithPath("runningGoalRoomNumber").description("ํ•ด๋‹น ๋กœ๋“œ๋งต์—์„œ ์ง„ํ–‰ ์ค‘์ธ ๊ณจ๋ฃธ ๊ฐœ์ˆ˜"), + fieldWithPath("completedGoalRoomNumber").description("ํ•ด๋‹น ๋กœ๋“œ๋งต์—์„œ ์™„๋ฃŒ๋œ ๊ณจ๋ฃธ ๊ฐœ์ˆ˜")))) + .andReturn(); + + //then + final RoadmapResponse roadmapResponse = jsonToClass(response, new TypeReference<>() { + }); + + assertThat(roadmapResponse) + .isEqualTo(expectedResponse); + } + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_์š”์ฒญ_์‹œ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws Exception { + // given + when(roadmapReadService.findRoadmap(anyLong())).thenThrow( + new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")); + + // when + // then + mockMvc.perform(get(API_PREFIX + "/roadmaps/{roadmapId}", 1L) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andExpect(jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")) + .andDo(documentationResultHandler.document( + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์„ธ์ง€") + ))); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์กฐ๊ฑด์—_๋”ฐ๋ผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final RoadmapForListResponses expected = ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(); + when(roadmapReadService.findRoadmapsByOrderType(any(), any(), any())) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps") + .param("categoryId", "1") + .param("filterCond", RoadmapOrderTypeRequest.LATEST.name()) + .param("lastId", "1") + .param("size", "10") + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + queryParameters( + parameterWithName("categoryId").description("์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””(๋ฏธ์ „์†ก ์‹œ ์ „์ฒด ์กฐํšŒ)") + .optional(), + parameterWithName("filterCond").description( + "ํ•„ํ„ฐ ์กฐ๊ฑด(GOAL_ROOM_COUNT, LATEST, PARTICIPANT_COUNT, REVIEW_RATE)") + .optional(), + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋กœ๋“œ๋งต ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("ํ•œ ํŽ˜์ด์ง€์—์„œ ๋ฐ›์•„์˜ฌ ๋กœ๋“œ๋งต์˜ ์ˆ˜")), + responseFields( + fieldWithPath("responses[0].roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””"), + fieldWithPath("responses[0].roadmapTitle").description("๋กœ๋“œ๋งต ์ œ๋ชฉ"), + fieldWithPath("responses[0].introduction").description("๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€"), + fieldWithPath("responses[0].difficulty").description("๋กœ๋“œ๋งต ๋‚œ์ด๋„"), + fieldWithPath("responses[0].recommendedRoadmapPeriod").description("๋กœ๋“œ๋งต ์ถ”์ฒœ ๊ธฐ๊ฐ„"), + fieldWithPath("responses[0].createdAt").description("๋กœ๋“œ๋งต ์ƒ์„ฑ ์‹œ๊ฐ„"), + fieldWithPath("responses[0].creator.id").description("๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ์•„์ด๋””"), + fieldWithPath("responses[0].creator.name").description("๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ์ด๋ฆ„"), + fieldWithPath("responses[0].creator.imageUrl").description( + "๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ"), + fieldWithPath("responses[0].category.id").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””"), + fieldWithPath("responses[0].category.name").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„"), + fieldWithPath("responses[0].tags[0].id").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์•„์ด๋””"), + fieldWithPath("responses[0].tags[0].name").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์ด๋ฆ„"), + fieldWithPath("hasNext").description("๋‹ค์Œ ์š”์†Œ์˜ ์กด์žฌ ์—ฌ๋ถ€") + ))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final RoadmapForListResponses roadmapForListResponses = objectMapper.readValue(response, + new TypeReference<>() { + }); + + assertThat(roadmapForListResponses) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๋ฅผ_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + when(roadmapReadService.findRoadmapsByOrderType(any(), any(), any())).thenThrow( + new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค. categoryId = 1L")); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps") + .param("categoryId", "1") + .param("filterCond", RoadmapOrderTypeRequest.LATEST.name()) + .param("size", "10") + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค. categoryId = 1L")) + .andDo(documentationResultHandler.document( + queryParameters( + parameterWithName("categoryId").description("์ž˜๋ชป๋œ ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””"), + parameterWithName("filterCond").description( + "ํ•„ํ„ฐ ์กฐ๊ฑด(GOAL_ROOM_COUNT, LATEST, PARTICIPANT_COUNT, REVIEW_RATE)") + .optional(), + parameterWithName("size").description("ํ•œ ํŽ˜์ด์ง€์—์„œ ๋ฐ›์•„์˜ฌ ๋กœ๋“œ๋งต์˜ ์ˆ˜")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค. categoryId = 1L"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ์‹œ_์‚ฌ์ด์ฆˆ_๊ฐ’์„_์ „์†กํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps") + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$[0].message").value("์‚ฌ์ด์ฆˆ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.")) + .andDo(documentationResultHandler.document( + responseFields(fieldWithPath("[0].message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final List errorResponse = objectMapper.readValue(response, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์‚ฌ์ด์ฆˆ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + assertThat(errorResponse.get(0)) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final List expected = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(); + when(roadmapReadService.findAllRoadmapCategories()) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get("/api/roadmaps/categories") + .contextPath(API_PREFIX)) + .andDo( + documentationResultHandler.document( + responseFields( + fieldWithPath("[0].id").description("์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””"), + fieldWithPath("[0].name").description("์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„") + ) + ) + ) + .andReturn() + .getResponse() + .getContentAsString(); + + // then + final List roadmapCategoryResponses = objectMapper.readValue(response, + new TypeReference<>() { + }); + + assertThat(roadmapCategoryResponses) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต์„_์กฐ๊ฑด๋ณ„๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค() throws Exception { + // given + final RoadmapForListResponses expected = ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(); + when(roadmapReadService.search(any(), any(), any())) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps/search") + .param("roadmapTitle", "roadmap") + .param("lastId", "1") + .param("creatorName", "์ฝ”๋ผ๋ฆฌ") + .param("tagName", "Java") + .param("filterCond", RoadmapOrderTypeRequest.LATEST.name()) + .param("size", "10") + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + queryParameters( + parameterWithName("roadmapTitle").description("๋กœ๋“œ๋งต ์ œ๋ชฉ ๊ฒ€์ƒ‰์–ด") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด: 1์ž ์ด์ƒ")) + .optional(), + parameterWithName("creatorName").description("ํฌ๋ฆฌ์—์ดํ„ฐ ๋‹‰๋„ค์ž„") + .optional(), + parameterWithName("tagName").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์ด๋ฆ„") + .attributes(new Attributes.Attribute(RESTRICT, "- ๊ธธ์ด: 1์ž ์ด์ƒ")) + .optional(), + parameterWithName("filterCond").description( + "ํ•„ํ„ฐ ์กฐ๊ฑด(GOAL_ROOM_COUNT, LATEST, PARTICIPANT_COUNT, REVIEW_RATE)") + .optional(), + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋กœ๋“œ๋งต ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("ํ•œ ํŽ˜์ด์ง€์—์„œ ๋ฐ›์•„์˜ฌ ๋กœ๋“œ๋งต์˜ ์ˆ˜")), + responseFields( + fieldWithPath("responses[0].roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””"), + fieldWithPath("responses[0].roadmapTitle").description("๋กœ๋“œ๋งต ์ œ๋ชฉ"), + fieldWithPath("responses[0].introduction").description("๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€"), + fieldWithPath("responses[0].difficulty").description("๋กœ๋“œ๋งต ๋‚œ์ด๋„"), + fieldWithPath("responses[0].recommendedRoadmapPeriod").description("๋กœ๋“œ๋งต ์ถ”์ฒœ ๊ธฐ๊ฐ„"), + fieldWithPath("responses[0].createdAt").description("๋กœ๋“œ๋งต ์ƒ์„ฑ ์‹œ๊ฐ„"), + fieldWithPath("responses[0].creator.id").description("๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ์•„์ด๋””"), + fieldWithPath("responses[0].creator.name").description("๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ์ด๋ฆ„"), + fieldWithPath("responses[0].creator.imageUrl").description( + "๋กœ๋“œ๋งต ํฌ๋ฆฌ์—์ดํ„ฐ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ"), + fieldWithPath("responses[0].category.id").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””"), + fieldWithPath("responses[0].category.name").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„"), + fieldWithPath("responses[0].tags[0].id").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์•„์ด๋””"), + fieldWithPath("responses[0].tags[0].name").description("๋กœ๋“œ๋งต ํƒœ๊ทธ ์ด๋ฆ„"), + fieldWithPath("hasNext").description("๋‹ค์Œ ์š”์†Œ์˜ ์กด์žฌ ์—ฌ๋ถ€") + ))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final RoadmapForListResponses roadmapForListResponses = objectMapper.readValue(response, + new TypeReference<>() { + }); + + assertThat(roadmapForListResponses) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๊ฒ€์ƒ‰์‹œ_์‚ฌ์ด์ฆˆ_๊ฐ’์„_์ „์†กํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps/search") + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$[0].message").value("์‚ฌ์ด์ฆˆ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.")) + .andDo(documentationResultHandler.document( + responseFields(fieldWithPath("[0].message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final List errorResponse = objectMapper.readValue(response, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์‚ฌ์ด์ฆˆ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + assertThat(errorResponse.get(0)) + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final MemberRoadmapResponses expected = ์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์กฐํšŒ์—_๋Œ€ํ•œ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(); + + when(roadmapReadService.findAllMemberRoadmaps(any(), any())) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps/me") + .header(HttpHeaders.AUTHORIZATION, "Bearer ") + .param("lastId", "1") + .param("size", "10") + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + queryParameters( + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋กœ๋“œ๋งต ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("ํ•œ ํŽ˜์ด์ง€์—์„œ ๋ฐ›์•„์˜ฌ ๋กœ๋“œ๋งต์˜ ์ˆ˜")), + responseFields( + fieldWithPath("responses[0].roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””"), + fieldWithPath("responses[0].roadmapTitle").description("๋กœ๋“œ๋งต ์ œ๋ชฉ"), + fieldWithPath("responses[0].difficulty").description("๋กœ๋“œ๋งต ๋‚œ์ด๋„"), + fieldWithPath("responses[0].createdAt").description("๋กœ๋“œ๋งต ์ƒ์„ฑ๋‚ ์งœ"), + fieldWithPath("responses[0].category.id").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์•„์ด๋””"), + fieldWithPath("responses[0].category.name").description("๋กœ๋“œ๋งต ์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„"), + fieldWithPath("hasNext").description("๋‹ค์Œ ์š”์†Œ์˜ ์กด์žฌ ์—ฌ๋ถ€") + ))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final MemberRoadmapResponses memberRoadmapRespons = objectMapper.readValue(response, + new TypeReference<>() { + }); + assertThat(memberRoadmapRespons) + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ• _๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws Exception { + // given + when(roadmapReadService.findAllMemberRoadmaps(any(), any())) + .thenThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps/me") + .header(HttpHeaders.AUTHORIZATION, "Bearer ") + .param("lastId", "1") + .param("size", "10") + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")) + .andDo( + documentationResultHandler.document( + requestHeaders( + headerWithName(AUTHORIZATION).description("์•ก์„ธ์Šค ํ† ํฐ")), + queryParameters( + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋กœ๋“œ๋งต ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("ํ•œ ํŽ˜์ด์ง€์—์„œ ๋ฐ›์•„์˜ฌ ๋กœ๋“œ๋งต์˜ ์ˆ˜")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€")))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, ErrorResponse.class); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐ๊ฑด์—_๋”ฐ๋ผ_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final RoadmapGoalRoomResponses ๊ณจ๋ฃธ_ํŽ˜์ด์ง€_์‘๋‹ต = ๊ณจ๋ฃธ_์‘๋‹ต๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + given(roadmapReadService.findRoadmapGoalRoomsByOrderType(any(), any(), any(CustomScrollRequest.class))) + .willReturn(๊ณจ๋ฃธ_ํŽ˜์ด์ง€_์‘๋‹ต); + + // when + final String ์‘๋‹ต๊ฐ’ = mockMvc.perform( + get(API_PREFIX + "/roadmaps/{roadmapId}/goal-rooms", 1L) + .param("filterCond", RoadmapOrderTypeRequest.LATEST.name()) + .param("lastId", "1") + .param("size", "10") + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")), + queryParameters( + parameterWithName("filterCond").description( + "์ •๋ ฌ ์กฐ๊ฑด(LATEST, CLOSE_TO_DEADLINE)").optional(), + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๊ณจ๋ฃธ ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("๋ฐ›์•„์˜ฌ ๊ณจ๋ฃธ์˜ ์ˆ˜")), + responseFields( + fieldWithPath("responses[0].goalRoomId").description("๊ณจ๋ฃธ ์•„์ด๋””"), + fieldWithPath("responses[0].name").description("๊ณจ๋ฃธ ์ด๋ฆ„"), + fieldWithPath("responses[0].currentMemberCount").description("ํ˜„์žฌ ๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์ธ์› ์ˆ˜"), + fieldWithPath("responses[0].limitedMemberCount").description( + "๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•  ์ˆ˜ ์žˆ๋Š” ์ œํ•œ ์ธ์› ์ˆ˜"), + fieldWithPath("responses[0].createdAt").description("๊ณจ๋ฃธ ์ƒ์„ฑ ๋‚ ์งœ์™€ ์‹œ๊ฐ„"), + fieldWithPath("responses[0].startDate").description("๊ณจ๋ฃธ์˜ ์‹œ์ž‘ ๋‚ ์งœ"), + fieldWithPath("responses[0].endDate").description("๊ณจ๋ฃธ์˜ ์ข…๋ฃŒ ๋‚ ์งœ"), + fieldWithPath("responses[0].goalRoomLeader.id").description("๊ณจ๋ฃธ ๋ฆฌ๋”์˜ ์•„์ด๋””"), + fieldWithPath("responses[0].goalRoomLeader.name").description("๊ณจ๋ฃธ ๋ฆฌ๋”์˜ ๋‹‰๋„ค์ž„"), + fieldWithPath("responses[0].goalRoomLeader.imageUrl").description( + "๊ณจ๋ฃธ ๋ฆฌ๋”์˜ ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ"), + fieldWithPath("hasNext").description("๋‹ค์Œ ์š”์†Œ์˜ ์กด์žฌ ์—ฌ๋ถ€") + ) + ) + ) + .andReturn().getResponse() + .getContentAsString(); + + // then + final RoadmapGoalRoomResponses ์‘๋‹ต๊ฐ’์œผ๋กœ_์ƒ์„ฑํ•œ_๊ณจ๋ฃธ_ํŽ˜์ด์ง€ = objectMapper.readValue(์‘๋‹ต๊ฐ’, + new TypeReference<>() { + }); + + final RoadmapGoalRoomResponses ์˜ˆ์ƒ๋˜๋Š”_๊ณจ๋ฃธ_ํŽ˜์ด์ง€_์‘๋‹ต = ๊ณจ๋ฃธ_์‘๋‹ต๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + assertThat(์‘๋‹ต๊ฐ’์œผ๋กœ_์ƒ์„ฑํ•œ_๊ณจ๋ฃธ_ํŽ˜์ด์ง€) + .usingRecursiveComparison() + .isEqualTo(์˜ˆ์ƒ๋˜๋Š”_๊ณจ๋ฃธ_ํŽ˜์ด์ง€_์‘๋‹ต); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐ๊ฑด์—_๋”ฐ๋ผ_์กฐํšŒํ• _๋•Œ_๋กœ๋“œ๋งต์ด_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ_๋ฐœ์ƒ() throws Exception { + // given + given(roadmapReadService.findRoadmapGoalRoomsByOrderType(any(), any(), any(CustomScrollRequest.class))) + .willThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")); + + // when + final MvcResult ์‘๋‹ต๊ฐ’ = mockMvc.perform( + get(API_PREFIX + "/roadmaps/{roadmapId}/goal-rooms", 1L) + .param("filterCond", RoadmapOrderTypeRequest.LATEST.name()) + .param("lastId", "1") + .param("size", "10") + .contextPath(API_PREFIX)) + .andExpectAll( + status().is4xxClientError(), + jsonPath("$.message").value("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")) + .andDo( + documentationResultHandler.document( + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””")), + queryParameters( + parameterWithName("filterCond").description( + "ํ•„ํ„ฐ ์กฐ๊ฑด(LATEST, PARTICIPATION_RATE)").optional(), + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๊ณจ๋ฃธ ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("๋ฐ›์•„์˜ฌ ๊ณจ๋ฃธ์˜ ์ˆ˜")), + responseFields(fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€"))) + ) + .andReturn(); + // then + final ErrorResponse errorResponse = jsonToClass(์‘๋‹ต๊ฐ’, new TypeReference<>() { + }); + final ErrorResponse expected = new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + assertThat(errorResponse) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๋ฆฌ๋ทฐ๋“ค์„_์กฐํšŒํ•œ๋‹ค() throws Exception { + // given + final List expected = List.of( + new RoadmapReviewResponse(1L, new MemberResponse(1L, "์ž‘์„ฑ์ž1", "image1-file-path"), + LocalDateTime.of(2023, 8, 15, 12, 30, 0, 123456), "๋ฆฌ๋ทฐ ๋‚ด์šฉ", 4.5), + new RoadmapReviewResponse(2L, new MemberResponse(2L, "์ž‘์„ฑ์ž2", "image2-file-path"), + LocalDateTime.of(2023, 8, 16, 12, 30, 0, 123456), "๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0) + ); + + when(roadmapReadService.findRoadmapReviews(anyLong(), any())) + .thenReturn(expected); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .param("lastId", "1") + .param("size", "10") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isOk()) + .andDo(documentationResultHandler.document( + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””") + ), + queryParameters( + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋ฆฌ๋ทฐ ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("ํ•œ ๋ฒˆ์— ์กฐํšŒํ•  ๋ฆฌ๋ทฐ๊ฐฏ์ˆ˜") + ), + responseFields( + fieldWithPath("[0].id").description("๋ฆฌ๋ทฐ ์•„์ด๋””"), + fieldWithPath("[0].member.id").description("์ž‘์„ฑ์ž ์•„์ด๋””"), + fieldWithPath("[0].member.name").description("์ž‘์„ฑ์ž ๋‹‰๋„ค์ž„"), + fieldWithPath("[0].member.imageUrl").description("์ž‘์„ฑ์ž ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ"), + fieldWithPath("[0].createdAt").description("๋ฆฌ๋ทฐ ์ตœ์ข… ์ž‘์„ฑ๋‚ ์งœ"), + fieldWithPath("[0].content").description("๋ฆฌ๋ทฐ ๋‚ด์šฉ"), + fieldWithPath("[0].rate").description("๋ณ„์ ") + ))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final List reviewResponse = objectMapper.readValue(response, + new TypeReference<>() { + }); + + assertThat(reviewResponse) + .usingRecursiveComparison() + .ignoringFields("createdAt") + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต_์•„์ด๋””์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws Exception { + // given + when(roadmapReadService.findRoadmapReviews(anyLong(), any())) + .thenThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")); + + // when + final String response = mockMvc.perform( + get(API_PREFIX + "/roadmaps/{roadmapId}/reviews", 1L) + .param("size", "10") + .contentType(MediaType.APPLICATION_JSON) + .contextPath(API_PREFIX)) + .andExpect(status().isNotFound()) + .andDo(documentationResultHandler.document( + pathParameters( + parameterWithName("roadmapId").description("๋กœ๋“œ๋งต ์•„์ด๋””") + ), + queryParameters( + parameterWithName("lastId") + .description("์ด์ „ ์š”์ฒญ์—์„œ ๋ฐ›์€ ์‘๋‹ต ์ค‘ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋ฆฌ๋ทฐ ์•„์ด๋”” (์ฒซ ์š”์ฒญ ์‹œ ๋ฏธ์ „์†ก)") + .optional(), + parameterWithName("size").description("ํ•œ ๋ฒˆ์— ์กฐํšŒํ•  ๋ฆฌ๋ทฐ๊ฐฏ์ˆ˜") + ), + responseFields( + fieldWithPath("message").description("์˜ˆ์™ธ ๋ฉ”์‹œ์ง€") + ))) + .andReturn().getResponse() + .getContentAsString(); + + // then + final ErrorResponse errorResponse = objectMapper.readValue(response, new TypeReference<>() { + }); + + assertThat(errorResponse.message()) + .isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + } + + private RoadmapResponse ๋‹จ์ผ_๋กœ๋“œ๋งต_์กฐํšŒ์—_๋Œ€ํ•œ_์‘๋‹ต() { + final RoadmapCategoryResponse category = new RoadmapCategoryResponse(1, "์šด๋™"); + final MemberResponse creator = new MemberResponse(1, "๋‹‰๋„ค์ž„", "profile-image-filepath"); + final List nodes = List.of( + new RoadmapNodeResponse(1L, "1๋ฒˆ ๋…ธ๋“œ", "1๋ฒˆ ๋…ธ๋“œ ์„ค๋ช…", List.of("image1-filepath", "image2-filepath")), + new RoadmapNodeResponse(2L, "2๋ฒˆ ๋…ธ๋“œ", "2๋ฒˆ ๋…ธ๋“œ ์„ค๋ช…", Collections.emptyList()) + ); + final List tags = List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2") + ); + return new RoadmapResponse(1L, category, "์ œ๋ชฉ", "์†Œ๊ฐœ๊ธ€", creator, + new RoadmapContentResponse(1L, "๋ณธ๋ฌธ", nodes), "EASY", 100, + ์˜ค๋Š˜, tags, 10L, 10L, 10L); + } + + private RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค() { + final List tags = List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2") + ); + + final RoadmapForListResponse roadmapResponse1 = new RoadmapForListResponse(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ1", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€1", "NORMAL", + 10, ์˜ค๋Š˜, new MemberResponse(1L, "์ฝ”๋ผ๋ฆฌ", "default-member-image"), new RoadmapCategoryResponse(1L, "์—ฌํ–‰"), + tags); + final RoadmapForListResponse roadmapResponse2 = new RoadmapForListResponse(2L, "๋กœ๋“œ๋งต ์ œ๋ชฉ2", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€2", + "DIFFICULT", 7, ์˜ค๋Š˜, new MemberResponse(2L, "๋ผ๋ฆฌ์ฝ”", "default-member-image"), + new RoadmapCategoryResponse(2L, "IT"), tags); + final List responses = List.of(roadmapResponse1, roadmapResponse2); + return new RoadmapForListResponses(responses, false); + } + + private List ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + final RoadmapCategoryResponse category1 = new RoadmapCategoryResponse(1L, "์–ดํ•™"); + final RoadmapCategoryResponse category2 = new RoadmapCategoryResponse(2L, "IT"); + final RoadmapCategoryResponse category3 = new RoadmapCategoryResponse(3L, "์‹œํ—˜"); + final RoadmapCategoryResponse category4 = new RoadmapCategoryResponse(4L, "์šด๋™"); + final RoadmapCategoryResponse category5 = new RoadmapCategoryResponse(5L, "๊ฒŒ์ž„"); + final RoadmapCategoryResponse category6 = new RoadmapCategoryResponse(6L, "์Œ์•…"); + final RoadmapCategoryResponse category7 = new RoadmapCategoryResponse(7L, "๋ผ์ดํ”„"); + final RoadmapCategoryResponse category8 = new RoadmapCategoryResponse(8L, "์—ฌ๊ฐ€"); + final RoadmapCategoryResponse category9 = new RoadmapCategoryResponse(9L, "๊ธฐํƒ€"); + return List.of(category1, category2, category3, category4, category5, category6, category7, category8, + category9); + } + + private MemberRoadmapResponses ์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์กฐํšŒ์—_๋Œ€ํ•œ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค() { + final List responses = List.of( + new MemberRoadmapResponse(3L, "์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", RoadmapDifficulty.DIFFICULT.name(), LocalDateTime.now(), + new RoadmapCategoryResponse(2L, "๊ฒŒ์ž„")), + new MemberRoadmapResponse(2L, "๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", RoadmapDifficulty.DIFFICULT.name(), LocalDateTime.now(), + new RoadmapCategoryResponse(1L, "์—ฌํ–‰")), + new MemberRoadmapResponse(1L, "์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", RoadmapDifficulty.DIFFICULT.name(), LocalDateTime.now(), + new RoadmapCategoryResponse(1L, "์—ฌํ–‰"))); + return new MemberRoadmapResponses(responses, true); + } + + private RoadmapGoalRoomResponses ๊ณจ๋ฃธ_์‘๋‹ต๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapGoalRoomResponse roadmapGoalRoomResponse1 = new RoadmapGoalRoomResponse(1L, "๊ณจ๋ฃธ ์ด๋ฆ„1", 3, 6, + LocalDateTime.of(2023, 7, 20, 13, 0, 0), + LocalDate.now(), LocalDate.now().plusDays(100), + new MemberResponse(1L, "ํ™ฉ์‹œ์ง„", "default-member-image")); + final RoadmapGoalRoomResponse roadmapGoalRoomResponse2 = new RoadmapGoalRoomResponse(2L, "๊ณจ๋ฃธ ์ด๋ฆ„2", 4, 10, + LocalDateTime.of(2023, 7, 10, 13, 0, 0), + LocalDate.now(), LocalDate.now().plusDays(100), + new MemberResponse(2L, "์‹œ์ง„์ด", "default-member-image")); + final List responses = List.of(roadmapGoalRoomResponse1, + roadmapGoalRoomResponse2); + return new RoadmapGoalRoomResponses(responses, false); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/ControllerTestHelper.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/ControllerTestHelper.java new file mode 100644 index 000000000..e48b28631 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/ControllerTestHelper.java @@ -0,0 +1,40 @@ +package co.kirikiri.controller.helper; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import co.kirikiri.common.interceptor.AuthInterceptor; +import co.kirikiri.common.resolver.MemberIdentifierArgumentResolver; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.restdocs.payload.FieldDescriptor; + +public class ControllerTestHelper extends RestDocsHelper { + + protected final String AUTHORIZATION = "Authorization"; + protected final String BEARER_TOKEN_FORMAT = "Bearer %s"; + + @MockBean + protected AuthInterceptor authInterceptor; + + @MockBean + private MemberIdentifierArgumentResolver memberIdentifierArgumentResolver; + + @BeforeEach + void setUp() { + when(authInterceptor.preHandle(any(), any(), any())) + .thenReturn(true); + when(memberIdentifierArgumentResolver.resolveArgument(any(), any(), any(), any())) + .thenReturn("Bearer Token"); + when(memberIdentifierArgumentResolver.supportsParameter(any())) + .thenReturn(true); + } + + protected List makeFieldDescriptor( + final List descriptions) { + return descriptions.stream() + .map(FieldDescriptionHelper::getDescriptor) + .toList(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/FieldDescriptionHelper.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/FieldDescriptionHelper.java new file mode 100644 index 000000000..e7cdaeb4f --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/FieldDescriptionHelper.java @@ -0,0 +1,47 @@ +package co.kirikiri.controller.helper; + +import static co.kirikiri.controller.helper.RestDocsHelper.RESTRICT; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; + +import org.springframework.restdocs.payload.FieldDescriptor; +import org.springframework.restdocs.snippet.Attributes; + +public class FieldDescriptionHelper { + + public static FieldDescriptor getDescriptor(final FieldDescription description) { + if (description.getRestriction() == null) { + return fieldWithPath(description.getPath()).description(description.getDescription()); + } + return fieldWithPath(description.getPath()).description(description.getDescription()) + .attributes(new Attributes.Attribute(RESTRICT, description.getRestriction())); + } + + public static class FieldDescription { + + private final String path; + private final String description; + private final String restriction; + + public FieldDescription(final String path, final String description) { + this(path, description, null); + } + + public FieldDescription(final String path, final String description, final String restriction) { + this.path = path; + this.description = description; + this.restriction = restriction; + } + + public String getPath() { + return path; + } + + public String getDescription() { + return description; + } + + public String getRestriction() { + return restriction; + } + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/RestDocsHelper.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/RestDocsHelper.java new file mode 100644 index 000000000..a79420ff8 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/RestDocsHelper.java @@ -0,0 +1,62 @@ +package co.kirikiri.controller.helper; + +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.UnsupportedEncodingException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Import; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.restdocs.operation.preprocess.Preprocessors; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.filter.CharacterEncodingFilter; + +@ActiveProfiles("test") +@Import(TestObjectMapperConfig.class) +@ExtendWith(RestDocumentationExtension.class) +public class RestDocsHelper { + + protected static final String API_PREFIX = "/api"; + protected static final String RESTRICT = "restrict"; + + @Autowired + protected ObjectMapper objectMapper; + + protected MockMvc mockMvc; + + protected RestDocumentationResultHandler documentationResultHandler; + + @BeforeEach + void setUp(final WebApplicationContext webApplicationContext, + final RestDocumentationContextProvider restDocumentationContextProvider) { + this.documentationResultHandler = MockMvcRestDocumentation.document( + "{class-name}/{method-name}", + Preprocessors.preprocessRequest(Preprocessors.prettyPrint()), + Preprocessors.preprocessResponse(Preprocessors.prettyPrint())); + + this.mockMvc = MockMvcBuilders + .webAppContextSetup(webApplicationContext) + .addFilter(new CharacterEncodingFilter("UTF-8", true)) + .alwaysDo(MockMvcResultHandlers.print()) + .alwaysDo(documentationResultHandler) + .apply(documentationConfiguration(restDocumentationContextProvider)) + .build(); + } + + protected T jsonToClass(final MvcResult mvcResult, final TypeReference typeReference) + throws JsonProcessingException, UnsupportedEncodingException { + return objectMapper.readValue(mvcResult.getResponse().getContentAsString(), typeReference); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/TestObjectMapperConfig.java b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/TestObjectMapperConfig.java new file mode 100644 index 000000000..1d0fb9f35 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/controller/helper/TestObjectMapperConfig.java @@ -0,0 +1,16 @@ +package co.kirikiri.controller.helper; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class TestObjectMapperConfig { + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper() + .registerModule(new JavaTimeModule()); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/auth/vo/EncryptedTokenTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/auth/vo/EncryptedTokenTest.java new file mode 100644 index 000000000..aaef1b68e --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/auth/vo/EncryptedTokenTest.java @@ -0,0 +1,21 @@ +package co.kirikiri.domain.auth.vo; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.auth.EncryptedToken; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class EncryptedTokenTest { + + @ParameterizedTest + @ValueSource(strings = {"a", "abc", "", "token", "abcdefghijklmnopqrstuvwxyz"}) + void ์ •์ƒ์ ์œผ๋กœ_ํ† ํฐ์„_์•”ํ˜ธํ™”ํ•œ๋‹ค(final String value) { + //given + //when + final EncryptedToken encryptedToken = new EncryptedToken(value); + + //then + assertThat(encryptedToken.getValue()).isNotEqualTo(value); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomMemberTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomMemberTest.java new file mode 100644 index 000000000..22164903d --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomMemberTest.java @@ -0,0 +1,88 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import java.time.LocalDateTime; +import org.junit.jupiter.api.Test; + +class GoalRoomMemberTest { + + @Test + void ๊ณจ๋ฃธ์˜_๋ฆฌ๋”์ด๋ฉด_true๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), null, null); + + // when + final boolean result = goalRoomMember.isLeader(); + + // then + assertThat(result).isTrue(); + } + + @Test + void ๊ณจ๋ฃธ์˜_๋ฆฌ๋”๊ฐ€_์•„๋‹ˆ๋ฉด_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), null, + null); + + // when + final boolean result = goalRoomMember.isLeader(); + + // then + assertThat(result).isFalse(); + } + + @Test + void ์ž…๋ ฅ๋ฐ›์€_๋ฉค๋ฒ„๊ฐ€_์ž์‹ ๊ณผ_๊ฐ™์€_๋ฉค๋ฒ„์ด๋ฉด_true๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member = new Member(new Identifier("identifier"), + new EncryptedPassword(new Password("password1!")), + new Nickname("name"), null, null); + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), null, + member); + + // when + final boolean result = goalRoomMember.isSameMember(member); + + // then + assertThat(result).isTrue(); + } + + @Test + void ์ž…๋ ฅ๋ฐ›์€_๋ฉค๋ฒ„๊ฐ€_์ž์‹ ๊ณผ_๋‹ค๋ฅธ_๋ฉค๋ฒ„์ด๋ฉด_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member1 = new Member(1L, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), + new Nickname("name1"), null, null); + final Member member2 = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), + new Nickname("name2"), null, null); + + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), null, + member1); + + // when + final boolean result = goalRoomMember.isSameMember(member2); + + // then + assertThat(result).isFalse(); + } + + @Test + void ํŒ”๋กœ์›Œ๊ฐ€_๋ฆฌ๋”๋กœ_๋ณ€๊ฒฝ๋œ๋‹ค() { + // given + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), null, + null); + + // when + goalRoomMember.becomeLeader(); + + // then + assertThat(goalRoomMember.isLeader()).isTrue(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomMembersTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomMembersTest.java new file mode 100644 index 000000000..086c665e9 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomMembersTest.java @@ -0,0 +1,92 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.Test; + +class GoalRoomMembersTest { + + private static final Member MEMBER1 = new Member(1L, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), + new Nickname("name1"), null, null); + private static final Member MEMBER2 = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), + new Nickname("name2"), null, null); + + @Test + void ์ž…๋ ฅ๋ฐ›์€_์‚ฌ์šฉ์ž๋ฅผ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ค‘์—์„œ_์ฐพ๋Š”๋‹ค() { + // given + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), null, + MEMBER1); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomMembers goalRoomMembers = new GoalRoomMembers(List.of(goalRoomMember1, goalRoomMember2)); + + // when + final GoalRoomMember findGoalRoomMember = goalRoomMembers.findByMember(MEMBER1).get(); + + // then + assertThat(findGoalRoomMember).isEqualTo(goalRoomMember1); + } + + @Test + void ๋‹ค์Œ_๋ฆฌ๋”๊ฐ€_๋ _์‚ฌ์šฉ์ž๋ฅผ_์ฐพ๋Š”๋‹ค() { + // given + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), null, + MEMBER1); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomMembers goalRoomMembers = new GoalRoomMembers(List.of(goalRoomMember1, goalRoomMember2)); + + // when + final GoalRoomMember nextLeader = goalRoomMembers.findNextLeader().get(); + + // then + assertThat(nextLeader).isEqualTo(goalRoomMember2); + } + + @Test + void ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž์˜_์ˆ˜๋ฅผ_๊ตฌํ•œ๋‹ค() { + // given + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), null, + MEMBER1); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomMembers goalRoomMembers = new GoalRoomMembers(List.of(goalRoomMember1, goalRoomMember2)); + + // when + final int size = goalRoomMembers.size(); + + // then + assertThat(size).isEqualTo(2); + } + + @Test + void ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž์—์„œ_์ž…๋ ต๋ฐ›์€_์‚ฌ์šฉ์ž๋ฅผ_์ œ๊ฑฐํ•œ๋‹ค() { + // given + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), null, + MEMBER1); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomMembers goalRoomMembers = new GoalRoomMembers(List.of(goalRoomMember1, goalRoomMember2)); + + // when + goalRoomMembers.remove(goalRoomMember1); + + // then + assertThat(goalRoomMembers) + .usingRecursiveComparison() + .isEqualTo(new GoalRoomMembers(List.of(goalRoomMember2))); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomPendingMemberTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomPendingMemberTest.java new file mode 100644 index 000000000..08ed3d818 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomPendingMemberTest.java @@ -0,0 +1,106 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.RoadmapContent; +import java.time.LocalDate; +import java.time.LocalDateTime; +import org.junit.jupiter.api.Test; + +class GoalRoomPendingMemberTest { + + @Test + void ๊ณจ๋ฃธ์˜_๋ฆฌ๋”์ด๋ฉด_True๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member = new Member(new Identifier("identifier"), new EncryptedPassword(new Password("password1")), + new Nickname("nickname"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(2023, 7, 20), "010-1111-1111")); + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("goalroom"), new LimitedMemberCount(10), + new RoadmapContent("content"), member); + + // when + final GoalRoomPendingMember goalRoomPendingMember = new GoalRoomPendingMember(GoalRoomRole.LEADER, goalRoom, + member); + + // then + assertThat(goalRoomPendingMember.isLeader()).isTrue(); + } + + @Test + void ๊ณจ๋ฃธ์˜_๋ฆฌ๋”๊ฐ€_์•„๋‹ˆ๋ฉด_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member = new Member(new Identifier("identifier"), new EncryptedPassword(new Password("password1")), + new Nickname("nickname"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(2023, 7, 20), "010-1111-1111")); + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("goalroom"), new LimitedMemberCount(10), + new RoadmapContent("content"), member); + + // when + final GoalRoomPendingMember goalRoomPendingMember = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, goalRoom, + member); + + // then + assertThat(goalRoomPendingMember.isLeader()).isFalse(); + } + + @Test + void ์ž…๋ ฅ๋ฐ›์€_๋ฉค๋ฒ„๊ฐ€_์ž์‹ ๊ณผ_๊ฐ™์€_๋ฉค๋ฒ„์ด๋ฉด_true๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member = new Member(new Identifier("identifier"), + new EncryptedPassword(new Password("password1!")), + new Nickname("name"), null, null); + final GoalRoomPendingMember goalRoomPendingMember = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), null, + member); + + // when + final boolean result = goalRoomPendingMember.isSameMember(member); + + // then + assertThat(result).isTrue(); + } + + @Test + void ์ž…๋ ฅ๋ฐ›์€_๋ฉค๋ฒ„๊ฐ€_์ž์‹ ๊ณผ_๋‹ค๋ฅธ_๋ฉค๋ฒ„์ด๋ฉด_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member1 = new Member(1L, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), + new Nickname("name1"), null, null); + final Member member2 = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), + new Nickname("name2"), null, null); + + final GoalRoomPendingMember goalRoomPendingMember = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), null, + member1); + + // when + final boolean result = goalRoomPendingMember.isSameMember(member2); + + // then + assertThat(result).isFalse(); + } + + @Test + void ํŒ”๋กœ์›Œ๊ฐ€_๋ฆฌ๋”๋กœ_๋ณ€๊ฒฝ๋œ๋‹ค() { + // given + final GoalRoomPendingMember goalRoomPendingMember = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), null, + null); + + // when + goalRoomPendingMember.becomeLeader(); + + // then + assertThat(goalRoomPendingMember.isLeader()).isTrue(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomPendingMembersTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomPendingMembersTest.java new file mode 100644 index 000000000..eaa84e5c0 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomPendingMembersTest.java @@ -0,0 +1,142 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.exception.NotFoundException; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.Test; + +class GoalRoomPendingMembersTest { + + private static final Member MEMBER1 = new Member(1L, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), + new Nickname("name1"), null, null); + private static final Member MEMBER2 = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), + new Nickname("name2"), null, null); + + @Test + void ๊ณจ๋ฃธ์˜_๋ฆฌ๋”๋ฅผ_์ฐพ๋Š”๋‹ค() { + // given + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("goalroom"), new LimitedMemberCount(10), + new RoadmapContent("content"), MEMBER1); + + // when + final GoalRoomPendingMembers goalRoomPendingMembers = new GoalRoomPendingMembers(List.of( + new GoalRoomPendingMember(GoalRoomRole.LEADER, goalRoom, MEMBER2), + new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, goalRoom, MEMBER1) + )); + + // then + assertThat(goalRoomPendingMembers.findGoalRoomLeader()).isEqualTo(MEMBER2); + } + + @Test + void ๊ณจ๋ฃธ์˜_๋ฆฌ๋”๊ฐ€_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("goalroom"), new LimitedMemberCount(10), + new RoadmapContent("content"), MEMBER1); + + // when + final GoalRoomPendingMembers goalRoomPendingMembers = new GoalRoomPendingMembers(List.of( + new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, goalRoom, MEMBER1), + new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, goalRoom, MEMBER2) + )); + + // then + assertThatThrownBy(() -> assertThat(goalRoomPendingMembers.findGoalRoomLeader())) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ์ž…๋ ฅ๋ฐ›์€_์‚ฌ์šฉ์ž๋ฅผ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ค‘์—์„œ_์ฐพ๋Š”๋‹ค() { + // given + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), null, + MEMBER1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomPendingMembers goalRoomPendingMembers = new GoalRoomPendingMembers( + List.of(goalRoomPendingMember1, goalRoomPendingMember2)); + + // when + final GoalRoomPendingMember findGoalRoomPendingMember = goalRoomPendingMembers.findByMember(MEMBER1).get(); + + // then + assertThat(findGoalRoomPendingMember).isEqualTo(goalRoomPendingMember1); + } + + @Test + void ๋‹ค์Œ_๋ฆฌ๋”๊ฐ€_๋ _์‚ฌ์šฉ์ž๋ฅผ_์ฐพ๋Š”๋‹ค() { + // given + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), null, + MEMBER1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomPendingMembers goalRoomPendingMembers = new GoalRoomPendingMembers( + List.of(goalRoomPendingMember1, goalRoomPendingMember2)); + + // when + final GoalRoomPendingMember nextLeader = goalRoomPendingMembers.findNextLeader().get(); + + // then + assertThat(nextLeader).isEqualTo(goalRoomPendingMember2); + } + + @Test + void ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž์˜_์ˆ˜๋ฅผ_๊ตฌํ•œ๋‹ค() { + // given + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), null, + MEMBER1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomPendingMembers goalRoomPendingMembers = new GoalRoomPendingMembers( + List.of(goalRoomPendingMember1, goalRoomPendingMember2)); + + // when + final int size = goalRoomPendingMembers.size(); + + // then + assertThat(size).isEqualTo(2); + } + + @Test + void ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž์—์„œ_์ž…๋ ต๋ฐ›์€_์‚ฌ์šฉ์ž๋ฅผ_์ œ๊ฑฐํ•œ๋‹ค() { + // given + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), null, + MEMBER1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), null, + MEMBER2); + + final GoalRoomPendingMembers goalRoomPendingMembers = new GoalRoomPendingMembers( + List.of(goalRoomPendingMember1, goalRoomPendingMember2)); + + // when + goalRoomPendingMembers.remove(goalRoomPendingMember1); + + // then + assertThat(goalRoomPendingMembers) + .usingRecursiveComparison() + .isEqualTo(new GoalRoomPendingMembers(List.of(goalRoomPendingMember2))); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodeTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodeTest.java new file mode 100644 index 000000000..5ac81ced1 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodeTest.java @@ -0,0 +1,108 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.exception.BadRequestException; +import java.time.LocalDate; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GoalRoomRoadmapNodeTest { + + @ParameterizedTest + @ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7}) + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final int daysToAdd) { + //given + final LocalDate startDate = LocalDate.now(); + final LocalDate endDate = startDate.plusDays(daysToAdd); + + //when + //then + assertDoesNotThrow(() -> new GoalRoomRoadmapNode(new Period(startDate, endDate), daysToAdd + 1, + new RoadmapNode("title", "content"))); + } + + @ParameterizedTest + @ValueSource(ints = {-1, -2, -3, -4, -5, -6, -7}) + void ๊ณจ๋ฃธ_๋…ธ๋“œ์˜_์ธ์ฆ_ํšŸ์ˆ˜๊ฐ€_์Œ์ˆ˜์ผ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final int checkCount) { + //given + final LocalDate startDate = LocalDate.now(); + final LocalDate endDate = startDate.plusDays(0); + + //when + //then + assertThatThrownBy(() -> new GoalRoomRoadmapNode(new Period(startDate, endDate), checkCount, + new RoadmapNode("title", "content"))) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(ints = {2, 3, 4, 5, 6, 7}) + void ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ• ๋•Œ_๊ธฐ๊ฐ„๋ณด๋‹ค_์ธ์ฆ_ํšŸ์ˆ˜๊ฐ€_ํฌ๋ฉด_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final int checkCount) { + //given + final LocalDate startDate = LocalDate.now(); + final LocalDate endDate = LocalDate.now(); + + //when + //then + assertThatThrownBy(() -> new GoalRoomRoadmapNode(new Period(startDate, endDate), checkCount, + new RoadmapNode("title", "content"))) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(longs = {1, 2, 3, 4, 5, 6, 7}) + void ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ• ๋•Œ_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์˜ค๋Š˜๋ณด๋‹ค_์ „์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final long daysToSubtract) { + //given + final LocalDate startDate = LocalDate.now().minusDays(daysToSubtract); + final LocalDate endDate = startDate.plusDays(7); + final int checkCount = 7; + + //when + //then + assertThatThrownBy(() -> new GoalRoomRoadmapNode(new Period(startDate, endDate), checkCount, + new RoadmapNode("title", "content"))) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(longs = {1, 2, 3, 4, 5, 6, 7}) + void ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ• ๋•Œ_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์ข…๋ฃŒ๋‚ ์งœ๋ณด๋‹ค_ํ›„์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final long daysToSubtract) { + //given + final LocalDate startDate = LocalDate.now(); + final LocalDate endDate = startDate.minusDays(daysToSubtract); + final int checkCount = 0; + + //when + //then + assertThatThrownBy(() -> new GoalRoomRoadmapNode(new Period(startDate, endDate), checkCount, + new RoadmapNode("title", "content"))) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"2300-07-01", "2300-07-06", "2300-07-15"}) + void ๋…ธ๋“œ๊ฐ€_์ง„ํ–‰_์ค‘์ธ_๋‚ ์งœ๋ฉด_true๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(final LocalDate date) { + final GoalRoomRoadmapNode goalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(LocalDate.of(2300, 7, 1), + LocalDate.of(2300, 7, 15)), + 7, new RoadmapNode("์ œ๋ชฉ", "๋‚ด์šฉ")); + + assertThat(goalRoomRoadmapNode.isDayOfNode(date)).isTrue(); + } + + @ParameterizedTest + @ValueSource(strings = {"2300-06-10", "2300-06-30", "2300-07-16", "2301-07-03"}) + void ๋…ธ๋“œ๊ฐ€_์ง„ํ–‰_์ค‘์ธ_๋‚ ์งœ๊ฐ€_์•„๋‹ˆ๋ฉด_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(final LocalDate date) { + final GoalRoomRoadmapNode goalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(LocalDate.of(2300, 7, 1), + LocalDate.of(2300, 7, 15)), + 7, new RoadmapNode("์ œ๋ชฉ", "๋‚ด์šฉ")); + + assertThat(goalRoomRoadmapNode.isDayOfNode(date)).isFalse(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodesTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodesTest.java new file mode 100644 index 000000000..b1de7bb22 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomRoadmapNodesTest.java @@ -0,0 +1,139 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.exception.BadRequestException; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GoalRoomRoadmapNodesTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LAYER = TODAY.plusDays(20); + private static final LocalDate THIRTY_DAY_LATER = TODAY.plusDays(30); + + @ParameterizedTest + @ValueSource(longs = {1, 2, 3, 4, 5, 100}) + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(final long daysToAdd) { + //given + final LocalDate firstStartDate = LocalDate.now(); + final LocalDate firstEndDate = firstStartDate.plusDays(daysToAdd); + final LocalDate secondStartDate = firstEndDate.plusDays(daysToAdd); + final LocalDate secondEndDate = secondStartDate.plusDays(daysToAdd); + + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(firstStartDate, firstEndDate), 0, null); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(secondStartDate, secondEndDate), 0, null); + + //when + //then + assertDoesNotThrow( + () -> new GoalRoomRoadmapNodes(List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode))); + } + + @ParameterizedTest + @ValueSource(longs = {0, 1, 2, 3, 4, 5, 100}) + void ๊ณจ๋ฃธ_๋…ธ๋“œ๋“ค_์ƒ์„ฑ_์‹œ_๊ธฐ๊ฐ„์ด_๊ฒน์น _๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final long value) { + //given + final LocalDate firstStartDate = LocalDate.now(); + final LocalDate firstEndDate = firstStartDate.plusDays(value); + final LocalDate secondStartDate = firstEndDate.minusDays(value); + final LocalDate secondEndDate = secondStartDate.plusDays(value); + + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(firstStartDate, firstEndDate), 0, null); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(secondStartDate, secondEndDate), 0, null); + + //when + //then + assertThatThrownBy(() -> new GoalRoomRoadmapNodes(List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode))) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ_์ƒ์„ฑ_์‹œ_๋นˆ_๋ฆฌ์ŠคํŠธ๊ฐ€_๋“ค์–ด์˜ค๋ฉด_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค() { + //given + //when + //then + assertDoesNotThrow(() -> new GoalRoomRoadmapNodes(Collections.emptyList())); + } + + @Test + void ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค_์ค‘_์ฒซ๋ฒˆ์งธ_์‹œ์ž‘๋‚ ์งœ๋ฅผ_๊ตฌํ•œ๋‹ค() { + // given + // when + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes(new ArrayList<>(List.of( + new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), 1, null), + new GoalRoomRoadmapNode(new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), 1, null)) + )); + + // expect + assertThat(goalRoomRoadmapNodes.getGoalRoomStartDate()).isEqualTo(TODAY); + } + + @Test + void ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค_์ค‘_๋งˆ์ง€๋ง‰_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๊ตฌํ•œ๋‹ค() { + // given + // when + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes(new ArrayList<>(List.of( + new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), 1, null), + new GoalRoomRoadmapNode(new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), 1, null)) + )); + + // then + assertThat(goalRoomRoadmapNodes.getGoalRoomEndDate()).isEqualTo(THIRTY_DAY_LATER); + } + + @Test + void ๋…ธ๋“œ์˜_์ด_๊ธฐ๊ฐ„์„_๋”ํ•œ๋‹ค() { + // given + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = ๊ณจ๋ฃธ_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + + // when + final int totalPeriod = goalRoomRoadmapNodes.addTotalPeriod(); + + // then + assertThat(totalPeriod) + .isSameAs(31); + } + + @Test + void ํ•ด๋‹น_๋‚ ์งœ์—_์ง„ํ–‰ํ•˜๋Š”_๊ณจ๋ฃธ_๋…ธ๋“œ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = ๊ณจ๋ฃธ_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + + assertAll( + () -> assertThat(goalRoomRoadmapNodes.getNodeByDate(TODAY).get()) + .isEqualTo(new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), + 10, new RoadmapNode("๋กœ๋“œ๋งต ์ œ๋ชฉ 1", "๋กœ๋“œ๋งต ๋‚ด์šฉ 1"))), + () -> assertThat(goalRoomRoadmapNodes.getNodeByDate(TEN_DAY_LATER).get()) + .isEqualTo(new GoalRoomRoadmapNode(new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), + 10, new RoadmapNode("๋กœ๋“œ๋งต ์ œ๋ชฉ 2", "๋กœ๋“œ๋งต ๋‚ด์šฉ 2"))) + ); + } + + private GoalRoomRoadmapNodes ๊ณจ๋ฃธ_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TODAY, TEN_DAY_LATER), + 10, new RoadmapNode("๋กœ๋“œ๋งต ์ œ๋ชฉ 1", "๋กœ๋“œ๋งต ๋‚ด์šฉ 1")); + + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), + 10, new RoadmapNode("๋กœ๋“œ๋งต ์ œ๋ชฉ 2", "๋กœ๋“œ๋งต ๋‚ด์šฉ 2")); + + return new GoalRoomRoadmapNodes( + List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode)); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomTest.java new file mode 100644 index 000000000..2fbafd1af --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomTest.java @@ -0,0 +1,302 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.exception.BadRequestException; +import java.time.LocalDate; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class GoalRoomTest { + + private static final GoalRoomName GOAL_ROOM_NAME = new GoalRoomName("๊ณจ๋ฃธ ์ด๋ฆ„"); + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LAYER = TODAY.plusDays(20); + private static final LocalDate THIRTY_DAY_LATER = TODAY.plusDays(30); + + private static Member member; + + @BeforeAll + static void setUp() { + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final EncryptedPassword encryptedPassword = new EncryptedPassword(password); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber); + member = new Member(1L, identifier, encryptedPassword, nickname, null, memberProfile); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ด_๊ธฐ๊ฐ„์„_๊ณ„์‚ฐํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + + // when + final int totalPeriod = goalRoom.calculateTotalPeriod(); + + // then + assertThat(totalPeriod) + .isSameAs(31); + } + + @Test + void ๊ณจ๋ฃธ์—_๋Œ€๊ธฐ์ค‘์ธ_์ธ์›์ˆ˜๋ฅผ_๊ณ„์‚ฐํ•œ๋‹ค() { + // given + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("goalroom"), new LimitedMemberCount(10), + new RoadmapContent("content"), member); + final Member member1 = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password1")), new Nickname("๋‹‰๋„ค์ž„2"), + null, + new MemberProfile(Gender.FEMALE, LocalDate.of(2023, 7, 20), "010-1111-1111")); + final Member member2 = new Member(3L, new Identifier("identifier3"), + new EncryptedPassword(new Password("password1")), new Nickname("๋‹‰๋„ค์ž„3"), + null, + new MemberProfile(Gender.FEMALE, LocalDate.of(2023, 7, 20), "010-1111-1111")); + + // when + goalRoom.join(member1); + goalRoom.join(member2); + + // then + assertThat(goalRoom.getCurrentMemberCount()).isEqualTo(3); + } + + @Test + void ๊ณจ๋ฃธ์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค() { + //given + final GoalRoom goalRoom = new GoalRoom(GOAL_ROOM_NAME, new LimitedMemberCount(10), + new RoadmapContent("๋กœ๋“œ๋งต ๋‚ด์šฉ"), member); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier12", "์‹œ์ง„์ด"); + + //when + goalRoom.join(follower); + + //then + final Integer currentMemberCount = goalRoom.getCurrentMemberCount(); + assertThat(currentMemberCount) + .isEqualTo(2); + } + + @Test + void ๋ชจ์ง‘์ค‘์ด_์•„๋‹Œ_๊ณจ๋ฃธ์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final GoalRoom goalRoom = new GoalRoom(GOAL_ROOM_NAME, new LimitedMemberCount(10), new RoadmapContent("๋กœ๋“œ๋งต ๋‚ด์šฉ"), + ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier1", "์‹œ์ง„์ด")); + goalRoom.start(); + + //when, then + assertThatThrownBy(() -> goalRoom.join(member)) + .isInstanceOf(BadRequestException.class) + .hasMessage("๋ชจ์ง‘ ์ค‘์ด์ง€ ์•Š์€ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ์ œํ•œ_์ธ์›์ด_๊ฐ€๋“_์ฐฌ_๊ณจ๋ฃธ์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final GoalRoom goalRoom = new GoalRoom(GOAL_ROOM_NAME, new LimitedMemberCount(1), new RoadmapContent("๋กœ๋“œ๋งต ๋‚ด์šฉ"), + ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier1", "์‹œ์ง„์ด")); + + //when,then + assertThatThrownBy(() -> goalRoom.join(member)) + .isInstanceOf(BadRequestException.class) + .hasMessage("์ œํ•œ ์ธ์›์ด ๊ฝ‰ ์ฐฌ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ์ด๋ฏธ_์ฐธ์—ฌ_์ค‘์ธ_์‚ฌ์šฉ์ž๋ฅผ_๊ณจ๋ฃธ์—_์ถ”๊ฐ€ํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final GoalRoom goalRoom = new GoalRoom(GOAL_ROOM_NAME, new LimitedMemberCount(2), + new RoadmapContent("๋กœ๋“œ๋งต ๋‚ด์šฉ"), member); + + //when,then + assertThatThrownBy(() -> goalRoom.join(member)) + .isInstanceOf(BadRequestException.class) + .hasMessage("์ด๋ฏธ ์ฐธ์—ฌํ•œ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ด_์ธ์ฆ_ํšŸ์ˆ˜๋ฅผ_๊ตฌํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + + //expect + assertThat(goalRoom.getAllCheckCount()).isEqualTo(20); + } + + @Test + void ๊ณจ๋ฃธ์ด_์‹œ์ž‘ํ•˜๊ธฐ_์ „์—_์ฐธ์—ฌ_๋ฉค๋ฒ„๋ฅผ_ํ™•์ธํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + + final Member ์ฐธ์—ฌ์ž = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier1", "ํŒ”๋กœ์›Œ"); + goalRoom.join(์ฐธ์—ฌ์ž); + + //expect + assertAll( + () -> assertThat(goalRoom.isGoalRoomMember(์ฐธ์—ฌ์ž)).isTrue(), + () -> assertThat(goalRoom.getCurrentMemberCount()).isEqualTo(2) + ); + } + + @Test + void ๊ณจ๋ฃธ์ด_์‹œ์ž‘ํ•œ_ํ›„์—_์ฐธ์—ฌ_๋ฉค๋ฒ„๋ฅผ_ํ™•์ธํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + + final Member ์ฐธ์—ฌ์ž = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier1", "ํŒ”๋กœ์›Œ"); +// goalRoom.join(์ฐธ์—ฌ์ž); + goalRoom.start(); + + //expect + assertAll( + () -> assertThat(goalRoom.isGoalRoomMember(์ฐธ์—ฌ์ž)).isFalse(), + () -> assertThat(goalRoom.getCurrentMemberCount()).isEqualTo(0) + ); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐ„๋‹ค() { + //given + final GoalRoom goalRoom = new GoalRoom(GOAL_ROOM_NAME, new LimitedMemberCount(2), + new RoadmapContent("๋กœ๋“œ๋งต ๋‚ด์šฉ"), member); + + // when + goalRoom.leave(member); + + // then + assertThat(goalRoom.isEmptyGoalRoom()).isTrue(); + } + + @Test + void ๊ณจ๋ฃธ์—_์ฐธ์—ฌํ•˜์ง€_์•Š์€_๋ฉค๋ฒ„๊ฐ€_๋‚˜๊ฐ€๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final GoalRoom goalRoom = new GoalRoom(GOAL_ROOM_NAME, new LimitedMemberCount(2), + new RoadmapContent("๋กœ๋“œ๋งต ๋‚ด์šฉ"), member); + + final Member notJoinMember = new Member(new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), + new Nickname("name2"), null, null); + + // when + // then + assertThatThrownBy(() -> goalRoom.leave(notJoinMember)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ์ด_์ข…๋ฃŒ๋œ์ง€_3๊ฐœ์›”_์ด์ƒ_์ง€๋‚˜์ง€_์•Š์œผ๋ฉด_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + + // when + final boolean result = goalRoom.isCompletedAfterMonths(3); + + // then + assertThat(result).isEqualTo(false); + } + + private Member ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), + "010-1234-5678"); + return new Member(new Identifier("cokirikiri"), + new EncryptedPassword(new Password("password1!")), new Nickname("์ฝ”๋ผ๋ฆฌ"), null, memberProfile); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final Long id, final String identifier, final String nickname) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, + LocalDate.of(1995, 9, 30), "010-1234-5678"); + + return new Member(id, new Identifier(identifier), new EncryptedPassword(new Password("password1!")), + new Nickname(nickname), null, memberProfile); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final Member creator) { + final RoadmapCategory category = new RoadmapCategory("๊ฒŒ์ž„"); + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmap; + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + roadmapNode1.addImages(new RoadmapNodeImages(Collections.emptyList())); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapContent roadmapContent, final Member creator) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), + new LimitedMemberCount(10), roadmapContent, creator); + final List roadmapNodes = roadmapContent.getNodes().getValues(); + + final RoadmapNode firstRoadmapNode = roadmapNodes.get(0); + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TODAY, TEN_DAY_LATER), 10, firstRoadmapNode); + + final RoadmapNode secondRoadmapNode = roadmapNodes.get(1); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), 10, secondRoadmapNode); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes( + List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode)); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoom; + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomToDoTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomToDoTest.java new file mode 100644 index 000000000..f1261acd2 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomToDoTest.java @@ -0,0 +1,52 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.exception.BadRequestException; +import java.time.LocalDate; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GoalRoomToDoTest { + + @ParameterizedTest + @ValueSource(ints = {0, 1, 2, 3, 4, 5, 6, 7}) + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ_ํˆฌ๋‘๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final int daysToAdd) { + //given + final LocalDate startDate = LocalDate.now(); + final LocalDate endDate = startDate.plusDays(daysToAdd); + + //when + //then + assertDoesNotThrow(() -> new GoalRoomToDo(new GoalRoomTodoContent("content"), new Period(startDate, endDate))); + } + + @ParameterizedTest + @ValueSource(longs = {1, 2, 3, 4, 5, 6, 7}) + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฅผ_์ƒ์„ฑํ• ๋•Œ_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์˜ค๋Š˜๋ณด๋‹ค_์ „์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final long daysToSubtract) { + //given + final LocalDate startDate = LocalDate.now().minusDays(daysToSubtract); + final LocalDate endDate = startDate.plusDays(7); + + //when + //then + assertThatThrownBy(() -> new GoalRoomToDo(new GoalRoomTodoContent("content"), new Period(startDate, endDate))) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(longs = {1, 2, 3, 4, 5, 6, 7}) + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฅผ_์ƒ์„ฑํ• ๋•Œ_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์ข…๋ฃŒ๋‚ ์งœ๋ณด๋‹ค_ํ›„์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final long daysToSubtract) { + //given + final LocalDate startDate = LocalDate.now(); + final LocalDate endDate = startDate.minusDays(daysToSubtract); + + //when + //then + assertThatThrownBy(() -> new GoalRoomToDo(new GoalRoomTodoContent("content"), new Period(startDate, endDate))) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomToDosTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomToDosTest.java new file mode 100644 index 000000000..699b2bb13 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/GoalRoomToDosTest.java @@ -0,0 +1,49 @@ +package co.kirikiri.domain.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.Period; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; + +class GoalRoomToDosTest { + + @Test + void ์•„์ด๋””๋กœ_ํˆฌ๋‘๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + // given + final GoalRoomToDo firstTodo = new GoalRoomToDo(1L, new GoalRoomTodoContent("ํˆฌ๋‘1"), + new Period(LocalDate.now(), LocalDate.now().plusDays(3))); + final GoalRoomToDo secondTodo = new GoalRoomToDo(2L, new GoalRoomTodoContent("ํˆฌ๋‘2"), + new Period(LocalDate.now(), LocalDate.now().plusDays(5))); + + final GoalRoomToDos goalRoomToDos = new GoalRoomToDos(List.of( + firstTodo, secondTodo + )); + + // when + final GoalRoomToDo findGoalRoomTodo = goalRoomToDos.findById(1L).get(); + + // then + assertThat(findGoalRoomTodo) + .isEqualTo(firstTodo); + } + + @Test + void ์•„์ด๋””๋กœ_ํˆฌ๋‘_์กฐํšŒ์‹œ_์—†์œผ๋ฉด_๋นˆ๊ฐ’์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final GoalRoomToDo firstTodo = new GoalRoomToDo(1L, new GoalRoomTodoContent("ํˆฌ๋‘1"), + new Period(LocalDate.now(), LocalDate.now().plusDays(3))); + final GoalRoomToDo secondTodo = new GoalRoomToDo(2L, new GoalRoomTodoContent("ํˆฌ๋‘2"), + new Period(LocalDate.now(), LocalDate.now().plusDays(5))); + + final GoalRoomToDos goalRoomToDos = new GoalRoomToDos(List.of( + firstTodo, secondTodo + )); + + // expected + assertThat(goalRoomToDos.findById(3L)) + .isEmpty(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/GoalRoomNameTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/GoalRoomNameTest.java new file mode 100644 index 000000000..ce8928f3f --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/GoalRoomNameTest.java @@ -0,0 +1,34 @@ +package co.kirikiri.domain.goalroom.vo; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GoalRoomNameTest { + + @ParameterizedTest + @ValueSource(ints = {1, 10, 20, 30, 40}) + void ๊ณจ๋ฃธ์˜_์ด๋ฆ„_๊ธธ์ด๊ฐ€_1์ด์ƒ_40์ดํ•˜์ผ_๋•Œ_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค(final int length) { + //given + final String value = "a".repeat(length); + + //when + //then + assertDoesNotThrow((() -> new GoalRoomName(value))); + } + + @ParameterizedTest + @ValueSource(ints = {0, 41, 42, 100}) + void ๊ณจ๋ฃธ์˜_์ด๋ฆ„_๊ธธ์ด๊ฐ€_1๋ฏธ๋งŒ_40์ดˆ๊ณผ์ผ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final int length) { + //given + final String value = "a".repeat(length); + + //when + //then + assertThatThrownBy(() -> new GoalRoomName(value)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/GoalRoomTodoContentTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/GoalRoomTodoContentTest.java new file mode 100644 index 000000000..31c2e5e77 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/GoalRoomTodoContentTest.java @@ -0,0 +1,34 @@ +package co.kirikiri.domain.goalroom.vo; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GoalRoomTodoContentTest { + + @ParameterizedTest + @ValueSource(ints = {1, 10, 20, 30, 40, 100, 200, 250}) + void ํˆฌ๋‘_์ปจํ…์ธ ์˜_๊ธธ์ด๊ฐ€_1์ด์ƒ_250์ดํ•˜์ผ_๋•Œ_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค(final int length) { + //given + final String value = "a".repeat(length); + + //when + //then + assertDoesNotThrow((() -> new GoalRoomTodoContent(value))); + } + + @ParameterizedTest + @ValueSource(ints = {0, 251, 252, 300}) + void ํˆฌ๋‘_์ปจํ…์ธ ์˜_๊ธธ์ด๊ฐ€_1๋ฏธ๋งŒ_250์ดˆ๊ณผ์ผ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final int length) { + //given + final String value = "a".repeat(length); + + //when + //then + assertThatThrownBy(() -> new GoalRoomTodoContent(value)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/LimitedMemberCountTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/LimitedMemberCountTest.java new file mode 100644 index 000000000..310413d9c --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/goalroom/vo/LimitedMemberCountTest.java @@ -0,0 +1,30 @@ +package co.kirikiri.domain.goalroom.vo; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class LimitedMemberCountTest { + + @ParameterizedTest + @ValueSource(ints = {1, 5, 10, 20}) + void ์ œํ•œ_์ธ์›_์ˆ˜๊ฐ€_1์ด์ƒ_20์ดํ•˜์ผ_๋•Œ_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค(final int value) { + //given + //when + //then + assertDoesNotThrow(() -> new LimitedMemberCount(value)); + } + + @ParameterizedTest + @ValueSource(ints = {0, 21, 22, 100}) + void ์ œํ•œ_์ธ์›_์ˆ˜๊ฐ€_1๋ฏธ๋งŒ_20์ดˆ๊ณผ์ผ_๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final int value) { + //given + //when + //then + assertThatThrownBy(() -> new LimitedMemberCount(value)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/EncryptedPasswordTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/EncryptedPasswordTest.java new file mode 100644 index 000000000..83d2fa36d --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/EncryptedPasswordTest.java @@ -0,0 +1,23 @@ +package co.kirikiri.domain.member.vo; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.member.EncryptedPassword; +import org.junit.jupiter.api.Test; + +class EncryptedPasswordTest { + + @Test + void ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ_์ •์ƒ์ ์œผ๋กœ_์•”ํ˜ธํ™”ํ•œ๋‹ค() { + //given + final Password password1 = new Password("password1!"); + final Password password2 = new Password("password1"); + + //when + final EncryptedPassword encryptedPassword1 = new EncryptedPassword(password1); + final EncryptedPassword encryptedPassword2 = new EncryptedPassword(password2); + + //then + assertThat(encryptedPassword1).isNotEqualTo(encryptedPassword2); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/IdentifierTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/IdentifierTest.java new file mode 100644 index 000000000..5ca7148bc --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/IdentifierTest.java @@ -0,0 +1,50 @@ +package co.kirikiri.domain.member.vo; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class IdentifierTest { + + @ParameterizedTest + @ValueSource(strings = {"ab12", "abcdefghijklmnopqrst"}) + void ์ •์ƒ์ ์œผ๋กœ_์•„์ด๋””๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String identifier) { + //given + //when + //then + assertDoesNotThrow(() -> new Identifier(identifier)); + } + + @ParameterizedTest + @ValueSource(strings = {"abc", "abcdefghijklmnopqrst1"}) + void ์•„์ด๋””_๊ธธ์ด๊ฐ€_4๋ฏธ๋งŒ_20์ดˆ๊ณผ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String identifier) { + //given + //when + //then + assertThatThrownBy(() -> new Identifier(identifier)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"Abcd", "ABCd", "abcdefG", "abcDefgHi", "abcdefghijklmnopqrsT"}) + void ์•„์ด๋””์—_๋Œ€๋ฌธ์ž๊ฐ€_์žˆ์„_๊ฒฝ์šฐ(final String identifier) { + //given + //when + //then + assertThatThrownBy(() -> new Identifier(identifier)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"abc~", "~!@#$%^&*()", "abcdef!"}) + void ์•„์ด๋””์—_ํŠน์ˆ˜๋ฌธ์ž๊ฐ€_์žˆ์„_๊ฒฝ์šฐ(final String identifier) { + //given + //when + //then + assertThatThrownBy(() -> new Identifier(identifier)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/NicknameTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/NicknameTest.java new file mode 100644 index 000000000..a3f4dca46 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/NicknameTest.java @@ -0,0 +1,30 @@ +package co.kirikiri.domain.member.vo; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class NicknameTest { + + @ParameterizedTest + @ValueSource(strings = {"ab", "abcdefgh", "AB", "ABCDEFGH", "~!", "~!@#$%^&"}) + void ์ •์ƒ์ ์œผ๋กœ_๋‹‰๋„ค์ž„์„_์ƒ์„ฑํ•œ๋‹ค(final String nickname) { + //given + //when + //then + assertDoesNotThrow(() -> new Nickname(nickname)); + } + + @ParameterizedTest + @ValueSource(strings = {"a", "abcdefghe"}) + void ๋‹‰๋„ค์ž„_๊ธธ์ด๊ฐ€_ํ‹€๋ฆด_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String nickname) { + //given + //when + //then + assertThatThrownBy(() -> new Nickname(nickname)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/PasswordTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/PasswordTest.java new file mode 100644 index 000000000..83c8ffee4 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/member/vo/PasswordTest.java @@ -0,0 +1,80 @@ +package co.kirikiri.domain.member.vo; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class PasswordTest { + + @ParameterizedTest + @ValueSource(strings = {"abcdefg1", "a1!@#$%^&*()~", "password12!@#$%"}) + void ์ •์ƒ์ ์œผ๋กœ_๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String password) { + //given + //when + //then + assertDoesNotThrow(() -> new Password(password)); + } + + @ParameterizedTest + @ValueSource(strings = {"abcdef1", "abcdefghijklmn12", "", " "}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ_๊ธธ์ด๊ฐ€_ํ‹€๋ฆด_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String password) { + //given + //when + //then + assertThatThrownBy(() -> new Password(password)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"Abcde1!", "abcdefghijklm1@โ‚ฉ"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€_ํ—ˆ์šฉ๋˜์ง€_์•Š๋Š”_๋ฌธ์ž์ธ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String password) { + //given + //when + //then + assertThatThrownBy(() -> new Password(password)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"Abcdef!", "Abcdefghijklm1@"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ์—_๋Œ€๋ฌธ์ž๊ฐ€_๋“ค์–ด์˜ฌ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String password) { + //given + //when + //then + assertThatThrownBy(() -> new Password(password)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"Abcdefโ‚ฉ", "bcdefghijklm1โ™‚"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ์—_ํ—ˆ์šฉ๋˜์ง€_์•Š์€_ํŠน์ˆ˜๋ฌธ์ž๊ฐ€_๋“ค์–ด์˜ฌ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String password) { + //given + //when + //then + assertThatThrownBy(() -> new Password(password)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"abcdefg", "sdfdsfsโ™‚"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ์—_์˜์†Œ๋ฌธ์ž๋งŒ_๋“ค์–ด์˜ฌ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String password) { + //given + //when + //then + assertThatThrownBy(() -> new Password(password)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(strings = {"12345678", "1234โ™‚"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ์—_์ˆซ์ž๋งŒ_๋“ค์–ด์˜ฌ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค(final String password) { + //given + //when + //then + assertThatThrownBy(() -> new Password(password)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapContentTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapContentTest.java new file mode 100644 index 000000000..18d578d63 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapContentTest.java @@ -0,0 +1,90 @@ +package co.kirikiri.domain.roadmap; + +import static co.kirikiri.domain.roadmap.RoadmapDifficulty.DIFFICULT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.exception.BadRequestException; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RoadmapContentTest { + + @Test + void ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์˜_๊ธธ์ด๊ฐ€_2000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final String content = "a".repeat(2001); + + // expect + assertThatThrownBy(() -> new RoadmapContent(content)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์€_null๊ฐ’์„_ํ—ˆ์šฉํ•œ๋‹ค() { + // given + final String content = null; + + // expect + assertDoesNotThrow(() -> new RoadmapContent(content)); + } + + @Test + void ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์—_๋…ธ๋“œ๋“ค์„_์ถ”๊ฐ€ํ•œ๋‹ค() { + // given + final RoadmapContent content = new RoadmapContent("content"); + + // when + content.addNodes( + new RoadmapNodes( + List.of(new RoadmapNode("title1", "content1"), new RoadmapNode("title2", "content1")))); + + // then + final RoadmapNodes nodes = content.getNodes(); + assertAll( + () -> assertThat(nodes.getValues()).hasSize(2), + () -> assertThat(nodes.getValues().get(0).getRoadmapContent()).isEqualTo(content), + () -> assertThat(nodes.getValues().get(1).getRoadmapContent()).isEqualTo(content) + ); + } + + @Test + void ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์—_๋…ธ๋“œ๋ฅผ_์ถ”๊ฐ€ํ• ๋•Œ_์ด๋ฆ„์ด_๊ฒน์น˜๋ฉด_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + // given + final RoadmapContent content = new RoadmapContent("content"); + + // when + // then + final String title = "title"; + assertThatThrownBy(() -> content.addNodes( + new RoadmapNodes( + List.of(new RoadmapNode(title, "content1"), new RoadmapNode(title, "content1"))))); + } + + @Test + void ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์˜_๋กœ๋“œ๋งต์ธ_๊ฒฝ์šฐ_false๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final RoadmapContent content = new RoadmapContent("content"); + final MemberProfile profile = new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "01011112222"); + final Member creator = new Member(new Identifier("creator"), + new EncryptedPassword(new Password("password1")), new Nickname("nickname"), null, profile); + final RoadmapCategory category = new RoadmapCategory(1L, "์—ฌ๊ฐ€"); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 30, DIFFICULT, creator, category); + + // when + roadmap.addContent(content); + + // then + assertThat(content.isNotSameRoadmap(roadmap)).isFalse(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapContentsTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapContentsTest.java new file mode 100644 index 000000000..2cc6762a0 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapContentsTest.java @@ -0,0 +1,27 @@ +package co.kirikiri.domain.roadmap; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class RoadmapContentsTest { + + @Test + void ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ถ”๊ฐ€ํ•œ๋‹ค() { + // given + final RoadmapNodes roadmapNodes = new RoadmapNodes(List.of(new RoadmapNode("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ"))); + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(roadmapNodes); + final RoadmapContents roadmapContents = new RoadmapContents(List.of(roadmapContent)); + final RoadmapContent updatedRoadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ ์ˆ˜์ •๋ณธ"); + updatedRoadmapContent.addNodes(roadmapNodes); + + // when + roadmapContents.add(updatedRoadmapContent); + + // then + assertThat(roadmapContents.getValues()).usingRecursiveComparison() + .isEqualTo(List.of(roadmapContent, updatedRoadmapContent)); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodeImagesTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodeImagesTest.java new file mode 100644 index 000000000..9d54048de --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodeImagesTest.java @@ -0,0 +1,83 @@ +package co.kirikiri.domain.roadmap; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.exception.BadRequestException; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RoadmapNodeImagesTest { + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๋“œ๋งต_๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + //given + final RoadmapNodeImage roadmapNodeImage1 = new RoadmapNodeImage("originalFIleName1.png", "server/file/path1", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage2 = new RoadmapNodeImage("originalFIleName2.png", "server/file/path2", + ImageContentType.PNG); + + //when + //then + assertDoesNotThrow(() -> new RoadmapNodeImages(List.of(roadmapNodeImage1, roadmapNodeImage2))); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ• ๋•Œ_2์žฅ_์ด์ƒ์ด๋ฉด_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final RoadmapNodeImage roadmapNodeImage1 = new RoadmapNodeImage("originalFIleName1.png", "server/file/path1", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage2 = new RoadmapNodeImage("originalFIleName2.png", "server/file/path2", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage3 = new RoadmapNodeImage("originalFIleName3.png", "server/file/path3", + ImageContentType.PNG); + + //when + //then + assertThatThrownBy( + () -> new RoadmapNodeImages(List.of(roadmapNodeImage1, roadmapNodeImage2, roadmapNodeImage3))) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ถ”๊ฐ€ํ• _๋•Œ_2์žฅ_์ด์ƒ์ด๋ฉด_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final RoadmapNodeImage roadmapNodeImage1 = new RoadmapNodeImage("originalFIleName1.png", "server/file/path1", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage2 = new RoadmapNodeImage("originalFIleName2.png", "server/file/path2", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage3 = new RoadmapNodeImage("originalFIleName3.png", "server/file/path3", + ImageContentType.PNG); + final RoadmapNodeImages roadmapNodeImages = new RoadmapNodeImages( + List.of(roadmapNodeImage1, roadmapNodeImage2)); + + //when + //then + assertThatThrownBy(() -> roadmapNodeImages.add(roadmapNodeImage3)) + .isInstanceOf(BadRequestException.class); + + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์—ฌ๋Ÿฌ์žฅ_์ถ”๊ฐ€ํ• _๋•Œ_2์žฅ_์ด์ƒ์ด๋ฉด_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final RoadmapNodeImage roadmapNodeImage1 = new RoadmapNodeImage("originalFIleName1.png", "server/file/path1", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage2 = new RoadmapNodeImage("originalFIleName2.png", "server/file/path2", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage3 = new RoadmapNodeImage("originalFIleName3.png", "server/file/path3", + ImageContentType.PNG); + final RoadmapNodeImage roadmapNodeImage4 = new RoadmapNodeImage("originalFIleName4.png", "server/file/path4", + ImageContentType.PNG); + final RoadmapNodeImages roadmapNodeImages = new RoadmapNodeImages( + List.of(roadmapNodeImage1, roadmapNodeImage2)); + + //when + //then + assertThatThrownBy( + () -> roadmapNodeImages.addAll(new RoadmapNodeImages(List.of(roadmapNodeImage3, roadmapNodeImage4)))) + .isInstanceOf(BadRequestException.class); + + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodeTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodeTest.java new file mode 100644 index 000000000..9b5f86d70 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodeTest.java @@ -0,0 +1,32 @@ +package co.kirikiri.domain.roadmap; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class RoadmapNodeTest { + + @ParameterizedTest + @ValueSource(ints = {0, 41}) + void ๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_1๋ณด๋‹ค_์ž‘๊ฑฐ๋‚˜_40๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int titleLength) { + // given + final String title = "a".repeat(titleLength); + + // expect + assertThatThrownBy(() -> new RoadmapNode(title, "๋กœ๋“œ๋งต ์„ค๋ช…")) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(ints = {0, 2001}) + void ๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์„ค๋ช…์˜_๊ธธ์ด๊ฐ€_1๋ณด๋‹ค_์ž‘๊ฑฐ๋‚˜_2000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int contentLength) { + // given + final String content = "a".repeat(contentLength); + + // expect + assertThatThrownBy(() -> new RoadmapNode("๋กœ๋“œ๋งต ์ œ๋ชฉ", content)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodesTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodesTest.java new file mode 100644 index 000000000..5dc3092c6 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapNodesTest.java @@ -0,0 +1,41 @@ +package co.kirikiri.domain.roadmap; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class RoadmapNodesTest { + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค() { + // given + final RoadmapNodes roadmapNodes = new RoadmapNodes(List.of(new RoadmapNode("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ1", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ"))); + + // when + roadmapNodes.add(new RoadmapNode("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ2", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ")); + + // then + assertThat(roadmapNodes.getValues()).hasSize(2); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์˜_๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์—…๋ฐ์ดํŠธํ•œ๋‹ค() { + // given + final RoadmapNodes roadmapNodes = new RoadmapNodes( + List.of(new RoadmapNode("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ1", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ1"), new RoadmapNode("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ2", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ2"))); + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + + // when + roadmapNodes.updateAllRoadmapContent(roadmapContent); + + // then + final List nodes = roadmapNodes.getValues(); + assertAll( + () -> assertThat(nodes.get(0).getRoadmapContent()).isEqualTo(roadmapContent), + () -> assertThat(nodes.get(1).getRoadmapContent()).isEqualTo(roadmapContent) + ); + } + +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapReviewTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapReviewTest.java new file mode 100644 index 000000000..e56c2f614 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapReviewTest.java @@ -0,0 +1,63 @@ +package co.kirikiri.domain.roadmap; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.exception.BadRequestException; +import java.time.LocalDate; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class RoadmapReviewTest { + + @ParameterizedTest + @ValueSource(doubles = {0, 0.5, 1, 4.5, 5}) + void ๋ณ„์ ์ด_0๋ถ€ํ„ฐ_5์‚ฌ์ด์˜_์†Œ์ˆ˜์ ์ด_5๋กœ_๋๋‚˜๋Š”_๊ฐ’์ด๋ฉด์„œ_๋‚ด์šฉ์ด_1000์ž_์ด๋‚ด๋ผ๋ฉด_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค(final Double rate) { + // given + final String content = "a".repeat(1000); + final MemberProfile profile = new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "01011112222"); + final Member member = new Member(new Identifier("creator"), new EncryptedPassword(new Password("password1")), + new Nickname("nickname"), null, profile); + + // expected + final RoadmapReview roadmapReview = + assertDoesNotThrow(() -> new RoadmapReview(content, rate, member)); + assertThat(roadmapReview) + .isInstanceOf(RoadmapReview.class); + } + + @Test + void ๋ฆฌ๋ทฐ_๋‚ด์šฉ์ด_1000์ž๋ฅผ_๋„˜์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final String content = "a".repeat(1001); + final MemberProfile profile = new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "01011112222"); + final Member member = new Member(new Identifier("creator"), new EncryptedPassword(new Password("password1")), + new Nickname("nickname"), null, profile); + + // expected + assertThatThrownBy(() -> new RoadmapReview(content, null, member)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(doubles = {-1, -1.5, 5.5, 1.2, 3.7, 4.55}) + void ๋ฆฌ๋ทฐ_๋ณ„์ ์ด_0๊ณผ_5์‚ฌ์ด์˜_์†Œ์ˆ˜์ _5_๋‹จ์œ„์˜_๊ฐ’์ด_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final double rate) { + // given + final MemberProfile profile = new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "01011112222"); + final Member member = new Member(new Identifier("creator"), new EncryptedPassword(new Password("password1")), + new Nickname("nickname"), null, profile); + + // expected + assertThatThrownBy(() -> new RoadmapReview("๋ฆฌ๋ทฐ", rate, member)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapTagsTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapTagsTest.java new file mode 100644 index 000000000..faf5f614a --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapTagsTest.java @@ -0,0 +1,59 @@ +package co.kirikiri.domain.roadmap; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.roadmap.vo.RoadmapTagName; +import co.kirikiri.exception.BadRequestException; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RoadmapTagsTest { + + @Test + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ์˜_์ˆ˜๊ฐ€_5๊ฐœ_์ดํ•˜๋ฉด_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค() { + // given + final List values = List.of( + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ1")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ2")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ3")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ4")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ5"))); + + // when + final RoadmapTags roadmapTags = assertDoesNotThrow(() -> new RoadmapTags(values)); + + // then + assertThat(roadmapTags) + .isInstanceOf(RoadmapTags.class); + } + + @Test + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ์˜_์ˆ˜๊ฐ€_5๊ฐœ_์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final List values = List.of( + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ1")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ2")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ3")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ4")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ5")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ6"))); + + // expected + assertThatThrownBy(() -> new RoadmapTags(values)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ_์ด๋ฆ„์—_์ค‘๋ณต์ด_์žˆ์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final List values = List.of( + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ1")), + new RoadmapTag(new RoadmapTagName("ํƒœ๊ทธ1"))); + + // expected + assertThatThrownBy(() -> new RoadmapTags(values)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapTest.java new file mode 100644 index 000000000..d436e79b9 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/RoadmapTest.java @@ -0,0 +1,100 @@ +package co.kirikiri.domain.roadmap; + +import static co.kirikiri.domain.roadmap.RoadmapDifficulty.DIFFICULT; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.exception.BadRequestException; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class RoadmapTest { + + private final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + private final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + private final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + private final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + + @Test + void ๋กœ๋“œ๋งต์ด_์„ฑ๊ณต์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค() { + // expect + assertDoesNotThrow(() -> new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 30, DIFFICULT, + creator, category)); + } + + @Test + void ๋กœ๋“œ๋งต์—_๋ณธ๋ฌธ์„_์ถ”๊ฐ€ํ•œ๋‹ค() { + // given + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 30, DIFFICULT, creator, category); + + // when + roadmap.addContent(roadmapContent); + + // then + final RoadmapContents contents = roadmap.getContents(); + assertThat(contents.getValues()).hasSize(1); + } + + @ParameterizedTest + @ValueSource(ints = {0, 41}) + void ๋กœ๋“œ๋งต_์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_1๋ณด๋‹ค_์ž‘๊ฑฐ๋‚˜_40๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int titleLength) { + // given + final String title = "a".repeat(titleLength); + + // expect + assertThatThrownBy(() -> new Roadmap(title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 30, DIFFICULT, creator, category)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(ints = {0, 151}) + void ๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€์˜_๊ธธ์ด๊ฐ€_1๋ณด๋‹ค_์ž‘๊ฑฐ๋‚˜_150๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int introductionLength) { + // given + final String introduction = "a".repeat(introductionLength); + + // expect + assertThatThrownBy(() -> new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", introduction, 30, DIFFICULT, creator, category)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @ValueSource(ints = {-1, 1001}) + void ๋กœ๋“œ๋งต_์ถ”์ฒœ_์†Œ์š”_๊ธฐ๊ฐ„์ด_0๋ณด๋‹ค_์ž‘๊ณ _1000๋ณด๋‹ค_ํฌ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int requiredPeriod) { + // expect + assertThatThrownBy(() -> new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", requiredPeriod, DIFFICULT, creator, category)) + .isInstanceOf(BadRequestException.class); + } + + private Member ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + final MemberProfile profile = new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "01011112222"); + + return new Member(new Identifier("creator"), new EncryptedPassword(new Password("password1")), + new Nickname("nickname"), null, profile); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + return new RoadmapCategory(1L, "์—ฌ๊ฐ€"); + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of(new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"), + new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ")); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/vo/RoadmapTagNameTest.java b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/vo/RoadmapTagNameTest.java new file mode 100644 index 000000000..dec613138 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/domain/roadmap/vo/RoadmapTagNameTest.java @@ -0,0 +1,49 @@ +package co.kirikiri.domain.roadmap.vo; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +class RoadmapTagNameTest { + + @ParameterizedTest + @ValueSource(strings = {"์˜ค", "์•ˆ๋…•ํ•˜์„ธ์š”10๊ธ€์ž์ž„"}) + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ_์ด๋ฆ„์ด_1๊ธ€์ž์—์„œ_10๊ธ€์ž_์‚ฌ์ด๋ฉด_์ •์ƒ_์ƒ์„ฑ๋œ๋‹ค(final String name) { + // when + final RoadmapTagName roadmapTagName = assertDoesNotThrow(() -> new RoadmapTagName(name)); + + // then + assertThat(roadmapTagName) + .isInstanceOf(RoadmapTagName.class); + } + + @ParameterizedTest + @ValueSource(ints = {0, 11}) + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ_์ด๋ฆ„์ด_1๊ธ€์ž_๋ฏธ๋งŒ์ด๊ฑฐ๋‚˜_10๊ธ€์ž_์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int length) { + // given + final String name = "a".repeat(length); + + // expected + assertThatThrownBy(() -> new RoadmapTagName(name)) + .isInstanceOf(BadRequestException.class); + } + + @ParameterizedTest + @CsvSource(value = {"์šฐ์™€ ์•ˆ๋…•:์šฐ์™€์•ˆ๋…•", "๊ณต ๋ฐฑ:๊ณต๋ฐฑ", " ๊ณต๋ฐฑ์—†์• ๊ธฐ:๊ณต๋ฐฑ์—†์• ๊ธฐ", "์šฐ์™€์•„ :์šฐ์™€์•„"}, delimiter = ':') + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ_์ด๋ฆ„์—_๊ณต๋ฐฑ์ด_๋“ค์–ด์˜ค๋ฉด_์ œ๊ฑฐํ•œ๋‹ค(final String name, final String removedSpaceValue) { + // given + final RoadmapTagName expected = new RoadmapTagName(removedSpaceValue); + + // when + final RoadmapTagName roadmapTagName = assertDoesNotThrow(() -> new RoadmapTagName(name)); + + // expected + assertThat(roadmapTagName) + .isEqualTo(expected); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/infra/AmazonS3FileServiceTest.java b/backend/kirikiri/src/test/java/co/kirikiri/infra/AmazonS3FileServiceTest.java new file mode 100644 index 000000000..d91d1b747 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/infra/AmazonS3FileServiceTest.java @@ -0,0 +1,105 @@ +package co.kirikiri.infra; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +import co.kirikiri.exception.ServerException; +import co.kirikiri.service.dto.FileInformation; +import com.amazonaws.AmazonServiceException; +import com.amazonaws.Protocol; +import com.amazonaws.SdkClientException; +import com.amazonaws.services.s3.AmazonS3; +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 org.springframework.core.env.Environment; +import org.springframework.http.HttpMethod; +import java.io.FileInputStream; +import java.net.MalformedURLException; +import java.net.URL; + +@ExtendWith(MockitoExtension.class) +class AmazonS3FileServiceTest { + + private static final String PATH = "/test/path/originalFilename.png"; + + @Mock + private AmazonS3 amazonS3; + + @Mock + private Environment environment; + + @InjectMocks + private AmazonS3FileService amazonS3FileService; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํŒŒ์ผ์„_์ €์žฅํ•œ๋‹ค() { + //given + when(environment.getProperty("cloud.aws.s3.root-directory")) + .thenReturn("rootDirectory"); + when(environment.getProperty("cloud.aws.s3.sub-directory")) + .thenReturn("subDirectory"); + when(environment.getProperty("cloud.aws.s3.bucket")) + .thenReturn("bucket"); + when(amazonS3.putObject(any(), any(), any(), any())) + .thenReturn(null); + final FileInformation fileInformation = new FileInformation("originalFileName.png", 100L, + "image/png", FileInputStream.nullInputStream()); + + //when + //then + assertDoesNotThrow(() -> amazonS3FileService.save(PATH, fileInformation)); + } + + @Test + void ํŒŒ์ผ_์ €์žฅ_์‹œ_AWS์„œ๋ฒ„์™€_์—ฐ๊ฒฐ์ด_์›ํ• ํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_ํ„ฐ์ง„๋‹ค() { + //given + when(amazonS3.putObject(any(), any(), any(), any())) + .thenThrow(new AmazonServiceException("server๊ฐ€ ์›ํ• ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")); + final FileInformation fileInformation = new FileInformation("originalFileName.png", 100L, + "image/png", FileInputStream.nullInputStream()); + + //when + //then + assertThatThrownBy(() -> amazonS3FileService.save(PATH, fileInformation)) + .isInstanceOf(ServerException.class); + } + + @Test + void ํŒŒ์ผ_์ €์žฅ_์‹œ_SDK_CLIENT์—์„œ_์˜ˆ์ƒ์น˜_๋ชปํ•œ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ_๊ฒฝ์šฐ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_ํ„ฐ์ง„๋‹ค() { + //given + when(amazonS3.putObject(any(), any(), any(), any())) + .thenThrow(new SdkClientException("sdk client ์›ํ• ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.")); + final FileInformation fileInformation = new FileInformation("originalFileName.png", 100L, + "image/png", FileInputStream.nullInputStream()); + + //when + //then + assertThatThrownBy(() -> amazonS3FileService.save(PATH, fileInformation)) + .isInstanceOf(ServerException.class); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํŒŒ์ผ_URL์„_์ƒ์„ฑํ•œ๋‹ค() throws MalformedURLException { + //given + final URL url = new URL(Protocol.HTTP.toString(), "host", 80, "file"); + when(environment.getProperty(anyString())) + .thenReturn("bucket"); + when(environment.getProperty(anyString())) + .thenReturn("60000"); + when(amazonS3.generatePresignedUrl(any())) + .thenReturn(url); + + //when + final URL result = amazonS3FileService.generateUrl("path", HttpMethod.GET); + + //then + assertThat(result).isEqualTo(url); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/AuthenticationIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/AuthenticationIntegrationTest.java new file mode 100644 index 000000000..e0680efb2 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/AuthenticationIntegrationTest.java @@ -0,0 +1,140 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•˜๋Š”_๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.ํ† ํฐ_์žฌ๋ฐœํ–‰; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_IDENTIFIER; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_PASSWORD; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.auth.request.ReissueTokenRequest; +import co.kirikiri.service.dto.auth.response.AuthenticationResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +class AuthenticationIntegrationTest extends InitIntegrationTest { + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๊ทธ์ธ์—_์„ฑ๊ณตํ•œ๋‹ค() { + //given + final LoginRequest ๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(DEFAULT_IDENTIFIER, DEFAULT_PASSWORD); + + //when + final ExtractableResponse ๋กœ๊ทธ์ธ_์‘๋‹ต = ์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•˜๋Š”_๋กœ๊ทธ์ธ(๋กœ๊ทธ์ธ_์š”์ฒญ); + + //then + assertThat(๋กœ๊ทธ์ธ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.OK.value()); + + final AuthenticationResponse ๋กœ๊ทธ์ธ_์‘๋‹ต_๋ฐ”๋”” = ๋กœ๊ทธ์ธ_์‘๋‹ต.as(AuthenticationResponse.class); + assertThat(๋กœ๊ทธ์ธ_์‘๋‹ต_๋ฐ”๋””.accessToken()).isNotEmpty(); + assertThat(๋กœ๊ทธ์ธ_์‘๋‹ต_๋ฐ”๋””.refreshToken()).isNotEmpty(); + } + + @Test + void ํšŒ์›์ด_์กด์žฌํ•˜์ง€_์•Š์„๋•Œ_๋กœ๊ทธ์ธ์—_์‹คํŒจํ•œ๋‹ค() { + //given + final LoginRequest ๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest("wrongmember1", "password1!"); + + //when + final ExtractableResponse ๋กœ๊ทธ์ธ_์‘๋‹ต = ์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•˜๋Š”_๋กœ๊ทธ์ธ(๋กœ๊ทธ์ธ_์š”์ฒญ); + + //then + assertThat(๋กœ๊ทธ์ธ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.UNAUTHORIZED.value()); + + final ErrorResponse ์‹คํŒจ_์‘๋‹ต_๋ฐ”๋”” = ๋กœ๊ทธ์ธ_์‘๋‹ต.as(ErrorResponse.class); + assertThat(์‹คํŒจ_์‘๋‹ต_๋ฐ”๋””.message()).isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€_ํ‹€๋ ธ์„๋•Œ_๋กœ๊ทธ์ธ์—_์‹คํŒจํ•œ๋‹ค() { + //given + final LoginRequest ๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(DEFAULT_IDENTIFIER, "password2@"); + + //when + final ExtractableResponse ๋กœ๊ทธ์ธ_์‘๋‹ต = ์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•˜๋Š”_๋กœ๊ทธ์ธ(๋กœ๊ทธ์ธ_์š”์ฒญ); + + //then + assertThat(๋กœ๊ทธ์ธ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.UNAUTHORIZED.value()); + + final ErrorResponse ์‹คํŒจ_์‘๋‹ต_๋ฐ”๋”” = ๋กœ๊ทธ์ธ_์‘๋‹ต.as(ErrorResponse.class); + assertThat(์‹คํŒจ_์‘๋‹ต_๋ฐ”๋””.message()).isEqualTo("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ์•„์ด๋””์™€_๋น„๋ฐ€๋ฒˆํ˜ธ์—_๋นˆ๊ฐ’์ด_์žˆ์„๋•Œ() throws JsonProcessingException { + //given + final LoginRequest ๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest("", ""); + + //when + final ExtractableResponse ๋กœ๊ทธ์ธ_์‘๋‹ต = ์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•˜๋Š”_๋กœ๊ทธ์ธ(๋กœ๊ทธ์ธ_์š”์ฒญ); + + //then + assertThat(๋กœ๊ทธ์ธ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + + final String responseBody = ๋กœ๊ทธ์ธ_์‘๋‹ต.asString(); + final List ๋กœ๊ทธ์ธ_์‘๋‹ต_๋ฐ”๋”” = jsonToClass(responseBody, new TypeReference<>() { + }); + final ErrorResponse ์•„์ด๋””_๋นˆ๊ฐ’_์˜ค๋ฅ˜_๋ฉ”์„ธ์ง€ = new ErrorResponse("์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final ErrorResponse ๋น„๋ฐ€๋ฒˆํ˜ธ_๋นˆ๊ฐ’_์˜ค๋ฅ˜_๋ฉ”์„ธ์ง€ = new ErrorResponse("๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + + assertThat(๋กœ๊ทธ์ธ_์‘๋‹ต_๋ฐ”๋””).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(์•„์ด๋””_๋นˆ๊ฐ’_์˜ค๋ฅ˜_๋ฉ”์„ธ์ง€, ๋น„๋ฐ€๋ฒˆํ˜ธ_๋นˆ๊ฐ’_์˜ค๋ฅ˜_๋ฉ”์„ธ์ง€)); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํ† ํฐ_์žฌ๋ฐœํ–‰์„_ํžŒ๋‹ค() { + //given + final ReissueTokenRequest ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ = new ReissueTokenRequest(๊ธฐ๋ณธ_์žฌ๋ฐœํ–‰_ํ† ํฐ); + + //when + final ExtractableResponse ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต = ํ† ํฐ_์žฌ๋ฐœํ–‰(ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ); + + //then + assertThat(ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.OK.value()); + + final AuthenticationResponse ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต_๋ฐ”๋”” = ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต.as(AuthenticationResponse.class); + assertThat(ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต_๋ฐ”๋””.accessToken()).isNotEmpty(); + assertThat(ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต_๋ฐ”๋””.refreshToken()).isNotEmpty(); + } + + @Test + void ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_๋นˆ๊ฐ’์„_๋ณด๋‚ผ๋•Œ() throws JsonProcessingException { + //given + final ReissueTokenRequest ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ = new ReissueTokenRequest(""); + + //when + final ExtractableResponse ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต = ํ† ํฐ_์žฌ๋ฐœํ–‰(ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ); + + //then + assertThat(ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + + final ErrorResponse errorResponse = new ErrorResponse("๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + final List ์—๋Ÿฌ_๋ฉ”์„ธ์ง€_๋ฐ”๋”” = jsonToClass(ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต.asString(), new TypeReference<>() { + }); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€_๋ฐ”๋””).usingRecursiveComparison() + .isEqualTo(List.of(errorResponse)); + } + + @Test + void ํ† ํฐ_์žฌ๋ฐœํ–‰_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๋ฆฌํ”„๋ ˆ์‹œ_ํ† ํฐ์„_๋ณด๋‚ผ๋•Œ() { + //given + final ReissueTokenRequest ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ = new ReissueTokenRequest("anyString"); + + //when + final ExtractableResponse ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต = ํ† ํฐ_์žฌ๋ฐœํ–‰(ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ); + + //then + assertThat(ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.UNAUTHORIZED.value()); + + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€_๋ฐ”๋”” = ํ† ํฐ_์žฌ๋ฐœํ–‰_์‘๋‹ต.as(ErrorResponse.class); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€_๋ฐ”๋””.message()).isEqualTo("Invalid Token"); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomCreateIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomCreateIntegrationTest.java new file mode 100644 index 000000000..a04844699 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomCreateIntegrationTest.java @@ -0,0 +1,1143 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€ํ›„_์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ •๋ ฌ_๊ธฐ์ค€์—†์ด_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์˜ค๋Š˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ด์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.ํšŒ์›๊ฐ€์ž…; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.goalroom.GoalRoomFilterTypeDto; +import co.kirikiri.service.dto.goalroom.request.CheckFeedRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.goalroom.response.GoalRoomMemberResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.io.IOException; +import java.time.LocalDate; +import java.time.Month; +import java.time.temporal.ChronoUnit; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.mock.web.MockMultipartFile; + +class GoalRoomCreateIntegrationTest extends InitIntegrationTest { + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.CREATED.value()); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.response().header("Location")).contains("/api/goal-rooms/"); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์ปจํ…์ธ _id๊ฐ€_๋นˆ๊ฐ’์ผ_๊ฒฝ์šฐ() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๋กœ๋“œ๋งต_์•„์ด๋””๊ฐ€_๋นˆ๊ฐ’์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(null, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๋กœ๋“œ๋งต_์•„์ด๋””๊ฐ€_๋นˆ๊ฐ’์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + + final List ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.as(new TypeRef<>() { + }); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋””).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(new ErrorResponse("๋กœ๋“œ๋งต ์ปจํ…์ธ  ์•„์ด๋””๋Š” ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."))); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_์ด๋ฆ„์ด_๋นˆ๊ฐ’์ผ_๊ฒฝ์šฐ() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ด๋ฆ„์ด_๋นˆ๊ฐ’์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(1L, null, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, + ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ด๋ฆ„์ด_๋นˆ๊ฐ’์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + final List ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋””).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(new ErrorResponse("๊ณจ๋ฃธ ์ด๋ฆ„์„ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."))); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›์ด_๋นˆ๊ฐ’์ผ_๊ฒฝ์šฐ() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ œํ•œ_์ธ์›์ด_๋นˆ๊ฐ’์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(1L, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, null, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, + ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ œํ•œ_์ธ์›์ด_๋นˆ๊ฐ’์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + final List ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋””).usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of(new ErrorResponse("๊ณจ๋ฃธ ์ œํ•œ ์ธ์›์€ ๋นˆ ๊ฐ’์ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."))); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๊ณจ๋ฃธ_์ด๋ฆ„์ด_40์ž_์ดˆ๊ณผ์ธ_๊ฒฝ์šฐ() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final String ์ ์ ˆํ•˜์ง€_์•Š์€_๊ธธ์ด์˜_๊ณจ๋ฃธ_์ด๋ฆ„ = "a".repeat(41); + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ ์ ˆํ•˜์ง€_์•Š์€_๊ธธ์ด์˜_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + + final ErrorResponse errorResponse = ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.as(ErrorResponse.class); + assertThat(errorResponse.message()).isEqualTo("๊ณจ๋ฃธ ์ด๋ฆ„์˜ ๊ธธ์ด๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์ˆ˜์™€_๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์ˆ˜๊ฐ€_๋งž์ง€_์•Š์„๋•Œ() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = Collections.emptyList(); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + + final ErrorResponse errorResponse = ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.as(ErrorResponse.class); + assertThat(errorResponse.message()).isEqualTo("๋ชจ๋“  ๋…ธ๋“œ์— ๋Œ€ํ•ด ๊ธฐ๊ฐ„์ด ์„ค์ •๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์ œํ•œ_์ธ์›์ด_20๋ช…_์ดˆ๊ณผ์ผ๋•Œ() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + + final int ์ดˆ๊ณผ๋œ_์ œํ•œ์ธ์› = 30; + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ดˆ๊ณผ๋œ_์ œํ•œ์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + + final ErrorResponse errorResponse = ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.as(ErrorResponse.class); + assertThat(errorResponse.message()).isEqualTo("์ œํ•œ ์ธ์› ์ˆ˜๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ์—_์ฐธ๊ฐ€_์š”์ฒญ์„_๋ณด๋‚ธ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ_์‘๋‹ต = ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + //then + assertThat(๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.OK.value()); + } + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ_์•„์ด๋””๋กœ_์ฐธ๊ฐ€_์š”์ฒญ์„_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final Long ์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ_์•„์ด๋”” = 1L; + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ_์‘๋‹ต = ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + final String ์˜ˆ์™ธ_๋ฉ”์‹œ์ง€ = ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ_์‘๋‹ต.asString(); + + assertAll( + () -> assertThat(๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NOT_FOUND.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์‹œ์ง€).contains("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = " + 1) + ); + } + + @Test + void ์ธ์›์ด_๊ฐ€๋“_์ฐฌ_๊ณจ๋ฃธ์—_์ฐธ๊ฐ€_์š”์ฒญ์„_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, 1, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, + ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + //when + final ExtractableResponse ์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + //then + final String ์˜ˆ์™ธ_๋ฉ”์‹œ์ง€ = ์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.asString(); + + assertAll( + () -> assertThat(์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์‹œ์ง€).contains("์ œํ•œ ์ธ์›์ด ๊ฝ‰ ์ฐฌ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + ); + } + + @Test + void ๋ชจ์ง‘_์ค‘์ด์ง€_์•Š์€_๊ณจ๋ฃธ์—_์ฐธ๊ฐ€_์š”์ฒญ์„_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + //when + final ExtractableResponse ์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + //then + final String ์˜ˆ์™ธ_๋ฉ”์‹œ์ง€ = ์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.asString(); + + assertAll( + () -> assertThat(์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์‹œ์ง€).contains("๋ชจ์ง‘ ์ค‘์ด์ง€ ์•Š์€ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + ); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์„_์š”์ฒญํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/jpeg", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description"); + + //when + final ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + assertAll( + () -> assertThat(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.CREATED.value()), + () -> assertThat(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.response().header("Location")) + .contains("originalFileName.jpeg") + ); + } + + @Test + void ์ธ์ฆ์šฉ_์‚ฌ์ง„์ด_์—†๋Š”_๊ฒฝ์šฐ_์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์ด_์‹คํŒจํ•œ๋‹ค() throws IOException { + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๋นˆ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/jpeg", "".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ = new CheckFeedRequest(๋นˆ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description"); + + //when + final ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ณจ๋ฃธ_์•„์ด๋””, ๋นˆ_์ด๋ฏธ์ง€_๊ฐ์ฒด, + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final ErrorResponse ์˜ˆ์™ธ_๋ฉ”์„ธ์ง€ = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.as(ErrorResponse.class); + + //then + assertAll( + () -> assertThat(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ธ์ฆ ํ”ผ๋“œ ๋“ฑ๋ก ์‹œ ์ด๋ฏธ์ง€๊ฐ€ ๋ฐ˜๋“œ์‹œ ํฌํ•จ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.") + ); + } + + @Test + void ์ธ์ฆ์šฉ_์‚ฌ์ง„์˜_ํ™•์žฅ์ž๊ฐ€_ํ—ˆ์šฉ๋˜์ง€_์•Š๋Š”_๊ฒฝ์šฐ_์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์ด_์‹คํŒจํ•œ๋‹ค() throws IOException { + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.gif", + "image/gif", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description"); + + //when + final ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final ErrorResponse ์˜ˆ์™ธ_๋ฉ”์„ธ์ง€ = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.as(ErrorResponse.class); + + //then + assertAll( + () -> assertThat(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์„ธ์ง€.message()).isEqualTo("ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ํ™•์žฅ์ž์ž…๋‹ˆ๋‹ค.") + ); + } + + @Test + void ํ•˜๋ฃจ์—_๋‘_๋ฒˆ_์ด์ƒ_์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์„_์š”์ฒญํ•˜๋Š”_๊ฒฝ์šฐ_์‹คํŒจํ•œ๋‹ค() throws IOException { + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/webp", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description"); + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //when + final ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final ErrorResponse ์˜ˆ์™ธ_๋ฉ”์„ธ์ง€ = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.as(ErrorResponse.class); + + //then + final List ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต = ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ •๋ ฌ_๊ธฐ์ค€์—†์ด_์กฐํšŒ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + + assertAll( + () -> assertThat(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.statusCode()) + .isEqualTo(HttpStatus.BAD_REQUEST.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ด๋ฏธ ์˜ค๋Š˜ ์ธ์ฆ ํ”ผ๋“œ๋ฅผ ๋“ฑ๋กํ•˜์˜€์Šต๋‹ˆ๋‹ค."), + () -> assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(0).accomplishmentRate()) + .isEqualTo(100 / (double) ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜) + ); + } + + @Test + void ์ง„ํ–‰_์ค‘์ธ_๋…ธ๋“œ์˜_ํ—ˆ์šฉ๋œ_์ธ์ฆ_ํšŸ์ˆ˜_์ด์ƒ_์š”์ฒญํ• _๊ฒฝ์šฐ_์‹คํŒจํ•œ๋‹ค() throws IOException { + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), 1, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/webp", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description"); + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //when + final ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final ErrorResponse ์˜ˆ์™ธ_๋ฉ”์„ธ์ง€ = ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.as(ErrorResponse.class); + + //then + assertAll( + () -> assertThat(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ด๋ฒˆ ๋…ธ๋“œ์—๋Š” ์ตœ๋Œ€ " + 1 + "๋ฒˆ๋งŒ ์ธ์ฆ ํ”ผ๋“œ๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.") + ); + } + + @Test + void ์ด๋ฏธ_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ์—_์ฐธ๊ฐ€_์š”์ฒญ์„_๋ณด๋‚ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //when + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final ExtractableResponse ์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //then + final String ์˜ˆ์™ธ_๋ฉ”์‹œ์ง€ = ์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.asString(); + + assertAll( + () -> assertThat(์ฐธ๊ฐ€_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์‹œ์ง€).contains("์ด๋ฏธ ์ฐธ์—ฌํ•œ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.") + ); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id()); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€ = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””, ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ); + + // then + assertThat(๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€.statusCode()).isEqualTo(HttpStatus.CREATED.value()); + final String header = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€.response() + .header(HttpHeaders.LOCATION); + assertThat(header).contains("/api/goal-rooms/1/todos/" + header.substring(24)); + } + + @Test + void ๊ณจ๋ฃธ์—_ํŒ”๋กœ์›Œ๊ฐ€_ํˆฌ๋‘_๋ฆฌ์ŠคํŠธ๋ฅผ_์ถ”๊ฐ€ํ• ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "password12!@#$%", "follower", + "010-2345-6789", GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, + ๋กœ๊ทธ์ธ(new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›๊ฐ€์ž…_์š”์ฒญ.password())).accessToken()); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id()); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€ = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””, ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ); + + // then + final ErrorResponse ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_๋ฐ”๋”” = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_๋ฐ”๋””).isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.")); + } + + @Test + void ์ข…๋ฃŒ๋œ_๊ณจ๋ฃธ์—_ํˆฌ๋‘_๋ฆฌ์ŠคํŠธ๋ฅผ_์ถ”๊ฐ€ํ• ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id()); + testTransactionService.๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + + //when + final ExtractableResponse ๊ณจ๋ฃธ_์ถ”๊ฐ€_์‘๋‹ต = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””, ๊ณจ๋ฃธ_ํˆฌ๋‘_๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ); + + //then + final ErrorResponse ๊ณจ๋ฃธ_์ถ”๊ฐ€_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_์ถ”๊ฐ€_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_์ถ”๊ฐ€_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(๊ณจ๋ฃธ_์ถ”๊ฐ€_์‘๋‹ต_๋ฐ”๋””).isEqualTo(new ErrorResponse("์ด๋ฏธ ์ข…๋ฃŒ๋œ ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘_๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id()); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + final Long ํˆฌ๋‘_์•„์ด๋”” = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€ํ›„_์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final GoalRoomToDoCheckResponse ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””, ํˆฌ๋‘_์•„์ด๋””) + .as(new TypeRef<>() { + }); + + // then + final GoalRoomToDoCheckResponse ์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’ = new GoalRoomToDoCheckResponse(true); + assertThat(๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’) + .isEqualTo(์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ๋ฅผ_ํ•ด์ œํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id()); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + final Long ํˆฌ๋‘_์•„์ด๋”” = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€ํ›„_์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””, ํˆฌ๋‘_์•„์ด๋””); + + // when + final GoalRoomToDoCheckResponse ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””, ํˆฌ๋‘_์•„์ด๋””) + .as(new TypeRef<>() { + }); + + // then + final GoalRoomToDoCheckResponse ์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’ = new GoalRoomToDoCheckResponse(false); + assertThat(๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’) + .isEqualTo(์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ_์‘๋‹ต๊ฐ’); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_๊ณจ๋ฃธ์ด_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + // when + final ErrorResponse ์—๋Ÿฌ_์‘๋‹ต = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, 1L, 1L) + .as(new TypeRef<>() { + }); + + // then + assertThat(์—๋Ÿฌ_์‘๋‹ต) + .isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_์‚ฌ์šฉ์ž๊ฐ€_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id()); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + final Long ํˆฌ๋‘_์•„์ด๋”” = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€ํ›„_์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + // when + final ErrorResponse ์—๋Ÿฌ_์‘๋‹ต = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””, ํˆฌ๋‘_์•„์ด๋””) + .as(new TypeRef<>() { + }); + + // then + assertThat(์—๋Ÿฌ_์‘๋‹ต) + .isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = " + ๊ณจ๋ฃธ_์•„์ด๋”” + + " memberIdentifier = " + ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier())); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์„_๋‚˜๊ฐ„๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_์™„๋ฃŒ๋œ_๊ณจ๋ฃธ์„_๋‚˜๊ฐ„๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + testTransactionService.๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final MemberGoalRoomResponse ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + final List ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต = ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ •๋ ฌ_๊ธฐ์ค€์—†์ด_์กฐํšŒ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final GoalRoomMemberResponse ์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ •๋ณด = new GoalRoomMemberResponse(ํŒ”๋กœ์›Œ_์‚ฌ์šฉ์ž_์ •๋ณด.id(), + ํŒ”๋กœ์›Œ_์‚ฌ์šฉ์ž_์ •๋ณด.nickname(), ํŒ”๋กœ์›Œ_์‚ฌ์šฉ์ž_์ •๋ณด.profileImageUrl(), 0D); + + assertThat(์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’.leaderId()).isEqualTo(ํŒ”๋กœ์›Œ_์‚ฌ์šฉ์ž_์ •๋ณด.id()); + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต).isEqualTo(List.of(์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ •๋ณด)); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws JsonProcessingException { + //given + final Long ์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ_์•„์ด๋”” = 1L; + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋””.message()).isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1"); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, + ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + final Long ํŒ”๋กœ์›Œ_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // then + final ErrorResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋””.message()).isEqualTo("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. memberId = " + ํŒ”๋กœ์›Œ_์•„์ด๋””); + } + + @Test + void ์™„๋ฃŒ๋œ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + final Long ํŒ”๋กœ์›Œ_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + testTransactionService.๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””); + + // when + + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // then + final ErrorResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋””.message()).isEqualTo("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. memberId = " + ํŒ”๋กœ์›Œ_์•„์ด๋””); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_๊ณจ๋ฃธ์ด_์ง„ํ–‰์ค‘์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋”” = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_๋ฐ”๋””.message()).isEqualTo("์ง„ํ–‰์ค‘์ธ ๊ณจ๋ฃธ์—์„œ๋Š” ๋‚˜๊ฐˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_๋ฆฌ๋”๊ฐ€_๋‚˜๊ฐ€๋ฉด_๋‹ค์Œ์œผ๋กœ_๋“ค์–ด์˜จ_์‚ฌ์šฉ์ž๊ฐ€_๋ฆฌ๋”๊ฐ€_๋œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follow1", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final MemberJoinRequest ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier3", "paswword2@", + "follow2", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ExtractableResponse ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ(1L, null, 2, + GoalRoomFilterTypeDto.LATEST.name()); + final RoadmapGoalRoomResponses ๊ณจ๋ฃธ_๋ชฉ๋ก = ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + assertThat(๊ณจ๋ฃธ_๋ชฉ๋ก.responses().get(0).currentMemberCount()).isEqualTo(2); + assertThat(๊ณจ๋ฃธ_๋ชฉ๋ก.responses().get(0).goalRoomLeader().name()).isEqualTo("follow1"); + } + + @Test + void ์™„๋ฃŒ๋œ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_๋ฆฌ๋”๊ฐ€_๋‚˜๊ฐ€๋ฉด_๋‹ค์Œ์œผ๋กœ_๋“ค์–ด์˜จ_์‚ฌ์šฉ์ž๊ฐ€_๋ฆฌ๋”๊ฐ€_๋œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follow1", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ1_์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberJoinRequest ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier3", "paswword2@", + "follow2", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + testTransactionService.๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final MemberGoalRoomResponse ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + assertThat(์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’.leaderId()).isEqualTo(ํŒ”๋กœ์›Œ1_์‚ฌ์šฉ์ž_์ •๋ณด.id()); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_ํŒ”๋กœ์›Œ๊ฐ€_๋‚˜๊ฐ€๋ฉด_๋ฆฌ๋”๋Š”_๋ณ€ํ•˜์ง€_์•Š๋Š”๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // then + final MemberGoalRoomResponse ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + assertThat(์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’.leaderId()).isEqualTo(๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””); + } + + @Test + void ์™„๋ฃŒ๋œ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_ํŒ”๋กœ์›Œ๊ฐ€_๋‚˜๊ฐ€๋ฉด_๋ฆฌ๋”๋Š”_๋ณ€ํ•˜์ง€_์•Š๋Š”๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + testTransactionService.๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // then + final MemberGoalRoomResponse ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + assertThat(์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’.leaderId()).isEqualTo(๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_๋‚จ์€_์‚ฌ์šฉ์ž๊ฐ€_์—†์œผ๋ฉด_๊ณจ๋ฃธ์€_์‚ญ์ œ๋œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + + final ExtractableResponse ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ(1L, null, 1, + GoalRoomFilterTypeDto.LATEST.name()); + final RoadmapGoalRoomResponses ๊ณจ๋ฃธ_๋ชฉ๋ก = ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + assertThat(๊ณจ๋ฃธ_๋ชฉ๋ก.responses()).hasSize(0); + } + + @Test + void ์™„๋ฃŒ๋œ_๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_๋‚จ์€_์‚ฌ์šฉ์ž๊ฐ€_์—†์œผ๋ฉด_๊ณจ๋ฃธ์€_์‚ญ์ œ๋œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + testTransactionService.๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””); + + // when + + final ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + assertThat(๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + + final ExtractableResponse ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ(1L, null, 1, + GoalRoomFilterTypeDto.LATEST.name()); + final RoadmapGoalRoomResponses ๊ณจ๋ฃธ_๋ชฉ๋ก = ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + assertThat(๊ณจ๋ฃธ_๋ชฉ๋ก.responses()).hasSize(0); + } + + @Test + void ๊ณจ๋ฃธ์„_์ •์ƒ์ ์œผ๋กœ_์‹œ์ž‘ํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต = ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + // then + final List ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ •๋ณด = ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ •๋ ฌ_๊ธฐ์ค€์—†์ด_์กฐํšŒ(๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoomMemberResponse ์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ •๋ณด = new GoalRoomMemberResponse(์‚ฌ์šฉ์ž_์ •๋ณด.id(), + ์‚ฌ์šฉ์ž_์ •๋ณด.nickname(), ์‚ฌ์šฉ์ž_์ •๋ณด.profileImageUrl(), 0D); + + assertThat(๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต.statusCode()) + .isEqualTo(HttpStatus.NO_CONTENT.value()); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ •๋ณด) + .isEqualTo(List.of(์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์ •๋ณด)); + } + + @Test + void ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•˜๋Š”_์‚ฌ์šฉ์ž๊ฐ€_๊ณจ๋ฃธ์˜_๋ฆฌ๋”๊ฐ€_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final MemberJoinRequest ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + ํšŒ์›๊ฐ€์ž…(๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final LoginRequest ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + final String ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต = ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_์•ก์„ธ์Šค_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + // then + final ErrorResponse errorResponse = ๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต.as(ErrorResponse.class); + assertThat(๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต.statusCode()) + .isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(errorResponse.message()) + .isEqualTo("๊ณจ๋ฃธ์˜ ๋ฆฌ๋”๋งŒ ๊ณจ๋ฃธ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๊ฐ€_๋ฏธ๋ž˜๋ผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), + (int) ChronoUnit.DAYS.between(์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„), ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final ExtractableResponse ๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต = ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ณจ๋ฃธ_์•„์ด๋””); + + // then + final ErrorResponse errorResponse = ๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต.as(ErrorResponse.class); + assertThat(๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต.statusCode()) + .isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(errorResponse.message()) + .isEqualTo("๊ณจ๋ฃธ์˜ ์‹œ์ž‘ ๋‚ ์งœ๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค."); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomReadIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomReadIntegrationTest.java new file mode 100644 index 000000000..def79455d --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomReadIntegrationTest.java @@ -0,0 +1,615 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์•„์ด๋””์™€_ํ† ํฐ์œผ๋กœ_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ „์ฒด_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ •๋ ฌ_๊ธฐ์ค€์—†์ด_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ_์ค‘_๊ณจ๋ฃธ_์ง„ํ–‰_์ƒํƒœ์—_๋”ฐ๋ผ_๋ชฉ๋ก์„_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‚ฌ์šฉ์ž์˜_๋ชจ๋“ _๊ณจ๋ฃธ_์กฐํšŒ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‚ผ์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์˜ค๋Š˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ด์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›; +import static co.kirikiri.integration.fixture.MemberAPIFixture.ํšŒ์›๊ฐ€์ž…; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsOrderType; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.goalroom.GoalRoomMemberSortTypeDto; +import co.kirikiri.service.dto.goalroom.request.CheckFeedRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.goalroom.response.CheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCertifiedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomMemberResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodeResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodesResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomTodoResponse; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberGoalRoomForListResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import org.springframework.mock.web.MockMultipartFile; + +class GoalRoomReadIntegrationTest extends InitIntegrationTest { + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + // when + final GoalRoomResponse ๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””) + .as(new TypeRef<>() { + }); + + // then + assertThat(๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’.name()).isEqualTo(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + // when + final GoalRoomCertifiedResponse ๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_์•„์ด๋””์™€_ํ† ํฐ์œผ๋กœ_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(๊ณจ๋ฃธ_์‘๋‹ต๊ฐ’.name()).isEqualTo(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomTodoRequest("content", ์ด์‹ญ์ผ_ํ›„, ์‚ผ์‹ญ์ผ_ํ›„); + ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ณจ๋ฃธ_ํˆฌ๋‘_์ƒ์„ฑ_์š”์ฒญ); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final List ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์‘๋‹ต๊ฐ’.get(0).startDate()) + .isEqualTo(์˜ค๋Š˜); + assertThat(๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์‘๋‹ต๊ฐ’.get(1).startDate()) + .isEqualTo(์ด์‹ญ์ผ_ํ›„); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ() { + // given + // when + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ(1L, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(์˜ˆ์™ธ_์‘๋‹ต) + .isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomTodoRequest("content", ์ด์‹ญ์ผ_ํ›„, ์‚ผ์‹ญ์ผ_ํ›„); + ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ณจ๋ฃธ_ํˆฌ๋‘_์ƒ์„ฑ_์š”์ฒญ); + + final MemberJoinRequest ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_์•ก์„ธ์Šค_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(์˜ˆ์™ธ_์‘๋‹ต) + .isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค. goalRoomId = " + ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” + + " memberIdentifier = identifier2")); + } + + @Test + void ์ง„ํ–‰์ค‘์ธ_์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/webp", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description"); + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // when + final MemberGoalRoomResponse ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // then + final MemberGoalRoomResponse ์˜ˆ์ƒ๋˜๋Š”_์‘๋‹ต๊ฐ’ = new MemberGoalRoomResponse(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, "RUNNING", ๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””, + 2, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„, ๋กœ๋“œ๋งต_์‘๋‹ต.content().id(), + new GoalRoomRoadmapNodesResponse(false, false, + List.of(new GoalRoomRoadmapNodeResponse(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), + "roadmap 1st week", ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜))), + List.of(new GoalRoomTodoResponse(1L, "GOAL_ROOM_TO_DO_CONTENT", ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„, + new GoalRoomToDoCheckResponse(false))), + List.of(new CheckFeedResponse(2L, "default-image-path", "image description", LocalDate.now()), + new CheckFeedResponse(1L, "default-image-path", "image description", LocalDate.now()))); + + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’) + .usingRecursiveComparison() + .ignoringFields("checkFeeds.imageUrl", "checkFeeds.createdAt") + .isEqualTo(์˜ˆ์ƒ๋˜๋Š”_์‘๋‹ต๊ฐ’); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘_์ „์—_์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ_์กฐํšŒ_์‹œ_์ธ์ฆ_ํ”ผ๋“œ๊ฐ€_๋นˆ_์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + //when + final MemberGoalRoomResponse ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + //then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.checkFeeds()).isEmpty(); + } + + @Test + void ์‚ฌ์šฉ์ž์˜_๋ชจ๋“ _๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), null); + ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final List ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_๋ชจ๋“ _๊ณจ๋ฃธ_์กฐํšŒ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.get(0).goalRoomId()).isEqualTo(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.get(1).goalRoomId()).isEqualTo(๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ_์ค‘_๋ชจ์ง‘_์ค‘์ธ_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ์ฒซ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(์ฒซ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ์ฒซ๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest("Content", ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), 10, ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต.content().id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, + 20, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ์ฒซ๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final List ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ_์ค‘_๊ณจ๋ฃธ_์ง„ํ–‰_์ƒํƒœ์—_๋”ฐ๋ผ_๋ชฉ๋ก์„_์กฐํšŒ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, "RECRUITING") + .as(new TypeRef<>() { + }); + + // then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.get(0).goalRoomId()).isEqualTo(๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ_์ค‘_์ง„ํ–‰_์ค‘์ธ_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ์ฒซ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(์ฒซ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ์ฒซ๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest("Content", ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), 10, ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต.content().id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, + 20, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ์ฒซ๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final List ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ_์ค‘_๊ณจ๋ฃธ_์ง„ํ–‰_์ƒํƒœ์—_๋”ฐ๋ผ_๋ชฉ๋ก์„_์กฐํšŒ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, "RUNNING") + .as(new TypeRef<>() { + }); + + // then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.get(0).goalRoomId()).isEqualTo(์ฒซ๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(๊ณจ๋ฃธ_๋…ธ๋“œ_์‘๋‹ต๊ฐ’.get(0).title()).isEqualTo("roadmap 1st week"); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + // when + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ(1L, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(์˜ˆ์™ธ_์‘๋‹ต๊ฐ’) + .isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต๊ฐ’ = ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_์•ก์„ธ์Šค_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(์˜ˆ์™ธ_์‘๋‹ต๊ฐ’) + .isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = identifier2")); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/jpeg", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ1 = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description1"); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ2 = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description2"); + + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ1, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ2, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + //when + final List ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””) + .as(new TypeRef<>() { + }); + + // then + assertThat(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.get(0).checkFeed().description()).isEqualTo(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ2.description()); + assertThat(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.get(1).checkFeed().description()).isEqualTo(์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ1.description()); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ธ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + //when + final Long ์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ_์•„์ด๋”” = 1L; + final ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ_์•„์ด๋””); + + // then + final ErrorResponse ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋”” = jsonToClass(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.asString(), new TypeReference<>() { + }); + assertThat(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋””).isEqualTo(new ErrorResponse("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒ์‹œ_๊ณจ๋ฃธ์—_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final MemberJoinRequest ๋‹ค๋ฅธ_ํšŒ์›_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ๋‹ค๋ฅธ_ํšŒ์›_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(๋‹ค๋ฅธ_ํšŒ์›_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ๋‹ค๋ฅธ_ํšŒ์›_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(๋‹ค๋ฅธ_ํšŒ์›_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ๋‹ค๋ฅธ_ํšŒ์›_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(๋‹ค๋ฅธ_ํšŒ์›_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/jpeg", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ1 = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description1"); + + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ1, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //when + final ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ(๋‹ค๋ฅธ_ํšŒ์›_์•ก์„ธ์Šค_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // then + final ErrorResponse ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋”” = jsonToClass(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.asString(), new TypeReference<>() { + }); + assertThat(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.FORBIDDEN.value()); + assertThat(์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋””).isEqualTo(new ErrorResponse("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + } + + @Test + void ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_๋‹ฌ์„ฑ๋ฅ ์ˆœ์œผ๋กœ_์ „์ฒด_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final MemberJoinRequest ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follow1", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final MemberJoinRequest ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier3", "paswword2@", + "follow2", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final Long ํŒ”๋กœ์›Œ1_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final Long ํŒ”๋กœ์›Œ2_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + + final LoginRequest ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + final LoginRequest ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + + final String ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final String ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile("image", "originalFileName.jpeg", + "image/jpeg", "tempImage".getBytes()); + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ1 = new CheckFeedRequest(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, "image description1"); + + ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ1, ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ); + + //when + final List ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต = ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ „์ฒด_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, + GoalRoomMemberSortTypeDto.ACCOMPLISHMENT_RATE.name()).as(new TypeRef<>() { + }); + + // then + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(0).memberId()).isEqualTo(ํŒ”๋กœ์›Œ1_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(1).memberId()).isEqualTo(๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(2).memberId()).isEqualTo(ํŒ”๋กœ์›Œ2_์•„์ด๋””); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ฐธ๊ฐ€ํ•œ_์ตœ์‹ ์ˆœ์œผ๋กœ_์ „์ฒด_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final MemberJoinRequest ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follow1", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final MemberJoinRequest ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier3", "paswword2@", + "follow2", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final Long ํŒ”๋กœ์›Œ1_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final Long ํŒ”๋กœ์›Œ2_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + + final LoginRequest ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + final LoginRequest ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + + final String ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final String ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ); + + //when + final List ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต = ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ „์ฒด_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, + GoalRoomMemberSortTypeDto.JOINED_DESC.name()).as(new TypeRef<>() { + }); + + // then + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(0).memberId()).isEqualTo(ํŒ”๋กœ์›Œ2_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(1).memberId()).isEqualTo(ํŒ”๋กœ์›Œ1_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(2).memberId()).isEqualTo(๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด_์กฐํšŒ์‹œ_์ •๋ ฌ๊ธฐ์ค€์„_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์ฐธ์—ฌํ•œ์ง€_์˜ค๋ž˜๋œ์ˆœ์œผ๋กœ_์ •๋ ฌํ•œ๋‹ค() throws IOException { + // given + final MemberJoinRequest ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follow1", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final MemberJoinRequest ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier3", "paswword2@", + "follow2", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final Long ํŒ”๋กœ์›Œ1_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final Long ํŒ”๋กœ์›Œ2_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + + final LoginRequest ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + final LoginRequest ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + + final String ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final String ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ); + + //when + final List ๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต = ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ •๋ ฌ_๊ธฐ์ค€์—†์ด_์กฐํšŒ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ) + .as(new TypeRef<>() { + }); + + // then + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(0).memberId()).isEqualTo(๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(1).memberId()).isEqualTo(ํŒ”๋กœ์›Œ1_์•„์ด๋””); + assertThat(๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_์‘๋‹ต.get(2).memberId()).isEqualTo(ํŒ”๋กœ์›Œ2_์•„์ด๋””); + } + + @Test + void ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + // when + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ „์ฒด_์กฐํšŒ(1L, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, + GoalRoomMemberSortTypeDto.ACCOMPLISHMENT_RATE.name()).as(new TypeRef<>() { + }); + + // then + assertThat(์˜ˆ์™ธ_์‘๋‹ต.message()).isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1"); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_๋ชฉ๋ก์„_๋งˆ๊ฐ์ž„๋ฐ•์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest("Content", ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), 10, ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, + 20, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapGoalRoomResponses ๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์‘๋‹ต1 = ๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, + RoadmapGoalRoomsOrderType.CLOSE_TO_DEADLINE.name(), 10).as( + new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์‘๋‹ต1.responses().get(0).goalRoomId()).isEqualTo(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์‘๋‹ต1.responses().get(1).goalRoomId()).isEqualTo(๋‘๋ฒˆ์งธ_๊ณจ๋ฃธ_์•„์ด๋””); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomSchedulerIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomSchedulerIntegrationTest.java new file mode 100644 index 000000000..d6db4ce0b --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/GoalRoomSchedulerIntegrationTest.java @@ -0,0 +1,222 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static co.kirikiri.integration.fixture.CommonFixture.LOCATION; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์˜ค๋Š˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ด์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.ํšŒ์›๊ฐ€์ž…; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomPendingMemberRepository; +import co.kirikiri.service.GoalRoomScheduler; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; + +class GoalRoomSchedulerIntegrationTest extends InitIntegrationTest { + + private final GoalRoomScheduler goalRoomScheduler; + private final GoalRoomPendingMemberRepository goalRoomPendingMemberRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + + public GoalRoomSchedulerIntegrationTest(final GoalRoomScheduler goalRoomScheduler, + final GoalRoomPendingMemberRepository goalRoomPendingMemberRepository, + final GoalRoomMemberRepository goalRoomMemberRepository) { + this.goalRoomScheduler = goalRoomScheduler; + this.goalRoomPendingMemberRepository = goalRoomPendingMemberRepository; + this.goalRoomMemberRepository = goalRoomMemberRepository; + } + + @Test + void ๊ณจ๋ฃธ์ด_์‹œ์ž‘๋˜๋ฉด_๊ณจ๋ฃธ_๋Œ€๊ธฐ_์‚ฌ์šฉ์ž์—์„œ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž๋กœ_์ด๋™ํ•˜๊ณ _๋Œ€๊ธฐ_์‚ฌ์šฉ์ž์—์„œ๋Š”_์ œ๊ฑฐ๋œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + final GoalRoom ๊ณจ๋ฃธ = new GoalRoom(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, null, null, null, null); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + // when + goalRoomScheduler.startGoalRooms(); + + // then + assertAll( + () -> assertThat(goalRoomPendingMemberRepository.findAllByGoalRoom(๊ณจ๋ฃธ)).isEmpty(), + () -> assertThat(goalRoomMemberRepository.findAllByGoalRoom(๊ณจ๋ฃธ)).hasSize(2) + ); + } + + @Test + void ๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์˜ค๋Š˜๋ณด๋‹ค_์ดํ›„์ด๋ฉด_์•„๋ฌด์ผ๋„_์ผ์–ด๋‚˜์ง€_์•Š๋Š”๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + final GoalRoom ๊ณจ๋ฃธ = new GoalRoom(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, null, null, null, null); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + testTransactionService.๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ์˜ค๋Š˜.plusDays(1)); + + // when + goalRoomScheduler.startGoalRooms(); + + // then + assertAll( + () -> assertThat(goalRoomPendingMemberRepository.findAllByGoalRoom(๊ณจ๋ฃธ)).hasSize(2), + () -> assertThat(goalRoomMemberRepository.findAllByGoalRoom(๊ณจ๋ฃธ)).isEmpty() + ); + } + + @Test + void ๊ณจ๋ฃธ_์ข…๋ฃŒ์‹œ_์ข…๋ฃŒ_๋‚ ์งœ๊ฐ€_์–ด์ œ์ธ_๊ณจ๋ฃธ์˜_์ƒํƒœ๊ฐ€_COMPLETED๋กœ_๋ณ€๊ฒฝ๋œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken(); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + testTransactionService.๊ณจ๋ฃธ์˜_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ์˜ค๋Š˜.minusDays(1)); + goalRoomScheduler.endGoalRooms(); + final MemberGoalRoomResponse ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.status()).isEqualTo(GoalRoomStatus.COMPLETED.name()); + } + + @Test + void ๊ณจ๋ฃธ_์ข…๋ฃŒ์‹œ_์ข…๋ฃŒ_๋‚ ์งœ๊ฐ€_์–ด์ œ๊ฐ€_์•„๋‹ˆ๋ฉด_์•„๋ฌด_์ผ๋„_์ผ์–ด๋‚˜์ง€_์•Š๋Š”๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken(); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + goalRoomScheduler.endGoalRooms(); + final MemberGoalRoomResponse ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.status()).isEqualTo(GoalRoomStatus.RUNNING.name()); + } + + @Test + void ์ง„ํ–‰_์ค‘์ธ_์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ์„_์กฐํšŒํ• _๋•Œ_์ง„ํ–‰_์ค‘์ธ_๋…ธ๋“œ_๊ธฐ๊ฐ„์ด_์•„๋‹ˆ๋ฉด_๋นˆ_์ธ์ฆํ”ผ๋“œ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ์‹ญ์ผ_ํ›„์—_์‹œ์ž‘ํ•˜๋Š”_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken(); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + testTransactionService.๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ์˜ค๋Š˜); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final MemberGoalRoomResponse ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + // then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.checkFeeds()).isEmpty(); + } + + @Test + void ๋ชจ์ง‘_์ค‘์ธ_์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ_์กฐํšŒ_์‹œ_์ธ์ฆ_ํ”ผ๋“œ๊ฐ€_๋นˆ_์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋”” = ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์‘๋‹ต); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken(); + + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + + //when + final MemberGoalRoomResponse ์š”์ฒญ_์‘๋‹ต๊ฐ’ = ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””); + + //then + assertThat(์š”์ฒญ_์‘๋‹ต๊ฐ’.checkFeeds()).isEmpty(); + } + + private Long ์‹ญ์ผ_ํ›„์—_์‹œ์ž‘ํ•˜๋Š”_๊ณจ๋ฃธ_์ƒ์„ฑ(final String ์•ก์„ธ์Šค_ํ† ํฐ, final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต) { + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์‹ญ์ผ_ํ›„, ์ด์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, + ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, + ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final String Location_ํ—ค๋” = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ์•ก์„ธ์Šค_ํ† ํฐ).response().header(LOCATION); + return Long.parseLong(Location_ํ—ค๋”.substring(16)); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/MemberCreateIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/MemberCreateIntegrationTest.java new file mode 100644 index 000000000..955714a8b --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/MemberCreateIntegrationTest.java @@ -0,0 +1,163 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.time.LocalDate; +import java.time.Month; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.http.HttpStatus; + +class MemberCreateIntegrationTest extends InitIntegrationTest { + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํšŒ์›๊ฐ€์ž…์„_์„ฑ๊ณตํ•œ๋‹ค() { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("ab12", "password12!@#$%", "hello", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.CREATED.value()); + } + + @ParameterizedTest + @ValueSource(strings = {"abc", "abcdefghijklmnopqrstu"}) + void ์•„์ด๋””_๊ธธ์ด๊ฐ€_ํ‹€๋ฆฐ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค(final String ํšŒ์›_์•„์ด๋””) { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest(ํšŒ์›_์•„์ด๋””, "password12!", "nickname", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(new TypeRef<>() { + }); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค."); + } + + @ParameterizedTest + @ValueSource(strings = {"Abcd", "abcdefghijklmnopqrsT", "๊ฐ€๋‚˜๋‹ค๋ผ"}) + void ์•„์ด๋””์—_ํ—ˆ์šฉ๋˜์ง€_์•Š์€_๋ฌธ์ž๊ฐ€_๋“ค์–ด์˜จ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค(final String ํšŒ์›_์•„์ด๋””) { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest(ํšŒ์›_์•„์ด๋””, "password12!", "nickname", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(ErrorResponse.class); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ์•„์ด๋””๊ฐ€_์ค‘๋ณต๋œ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค() { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("ab12", "password12!", "hello", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(ErrorResponse.class); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.CONFLICT.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์•„์ด๋””์ž…๋‹ˆ๋‹ค."); + } + + @ParameterizedTest + @ValueSource(strings = {"abcde1!", "abcdefghijklmn12"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ_๊ธธ์ด๊ฐ€_ํ‹€๋ฆฐ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค(final String password) { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("ab12", password, "nickname", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(ErrorResponse.class); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค."); + } + + @ParameterizedTest + @ValueSource(strings = {"abcdef1/", "abcdefghij1โ‚ฉ", "abcdefgH1!"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ์—_ํ—ˆ์šฉ๋˜์ง€_์•Š์€_๋ฌธ์ž๊ฐ€_๋“ค์–ด์˜จ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค(final String password) { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("ab12", password, "nickname", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(ErrorResponse.class); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค."); + } + + @ParameterizedTest + @ValueSource(strings = {"abcdefgh", "abcdefghijkl"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ์—_์˜์†Œ๋ฌธ์ž๋งŒ_๋“ค์–ด์˜จ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค(final String password) { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("ab12", password, "nickname", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(ErrorResponse.class); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค."); + } + + @ParameterizedTest + @ValueSource(strings = {"12345678", "12345678910"}) + void ๋น„๋ฐ€๋ฒˆํ˜ธ์—_์ˆซ์ž๋งŒ_๋“ค์–ด์˜จ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค(final String password) { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("ab12", password, "nickname", "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(ErrorResponse.class); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์ž…๋‹ˆ๋‹ค."); + } + + @ParameterizedTest + @ValueSource(strings = {"a", "abcdefghi"}) + void ๋‹‰๋„ค์ž„_๊ธธ์ด๊ฐ€_ํ‹€๋ฆฐ_๊ฒฝ์šฐ_ํšŒ์›๊ฐ€์ž…์—_์‹คํŒจํ•œ๋‹ค(final String nickname) { + //given + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("ab12", "password12!@#$%", nickname, "010-1234-5678", + GenderType.MALE, LocalDate.of(2023, Month.JULY, 12)); + + //when + final ExtractableResponse ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + + //then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.as(ErrorResponse.class); + assertThat(ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์ œ์•ฝ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š๋Š” ๋‹‰๋„ค์ž„์ž…๋‹ˆ๋‹ค."); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/MemberReadIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/MemberReadIntegrationTest.java new file mode 100644 index 000000000..f45524206 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/MemberReadIntegrationTest.java @@ -0,0 +1,82 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_BIRTHDAY; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_GENDER_TYPE; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_IDENTIFIER; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_NICKNAME; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_PHONE_NUMBER; +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.ํšŒ์›๊ฐ€์ž…; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.member.Gender; +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberInformationForPublicResponse; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +class MemberReadIntegrationTest extends InitIntegrationTest { + + @Test + void ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด๋ฅผ_์„ฑ๊ณต์ ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws JsonProcessingException { + // given + // when + final ExtractableResponse ์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋”” = jsonToClass(์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต.asString(), + new TypeReference<>() { + }); + final MemberInformationResponse ์˜ˆ์ƒํ•˜๋Š”_์‘๋‹ต๊ฐ’ = new MemberInformationResponse(๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””, DEFAULT_NICKNAME, null, + DEFAULT_GENDER_TYPE.name(), DEFAULT_IDENTIFIER, DEFAULT_PHONE_NUMBER, DEFAULT_BIRTHDAY); + + assertThat(์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋””).usingRecursiveComparison() + .ignoringFields("profileImageUrl") + .isEqualTo(์˜ˆ์ƒํ•˜๋Š”_์‘๋‹ต๊ฐ’); + } + + @Test + void ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด๋ฅผ_์„ฑ๊ณต์ ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws JsonProcessingException { + // given + final MemberJoinRequest ๋‹ค๋ฅธ_ํšŒ์›์˜_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "password2!", + "hello", DEFAULT_PHONE_NUMBER, DEFAULT_GENDER_TYPE, DEFAULT_BIRTHDAY); + final Long ๋‹ค๋ฅธ_ํšŒ์›_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(๋‹ค๋ฅธ_ํšŒ์›์˜_๊ฐ€์ž…_์š”์ฒญ); + + // when + final ExtractableResponse ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋‹ค๋ฅธ_ํšŒ์›_์•„์ด๋””); + + // then + final MemberInformationForPublicResponse ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋”” = jsonToClass(ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต.asString(), + new TypeReference<>() { + }); + final MemberInformationForPublicResponse ์˜ˆ์ƒํ•˜๋Š”_์‘๋‹ต๊ฐ’ = new MemberInformationForPublicResponse("hello", + null, + Gender.MALE.name()); + + assertThat(ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต_๋ฐ”๋””).usingRecursiveComparison() + .ignoringFields("profileImageUrl") + .isEqualTo(์˜ˆ์ƒํ•˜๋Š”_์‘๋‹ต๊ฐ’); + } + + @Test + void ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด๋ฅผ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์‹คํŒจํ•œ๋‹ค() throws JsonProcessingException { + // given + // when + final ExtractableResponse ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, 2L); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = jsonToClass(ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต.asString(), + new TypeReference<>() { + }); + assertThat(ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค. memberId = 2"); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapCreateIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapCreateIntegrationTest.java new file mode 100644 index 000000000..237e00877 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapCreateIntegrationTest.java @@ -0,0 +1,371 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static co.kirikiri.integration.fixture.CommonFixture.์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.CommonFixture.์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.ํšŒ์›๊ฐ€์ž…; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์‚ญ์ œ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.io.IOException; +import java.time.LocalDate; +import java.util.Collections; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.http.HttpStatus; + +class RoadmapCreateIntegrationTest extends InitIntegrationTest { + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค() throws IOException { + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // expect + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.CREATED); + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’); + assertThat(๋กœ๋“œ๋งต_์•„์ด๋””).isEqualTo(1L); + } + + @Test + void ๋ณธ๋ฌธ์˜_๊ฐ’์ด_์—†๋Š”_๋กœ๋“œ๋งต์ด_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑํ•œ๋‹ค() throws IOException { + // given + final String ๋กœ๋“œ๋งต_๋ณธ๋ฌธ = null; + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", ๋กœ๋“œ๋งต_๋ณธ๋ฌธ, + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.CREATED); + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’); + assertThat(๋กœ๋“œ๋งต_์•„์ด๋””).isEqualTo(1L); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์ž˜๋ชป๋œ_๋นˆ๊ฐ’์„_๋„˜๊ธฐ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final Long ์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋”” = null; + final String ๋กœ๋“œ๋งต_์ œ๋ชฉ = null; + final String ๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€ = null; + final RoadmapDifficultyType ๋กœ๋“œ๋งต_๋‚œ์ด๋„ = null; + final Integer ์ถ”์ฒœ_์†Œ์š”_๊ธฐ๊ฐ„ = null; + final String ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ = null; + final String ๋กœ๋“œ๋งต_๋…ธ๋“œ_์„ค๋ช… = null; + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””, ๋กœ๋“œ๋งต_์ œ๋ชฉ, ๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€, "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + ๋กœ๋“œ๋งต_๋‚œ์ด๋„, ์ถ”์ฒœ_์†Œ์š”_๊ธฐ๊ฐ„, + List.of(new RoadmapNodeSaveRequest(๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ, ๋กœ๋“œ๋งต_๋…ธ๋“œ_์„ค๋ช…, Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final List ์—๋Ÿฌ_๋ฉ”์‹œ์ง€๋“ค = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์‹œ์ง€๋“ค) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .isEqualTo(List.of( + new ErrorResponse("์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."), + new ErrorResponse("๋กœ๋“œ๋งต์˜ ์ œ๋ชฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."), + new ErrorResponse("๋กœ๋“œ๋งต์˜ ์†Œ๊ฐœ๊ธ€์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."), + new ErrorResponse("๋‚œ์ด๋„๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."), + new ErrorResponse("์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."), + new ErrorResponse("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."), + new ErrorResponse("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."))); + } + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๋ฅผ_์ž…๋ ฅํ•œ_๊ฒฝ์šฐ_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final long ์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋”” = 2L; + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.NOT_FOUND); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ์นดํ…Œ๊ณ ๋ฆฌ์ž…๋‹ˆ๋‹ค. categoryId = 2"); + + } + + @Test + void ์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_40๋ณด๋‹ค_ํฌ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final String ๋กœ๋“œ๋งต_์ œ๋ชฉ = "a".repeat(41); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), ๋กœ๋“œ๋งต_์ œ๋ชฉ, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("๋กœ๋“œ๋งต ์ œ๋ชฉ์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 40๊ธ€์ž์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ์†Œ๊ฐœ๊ธ€์˜_๊ธธ์ด๊ฐ€_150๋ณด๋‹ค_ํฌ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final String ๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€ = "a".repeat(151); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", ๋กœ๋“œ๋งต_์†Œ๊ฐœ๊ธ€, "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 150๊ธ€์ž์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ๋ณธ๋ฌธ์˜_๊ธธ์ด๊ฐ€_2000๋ณด๋‹ค_ํฌ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final String ๋กœ๋“œ๋งต_๋ณธ๋ฌธ = "a".repeat(2001); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", ๋กœ๋“œ๋งต_๋ณธ๋ฌธ, + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("๋กœ๋“œ๋งต ๋ณธ๋ฌธ์˜ ๊ธธ์ด๋Š” ์ตœ๋Œ€ 2000๊ธ€์ž์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ์ถ”์ฒœ_์†Œ์š”_๊ธฐ๊ฐ„์ด_0๋ณด๋‹ค_์ž‘์œผ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final Integer ์ถ”์ฒœ_์†Œ์š”_๊ธฐ๊ฐ„ = -1; + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, ์ถ”์ฒœ_์†Œ์š”_๊ธฐ๊ฐ„, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("๋กœ๋“œ๋งต ์ถ”์ฒœ ์†Œ์š” ๊ธฐ๊ฐ„์€ ์ตœ์†Œ 0์ผ, ์ตœ๋Œ€ 1000์ผ์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ž…๋ ฅํ•˜์ง€_์•Š์œผ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค = null; + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค, List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final List ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.get(0).message()).isEqualTo("๋กœ๋“œ๋งต์˜ ์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์ œ๋ชฉ์˜_๊ธธ์ด๊ฐ€_40๋ณด๋‹ค_ํฌ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final String ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ = "a".repeat(41); + final List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค = List.of( + new RoadmapNodeSaveRequest(๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", Collections.emptyList())); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค, List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์ œ๋ชฉ์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 40๊ธ€์ž์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ์˜_์„ค๋ช…์˜_๊ธธ์ด๊ฐ€_2000๋ณด๋‹ค_ํฌ๋ฉด_์‹คํŒจํ•œ๋‹ค() throws IOException { + // given + final String ๋กœ๋“œ๋งต_๋…ธ๋“œ_์„ค๋ช… = "a".repeat(2001); + final List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค = List.of( + new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ", ๋กœ๋“œ๋งต_๋…ธ๋“œ_์„ค๋ช…, Collections.emptyList())); + testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰"); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค, List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("๋กœ๋“œ๋งต ๋…ธ๋“œ์˜ ์„ค๋ช…์˜ ๊ธธ์ด๋Š” ์ตœ์†Œ 1๊ธ€์ž, ์ตœ๋Œ€ 2000๊ธ€์ž์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ_์ด๋ฆ„์ด_์ค‘๋ณต๋˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final List ํƒœ๊ทธ_์ €์žฅ_์š”์ฒญ = List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ"), + new RoadmapTagSaveRequest("ํƒœ๊ทธ")); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ", "๋กœ๋“œ๋งต ๋…ธ๋“œ ์„ค๋ช…", Collections.emptyList())), ํƒœ๊ทธ_์ €์žฅ_์š”์ฒญ); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("ํƒœ๊ทธ ์ด๋ฆ„์€ ์ค‘๋ณต๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ_๊ฐœ์ˆ˜๊ฐ€_5๊ฐœ_์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final List ํƒœ๊ทธ_์ €์žฅ_์š”์ฒญ = List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"), + new RoadmapTagSaveRequest("ํƒœ๊ทธ2"), new RoadmapTagSaveRequest("ํƒœ๊ทธ3"), + new RoadmapTagSaveRequest("ํƒœ๊ทธ4"), new RoadmapTagSaveRequest("ํƒœ๊ทธ5"), + new RoadmapTagSaveRequest("ํƒœ๊ทธ6")); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ", "๋กœ๋“œ๋งต ๋…ธ๋“œ ์„ค๋ช…", Collections.emptyList())), ํƒœ๊ทธ_์ €์žฅ_์š”์ฒญ); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("ํƒœ๊ทธ์˜ ๊ฐœ์ˆ˜๋Š” ์ตœ๋Œ€ 5๊ฐœ๊นŒ์ง€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."); + } + + @ParameterizedTest + @ValueSource(ints = {0, 11}) + void ๋กœ๋“œ๋งต_ํƒœ๊ทธ_์ด๋ฆ„์˜_๊ธธ์ด๊ฐ€_1์ž_๋ฏธ๋งŒ_10์ž_์ดˆ๊ณผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int nameLength) throws IOException { + // given + final String ํƒœ๊ทธ_์ด๋ฆ„ = "a".repeat(nameLength); + final List ํƒœ๊ทธ_์ €์žฅ_์š”์ฒญ = List.of(new RoadmapTagSaveRequest(ํƒœ๊ทธ_์ด๋ฆ„)); + + final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต ๋…ธ๋“œ ์ œ๋ชฉ", "๋กœ๋“œ๋งต ๋…ธ๋“œ ์„ค๋ช…", Collections.emptyList())), ํƒœ๊ทธ_์ €์žฅ_์š”์ฒญ); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’ = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’.as(new TypeRef<>() { + }); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์‘๋‹ต๊ฐ’, HttpStatus.BAD_REQUEST); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("ํƒœ๊ทธ ์ด๋ฆ„์€ ์ตœ์†Œ 1์ž๋ถ€ํ„ฐ ์ตœ๋Œ€ 10์ž๊นŒ์ง€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ์ด_์ƒ์„ฑ๋œ_์ ์ด_์—†๋Š”_๋กœ๋“œ๋งต์„_์ •์ƒ์ ์œผ๋กœ_์‚ญ์ œํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต = ๋กœ๋“œ๋งต_์‚ญ์ œ(๋กœ๋“œ๋งต_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต, HttpStatus.NO_CONTENT); + } + + @Test + void ๋กœ๋“œ๋งต์„_์‚ญ์ œํ• _๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋”” = 1L; + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต = ๋กœ๋“œ๋งต_์‚ญ์ œ(์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต.as(ErrorResponse.class); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต, HttpStatus.NOT_FOUND); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + + } + + @Test + void ๋กœ๋“œ๋งต์„_์‚ญ์ œํ• _๋•Œ_์ž์‹ ์ด_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์ด_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + ํšŒ์›๊ฐ€์ž…(new MemberJoinRequest("identifier2", "password2!", "name2", "010-1111-2222", GenderType.FEMALE, + LocalDate.now())); + final String ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_๋กœ๊ทธ์ธ_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, + ๋กœ๊ทธ์ธ(new LoginRequest("identifier2", "password2!")).accessToken()); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต = ๋กœ๋“œ๋งต_์‚ญ์ œ(๋กœ๋“œ๋งต_์•„์ด๋””, ๋‹ค๋ฅธ_์‚ฌ์šฉ์ž_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // then + final ErrorResponse ์—๋Ÿฌ_๋ฉ”์„ธ์ง€ = ๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต.as(ErrorResponse.class); + ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(๋กœ๋“œ๋งต_์‚ญ์ œ_์‘๋‹ต, HttpStatus.FORBIDDEN); + assertThat(์—๋Ÿฌ_๋ฉ”์„ธ์ง€.message()).isEqualTo("ํ•ด๋‹น ๋กœ๋“œ๋งต์„ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."); + + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReadIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReadIntegrationTest.java new file mode 100644 index 000000000..e6230bd21 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReadIntegrationTest.java @@ -0,0 +1,217 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์ด์ „์—_๋ฐ›์€_๋กœ๋“œ๋งต์˜_์ œ์ผ๋งˆ์ง€๋ง‰_์•„์ด๋””_์ดํ›„์˜_์กฐ๊ฑด์œผ๋กœ_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋ชจ๋“ _์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.์‚ฌ์ด์ฆˆ_์—†์ด_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.์‚ฌ์ด์ฆˆ๋ณ„๋กœ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapCategoryResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +class RoadmapReadIntegrationTest extends InitIntegrationTest { + + @Test + void ์กด์žฌํ•˜๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_์š”์ฒญํ–ˆ์„_๋•Œ_๋‹จ์ผ_๋กœ๋“œ๋งต_์ •๋ณด_์กฐํšŒ๋ฅผ_์„ฑ๊ณตํ•œ๋‹ค() throws IOException { + //given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ๋‹ค๋ฅธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‹ค๋ฅธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + //when + final ExtractableResponse ๋‹จ์ผ_๋กœ๋“œ๋งต_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + //then + final RoadmapResponse ๋‹จ์ผ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋‹จ์ผ_๋กœ๋“œ๋งต_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.as(new TypeRef<>() { + }); + + assertAll( + () -> assertThat(๋‹จ์ผ_๋กœ๋“œ๋งต_์กฐํšŒ_์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()) + .isEqualTo(HttpStatus.OK.value()), + () -> assertThat(๋‹จ์ผ_๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId()) + .isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””) + ); + } + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_์š”์ฒญํ–ˆ์„_๋•Œ_์กฐํšŒ๋ฅผ_์‹คํŒจํ•œ๋‹ค() { + //given + final Long ์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋”” = 1L; + + //when + final ExtractableResponse ์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•œ๋‹ค(์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””); + + //then + final String ์˜ˆ์™ธ_๋ฉ”์‹œ์ง€ = ์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.asString(); + + assertAll( + () -> assertThat(์š”์ฒญ์—_๋Œ€ํ•œ_์‘๋‹ต.statusCode()).isEqualTo(HttpStatus.NOT_FOUND.value()), + () -> assertThat(์˜ˆ์™ธ_๋ฉ”์‹œ์ง€).contains("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = " + ์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””) + ); + } + + @Test + void ์‚ฌ์ด์ฆˆ_์กฐ๊ฑด์œผ๋กœ_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "thrid roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์‚ฌ์ด์ฆˆ๋ณ„๋กœ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค(10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(2).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ๋กœ๋“œ๋งต_์กฐํšŒ์‹œ_์‚ฌ์ด์ฆˆ_์กฐ๊ฑด์„_์ฃผ์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // when + final List ์˜ˆ์™ธ_๋ฉ”์‹œ์ง€ = ์‚ฌ์ด์ฆˆ_์—†์ด_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(์˜ˆ์™ธ_๋ฉ”์‹œ์ง€.get(0)) + .isEqualTo(new ErrorResponse("์‚ฌ์ด์ฆˆ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.")); + } + + @Test + void ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ฆฌ์ŠคํŠธ๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + // given + final List ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ฆฌ์ŠคํŠธ = testTransactionService.๋ชจ๋“ _๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("IT", "์—ฌ๊ฐ€", "์šด๋™", "์‹œํ—˜", + "๊ฒŒ์ž„"); + + // when + final List ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ = ๋ชจ๋“ _์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์กฐํšŒํ•œ๋‹ค() + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.get(0).id()).isEqualTo(1L); + assertThat(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.get(0).name()).isEqualTo("์—ฌํ–‰"); + for (int index = 1; index < ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.size(); index++) { + assertThat(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.get(index).id()).isEqualTo(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ฆฌ์ŠคํŠธ.get(index - 1).getId()); + assertThat(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.get(index).name()).isEqualTo(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ฆฌ์ŠคํŠธ.get(index - 1).getName()); + } + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "์„ธ๋ฒˆ์จฐ ๋กœ๋“œ๋งต", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final MemberRoadmapResponses ์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ = ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.hasNext()).isFalse(); + assertThat(์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.responses().get(0).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.responses().get(1).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.responses().get(2).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ์‹œ_๋‹ค์Œ_์š”์†Œ๊ฐ€_์กด์žฌํ•˜๋ฉด_hasNext๊ฐ€_true๋กœ_๋ฐ˜ํ™˜๋œ๋‹ค() throws IOException { + // given + ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.LATEST, ๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), 1) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isTrue(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์ด์ „์—_๋ฐ›์•„์˜จ_๋ฆฌ์ŠคํŠธ_์ดํ›„๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "์„ธ๋ฒˆ์จฐ ๋กœ๋“œ๋งต", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final MemberRoadmapResponses ์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ = ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์ด์ „์—_๋ฐ›์€_๋กœ๋“œ๋งต์˜_์ œ์ผ๋งˆ์ง€๋ง‰_์•„์ด๋””_์ดํ›„์˜_์กฐ๊ฑด์œผ๋กœ_์กฐํšŒํ•œ๋‹ค( + ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, 10, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” + ) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.hasNext()).isFalse(); + assertThat(์‚ฌ์šฉ์ž_๋กœ๋“œ๋งต_์‘๋‹ต_๋ฆฌ์ŠคํŠธ.responses().get(0).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReadOrderIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReadOrderIntegrationTest.java new file mode 100644 index 000000000..67c414c4a --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReadOrderIntegrationTest.java @@ -0,0 +1,418 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์˜ค๋Š˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.์ •๋ ฌ๋œ_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import io.restassured.common.mapper.TypeRef; +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RoadmapReadOrderIntegrationTest extends InitIntegrationTest { + + @Test + void ํŠน์ •_์นดํ…Œ๊ณ ๋ฆฌ์˜_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ๊ธฐ๋ณธ, ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌํ–‰, ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌ๊ฐ€ + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.LATEST, ๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ํŠน์ •_์นดํ…Œ๊ณ ๋ฆฌ์˜_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_๋ฆฌ๋ทฐ_ํ‰์ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ๊ธฐ๋ณธ, ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌํ–‰, ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌ๊ฐ€ + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ1 = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier2", "๋‹‰๋„ค์ž„2"); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์ฐธ์—ฌ์ž์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ1, ๋กœ๋“œ๋งต_์‘๋‹ต); + + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์˜ ๋ฆฌ๋ทฐ ์ถ”๊ฐ€ + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 4.0); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ1, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2 = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier3", "๋‹‰๋„ค์ž„3"); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์ฐธ์—ฌ์ž์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์˜ ๋ฆฌ๋ทฐ ์ถ”๊ฐ€ + final RoadmapReviewSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.REVIEW_RATE, ๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), + 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ํŠน์ •_์นดํ…Œ๊ณ ๋ฆฌ์˜_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_๊ณจ๋ฃธ_๊ฐœ์ˆ˜์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ๊ธฐ๋ณธ, ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌํ–‰, ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌ๊ฐ€ + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์— ๋Œ€ํ•œ ๊ณจ๋ฃธ ์ƒ์„ฑ + ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + // ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.GOAL_ROOM_COUNT, + ๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ํŠน์ •_์นดํ…Œ๊ณ ๋ฆฌ์˜_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์ฐธ์—ฌ์ž์ˆ˜_์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ๊ธฐ๋ณธ, ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌํ–‰, ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌ๊ฐ€ + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์— ๋Œ€ํ•œ ๊ณจ๋ฃธ ์ƒ์„ฑ ๋ฐ ์ฐธ๊ฐ€ ์‹ ์ฒญ + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋”” = ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier2", "๋‹‰๋„ค์ž„2"); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋””); + + // ๋‹ค๋ฅธ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.PARTICIPANT_COUNT, + ๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ์ „์ฒด_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.LATEST, 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(2).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ์ „์ฒด_์นดํ…Œ๊ณ ๋ฆฌ์˜_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_๋ฆฌ๋ทฐ_ํ‰์ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ๊ธฐ๋ณธ, ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌํ–‰, ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌ๊ฐ€ + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ1 = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier2", "๋‹‰๋„ค์ž„2"); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์ฐธ์—ฌ์ž์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ1, ๋กœ๋“œ๋งต_์‘๋‹ต); + + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์˜ ๋ฆฌ๋ทฐ ์ถ”๊ฐ€ + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 4.0); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ1, ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2 = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier3", "๋‹‰๋„ค์ž„3"); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์ฐธ์—ฌ์ž์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์˜ ๋ฆฌ๋ทฐ ์ถ”๊ฐ€ + final RoadmapReviewSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ3 = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier4", "๋‹‰๋„ค์ž„4"); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์ฐธ์—ฌ์ž์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ3, ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + // ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์˜ ๋ฆฌ๋ทฐ ์ถ”๊ฐ€ + final RoadmapReviewSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 3.5); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ3, ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””, ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.REVIEW_RATE, 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(2).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ์ „์ฒด_์นดํ…Œ๊ณ ๋ฆฌ์˜_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_๊ณจ๋ฃธ_๊ฐœ์ˆ˜์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ๊ธฐ๋ณธ, ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌํ–‰, ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌ๊ฐ€ + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์— ๋Œ€ํ•œ ๊ณจ๋ฃธ ์ƒ์„ฑ + ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + // ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์— ๋Œ€ํ•œ ๊ณจ๋ฃธ ์ƒ์„ฑ + ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.GOAL_ROOM_COUNT, 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(2).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ์ „์ฒด_์นดํ…Œ๊ณ ๋ฆฌ์˜_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์ฐธ์—ฌ์ž์ˆ˜_์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + // ๊ธฐ๋ณธ, ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌํ–‰, ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต - ์—ฌ๊ฐ€ + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์— ๋Œ€ํ•œ ๊ณจ๋ฃธ ์ƒ์„ฑ ๋ฐ ์ฐธ๊ฐ€ ์‹ ์ฒญ + final Long ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋”” = ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier2", "๋‹‰๋„ค์ž„2"); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋””); + + // ๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต ์ƒ์„ฑ + final RoadmapCategory ๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapSaveRequest ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๋‹ค๋ฅธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + // ์„ธ ๋ฒˆ์งธ ๋กœ๋“œ๋งต์— ๋Œ€ํ•œ ๊ณจ๋ฃธ ์ƒ์„ฑ ๋ฐ ์ฐธ๊ฐ€ ์‹ ์ฒญ + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋”” = ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์‘๋‹ต); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2 = ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค("identifier3", "๋‹‰๋„ค์ž„3"); + ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋””, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ2); + ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_์•„์ด๋””); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ •๋ ฌ๋œ_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(RoadmapOrderType.PARTICIPANT_COUNT, 10) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(2).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + private Long ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต) { + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + return ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + } + + private void ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์ฐธ์—ฌ์ž์—_์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค(final String ์•ก์„ธ์Šค_ํ† ํฐ, final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต) { + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberInformationResponse ๋ฆฌ๋”_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(๋ฆฌ๋”_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReviewCreateIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReviewCreateIntegrationTest.java new file mode 100644 index 000000000..6d88168b1 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReviewCreateIntegrationTest.java @@ -0,0 +1,277 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์˜ค๋Š˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.ํšŒ์›๊ฐ€์ž…; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +class RoadmapReviewCreateIntegrationTest extends InitIntegrationTest { + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberInformationResponse ๋ฆฌ๋”_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(๋ฆฌ๋”_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + + // when + final ExtractableResponse ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + assertThat(๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.statusCode()) + .isEqualTo(HttpStatus.CREATED.value()); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋ณ„์ ์ด_null์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(์‚ฌ์šฉ์ž_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest(" ", null); + + // when + final ExtractableResponse ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, 1L, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + final List ์˜ˆ์™ธ_์‘๋‹ต = ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.as(new TypeRef<>() { + }); + assertThat(๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์˜ˆ์™ธ_์‘๋‹ต.get(0).message()).isEqualTo("๋ณ„์ ์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋ณ„์ ์ด_์ž˜๋ชป๋œ_๊ฐ’์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(์‚ฌ์šฉ์ž_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 2.4); + + // when + final ExtractableResponse ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.as(ErrorResponse.class); + assertThat(๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์˜ˆ์™ธ_์‘๋‹ต.message()).isEqualTo("๋ณ„์ ์€ 0๋ถ€ํ„ฐ 5๊นŒ์ง€ 0.5 ๋‹จ์œ„๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋‚ด์šฉ์ด_1000์ž๊ฐ€_๋„˜์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(์‚ฌ์šฉ์ž_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + + final String ์—„์ฒญ_๊ธด_๋ฆฌ๋ทฐ_๋‚ด์šฉ = "a".repeat(1001); + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest(์—„์ฒญ_๊ธด_๋ฆฌ๋ทฐ_๋‚ด์šฉ, 5.0); + + // when + final ExtractableResponse ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.as(ErrorResponse.class); + assertThat(๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์˜ˆ์™ธ_์‘๋‹ต.message()).isEqualTo("๋ฆฌ๋ทฐ๋Š” ์ตœ๋Œ€ 1000๊ธ€์ž๊นŒ์ง€ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + + // when + final ExtractableResponse ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, 1L, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.as(ErrorResponse.class); + assertThat(๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.statusCode()).isEqualTo(HttpStatus.NOT_FOUND.value()); + assertThat(์˜ˆ์™ธ_์‘๋‹ต.message()).isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์ด_์—†๋‹ค๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + + // when + final ExtractableResponse ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.as(ErrorResponse.class); + assertThat(๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์˜ˆ์™ธ_์‘๋‹ต.message()).isEqualTo("๋กœ๋“œ๋งต์— ๋Œ€ํ•ด์„œ ์™„๋ฃŒ๋œ ๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. roadmapId = " + ๋กœ๋“œ๋งต_์•„์ด๋”” + + " memberIdentifier = identifier2"); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_๋กœ๋“œ๋งต_์ƒ์„ฑ์ž๊ฐ€_๋ฆฌ๋ทฐ๋ฅผ_๋‹ฌ๋ ค๊ณ _ํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(์‚ฌ์šฉ์ž_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + + // when + final ExtractableResponse ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.as(ErrorResponse.class); + assertThat(๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ_๊ฒฐ๊ณผ.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์˜ˆ์™ธ_์‘๋‹ต.message()).isEqualTo("๋กœ๋“œ๋งต ์ƒ์„ฑ์ž๋Š” ๋ฆฌ๋ทฐ๋ฅผ ๋‹ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. roadmapId = " + ๋กœ๋“œ๋งต_์•„์ด๋”” + + " memberId = " + ๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ์‹œ_์ด๋ฏธ_๋ฆฌ๋ทฐ๋ฅผ_๋‹จ์ ์ด_์žˆ์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "follower", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + final Long ํŒ”๋กœ์›Œ_์•„์ด๋”” = ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(์‚ฌ์šฉ์ž_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + + // when + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // when + final ExtractableResponse ๋‘๋ฒˆ์งธ_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ๊ฒฐ๊ณผ = ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // then + final ErrorResponse ์˜ˆ์™ธ_์‘๋‹ต = ๋‘๋ฒˆ์งธ_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ๊ฒฐ๊ณผ.as(ErrorResponse.class); + assertThat(๋‘๋ฒˆ์งธ_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ๊ฒฐ๊ณผ.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); + assertThat(์˜ˆ์™ธ_์‘๋‹ต.message()).isEqualTo("์ด๋ฏธ ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. roadmapId = " + ๋กœ๋“œ๋งต_์•„์ด๋”” + + " memberId = " + ํŒ”๋กœ์›Œ_์•„์ด๋””); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReviewReadIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReviewReadIntegrationTest.java new file mode 100644 index 000000000..63250b791 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapReviewReadIntegrationTest.java @@ -0,0 +1,174 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.ํšŒ์›๊ฐ€์ž…; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ๋ฅผ_์กฐํšŒํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.CustomScrollRequest; +import co.kirikiri.service.dto.ErrorResponse; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import co.kirikiri.service.dto.member.response.MemberResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import io.restassured.common.mapper.TypeRef; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +class RoadmapReviewReadIntegrationTest extends InitIntegrationTest { + + @Test + void ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๋ฆฌ๋ทฐ๋ฅผ_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "leader", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ๋ฆฌ๋”_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ๋ฆฌ๋”_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(๋ฆฌ๋”_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ๋ฆฌ๋”_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๋ฆฌ๋”_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberJoinRequest ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier3", "paswword2@", + "follow1", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ1_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ1_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ1_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberJoinRequest ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier4", "paswword2@", + "follow2", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ2_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ2_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ2_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(๋ฆฌ๋”_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ1_์ •๋ณด, ํŒ”๋กœ์›Œ2_์ •๋ณด); + + final RoadmapReviewSaveRequest ๋ฆฌ๋”_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("๋ฆฌ๋” ๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0); + final RoadmapReviewSaveRequest ํŒ”๋กœ์›Œ1_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("ํŒ”๋กœ์›Œ1 ๋ฆฌ๋ทฐ ๋‚ด์šฉ", 1.5); + final RoadmapReviewSaveRequest ํŒ”๋กœ์›Œ2_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ = new RoadmapReviewSaveRequest("ํŒ”๋กœ์›Œ2 ๋ฆฌ๋ทฐ ๋‚ด์šฉ", 3.0); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(๋ฆฌ๋”_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ๋ฆฌ๋”_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ1_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ํŒ”๋กœ์›Œ1_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ2_์•ก์„ธ์Šค_ํ† ํฐ, ๋กœ๋“œ๋งต_์•„์ด๋””, ํŒ”๋กœ์›Œ2_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ); + + // when + final CustomScrollRequest ์ฒซ๋ฒˆ์งธ_์Šคํฌ๋กค_์š”์ฒญ = new CustomScrollRequest(null, 2); + final ExtractableResponse ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต = ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ๋ฅผ_์กฐํšŒํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””, ์ฒซ๋ฒˆ์งธ_์Šคํฌ๋กค_์š”์ฒญ); + final List ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’ = jsonToClass(์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต.asString(), + new TypeReference<>() { + }); + + final CustomScrollRequest ๋‘๋ฒˆ์งธ_์Šคํฌ๋กค_์š”์ฒญ = new CustomScrollRequest(์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’.get(1).id(), 2); + final ExtractableResponse ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต = ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ๋ฅผ_์กฐํšŒํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””, ๋‘๋ฒˆ์งธ_์Šคํฌ๋กค_์š”์ฒญ); + final List ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’ = jsonToClass(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต.asString(), + new TypeReference<>() { + }); + + // then + final List ์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์š”์ฒญ_์˜ˆ์ƒ๊ฐ’ = List.of( + new RoadmapReviewResponse(3L, new MemberResponse(4L, "follow2", ํŒ”๋กœ์›Œ2_์ •๋ณด.profileImageUrl()), + LocalDateTime.now(), "ํŒ”๋กœ์›Œ2 ๋ฆฌ๋ทฐ ๋‚ด์šฉ", 3.0), + new RoadmapReviewResponse(2L, new MemberResponse(3L, "follow1", ํŒ”๋กœ์›Œ1_์ •๋ณด.profileImageUrl()), + LocalDateTime.now(), "ํŒ”๋กœ์›Œ1 ๋ฆฌ๋ทฐ ๋‚ด์šฉ", 1.5)); + + final List ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์š”์ฒญ_์˜ˆ์ƒ๊ฐ’ = List.of( + new RoadmapReviewResponse(1L, new MemberResponse(2L, "leader", ๋ฆฌ๋”_์ •๋ณด.profileImageUrl()), + LocalDateTime.now(), "๋ฆฌ๋” ๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0)); + + assertAll( + () -> assertThat(์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’) + .usingRecursiveComparison() + .ignoringFields("createdAt") + .isEqualTo(์ฒซ๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์š”์ฒญ_์˜ˆ์ƒ๊ฐ’), + () -> assertThat(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’) + .usingRecursiveComparison() + .ignoringFields("createdAt") + .isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์š”์ฒญ_์˜ˆ์ƒ๊ฐ’) + ); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์š”์ฒญ_์‹œ_์ž‘์„ฑ๋œ_๋ฆฌ๋ทฐ๊ฐ€_์—†๋‹ค๋ฉด_๋นˆ_๊ฐ’์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws IOException { + // given + final Long ๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””); + + final MemberJoinRequest ๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier2", "paswword2@", + "leader", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ๋ฆฌ๋”_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(๋ฆฌ๋”_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ๋ฆฌ๋”_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(๋ฆฌ๋”_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ๋ฆฌ๋”_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๋ฆฌ๋”_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest("identifier3", "paswword2@", + "follow1", "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ).as(new TypeRef<>() { + }); + + final GoalRoom ๊ณจ๋ฃธ = testTransactionService.์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(๋กœ๋“œ๋งต_์‘๋‹ต); + testTransactionService.๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(๋ฆฌ๋”_์ •๋ณด, ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ_์ •๋ณด); + + final CustomScrollRequest ์Šคํฌ๋กค_์š”์ฒญ = new CustomScrollRequest(null, 10); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต = ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ๋ฅผ_์กฐํšŒํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””, ์Šคํฌ๋กค_์š”์ฒญ); + + // then + final List ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’ = jsonToClass(๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต.asString(), + new TypeReference<>() { + }); + + assertThat(๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’).isEmpty(); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์š”์ฒญ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_์š”์ฒญ_์‹œ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws JsonProcessingException { + //when + final CustomScrollRequest ์Šคํฌ๋กค_์š”์ฒญ = new CustomScrollRequest(null, 10); + + // when + final ExtractableResponse ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต = ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ๋ฅผ_์กฐํšŒํ•œ๋‹ค(1L, ์Šคํฌ๋กค_์š”์ฒญ); + + // then + final ErrorResponse ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’ = jsonToClass(๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต.asString(), + new TypeReference<>() { + }); + + assertAll( + () -> assertThat(๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต.statusCode()) + .isEqualTo(HttpStatus.NOT_FOUND.value()), + () -> assertThat(๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‘๋‹ต๊ฐ’.message()) + .isEqualTo("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1") + ); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapSchedulerIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapSchedulerIntegrationTest.java new file mode 100644 index 000000000..406714c21 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapSchedulerIntegrationTest.java @@ -0,0 +1,141 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์˜ค๋Š˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์‚ญ์ œ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import co.kirikiri.service.RoadmapScheduler; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class RoadmapSchedulerIntegrationTest extends InitIntegrationTest { + + private static final LocalDate ํ˜„์žฌ๋ถ€ํ„ฐ_3๊ฐœ์›”_1์ผ_์ „ = ์˜ค๋Š˜.minusMonths(3).minusDays(1); + + private final RoadmapScheduler roadmapScheduler; + private final RoadmapRepository roadmapRepository; + + public RoadmapSchedulerIntegrationTest(final RoadmapScheduler roadmapScheduler, + final RoadmapRepository roadmapRepository) { + this.roadmapScheduler = roadmapScheduler; + this.roadmapRepository = roadmapRepository; + } + + @Test + void ์‚ญ์ œ๋œ_์ƒํƒœ์˜_๋กœ๋“œ๋งต์„_์‚ญ์ œ์‹œ_๋ชจ๋“ _๊ณจ๋ฃธ์ด_์ข…๋ฃŒ๋œ์ง€_3๊ฐœ์›”์ด_์ง€๋‚ฌ์œผ๋ฉด_์ •์ƒ์ ์œผ๋กœ_์‚ญ์ œํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋””1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ2 = new GoalRoomTodoRequest("๊ณจ๋ฃธ ํˆฌ๋‘", ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ2 = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ2 = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ2, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ2); + + final Long ๊ณจ๋ฃธ_์•„์ด๋””2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ2, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + ๋กœ๋“œ๋งต_์‚ญ์ œ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + testTransactionService.๊ณจ๋ฃธ์˜_์ƒํƒœ์™€_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””1, GoalRoomStatus.COMPLETED, ํ˜„์žฌ๋ถ€ํ„ฐ_3๊ฐœ์›”_1์ผ_์ „); + testTransactionService.๊ณจ๋ฃธ์˜_์ƒํƒœ์™€_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””2, GoalRoomStatus.COMPLETED, ํ˜„์žฌ๋ถ€ํ„ฐ_3๊ฐœ์›”_1์ผ_์ „); + + // when + roadmapScheduler.deleteRoadmaps(); + + // then + assertThat(roadmapRepository.findAll()).hasSize(0); + } + + @Test + void ์‚ญ์ œ๋œ_์ƒํƒœ์˜_๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_์ข…๋ฃŒ๋˜์ง€_์•Š์€_๊ณจ๋ฃธ์ด_์žˆ์œผ๋ฉด_์‚ญ์ œ๋˜์ง€_์•Š๋Š”๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋””1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ2 = new GoalRoomTodoRequest("๊ณจ๋ฃธ ํˆฌ๋‘", ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ2 = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ2 = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ2, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ2); + + final Long ๊ณจ๋ฃธ_์•„์ด๋””2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ2, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + ๋กœ๋“œ๋งต_์‚ญ์ œ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + testTransactionService.๊ณจ๋ฃธ์˜_์ƒํƒœ์™€_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””1, GoalRoomStatus.COMPLETED, ํ˜„์žฌ๋ถ€ํ„ฐ_3๊ฐœ์›”_1์ผ_์ „); + + // when + roadmapScheduler.deleteRoadmaps(); + + // then + assertThat(roadmapRepository.findAll()).hasSize(1); + } + + @Test + void ์‚ญ์ œ๋œ_์ƒํƒœ์˜_๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_์ข…๋ฃŒ๋œ์ง€_3๊ฐœ์›”์ด_์ง€๋‚˜์ง€_์•Š์€_๊ณจ๋ฃธ์ด_์žˆ์œผ๋ฉด_์‚ญ์ œ๋˜์ง€_์•Š๋Š”๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต = ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + + final Long ๊ณจ๋ฃธ_์•„์ด๋””1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ2 = new GoalRoomTodoRequest("๊ณจ๋ฃธ ํˆฌ๋‘", ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ2 = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ2 = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ2, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ2); + + final Long ๊ณจ๋ฃธ_์•„์ด๋””2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ2, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + ๋กœ๋“œ๋งต_์‚ญ์ œ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + testTransactionService.๊ณจ๋ฃธ์˜_์ƒํƒœ์™€_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””1, GoalRoomStatus.COMPLETED, ํ˜„์žฌ๋ถ€ํ„ฐ_3๊ฐœ์›”_1์ผ_์ „); + testTransactionService.๊ณจ๋ฃธ์˜_์ƒํƒœ์™€_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””2, GoalRoomStatus.COMPLETED, ์˜ค๋Š˜); + + // when + roadmapScheduler.deleteRoadmaps(); + + // then + assertThat(roadmapRepository.findAll()).hasSize(1); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapSearchIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapSearchIntegrationTest.java new file mode 100644 index 000000000..9d9218533 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/RoadmapSearchIntegrationTest.java @@ -0,0 +1,103 @@ +package co.kirikiri.integration; + +import static co.kirikiri.integration.fixture.MemberAPIFixture.์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.๋กœ๋“œ๋งต_์ƒ์„ฑ; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.์ œ๋ชฉ์œผ๋กœ_์ตœ์‹ ์ˆœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_๊ฒ€์ƒ‰ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.ํฌ๋ฆฌ์—์ดํ„ฐ_๋‹‰๋„ค์ž„์œผ๋กœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.RoadmapAPIFixture.ํƒœ๊ทธ_์ด๋ฆ„์œผ๋กœ_์ตœ์‹ ์ˆœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_๊ฒ€์ƒ‰ํ•œ๋‹ค; +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.integration.helper.InitIntegrationTest; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import io.restassured.common.mapper.TypeRef; +import java.io.IOException; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RoadmapSearchIntegrationTest extends InitIntegrationTest { + + @Test + void ๋กœ๋“œ๋งต์„_์ œ๋ชฉ์„_๊ธฐ์ค€์œผ๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค() throws IOException { + // given + ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "third roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ์ œ๋ชฉ์œผ๋กœ_์ตœ์‹ ์ˆœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_๊ฒ€์ƒ‰ํ•œ๋‹ค(10, "roadmap") + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ๋กœ๋“œ๋งต์„_ํฌ๋ฆฌ์—์ดํ„ฐ_๋‹‰๋„ค์ž„_๊ธฐ์ค€์œผ๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค() throws IOException { + // given + final Long ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด = ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ).as(new TypeRef<>() { + }); + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("๋‹ค๋ฅธ ํƒœ๊ทธ1"))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ํฌ๋ฆฌ์—์ดํ„ฐ_๋‹‰๋„ค์ž„์œผ๋กœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(10, ์‚ฌ์šฉ์ž_์ •๋ณด.nickname()) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } + + @Test + void ๋กœ๋“œ๋งต์„_ํƒœ๊ทธ_์ด๋ฆ„์„_๊ธฐ์ค€์œผ๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค() throws IOException { + // given + final String ํƒœ๊ทธ_์ด๋ฆ„ = "tag name"; + + ๋กœ๋“œ๋งต_์ƒ์„ฑ(๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "second roadmap", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest(ํƒœ๊ทธ_์ด๋ฆ„))); + final Long ๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + final RoadmapSaveRequest ์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "์„ธ๋ฒˆ์จฐ ๋กœ๋“œ๋งต", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋‹ค๋ฅธ ๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋‹ค๋ฅธ ๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest(ํƒœ๊ทธ_์ด๋ฆ„))); + final Long ์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋”” = ๋กœ๋“œ๋งต_์ƒ์„ฑ(์„ธ๋ฒˆ์จฐ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + + // when + final RoadmapForListResponses ๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต = ํƒœ๊ทธ_์ด๋ฆ„์œผ๋กœ_์ตœ์‹ ์ˆœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_๊ฒ€์ƒ‰ํ•œ๋‹ค(10, ํƒœ๊ทธ_์ด๋ฆ„) + .response() + .as(new TypeRef<>() { + }); + + // then + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.hasNext()).isFalse(); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(0).roadmapId()).isEqualTo(์„ธ๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + assertThat(๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์‘๋‹ต.responses().get(1).roadmapId()).isEqualTo(๋‘๋ฒˆ์งธ_๋กœ๋“œ๋งต_์•„์ด๋””); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/AuthenticationAPIFixture.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/AuthenticationAPIFixture.java new file mode 100644 index 000000000..09e803db7 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/AuthenticationAPIFixture.java @@ -0,0 +1,48 @@ +package co.kirikiri.integration.fixture; + +import static co.kirikiri.integration.fixture.CommonFixture.API_PREFIX; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_IDENTIFIER; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_PASSWORD; +import static io.restassured.RestAssured.given; + +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.auth.request.ReissueTokenRequest; +import co.kirikiri.service.dto.auth.response.AuthenticationResponse; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.springframework.http.MediaType; + +public class AuthenticationAPIFixture { + + public static ExtractableResponse ์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•˜๋Š”_๋กœ๊ทธ์ธ(final LoginRequest ๋กœ๊ทธ์ธ_์š”์ฒญ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .body(๋กœ๊ทธ์ธ_์š”์ฒญ) + .post(API_PREFIX + "/auth/login") + .then() + .log().all() + .extract(); + } + + public static AuthenticationResponse ๋กœ๊ทธ์ธ(final LoginRequest ๋กœ๊ทธ์ธ_์š”์ฒญ) { + return ์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•˜๋Š”_๋กœ๊ทธ์ธ(๋กœ๊ทธ์ธ_์š”์ฒญ).as(AuthenticationResponse.class); + } + + public static AuthenticationResponse ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ() { + final LoginRequest request = new LoginRequest(DEFAULT_IDENTIFIER, DEFAULT_PASSWORD); + return ๋กœ๊ทธ์ธ(request); + } + + public static ExtractableResponse ํ† ํฐ_์žฌ๋ฐœํ–‰(final ReissueTokenRequest ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .body(ํ† ํฐ_์žฌ๋ฐœํ–‰_์š”์ฒญ) + .post(API_PREFIX + "/auth/reissue") + .then() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .log().all() + .extract(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/CommonFixture.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/CommonFixture.java new file mode 100644 index 000000000..1442dfba1 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/CommonFixture.java @@ -0,0 +1,24 @@ +package co.kirikiri.integration.fixture; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; + +public class CommonFixture { + + public static final String BEARER_TOKEN_FORMAT = "Bearer %s"; + public static final String AUTHORIZATION = "Authorization"; + public static final String LOCATION = "Location"; + public static String API_PREFIX = "/api"; + + public static void ์‘๋‹ต_์ƒํƒœ_์ฝ”๋“œ_๊ฒ€์ฆ(final ExtractableResponse ์‘๋‹ต, final HttpStatus http_์ƒํƒœ) { + assertThat(์‘๋‹ต.statusCode()).isEqualTo(http_์ƒํƒœ.value()); + } + + public static Long ์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(final ExtractableResponse ์‘๋‹ต) { + return Long.parseLong(์‘๋‹ต.header(HttpHeaders.LOCATION).split("/")[3]); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/GoalRoomAPIFixture.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/GoalRoomAPIFixture.java new file mode 100644 index 000000000..87c56b030 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/GoalRoomAPIFixture.java @@ -0,0 +1,303 @@ +package co.kirikiri.integration.fixture; + +import static co.kirikiri.integration.fixture.CommonFixture.API_PREFIX; +import static co.kirikiri.integration.fixture.CommonFixture.AUTHORIZATION; +import static co.kirikiri.integration.fixture.CommonFixture.LOCATION; +import static io.restassured.RestAssured.given; + +import co.kirikiri.service.dto.goalroom.request.CheckFeedRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import io.restassured.common.mapper.TypeRef; +import io.restassured.http.Header; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; + +public class GoalRoomAPIFixture { + + public static final LocalDate ์˜ค๋Š˜ = LocalDate.now(); + public static final LocalDate ์‹ญ์ผ_ํ›„ = ์˜ค๋Š˜.plusDays(10L); + public static final LocalDate ์ด์‹ญ์ผ_ํ›„ = ์‹ญ์ผ_ํ›„.plusDays(10L); + public static final LocalDate ์‚ผ์‹ญ์ผ_ํ›„ = ์ด์‹ญ์ผ_ํ›„.plusDays(10L); + public static final String ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„ = "GOAL_ROOM_NAME"; + public static final int ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์› = 20; + public static final String ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ  = "GOAL_ROOM_TO_DO_CONTENT"; + public static final int ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜ = (int) ChronoUnit.DAYS.between(์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + + public static Long ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, final String ์•ก์„ธ์Šค_ํ† ํฐ) { + final String ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_Location_ํ—ค๋” = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ์•ก์„ธ์Šค_ํ† ํฐ).response().getHeader(LOCATION); + return Long.parseLong(๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต_Location_ํ—ค๋”.substring(16)); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ(final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, final String ์•ก์„ธ์Šค_ํ† ํฐ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .body(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ) + .header(new Header(HttpHeaders.AUTHORIZATION, ์•ก์„ธ์Šค_ํ† ํฐ)) + .post(API_PREFIX + "/goal-rooms") + .then() + .log().all() + .extract(); + } + + public static Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์ƒ์„ฑ(final String ์•ก์„ธ์Šค_ํ† ํฐ, final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต) { + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, + ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final String Location_ํ—ค๋” = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ์•ก์„ธ์Šค_ํ† ํฐ).response().header(LOCATION); + return Long.parseLong(Location_ํ—ค๋”.substring(16)); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ(final Long ๊ณจ๋ฃธ_์•„์ด๋””, final String ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ) { + return given() + .log().all() + .header(AUTHORIZATION, ํŒ”๋กœ์›Œ_์•ก์„ธ์Šค_ํ† ํฐ) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .post(API_PREFIX + "/goal-rooms/{goalRoomId}/join", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_๋‚˜๊ฐ€๊ธฐ_์š”์ฒญ(final Long ๊ณจ๋ฃธ_์•„์ด๋””, final String ๊ณจ๋ฃธ_์ฐธ์—ฌ์ž_์•ก์„ธ์Šค_ํ† ํฐ) { + return given() + .log().all() + .header(AUTHORIZATION, ๊ณจ๋ฃธ_์ฐธ์—ฌ์ž_์•ก์„ธ์Šค_ํ† ํฐ) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .post(API_PREFIX + "/goal-rooms/{goalRoomId}/leave", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ_์š”์ฒญ(final Long roadmapId, final LocalDateTime lastValue, + final int size, + final String filterCond) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .pathParam("roadmapId", roadmapId) + .param("lastCreatedAt", lastValue) + .param("size", size) + .param("filterCond", filterCond) + .when() + .get(API_PREFIX + "/roadmaps/{roadmapId}/goal-rooms", roadmapId) + .then().log().all() + .extract(); + } + + public static Long ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ƒ์„ฑ(final String ์•ก์„ธ์Šค_ํ† ํฐ, final Long ๋กœ๋“œ๋งต_์•„์ด๋””, final Long ๋กœ๋“œ๋งต_๋…ธ๋“œ_์•„์ด๋””) { + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_๋…ธ๋“œ_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์•„์ด๋””, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final ExtractableResponse ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต = ๊ณจ๋ฃธ_์ƒ์„ฑ(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ์•ก์„ธ์Šค_ํ† ํฐ); + final String Location_ํ—ค๋” = ๊ณจ๋ฃธ_์ƒ์„ฑ_์‘๋‹ต.response().header("Location"); + return Long.parseLong(Location_ํ—ค๋”.substring(16)); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€(final String ์•ก์„ธ์Šค_ํ† ํฐ, final Long ๊ณจ๋ฃธ_์•„์ด๋””, + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .body(๊ณจ๋ฃธ_ํˆฌ๋‘_๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ) + .header(new Header(HttpHeaders.AUTHORIZATION, ์•ก์„ธ์Šค_ํ† ํฐ)) + .post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static Long ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€ํ›„_์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(final String ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด, final Long ๊ณจ๋ฃธ_์•„์ด๋””) { + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final String ์‘๋‹ต_ํ—ค๋”๊ฐ’ = ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€(๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด, ๊ณจ๋ฃธ_์•„์ด๋””, ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€_์š”์ฒญ) + .response() + .getHeader(LOCATION) + .replace(API_PREFIX + "/goal-rooms/" + ๊ณจ๋ฃธ_์•„์ด๋”” + "/todos/", ""); + return Long.valueOf(์‘๋‹ต_ํ—ค๋”๊ฐ’); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค(final String ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด, final Long ๊ณจ๋ฃธ_์•„์ด๋””, + final Long ํˆฌ๋‘_์•„์ด๋””) { + return given() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด) + .log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .post(API_PREFIX + "/goal-rooms/{goalRoomId}/todos/{todoId}", ๊ณจ๋ฃธ_์•„์ด๋””, ํˆฌ๋‘_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก(final Long ๊ณจ๋ฃธ_์•„์ด๋””, final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด, + final CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ, final String ๋กœ๊ทธ์ธ_ํ† ํฐ) + throws IOException { + return given().log().all() + .multiPart(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getName(), ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getOriginalFilename(), + ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getBytes(), ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getContentType()) + .formParam("description", ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ.description()) + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .when() + .post(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค(final String ๋กœ๊ทธ์ธ_ํ† ํฐ, final Long ๊ณจ๋ฃธ_์•„์ด๋””) { + final ExtractableResponse ๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต = given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .header(new Header(HttpHeaders.AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ)) + .post(API_PREFIX + "/goal-rooms/{goalRoomId}/start", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + return ๊ณจ๋ฃธ_์‹œ์ž‘_์š”์ฒญ_์‘๋‹ต; + } + + public static ExtractableResponse ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ •๋ ฌ_๊ธฐ์ค€์—†์ด_์กฐํšŒ(final Long ๊ณจ๋ฃธ_์•„์ด๋””, final String ๋กœ๊ทธ์ธ_ํ† ํฐ) { + return given().log().all() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}/members", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static MemberGoalRoomResponse ์‚ฌ์šฉ์ž์˜_ํŠน์ •_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค(final String ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด, final Long ๊ณจ๋ฃธ_์•„์ด๋””) { + return given().log().all() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}/me", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract() + .as(new TypeRef<>() { + }); + } + + public static ExtractableResponse ์ธ์ฆ_ํ”ผ๋“œ_์ „์ฒด_์กฐํšŒ_์š”์ฒญ(final String ์•ก์„ธ์Šค_ํ† ํฐ, final Long ๊ณจ๋ฃธ_์•„์ด๋””) { + return given().log().all() + .header(AUTHORIZATION, ์•ก์„ธ์Šค_ํ† ํฐ) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}/checkFeeds", ๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒ(final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””) { + return given() + .log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}", ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_์•„์ด๋””์™€_ํ† ํฐ์œผ๋กœ_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒ(final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, final String ๋กœ๊ทธ์ธ_ํ† ํฐ) { + return given() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}", ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ(final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, final String ๋กœ๊ทธ์ธ_ํ† ํฐ) { + return given() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}/todos", ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ์‚ฌ์šฉ์ž์˜_๋ชจ๋“ _๊ณจ๋ฃธ_์กฐํšŒ(final String ๋กœ๊ทธ์ธ_ํ† ํฐ) { + return given().log().all() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .when() + .get(API_PREFIX + "/goal-rooms/me") + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ_์ค‘_๊ณจ๋ฃธ_์ง„ํ–‰_์ƒํƒœ์—_๋”ฐ๋ผ_๋ชฉ๋ก์„_์กฐํšŒ(final String ๋กœ๊ทธ์ธ_ํ† ํฐ, + final String ๊ณจ๋ฃธ_์ง„ํ–‰_์ƒํƒœ) { + return given().log().all() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .queryParam("statusCond", ๊ณจ๋ฃธ_์ง„ํ–‰_์ƒํƒœ) + .when() + .get(API_PREFIX + "/goal-rooms/me") + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ_๋…ธ๋“œ_์กฐํšŒ(final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, final String ๋กœ๊ทธ์ธ_ํ† ํฐ) { + return given() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}/nodes", ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๊ณจ๋ฃธ์˜_์‚ฌ์šฉ์ž_์ •๋ณด๋ฅผ_์ „์ฒด_์กฐํšŒ(final Long ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, final String ๋กœ๊ทธ์ธ_ํ† ํฐ, + final String ์ •๋ ฌ์กฐ๊ฑด) { + return given().log().all() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/goal-rooms/{goalRoomId}/members?sortCond={sortType}", ๊ธฐ๋ณธ_๊ณจ๋ฃธ_์•„์ด๋””, ์ •๋ ฌ์กฐ๊ฑด) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๋กœ๋“œ๋งต_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋ชฉ๋ก_์กฐํšŒ(final String ๋กœ๊ทธ์ธ_ํ† ํฐ, final Long ๋กœ๋“œ๋งต_์•„์ด๋””, + final String ๊ณจ๋ฃธ_์ •๋ ฌ_์กฐ๊ฑด, final Integer ์‚ฌ์ด์ฆˆ) { + return given().log().all() + .header(AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .when() + .get(API_PREFIX + + "/roadmaps/{roadmapId}/goal-rooms?filterCond={orderType}&size={size}", + ๋กœ๋“œ๋งต_์•„์ด๋””, ๊ณจ๋ฃธ_์ •๋ ฌ_์กฐ๊ฑด, ์‚ฌ์ด์ฆˆ) + .then() + .log().all() + .extract(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/MemberAPIFixture.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/MemberAPIFixture.java new file mode 100644 index 000000000..1bb9e43f2 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/MemberAPIFixture.java @@ -0,0 +1,79 @@ +package co.kirikiri.integration.fixture; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.API_PREFIX; +import static co.kirikiri.integration.fixture.CommonFixture.AUTHORIZATION; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static io.restassured.RestAssured.given; + +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import java.time.LocalDate; +import java.time.Month; +import org.springframework.http.MediaType; + +public class MemberAPIFixture { + + public static final String DEFAULT_IDENTIFIER = "identifier1"; + public static final String DEFAULT_PASSWORD = "password1!"; + public static final String DEFAULT_NICKNAME = "nickname"; + public static final String DEFAULT_PHONE_NUMBER = "010-1234-5678"; + public static final LocalDate DEFAULT_BIRTHDAY = LocalDate.of(2023, Month.JULY, 12); + public static final GenderType DEFAULT_GENDER_TYPE = GenderType.MALE; + + public static ExtractableResponse ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .body(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ) + .post(API_PREFIX + "/members/join") + .then() + .log().all() + .extract(); + } + + public static Long ํšŒ์›๊ฐ€์ž…(final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ) { + final Response ํšŒ์›๊ฐ€์ž…_์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ).response(); + final String Location_ํ—ค๋” = ํšŒ์›๊ฐ€์ž…_์‘๋‹ต.header("Location"); + return Long.parseLong(Location_ํ—ค๋”.substring(13)); + } + + public static Long ๊ธฐ๋ณธ_ํšŒ์›๊ฐ€์ž…() { + final MemberJoinRequest ํšŒ์›๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest(DEFAULT_IDENTIFIER, DEFAULT_PASSWORD, DEFAULT_NICKNAME, + DEFAULT_PHONE_NUMBER, DEFAULT_GENDER_TYPE, DEFAULT_BIRTHDAY); + return ํšŒ์›๊ฐ€์ž…(ํšŒ์›๊ฐ€์ž…_์š”์ฒญ); + } + + public static ExtractableResponse ์š”์ฒญ์„_๋ฐ›๋Š”_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด_์กฐํšŒ_์š”์ฒญ(final String ์•ก์„ธ์Šค_ํ† ํฐ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .header(AUTHORIZATION, ์•ก์„ธ์Šค_ํ† ํฐ) + .get(API_PREFIX + "/members/me") + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ์š”์ฒญ์„_๋ฐ›๋Š”_ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด_์กฐํšŒ(final String ์•ก์„ธ์Šค_ํ† ํฐ, final Long ์กฐํšŒํ• _ํšŒ์›_์•„์ด๋””) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .header(AUTHORIZATION, ์•ก์„ธ์Šค_ํ† ํฐ) + .get(API_PREFIX + "/members/{memberId}", ์กฐํšŒํ• _ํšŒ์›_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static String ์‚ฌ์šฉ์ž๋ฅผ_์ถ”๊ฐ€ํ•˜๊ณ _ํ† ํฐ์„_์กฐํšŒํ•œ๋‹ค(final String ์•„์ด๋””, final String ๋‹‰๋„ค์ž„) { + final MemberJoinRequest ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ = new MemberJoinRequest(์•„์ด๋””, "paswword2@", + ๋‹‰๋„ค์ž„, "010-1234-1234", GenderType.FEMALE, LocalDate.of(1999, 9, 9)); + final LoginRequest ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ = new LoginRequest(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.identifier(), ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ.password()); + ํšŒ์›๊ฐ€์ž…(ํŒ”๋กœ์›Œ_ํšŒ์›_๊ฐ€์ž…_์š”์ฒญ); + return String.format(BEARER_TOKEN_FORMAT, ๋กœ๊ทธ์ธ(ํŒ”๋กœ์›Œ_๋กœ๊ทธ์ธ_์š”์ฒญ).accessToken()); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/RoadmapAPIFixture.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/RoadmapAPIFixture.java new file mode 100644 index 000000000..ab718d8aa --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/fixture/RoadmapAPIFixture.java @@ -0,0 +1,213 @@ +package co.kirikiri.integration.fixture; + +import static co.kirikiri.integration.fixture.CommonFixture.API_PREFIX; +import static co.kirikiri.integration.fixture.CommonFixture.AUTHORIZATION; +import static io.restassured.RestAssured.given; + +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.service.dto.CustomScrollRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import io.restassured.specification.RequestSpecification; +import java.io.IOException; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; + +public class RoadmapAPIFixture { + + private static final ObjectMapper objectMapper = new ObjectMapper() + .registerModule(new JavaTimeModule()); + + public static Long ๋กœ๋“œ๋งต_์ƒ์„ฑ(final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, final String ์•ก์„ธ์Šค_ํ† ํฐ) throws IOException { + final Response ์‘๋‹ต = ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ, ์•ก์„ธ์Šค_ํ† ํฐ).response(); + return Long.parseLong(์‘๋‹ต.header(HttpHeaders.LOCATION).split("/")[3]); + } + + public static ExtractableResponse ์š”์ฒญ์„_๋ฐ›๋Š”_์ด๋ฏธ์ง€๊ฐ€_ํฌํ•จ๋œ_๋กœ๋“œ๋งต_์ƒ์„ฑ(final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, + final String accessToken) + throws IOException { + final String jsonRequest = objectMapper.writeValueAsString(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’); + + RequestSpecification requestSpecification = given().log().all() + .header(HttpHeaders.AUTHORIZATION, accessToken) + .contentType(MediaType.MULTIPART_FORM_DATA_VALUE + "; charset=utf-8") + .multiPart("jsonData", "jsonData.json", jsonRequest, MediaType.APPLICATION_JSON_VALUE); + + requestSpecification = makeRequestSpecification(๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, requestSpecification); + + return requestSpecification + .log().all() + .post(API_PREFIX + "/roadmaps") + .then().log().all() + .extract(); + } + + private static RequestSpecification makeRequestSpecification(final RoadmapSaveRequest ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’, + RequestSpecification requestSpecification) + throws IOException { + if (๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’.roadmapNodes() == null) { + return requestSpecification; + } + for (final RoadmapNodeSaveRequest roadmapNode : ๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ๊ฐ’.roadmapNodes()) { + final String ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ = roadmapNode.getTitle() != null ? roadmapNode.getTitle() : "name"; + final MockMultipartFile ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด = new MockMultipartFile(๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ, "originalFileName.jpeg", + "image/jpeg", "tempImage".getBytes()); + requestSpecification = requestSpecification + .multiPart(๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getName(), ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getOriginalFilename(), + ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getBytes(), ๊ฐ€์งœ_์ด๋ฏธ์ง€_๊ฐ์ฒด.getContentType()); + } + return requestSpecification; + } + + public static ExtractableResponse ๋กœ๋“œ๋งต_์‚ญ์ œ(final Long ์‚ญ์ œํ• _๋กœ๋“œ๋งต_์•„์ด๋””, final String ๋กœ๊ทธ์ธ_ํ† ํฐ) { + return given().log().all() + .header(HttpHeaders.AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .delete(API_PREFIX + "/roadmaps/{roadmapId}", ์‚ญ์ œํ• _๋กœ๋“œ๋งต_์•„์ด๋””) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•œ๋‹ค(final Long ๋กœ๋“œ๋งต_์•„์ด๋””) { + return given() + .log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .get(API_PREFIX + "/roadmaps/{roadmapId}", ๋กœ๋“œ๋งต_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static RoadmapResponse ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•˜๊ณ _์‘๋‹ต๊ฐ์ฒด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(final Long ๋กœ๋“œ๋งต_์•„์ด๋””) { + return ๋กœ๋“œ๋งต์„_์•„์ด๋””๋กœ_์กฐํšŒํ•œ๋‹ค(๋กœ๋“œ๋งต_์•„์ด๋””) + .response() + .as(RoadmapResponse.class); + } + + public static ExtractableResponse ์ •๋ ฌ๋œ_์นดํ…Œ๊ณ ๋ฆฌ๋ณ„_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(final RoadmapOrderType ์ •๋ ฌ_์กฐ๊ฑด, + final Long ๊ฒ€์ƒ‰ํ• _์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””, final int ํŽ˜์ด์ง€_ํฌ๊ธฐ) { + return given() + .log().all() + .when() + .get("/api/roadmaps?size=" + ํŽ˜์ด์ง€_ํฌ๊ธฐ + "&filterCond=" + ์ •๋ ฌ_์กฐ๊ฑด.name() + "&categoryId=" + ๊ฒ€์ƒ‰ํ• _์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์ด์ „์—_๋ฐ›์€_๋กœ๋“œ๋งต์˜_์ œ์ผ๋งˆ์ง€๋ง‰_์•„์ด๋””_์ดํ›„์˜_์กฐ๊ฑด์œผ๋กœ_์กฐํšŒํ•œ๋‹ค( + final String ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด, final int ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ, final Long ๋งˆ์ง€๋ง‰_๋กœ๋“œ๋งต_์•„์ด๋””) { + return given() + .log().all() + .when() + .header(HttpHeaders.AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด) + .get("/api/roadmaps/me?lastId=" + ๋งˆ์ง€๋ง‰_๋กœ๋“œ๋งต_์•„์ด๋”” + "&size=" + ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค(final String ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด, final int ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ) { + return given() + .log().all() + .when() + .header(HttpHeaders.AUTHORIZATION, ๋กœ๊ทธ์ธ_ํ† ํฐ_์ •๋ณด) + .get("/api/roadmaps/me?size=" + ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ๋ชจ๋“ _์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + return given() + .log().all() + .when() + .get("/api/roadmaps/categories") + .then().log().all() + .extract(); + } + + public static ExtractableResponse ์‚ฌ์ด์ฆˆ๋ณ„๋กœ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค(final Integer size) { + return given() + .log().all() + .when() + .get("/api/roadmaps?size=" + size) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ์‚ฌ์ด์ฆˆ_์—†์ด_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() { + return given() + .log().all() + .when() + .get("/api/roadmaps") + .then().log().all() + .extract(); + } + + public static ExtractableResponse ๋ฆฌ๋ทฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String ํŒ”๋กœ์›Œ_ํ† ํฐ_์ •๋ณด, final Long ๋กœ๋“œ๋งต_์•„์ด๋””, + final RoadmapReviewSaveRequest ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .header(AUTHORIZATION, ํŒ”๋กœ์›Œ_ํ† ํฐ_์ •๋ณด) + .body(๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ƒ์„ฑ_์š”์ฒญ) + .post("/api/roadmaps/" + ๋กœ๋“œ๋งต_์•„์ด๋”” + "/reviews") + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ๋ฅผ_์กฐํšŒํ•œ๋‹ค(final Long ๋กœ๋“œ๋งต_์•„์ด๋””, final CustomScrollRequest ์Šคํฌ๋กค_์š”์ฒญ) { + return given().log().all() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when() + .param("lastId", ์Šคํฌ๋กค_์š”์ฒญ.lastId()) + .param("size", ์Šคํฌ๋กค_์š”์ฒญ.size()) + .get("/api/roadmaps/{roadmapId}/reviews", ๋กœ๋“œ๋งต_์•„์ด๋””) + .then() + .log().all() + .extract(); + } + + public static ExtractableResponse ์ •๋ ฌ๋œ_๋กœ๋“œ๋งต_๋ฆฌ์ŠคํŠธ_์กฐํšŒ(final RoadmapOrderType ์ •๋ ฌ_์กฐ๊ฑด, final int ํŽ˜์ด์ง€_ํฌ๊ธฐ) { + return given() + .log().all() + .when() + .get("/api/roadmaps?size=" + ํŽ˜์ด์ง€_ํฌ๊ธฐ + "&filterCond=" + ์ •๋ ฌ_์กฐ๊ฑด.name()) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ํƒœ๊ทธ_์ด๋ฆ„์œผ๋กœ_์ตœ์‹ ์ˆœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_๊ฒ€์ƒ‰ํ•œ๋‹ค(final int ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ, final String ํƒœ๊ทธ) { + return given() + .log().all() + .when() + .get("/api/roadmaps/search?size=" + ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ + "&tagName=" + ํƒœ๊ทธ) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ํฌ๋ฆฌ์—์ดํ„ฐ_๋‹‰๋„ค์ž„์œผ๋กœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final int ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ, final String ํฌ๋ฆฌ์—์ดํ„ฐ_๋‹‰๋„ค์ž„) { + return given() + .log().all() + .when() + .get("/api/roadmaps/search?size=" + ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ + "&creatorName=" + ํฌ๋ฆฌ์—์ดํ„ฐ_๋‹‰๋„ค์ž„) + .then().log().all() + .extract(); + } + + public static ExtractableResponse ์ œ๋ชฉ์œผ๋กœ_์ตœ์‹ ์ˆœ_์ •๋ ฌ๋œ_๋กœ๋“œ๋งต์„_๊ฒ€์ƒ‰ํ•œ๋‹ค(final int ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ, final String ๋กœ๋“œ๋งต_์ œ๋ชฉ) { + return given() + .log().all() + .when() + .get("/api/roadmaps/search?size=" + ํŽ˜์ด์ง€_์‚ฌ์ด์ฆˆ + "&roadmapTitle=" + ๋กœ๋“œ๋งต_์ œ๋ชฉ) + .then().log().all() + .extract(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/DatabaseCleaner.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/DatabaseCleaner.java new file mode 100644 index 000000000..6a89e221d --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/DatabaseCleaner.java @@ -0,0 +1,68 @@ +package co.kirikiri.integration.helper; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import org.hibernate.Session; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.stereotype.Component; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +@Component +@ActiveProfiles("test") +@Transactional +public class DatabaseCleaner implements InitializingBean { + + private static final List SYSTEM_TABLE_NAMES = List.of("CONSTANTS", "ENUM_VALUES", "INDEXES", + "INDEX_COLUMNS", "INFORMATION_SCHEMA_CATALOG_NAME", "IN_DOUBT", "LOCKS", + "QUERY_STATISTICS", "RIGHTS", "ROLES", "SESSIONS", "SESSION_STATE", "SETTINGS", "SYNONYMS", "USERS"); + + @PersistenceContext + private EntityManager entityManager; + private List tableNames; + + @Override + public void afterPropertiesSet() { + final Session session = entityManager.unwrap(Session.class); + session.doWork(this::extractTableNames); + } + + private void extractTableNames(final Connection conn) throws SQLException { + final List tableNames = new ArrayList<>(); + + final ResultSet tables = conn.getMetaData() + .getTables(conn.getCatalog(), null, "%", new String[]{"TABLE"}); + + while (tables.next()) { + final String tableName = tables.getString("TABLE_NAME"); + if (!SYSTEM_TABLE_NAMES.contains(tableName)) { + tableNames.add(tableName); + } + } + + this.tableNames = tableNames; + } + + public void execute() { + final Session session = entityManager.unwrap(Session.class); + session.doWork(this::cleanUpDatabase); + } + + private void cleanUpDatabase(final Connection conn) throws SQLException { + final Statement statement = conn.createStatement(); + statement.executeUpdate("SET REFERENTIAL_INTEGRITY FALSE"); + + for (final String tableName : tableNames) { + statement.executeUpdate("TRUNCATE TABLE " + tableName); + statement.executeUpdate("ALTER TABLE " + tableName + " ALTER COLUMN id RESTART WITH 1"); + } + + statement.executeUpdate("SET REFERENTIAL_INTEGRITY TRUE"); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/InitIntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/InitIntegrationTest.java new file mode 100644 index 000000000..aede0b1f6 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/InitIntegrationTest.java @@ -0,0 +1,34 @@ +package co.kirikiri.integration.helper; + +import static co.kirikiri.integration.fixture.AuthenticationAPIFixture.๊ธฐ๋ณธ_๋กœ๊ทธ์ธ; +import static co.kirikiri.integration.fixture.CommonFixture.BEARER_TOKEN_FORMAT; +import static co.kirikiri.integration.fixture.MemberAPIFixture.๊ธฐ๋ณธ_ํšŒ์›๊ฐ€์ž…; + +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; + +public class InitIntegrationTest extends IntegrationTest { + + protected static Long ๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋””; + protected static String ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ; + protected static String ๊ธฐ๋ณธ_์žฌ๋ฐœํ–‰_ํ† ํฐ; + protected static RoadmapCategory ๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ; + protected static RoadmapSaveRequest ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ; + + @BeforeEach + void init() { + ๊ธฐ๋ณธ_ํšŒ์›_์•„์ด๋”” = ๊ธฐ๋ณธ_ํšŒ์›๊ฐ€์ž…(); + ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ = String.format(BEARER_TOKEN_FORMAT, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ().accessToken()); + ๊ธฐ๋ณธ_์žฌ๋ฐœํ–‰_ํ† ํฐ = ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ().refreshToken(); + ๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ = testTransactionService.๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰"); + ๊ธฐ๋ณธ_๋กœ๋“œ๋งต_์ƒ์„ฑ_์š”์ฒญ = new RoadmapSaveRequest(๊ธฐ๋ณธ_์นดํ…Œ๊ณ ๋ฆฌ.getId(), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("roadmap 1st week", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ", null)), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ1"))); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/IntegrationTest.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/IntegrationTest.java new file mode 100644 index 000000000..63d9c360f --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/IntegrationTest.java @@ -0,0 +1,52 @@ +package co.kirikiri.integration.helper; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestConstructor; +import org.springframework.test.context.TestConstructor.AutowireMode; + +@ActiveProfiles("test") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@TestConstructor(autowireMode = AutowireMode.ALL) +@Import(TestConfig.class) +public class IntegrationTest { + +// @Value("${server.servlet.contextPath}") +// protected String API_PREFIX; + + @LocalServerPort + private int port; + + @Autowired + protected ObjectMapper objectMapper; + + @Autowired + protected TestTransactionService testTransactionService; + + @Autowired + private DatabaseCleaner databaseCleaner; + + @BeforeEach + void setUp() { + RestAssured.port = port; + } + + @AfterEach + void tearDown() { + databaseCleaner.execute(); + } + + protected T jsonToClass(final String responseBody, final TypeReference typeReference) + throws JsonProcessingException { + return objectMapper.readValue(responseBody, typeReference); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestConfig.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestConfig.java new file mode 100644 index 000000000..a8800178c --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestConfig.java @@ -0,0 +1,34 @@ +package co.kirikiri.integration.helper; + +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.service.FileService; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class TestConfig { + + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final GoalRoomRepository goalRoomRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + + public TestConfig(final RoadmapCategoryRepository roadmapCategoryRepository, + final GoalRoomRepository goalRoomRepository, + final GoalRoomMemberRepository goalRoomMemberRepository) { + this.roadmapCategoryRepository = roadmapCategoryRepository; + this.goalRoomRepository = goalRoomRepository; + this.goalRoomMemberRepository = goalRoomMemberRepository; + } + + @Bean + public FileService fileService() { + return new TestFileService(); + } + + @Bean + public TestTransactionService testTransactionService() { + return new TestTransactionService(roadmapCategoryRepository, goalRoomRepository, goalRoomMemberRepository); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestFileService.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestFileService.java new file mode 100644 index 000000000..5803f3af2 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestFileService.java @@ -0,0 +1,23 @@ +package co.kirikiri.integration.helper; + +import co.kirikiri.service.FileService; +import co.kirikiri.service.dto.FileInformation; +import org.springframework.http.HttpMethod; +import java.net.MalformedURLException; +import java.net.URL; + +public class TestFileService implements FileService { + + @Override + public void save(final String path, final FileInformation fileInformation) { + } + + @Override + public URL generateUrl(final String path, final HttpMethod httpMethod) { + try { + return new URL("http://example.com" + path); + } catch (final MalformedURLException exception) { + throw new RuntimeException(exception); + } + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestTransactionService.java b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestTransactionService.java new file mode 100644 index 000000000..967dc41a0 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/integration/helper/TestTransactionService.java @@ -0,0 +1,139 @@ +package co.kirikiri.integration.helper; + +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์‹ญ์ผ_ํ›„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์˜ค๋Š˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›; +import static co.kirikiri.integration.fixture.GoalRoomAPIFixture.์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ ; +import static co.kirikiri.integration.fixture.MemberAPIFixture.DEFAULT_PASSWORD; +import static co.kirikiri.integration.helper.InitIntegrationTest.๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +public class TestTransactionService { + + @PersistenceContext + private EntityManager em; + + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final GoalRoomRepository goalRoomRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + + public TestTransactionService(final RoadmapCategoryRepository roadmapCategoryRepository, + final GoalRoomRepository goalRoomRepository, + final GoalRoomMemberRepository goalRoomMemberRepository) { + this.roadmapCategoryRepository = roadmapCategoryRepository; + this.goalRoomRepository = goalRoomRepository; + this.goalRoomMemberRepository = goalRoomMemberRepository; + } + + public List ๋ชจ๋“ _๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String... ์นดํ…Œ๊ณ ๋ฆฌ_์ด๋ฆ„_๋ชฉ๋ก) { + final List roadmapCategories = new ArrayList<>(); + for (final String ์นดํ…Œ๊ณ ๋ฆฌ_์ด๋ฆ„ : ์นดํ…Œ๊ณ ๋ฆฌ_์ด๋ฆ„_๋ชฉ๋ก) { + final RoadmapCategory ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(์นดํ…Œ๊ณ ๋ฆฌ_์ด๋ฆ„); + roadmapCategories.add(new RoadmapCategory(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ.getId(), ์นดํ…Œ๊ณ ๋ฆฌ_์ด๋ฆ„)); + } + roadmapCategoryRepository.saveAll(roadmapCategories); + return roadmapCategories; + } + + public RoadmapCategory ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String ์นดํ…Œ๊ณ ๋ฆฌ_์ด๋ฆ„) { + final RoadmapCategory ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ = new RoadmapCategory(์นดํ…Œ๊ณ ๋ฆฌ_์ด๋ฆ„); + return roadmapCategoryRepository.save(๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ); + } + + public GoalRoom ๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(final Long ๊ณจ๋ฃธ_์•„์ด๋””) { + final GoalRoom ๊ณจ๋ฃธ = goalRoomRepository.findById(๊ณจ๋ฃธ_์•„์ด๋””).get(); + ๊ณจ๋ฃธ.complete(); + return goalRoomRepository.save(๊ณจ๋ฃธ); + } + + public GoalRoom ์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapResponse ๋กœ๋“œ๋งต_์‘๋‹ต) { + final GoalRoomTodoRequest ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ = new GoalRoomTodoRequest(์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ปจํ…์ธ , ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„); + final List ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ = List.of( + new GoalRoomRoadmapNodeRequest(๋กœ๋“œ๋งต_์‘๋‹ต.content().nodes().get(0).id(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_๋…ธ๋“œ_์ธ์ฆ_ํšŸ์ˆ˜, ์˜ค๋Š˜, ์‹ญ์ผ_ํ›„)); + final GoalRoomCreateRequest ๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ = new GoalRoomCreateRequest(๋กœ๋“œ๋งต_์‘๋‹ต.roadmapId(), ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ด๋ฆ„, ์ •์ƒ์ ์ธ_๊ณจ๋ฃธ_์ œํ•œ_์ธ์›, + ๊ณจ๋ฃธ_ํˆฌ๋‘_์š”์ฒญ, ๊ณจ๋ฃธ_๋…ธ๋“œ_๋ณ„_๊ธฐ๊ฐ„_์š”์ฒญ); + final Long ๊ณจ๋ฃธ_์•„์ด๋”” = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•˜๊ณ _์•„์ด๋””๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(๊ณจ๋ฃธ_์ƒ์„ฑ_์š”์ฒญ, ๊ธฐ๋ณธ_๋กœ๊ทธ์ธ_ํ† ํฐ); + return ๊ณจ๋ฃธ์„_์™„๋ฃŒ์‹œํ‚จ๋‹ค(๊ณจ๋ฃธ_์•„์ด๋””); + } + + public void ๊ณจ๋ฃธ์—_๋Œ€ํ•œ_์ฐธ์—ฌ์ž_๋ฆฌ์ŠคํŠธ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final MemberInformationResponse ๋ฆฌ๋”_์ •๋ณด, final GoalRoom ๊ณจ๋ฃธ, + final MemberInformationResponse... ํŒ”๋กœ์›Œ๋“ค_์ •๋ณด) { + final Member ๋ฆฌ๋” = ์‚ฌ์šฉ์ž_์ •๋ณด์—์„œ_์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(๋ฆฌ๋”_์ •๋ณด); + final GoalRoomMember ๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ๋” = new GoalRoomMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 1, 12, 0), ๊ณจ๋ฃธ, ๋ฆฌ๋”); + final List ๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ์ŠคํŠธ = new ArrayList<>(); + ๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ์ŠคํŠธ.add(๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ๋”); + + for (final MemberInformationResponse ํŒ”๋กœ์›Œ_์ •๋ณด : ํŒ”๋กœ์›Œ๋“ค_์ •๋ณด) { + final Member ํŒ”๋กœ์›Œ = ์‚ฌ์šฉ์ž_์ •๋ณด์—์„œ_์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(ํŒ”๋กœ์›Œ_์ •๋ณด); + final GoalRoomMember ๊ณจ๋ฃธ_๋ฉค๋ฒ„_ํŒ”๋กœ์›Œ = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 5, 18, 0), ๊ณจ๋ฃธ, ํŒ”๋กœ์›Œ); + ๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ์ŠคํŠธ.add(๊ณจ๋ฃธ_๋ฉค๋ฒ„_ํŒ”๋กœ์›Œ); + } + ๊ณจ๋ฃธ_๋ฉค๋ฒ„๋ฅผ_์ €์žฅํ•œ๋‹ค(๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ์ŠคํŠธ); + } + + private Member ์‚ฌ์šฉ์ž_์ •๋ณด์—์„œ_์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final MemberInformationResponse ์‚ฌ์šฉ์ž_์ •๋ณด) { + final MemberProfile memberProfile = new MemberProfile(Gender.valueOf(์‚ฌ์šฉ์ž_์ •๋ณด.gender()), ์‚ฌ์šฉ์ž_์ •๋ณด.birthday(), + ์‚ฌ์šฉ์ž_์ •๋ณด.phoneNumber()); + return new Member(์‚ฌ์šฉ์ž_์ •๋ณด.id(), new Identifier(์‚ฌ์šฉ์ž_์ •๋ณด.identifier()), new EncryptedPassword(new Password( + DEFAULT_PASSWORD)), new Nickname(์‚ฌ์šฉ์ž_์ •๋ณด.nickname()), null, memberProfile); + } + + public void ๊ณจ๋ฃธ_๋ฉค๋ฒ„๋ฅผ_์ €์žฅํ•œ๋‹ค(final List ๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ์ŠคํŠธ) { + goalRoomMemberRepository.saveAll(๊ณจ๋ฃธ_๋ฉค๋ฒ„_๋ฆฌ์ŠคํŠธ); + } + + public void ๊ณจ๋ฃธ์˜_์ƒํƒœ์™€_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(final Long ๊ณจ๋ฃธ_์•„์ด๋””, final GoalRoomStatus ๊ณจ๋ฃธ_์ƒํƒœ, final LocalDate ๋ณ€๊ฒฝํ• _์ข…๋ฃŒ๋‚ ์งœ) { + em.createQuery("update GoalRoom g set endDate = :endDate, status = :status where id = :goalRoomId") + .setParameter("status", ๊ณจ๋ฃธ_์ƒํƒœ) + .setParameter("endDate", ๋ณ€๊ฒฝํ• _์ข…๋ฃŒ๋‚ ์งœ) + .setParameter("goalRoomId", ๊ณจ๋ฃธ_์•„์ด๋””) + .executeUpdate(); + } + + public void ๊ณจ๋ฃธ์˜_์ข…๋ฃŒ๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(final Long ๊ณจ๋ฃธ_์•„์ด๋””, final LocalDate ๋ณ€๊ฒฝํ• _์ข…๋ฃŒ๋‚ ์งœ) { + em.createQuery("update GoalRoom g set endDate = :endDate where id = :goalRoomId") + .setParameter("goalRoomId", ๊ณจ๋ฃธ_์•„์ด๋””) + .setParameter("endDate", ๋ณ€๊ฒฝํ• _์ข…๋ฃŒ๋‚ ์งœ) + .executeUpdate(); + } + + public void ๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๋ฅผ_๋ณ€๊ฒฝํ•œ๋‹ค(final Long ๊ณจ๋ฃธ_์•„์ด๋””, final LocalDate ๋ณ€๊ฒฝํ• _์‹œ์ž‘๋‚ ์งœ) { + em.createQuery("update GoalRoom g set startDate = :startDate where id = :goalRoomId") + .setParameter("goalRoomId", ๊ณจ๋ฃธ_์•„์ด๋””) + .setParameter("startDate", ๋ณ€๊ฒฝํ• _์‹œ์ž‘๋‚ ์งœ) + .executeUpdate(); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/auth/RefreshTokenRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/auth/RefreshTokenRepositoryTest.java new file mode 100644 index 000000000..7a3cc0cb6 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/auth/RefreshTokenRepositoryTest.java @@ -0,0 +1,66 @@ +package co.kirikiri.persistence.auth; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.auth.EncryptedToken; +import co.kirikiri.domain.auth.RefreshToken; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class RefreshTokenRepositoryTest { + + private static Member member; + + private final RefreshTokenRepository refreshTokenRepository; + private final MemberRepository memberRepository; + + public RefreshTokenRepositoryTest(final RefreshTokenRepository refreshTokenRepository, + final MemberRepository memberRepository) { + this.refreshTokenRepository = refreshTokenRepository; + this.memberRepository = memberRepository; + } + + @BeforeAll + static void setUp() { + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final EncryptedPassword encryptedPassword = new EncryptedPassword(password); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber); + member = new Member(identifier, encryptedPassword, nickname, null, memberProfile); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_์ทจ์†Œ๋˜์ง€_์•Š์€_๋ฆฌํ”„๋ ˆ์‹œ_ํ† ํฐ์„_์ฐพ์•„์˜จ๋‹ค() { + //given + final EncryptedToken encryptedToken = new EncryptedToken("refreshToken"); + final LocalDateTime now = LocalDateTime.now(); + final RefreshToken refreshToken = new RefreshToken(encryptedToken, now, member); + memberRepository.save(member); + refreshTokenRepository.save(refreshToken); + + //when + final Optional optionalRefreshToken = refreshTokenRepository.findByTokenAndIsRevokedFalse( + encryptedToken); + + //then + assertThat(optionalRefreshToken).isNotEmpty(); + final RefreshToken result = optionalRefreshToken.get(); + assertThat(result.getToken()).usingRecursiveComparison() + .isEqualTo(encryptedToken); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/dto/RoadmapSearchTagNameTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/dto/RoadmapSearchTagNameTest.java new file mode 100644 index 000000000..fb9553bf2 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/dto/RoadmapSearchTagNameTest.java @@ -0,0 +1,45 @@ +package co.kirikiri.persistence.dto; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +class RoadmapSearchTagNameTest { + + @ParameterizedTest + @CsvSource(value = {"์•ˆ ๋…•:์•ˆ๋…•", "์•ˆ๋…• :์•ˆ๋…•", " ์•ˆ๋…•:์•ˆ๋…•"}, delimiter = ':') + void ๊ฒ€์ƒ‰์–ด์—_๊ณต๋ฐฑ์ด_๋“ค์–ด๊ฐ€๋ฉด_์ œ๊ฑฐํ•œ๋‹ค(final String name, final String removedBlankName) { + // when + final RoadmapSearchTagName searchTagName = assertDoesNotThrow(() -> new RoadmapSearchTagName(name)); + + // then + assertThat(searchTagName.value()) + .isEqualTo(removedBlankName); + } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + void ๊ฒ€์ƒ‰์–ด๊ฐ€_1์ž์ด์ƒ์ด๋ฉด_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค(final int length) { + // given + final String name = "a".repeat(length); + + // expected + assertDoesNotThrow(() -> new RoadmapSearchTagName(name)); + } + + @ParameterizedTest + @ValueSource(ints = {0}) + void ๊ฒ€์ƒ‰์–ด๊ฐ€_1์ž๋ฏธ๋งŒ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int length) { + // given + final String name = "a".repeat(length); + + // expected + assertThatThrownBy(() -> new RoadmapSearchTagName(name)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/dto/RoadmapSearchTitleTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/dto/RoadmapSearchTitleTest.java new file mode 100644 index 000000000..3b1fc8512 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/dto/RoadmapSearchTitleTest.java @@ -0,0 +1,45 @@ +package co.kirikiri.persistence.dto; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.BadRequestException; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; + +class RoadmapSearchTitleTest { + + @ParameterizedTest + @CsvSource(value = {"์•ˆ ๋…•:์•ˆ๋…•", "์•ˆ๋…• :์•ˆ๋…•", " ์•ˆ๋…•:์•ˆ๋…•"}, delimiter = ':') + void ๊ฒ€์ƒ‰์–ด์—_๊ณต๋ฐฑ์ด_๋“ค์–ด๊ฐ€๋ฉด_์ œ๊ฑฐํ•œ๋‹ค(final String title, final String removedBlankTitle) { + // when + final RoadmapSearchTitle searchTitle = assertDoesNotThrow(() -> new RoadmapSearchTitle(title)); + + // then + assertThat(searchTitle.value()) + .isEqualTo(removedBlankTitle); + } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + void ๊ฒ€์ƒ‰์–ด๊ฐ€_1์ž์ด์ƒ์ด๋ฉด_์ •์ƒ์ ์œผ๋กœ_์ƒ์„ฑ๋œ๋‹ค(final int length) { + // given + final String title = "a".repeat(length); + + // expected + assertDoesNotThrow(() -> new RoadmapSearchTitle(title)); + } + + @ParameterizedTest + @ValueSource(ints = {0}) + void ๊ฒ€์ƒ‰์–ด๊ฐ€_1์ž๋ฏธ๋งŒ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค(final int length) { + // given + final String title = "a".repeat(length); + + // expected + assertThatThrownBy(() -> new RoadmapSearchTitle(title)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/CheckFeedRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/CheckFeedRepositoryTest.java new file mode 100644 index 000000000..ba07f357b --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/CheckFeedRepositoryTest.java @@ -0,0 +1,505 @@ +package co.kirikiri.persistence.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImage; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class CheckFeedRepositoryTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LAYER = TODAY.plusDays(20); + private static final LocalDate THIRTY_DAY_LATER = TODAY.plusDays(30); + private static final LocalDateTime TODAY_START = TODAY.atStartOfDay(); + private static final LocalDateTime TOMORROW_START = TODAY_START.plusDays(1); + private static final LocalDateTime DAY_AFTER_TOMORROW_START = TODAY_START.plusDays(2); + + private final MemberRepository memberRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final RoadmapRepository roadmapRepository; + private final GoalRoomRepository goalRoomRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + private final CheckFeedRepository checkFeedRepository; + + public CheckFeedRepositoryTest(final MemberRepository memberRepository, + final RoadmapCategoryRepository roadmapCategoryRepository, + final RoadmapRepository roadmapRepository, + final GoalRoomRepository goalRoomRepository, + final GoalRoomMemberRepository goalRoomMemberRepository, + final CheckFeedRepository checkFeedRepository) { + this.memberRepository = memberRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + this.roadmapRepository = roadmapRepository; + this.goalRoomRepository = goalRoomRepository; + this.goalRoomMemberRepository = goalRoomMemberRepository; + this.checkFeedRepository = checkFeedRepository; + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_ํ•ด๋‹น_๊ณจ๋ฃธ์—์„œ_์˜ค๋Š˜_์˜ฌ๋ฆฐ_ํ”ผ๋“œ์˜_์กด์žฌ์œ ๋ฌด๋ฅผ_ํ™•์ธํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode, joinedMember); + + //when + final boolean isUpdateToday = checkFeedRepository.findByGoalRoomMemberAndDateTime(joinedMember, + TODAY_START, TOMORROW_START).isPresent(); + + final boolean isUpdateTomorrow = checkFeedRepository.findByGoalRoomMemberAndDateTime(joinedMember, + TOMORROW_START, DAY_AFTER_TOMORROW_START).isPresent(); + + //then + assertAll( + () -> assertThat(isUpdateToday).isTrue(), + () -> assertThat(isUpdateTomorrow).isFalse() + ); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_ํ˜„์žฌ_์ง„ํ–‰์ค‘์ธ_๋…ธ๋“œ์—์„œ_์ธ์ฆํ•œ_ํšŸ์ˆ˜๋ฅผ_ํ™•์ธํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode, joinedMember); + + //when + final int checkCount = checkFeedRepository.countByGoalRoomMemberAndGoalRoomRoadmapNode(joinedMember, + goalRoomRoadmapNode); + + //then + assertThat(checkCount).isEqualTo(4); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_๊ณจ๋ฃธ์—์„œ_๋“ฑ๋กํ•œ_์ธ์ฆ_ํ”ผ๋“œ_ํšŸ์ˆ˜๋ฅผ_ํ™•์ธํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1); + + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + + //when + final int checkCount = checkFeedRepository.countByGoalRoomMember(joinedMember); + + //then + assertThat(checkCount).isEqualTo(6); + } + + @Test + void ํŠน์ •_๊ณจ๋ฃธ์—์„œ_๋“ฑ๋ก๋œ_๋ชจ๋“ _์ธ์ฆ_ํ”ผ๋“œ๋“ค์„_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, creator); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom1, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom1, + member); + final GoalRoomMember otherLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom2, + creator); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom1.getGoalRoomRoadmapNodes().getValues().get(0); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom1.getGoalRoomRoadmapNodes().getValues().get(1); + final GoalRoomRoadmapNode otherGoalRoomRoadmapNode = goalRoom2.getGoalRoomRoadmapNodes().getValues().get(0); + + final CheckFeed checkFeed1 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed2 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed3 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed4 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + final CheckFeed checkFeed5 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + final CheckFeed checkFeed6 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(otherGoalRoomRoadmapNode, otherLeader); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(otherGoalRoomRoadmapNode, otherLeader); + + //when + final List checkFeeds = checkFeedRepository.findByGoalRoom(goalRoom1); + + assertThat(checkFeeds) + .hasSize(6) + .isEqualTo(List.of(checkFeed6, checkFeed5, checkFeed4, checkFeed3, checkFeed2, checkFeed1)); + } + + @Test + void ๊ณจ๋ฃธ์ด_์ง„ํ–‰์ค‘์ผ_๋•Œ_ํŠน์ •_๋…ธ๋“œ_๋™์•ˆ_๋“ฑ๋ก๋œ_์ธ์ฆ_ํ”ผ๋“œ๋“ค์„_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1); + + final CheckFeed checkFeed1 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed2 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed3 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed4 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + final CheckFeed checkFeed5 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + final CheckFeed checkFeed6 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + + //when + final List checkFeeds1 = checkFeedRepository + .findByRunningGoalRoomRoadmapNode(goalRoomRoadmapNode1); + final List checkFeeds2 = checkFeedRepository + .findByRunningGoalRoomRoadmapNode(goalRoomRoadmapNode2); + + assertAll( + () -> assertThat(checkFeeds1) + .hasSize(3) + .isEqualTo(List.of(checkFeed3, checkFeed2, checkFeed1)), + () -> assertThat(checkFeeds2) + .hasSize(3) + .isEqualTo(List.of(checkFeed6, checkFeed5, checkFeed4)) + ); + } + + @Test + void ์ง„ํ–‰์ค‘์ธ_๊ณจ๋ฃธ์—์„œ_ํŠน์ •_๋…ธ๋“œ_๊ธฐ๊ฐ„์ด_์•„๋‹ˆ๋ฉด_๋นˆ_์ธ์ฆ_ํ”ผ๋“œ๋“ค_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1); + + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + + //when + final List checkFeeds1 = checkFeedRepository + .findByGoalRoomRoadmapNode(null); + + assertThat(checkFeeds1).isEmpty(); + } + + @Test + void ๊ณจ๋ฃธ์ด_์™„๋ฃŒ๋์„_๋•Œ๋Š”_ํŠน์ •ํ•œ_๋…ธ๋“œ_๋™์•ˆ์ด_์•„๋‹Œ_๋ชจ๋“ _๊ธฐ๊ฐ„_๋™์•ˆ_๋“ฑ๋ก๋œ_์ธ์ฆ_ํ”ผ๋“œ๋“ค์„_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1); + + final CheckFeed checkFeed1 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed2 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed3 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + final CheckFeed checkFeed4 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + final CheckFeed checkFeed5 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + final CheckFeed checkFeed6 = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, joinedMember); + + //when + final List checkFeeds = checkFeedRepository.findByGoalRoom(goalRoom); + + //then + assertThat(checkFeeds) + .isEqualTo(List.of(checkFeed6, checkFeed5, checkFeed4, checkFeed3, checkFeed2, checkFeed1)); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ๊ฐ’์œผ๋กœ_null์ด_๋“ค์–ด์˜ค๋ฉด_๋นˆ_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + //given + //when + final List checkFeeds = checkFeedRepository.findByGoalRoomRoadmapNode(null); + + //then + assertThat(checkFeeds).isEmpty(); + } + + @Test + void ๊ณจ๋ฃธ_์ง„ํ–‰_์ค‘์—_ํŠน์ •_๋…ธ๋“œ_๋™์•ˆ_๋“ฑ๋ก๋œ_์ธ์ฆ_ํ”ผ๋“œ๋“ค์„_๋“ฑ๋กํ•œ_์‚ฌ์šฉ์ž์˜_์ •๋ณด์™€_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1); + + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, leader); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, leader); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, leader); + + //when + final List checkFeeds1 = checkFeedRepository.findByRunningGoalRoomRoadmapNodeWithMemberAndMemberImage( + goalRoomRoadmapNode1); + final List checkFeeds2 = checkFeedRepository.findByRunningGoalRoomRoadmapNodeWithMemberAndMemberImage( + goalRoomRoadmapNode2); + + //then + final CheckFeed expected1 = new CheckFeed("src/test/resources/testImage", ImageContentType.JPEG, + "originalFileName", "์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ", goalRoomRoadmapNode1, joinedMember); + final CheckFeed expected2 = new CheckFeed("src/test/resources/testImage", ImageContentType.JPEG, + "originalFileName", "์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ", goalRoomRoadmapNode2, leader); + + assertAll( + () -> assertThat(checkFeeds1).hasSize(3) + .usingRecursiveComparison() + .ignoringFields("id", "createdAt") + .isEqualTo(List.of(expected1, expected1, expected1)), + () -> assertThat(checkFeeds1.get(0).getGoalRoomMember().getMember().getNickname().getValue()) + .isEqualTo("์ฐธ์—ฌ์ž"), + () -> assertThat(checkFeeds1.get(0).getGoalRoomMember().getMember().getImage().getServerFilePath()) + .isEqualTo("serverFilePath"), + () -> assertThat(checkFeeds2).hasSize(3) + .usingRecursiveComparison() + .ignoringFields("id", "createdAt") + .isEqualTo(List.of(expected2, expected2, expected2)), + () -> assertThat(checkFeeds2.get(0).getGoalRoomMember().getMember().getNickname().getValue()) + .isEqualTo("์ฝ”๋ผ๋ฆฌ"), + () -> assertThat(checkFeeds2.get(0).getGoalRoomMember().getMember().getImage().getServerFilePath()) + .isEqualTo("serverFilePath") + ); + } + + @Test + void ๊ณจ๋ฃธ_์™„๋ฃŒ_์‹œ_๋ชจ๋“ _๊ธฐ๊ฐ„_๋™์•ˆ_๋“ฑ๋ก๋œ_์ธ์ฆ_ํ”ผ๋“œ๋“ค์„_๋“ฑ๋กํ•œ_์‚ฌ์šฉ์ž์˜_์ •๋ณด์™€_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("cokiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("participant", "์ฐธ์—ฌ์ž"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(targetRoadmapContent, member); + + final GoalRoomMember leader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + final GoalRoomMember joinedMember = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + member); + goalRoomMemberRepository.saveAll(List.of(leader, joinedMember)); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = goalRoom.getGoalRoomRoadmapNodes().getValues().get(1); + + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode1, joinedMember); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, leader); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, leader); + ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(goalRoomRoadmapNode2, leader); + + //when + final List checkFeeds = checkFeedRepository.findByGoalRoomWithMemberAndMemberImage(goalRoom); + + //then + final CheckFeed expected1 = new CheckFeed("src/test/resources/testImage", ImageContentType.JPEG, + "originalFileName", "์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ", goalRoomRoadmapNode1, joinedMember); + final CheckFeed expected2 = new CheckFeed("src/test/resources/testImage", ImageContentType.JPEG, + "originalFileName", "์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ", goalRoomRoadmapNode2, leader); + + assertThat(checkFeeds).hasSize(6) + .usingRecursiveComparison() + .ignoringFields("id", "createdAt") + .isEqualTo(List.of(expected2, expected2, expected2, expected1, expected1, expected1)); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค(final String identifier, final String nickname) { + final MemberImage memberImage = new MemberImage("originalFileName", "serverFilePath", ImageContentType.PNG); + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, + LocalDate.of(1990, 1, 1), "010-1234-5678"); + final Member creator = new Member(new Identifier(identifier), new EncryptedPassword(new Password("password1!")), + new Nickname(nickname), memberImage, memberProfile); + return memberRepository.save(creator); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String name) { + final RoadmapCategory roadmapCategory = new RoadmapCategory(name); + return roadmapCategoryRepository.save(roadmapCategory); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(final Member creator, final RoadmapCategory category) { + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmapRepository.save(roadmap); + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + roadmapNode1.addImages(new RoadmapNodeImages(๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค())); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private List ๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of( + new RoadmapNodeImage("node-image1.png", "node-image1-save-path", ImageContentType.PNG), + new RoadmapNodeImage("node-image2.png", "node-image2-save-path", ImageContentType.PNG) + ); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ €์žฅํ•œ๋‹ค(final RoadmapContent roadmapContent, final Member member) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(10), + roadmapContent, member); + final List roadmapNodes = roadmapContent.getNodes().getValues(); + + final RoadmapNode firstRoadmapNode = roadmapNodes.get(0); + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TODAY, TEN_DAY_LATER), + 10, firstRoadmapNode); + + final RoadmapNode secondRoadmapNode = roadmapNodes.get(1); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), + 10, secondRoadmapNode); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes( + List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode)); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoomRepository.save(goalRoom); + } + + private CheckFeed ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ €์žฅํ•œ๋‹ค(final GoalRoomRoadmapNode goalRoomRoadmapNode, final GoalRoomMember joinedMember) { + return checkFeedRepository.save( + new CheckFeed("src/test/resources/testImage", ImageContentType.JPEG, + "originalFileName", "์ธ์ฆ ํ”ผ๋“œ ๋ณธ๋ฌธ", goalRoomRoadmapNode, joinedMember)); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomMemberRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomMemberRepositoryTest.java new file mode 100644 index 000000000..ca306c9a7 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomMemberRepositoryTest.java @@ -0,0 +1,365 @@ +package co.kirikiri.persistence.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImage; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class GoalRoomMemberRepositoryTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LAYER = TODAY.plusDays(20); + private static final LocalDate THIRTY_DAY_LATER = TODAY.plusDays(30); + + private final MemberRepository memberRepository; + private final RoadmapRepository roadmapRepository; + private final GoalRoomRepository goalRoomRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + + public GoalRoomMemberRepositoryTest(final MemberRepository memberRepository, + final RoadmapRepository roadmapRepository, + final GoalRoomRepository goalRoomRepository, + final RoadmapCategoryRepository roadmapCategoryRepository, + final GoalRoomMemberRepository goalRoomMemberRepository) { + this.memberRepository = memberRepository; + this.roadmapRepository = roadmapRepository; + this.goalRoomRepository = goalRoomRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + this.goalRoomMemberRepository = goalRoomMemberRepository; + } + + @Test + void ๊ณจ๋ฃธ๊ณผ_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), savedGoalRoom, creator); + final GoalRoomMember expected = goalRoomMemberRepository.save(goalRoomMember); + + // when + final Optional findGoalRoomMember = goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier( + savedGoalRoom, new Identifier("cokirikiri")); + + // then + assertThat(findGoalRoomMember.get()) + .usingRecursiveComparison() + .ignoringFields("id") + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ๊ณผ_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_๋ชฉ๋ก_์กฐํšŒ์‹œ_์—†์œผ๋ฉด_๋นˆ๊ฐ’์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + // when + final Optional findGoalRoomMember = goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier( + savedGoalRoom, new Identifier("cokirikiri2")); + + // then + assertThat(findGoalRoomMember) + .isEmpty(); + } + + @Test + void ๊ณจ๋ฃธ์œผ๋กœ_์‚ฌ์šฉ์ž_๋ชฉ๋ก๊ณผ_๋ฉค๋ฒ„๋ฅผ_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), savedGoalRoom, member1); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 20, 12, 0, 0), savedGoalRoom, member2); + final GoalRoomMember goalRoomMember3 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 21, 12, 0, 0), savedGoalRoom, member3); + final List expected = goalRoomMemberRepository.saveAll( + List.of(goalRoomMember1, goalRoomMember2, goalRoomMember3)); + + // when + final List findGoalRoomMembers = goalRoomMemberRepository.findAllByGoalRoom( + goalRoom); + + // then + assertThat(findGoalRoomMembers) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž๋ฅผ_์กฐํšŒํ•˜๊ณ _๋“ค์–ด์˜จ์ง€_์˜ค๋ž˜๋œ_์ˆœ์„œ๋Œ€๋กœ_์ •๋ ฌํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), savedGoalRoom, member1); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 20, 12, 0, 0), savedGoalRoom, member2); + final GoalRoomMember goalRoomMember3 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 21, 12, 0, 0), savedGoalRoom, member3); + final List expected = goalRoomMemberRepository.saveAll( + List.of(goalRoomMember1, goalRoomMember2, goalRoomMember3)); + + // when + final List goalRoomMembers = goalRoomMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), GoalRoomMemberSortType.JOINED_ASC); + + // then + assertThat(goalRoomMembers) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž๋ฅผ_์กฐํšŒํ•˜๊ณ _๋งˆ์ง€๋ง‰์œผ๋กœ_๋“ค์–ด์˜จ_์ˆœ์„œ๋Œ€๋กœ_์ •๋ ฌํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), savedGoalRoom, member1); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 20, 12, 0, 0), savedGoalRoom, member2); + final GoalRoomMember goalRoomMember3 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 21, 12, 0, 0), savedGoalRoom, member3); + final GoalRoomMember savedGoalRoomMember1 = goalRoomMemberRepository.save(goalRoomMember1); + final GoalRoomMember savedGoalRoomMember2 = goalRoomMemberRepository.save(goalRoomMember2); + final GoalRoomMember savedGoalRoomMember3 = goalRoomMemberRepository.save(goalRoomMember3); + + // when + final List goalRoomMembers = goalRoomMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), GoalRoomMemberSortType.JOINED_DESC); + + // then + assertThat(goalRoomMembers) + .isEqualTo(List.of(savedGoalRoomMember3, savedGoalRoomMember2, savedGoalRoomMember1)); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž๋ฅผ_์กฐํšŒํ•˜๊ณ _๋‹ฌ์„ฑ๋ฅ ์ด_๋†’์€_์ˆœ๋Œ€๋กœ_์ •๋ ฌํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), savedGoalRoom, member1); + goalRoomMember1.updateAccomplishmentRate(30.0); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 20, 12, 0, 0), savedGoalRoom, member2); + goalRoomMember2.updateAccomplishmentRate(70.0); + final GoalRoomMember goalRoomMember3 = new GoalRoomMember(GoalRoomRole.FOLLOWER, + LocalDateTime.of(2023, 7, 21, 12, 0, 0), savedGoalRoom, member3); + goalRoomMember3.updateAccomplishmentRate(10.0); + final List expected = goalRoomMemberRepository.saveAll( + List.of(goalRoomMember2, goalRoomMember1, goalRoomMember3)); + + // when + final List goalRoomMembers1 = goalRoomMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), GoalRoomMemberSortType.ACCOMPLISHMENT_RATE); + final List goalRoomMembers2 = goalRoomMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), null); + + // then + assertThat(goalRoomMembers1) + .isEqualTo(expected); + assertThat(goalRoomMembers2) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋ฉค๋ฒ„๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password!1", "name1", "01011111111"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + goalRoomRepository.save(goalRoom); + + final GoalRoomMember goalRoomMember = new GoalRoomMember( + GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator + ); + goalRoomMemberRepository.save(goalRoomMember); + + // when + final GoalRoomMember findGoalRoomMember = goalRoomMemberRepository.findGoalRoomMember(goalRoom.getId(), + creator.getIdentifier()).get(); + + // then + Assertions.assertThat(findGoalRoomMember) + .usingRecursiveComparison() + .ignoringFields("joinedAt") + .isEqualTo(goalRoomMember); + } + + private Member ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค() { + final MemberImage memberImage = new MemberImage("originalFileName", "serverFilePath", ImageContentType.JPG); + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), "010-1234-5678"); + final Member creator = new Member(1L, new Identifier("cokirikiri"), + new EncryptedPassword(new Password("password1!")), new Nickname("์ฝ”๋ผ๋ฆฌ"), memberImage, memberProfile); + return memberRepository.save(creator); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String identifier, final String password, final String nickname, + final String phoneNumber) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), phoneNumber); + final Member member = new Member(new Identifier(identifier), + new EncryptedPassword(new Password(password)), new Nickname(nickname), + new MemberImage("file-name", "file-path", ImageContentType.PNG), memberProfile); + return memberRepository.save(member); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String name) { + final RoadmapCategory roadmapCategory = new RoadmapCategory(name); + return roadmapCategoryRepository.save(roadmapCategory); + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + roadmapNode1.addImages(new RoadmapNodeImages(๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค())); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private List ๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of( + new RoadmapNodeImage("node-image1.png", "node-image1-save-path", ImageContentType.PNG), + new RoadmapNodeImage("node-image2.png", "node-image2-save-path", ImageContentType.PNG) + ); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(final Member creator, final RoadmapCategory category) { + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmapRepository.save(roadmap); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapContent roadmapContent, final Member member) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(10), + roadmapContent, member); + final List roadmapNodes = roadmapContent.getNodes().getValues(); + + final RoadmapNode firstRoadmapNode = roadmapNodes.get(0); + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TODAY, TEN_DAY_LATER), 10, firstRoadmapNode); + + final RoadmapNode secondRoadmapNode = roadmapNodes.get(1); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), + 10, secondRoadmapNode); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes( + List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode)); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoom; + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberRepositoryTest.java new file mode 100644 index 000000000..080c9dbdb --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomPendingMemberRepositoryTest.java @@ -0,0 +1,382 @@ +package co.kirikiri.persistence.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImage; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.persistence.goalroom.dto.GoalRoomMemberSortType; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class GoalRoomPendingMemberRepositoryTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LAYER = TODAY.plusDays(20); + private static final LocalDate THIRTY_DAY_LATER = TODAY.plusDays(30); + + private final MemberRepository memberRepository; + private final RoadmapRepository roadmapRepository; + private final GoalRoomRepository goalRoomRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final GoalRoomPendingMemberRepository goalRoomPendingMemberRepository; + + public GoalRoomPendingMemberRepositoryTest(final MemberRepository memberRepository, + final RoadmapCategoryRepository roadmapCategoryRepository, + final RoadmapRepository roadmapRepository, + final GoalRoomRepository goalRoomRepository, + final GoalRoomPendingMemberRepository goalRoomPendingMemberRepository) { + this.memberRepository = memberRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + this.roadmapRepository = roadmapRepository; + this.goalRoomRepository = goalRoomRepository; + this.goalRoomPendingMemberRepository = goalRoomPendingMemberRepository; + } + + @Test + void ๊ณจ๋ฃธ๊ณผ_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_๋Œ€๊ธฐ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final GoalRoomPendingMember expected = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), savedGoalRoom, creator); + + // when + final Optional findGoalRoomPendingMember = goalRoomPendingMemberRepository.findByGoalRoomAndMemberIdentifier( + savedGoalRoom, new Identifier("cokirikiri")); + + // then + assertThat(findGoalRoomPendingMember.get()) + .usingRecursiveComparison() + .ignoringFields("id", "joinedAt") + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ๊ณผ_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_๋Œ€๊ธฐ_๋ชฉ๋ก_์กฐํšŒ์‹œ_์—†์œผ๋ฉด_๋นˆ๊ฐ’์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + // when + final Optional findGoalRoomPendingMember = goalRoomPendingMemberRepository.findByGoalRoomAndMemberIdentifier( + savedGoalRoom, new Identifier("cokirikiri2")); + + // then + assertThat(findGoalRoomPendingMember) + .isEmpty(); + } + + @Test + void ๊ณจ๋ฃธ์œผ๋กœ_์‚ฌ์šฉ์ž_๋Œ€๊ธฐ_๋ชฉ๋ก๊ณผ_๋ฉค๋ฒ„๋ฅผ_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomPendingMember goalRoomPendingMember = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), savedGoalRoom, creator); + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member2); + final GoalRoomPendingMember goalRoomPendingMember3 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member3); + goalRoomPendingMemberRepository.saveAll( + List.of(goalRoomPendingMember1, goalRoomPendingMember2, goalRoomPendingMember3)); + + final List expected = List.of(goalRoomPendingMember, goalRoomPendingMember1, + goalRoomPendingMember2, goalRoomPendingMember3); + + // when + final List findGoalRoomPendingMembers = goalRoomPendingMemberRepository.findAllByGoalRoom( + goalRoom); + + // then + assertThat(findGoalRoomPendingMembers) + .usingRecursiveComparison() + .ignoringFields("id", "joinedAt") + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์—_์ฐธ๊ฐ€ํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password!2", "name", "010-1111-1111"); + + //when + savedGoalRoom.join(follower); + + //then + final List goalRoomPendingMembers = goalRoomPendingMemberRepository.findByGoalRoom( + goalRoom); + + final List members = goalRoomPendingMembers.stream() + .map(GoalRoomPendingMember::getMember) + .toList(); + + Assertions.assertAll( + () -> assertThat(goalRoomPendingMembers).hasSize(2), + () -> assertThat(members).contains(follower) + ); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž๋ฅผ_์กฐํšŒํ•˜๊ณ _๋“ค์–ด์˜จ์ง€_์˜ค๋ž˜๋œ_์ˆœ์„œ๋Œ€๋กœ_์ •๋ ฌํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomPendingMember goalRoomPendingMember0 = goalRoom.getGoalRoomPendingMembers().getValues().get(0); + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member2); + final GoalRoomPendingMember goalRoomPendingMember3 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member3); + goalRoomPendingMemberRepository.saveAll( + List.of(goalRoomPendingMember1, goalRoomPendingMember2, goalRoomPendingMember3)); + final List expected = List.of(goalRoomPendingMember0, goalRoomPendingMember1, + goalRoomPendingMember2, goalRoomPendingMember3); + + // when + final List goalRoomPendingMembers = goalRoomPendingMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), GoalRoomMemberSortType.JOINED_ASC); + + // then + assertThat(goalRoomPendingMembers) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž๋ฅผ_์กฐํšŒํ•˜๊ณ _๋งˆ์ง€๋ง‰์œผ๋กœ_๋“ค์–ด์˜จ_์ˆœ์„œ๋Œ€๋กœ_์ •๋ ฌํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomPendingMember goalRoomPendingMember0 = goalRoom.getGoalRoomPendingMembers().getValues().get(0); + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), savedGoalRoom, member1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member2); + final GoalRoomPendingMember goalRoomPendingMember3 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member3); + final GoalRoomPendingMember savedGoalRoomPendingMember1 = goalRoomPendingMemberRepository.save( + goalRoomPendingMember1); + final GoalRoomPendingMember savedGoalRoomPendingMember2 = goalRoomPendingMemberRepository.save( + goalRoomPendingMember2); + final GoalRoomPendingMember savedGoalRoomPendingMember3 = goalRoomPendingMemberRepository.save( + goalRoomPendingMember3); + final List expected = List.of(savedGoalRoomPendingMember3, savedGoalRoomPendingMember2, + savedGoalRoomPendingMember1, goalRoomPendingMember0); + + // when + final List goalRoomPendingMembers = goalRoomPendingMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), GoalRoomMemberSortType.JOINED_DESC); + + // then + assertThat(goalRoomPendingMembers) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž๋ฅผ_์กฐํšŒํ•˜๊ณ _์ •๋ ฌ์กฐ๊ฑด์„_๋‹ฌ์„ฑ๋ฅ ์ˆœ_๋˜๋Š”_์ž…๋ ฅํ•˜์ง€_์•Š์€๊ฒฝ์šฐ_์ฐธ์—ฌํ•œ์ˆœ์œผ๋กœ_์ •๋ ฌํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(creator, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(targetRoadmapContent, creator); + final GoalRoom savedGoalRoom = goalRoomRepository.save(goalRoom); + + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier1", "password2!", "name1", "010-1111-1111"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier2", "password3!", "name2", "010-1111-1112"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomPendingMember goalRoomPendingMember0 = goalRoom.getGoalRoomPendingMembers().getValues().get(0); + final GoalRoomPendingMember goalRoomPendingMember1 = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), savedGoalRoom, member1); + final GoalRoomPendingMember goalRoomPendingMember2 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member2); + final GoalRoomPendingMember goalRoomPendingMember3 = new GoalRoomPendingMember(GoalRoomRole.FOLLOWER, + LocalDateTime.now(), savedGoalRoom, member3); + goalRoomPendingMemberRepository.saveAll( + List.of(goalRoomPendingMember1, goalRoomPendingMember2, goalRoomPendingMember3)); + final List expected = List.of(goalRoomPendingMember0, goalRoomPendingMember1, + goalRoomPendingMember2, goalRoomPendingMember3); + + // when + final List goalRoomPendingMembers1 = goalRoomPendingMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), GoalRoomMemberSortType.ACCOMPLISHMENT_RATE); + final List goalRoomPendingMembers2 = goalRoomPendingMemberRepository.findByGoalRoomIdOrderedBySortType( + savedGoalRoom.getId(), null); + + // then + assertThat(goalRoomPendingMembers1) + .isEqualTo(expected); + assertThat(goalRoomPendingMembers2) + .isEqualTo(expected); + } + + private Member ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค() { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), "010-1234-5678"); + final Member creator = new Member(new Identifier("cokirikiri"), + new EncryptedPassword(new Password("password1!")), new Nickname("์ฝ”๋ผ๋ฆฌ"), + new MemberImage("originalFileName", "serverFilePath", ImageContentType.PNG), memberProfile); + return memberRepository.save(creator); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String identifier, final String password, final String nickname, + final String phoneNumber) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), phoneNumber); + final Member member = new Member(new Identifier(identifier), new EncryptedPassword(new Password(password)), + new Nickname(nickname), new MemberImage("originalFileName", "serverFilePath", ImageContentType.PNG), + memberProfile); + return memberRepository.save(member); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String name) { + final RoadmapCategory roadmapCategory = new RoadmapCategory(name); + return roadmapCategoryRepository.save(roadmapCategory); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(final Member creator, final RoadmapCategory category) { + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmapRepository.save(roadmap); + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + roadmapNode1.addImages(new RoadmapNodeImages(๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค())); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private List ๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of( + new RoadmapNodeImage("node-image1.png", "node-image1-save-path", ImageContentType.PNG), + new RoadmapNodeImage("node-image2.png", "node-image2-save-path", ImageContentType.PNG) + ); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapContent roadmapContent, final Member member) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(10), + roadmapContent, member); + final List roadmapNodes = roadmapContent.getNodes().getValues(); + + final RoadmapNode firstRoadmapNode = roadmapNodes.get(0); + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TODAY, TEN_DAY_LATER), + 10, firstRoadmapNode); + + final RoadmapNode secondRoadmapNode = roadmapNodes.get(1); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), + 10, secondRoadmapNode); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes( + List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode)); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoom; + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomRepositoryTest.java new file mode 100644 index 000000000..a70ced50d --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomRepositoryTest.java @@ -0,0 +1,558 @@ +package co.kirikiri.persistence.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomStatus; +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsOrderType; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import java.time.LocalDate; +import java.util.List; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class GoalRoomRepositoryTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LAYER = TODAY.plusDays(20); + private static final LocalDate THIRTY_DAY_LATER = TODAY.plusDays(30); + + private final MemberRepository memberRepository; + private final RoadmapRepository roadmapRepository; + private final GoalRoomRepository goalRoomRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + + public GoalRoomRepositoryTest(final MemberRepository memberRepository, + final RoadmapRepository roadmapRepository, + final GoalRoomRepository goalRoomRepository, + final RoadmapCategoryRepository roadmapCategoryRepository) { + this.memberRepository = memberRepository; + this.roadmapRepository = roadmapRepository; + this.goalRoomRepository = goalRoomRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), goalRoomPendingMember1); + goalRoomRepository.save(goalRoom); + + // when + final GoalRoom findGoalRoom = goalRoomRepository.findByIdWithRoadmapContent(goalRoom.getId()) + .get(); + + // then + assertThat(findGoalRoom) + .usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(goalRoom); + } + + @Test + void ๊ณจ๋ฃธ์„_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), goalRoomPendingMember1); + goalRoomRepository.save(goalRoom1); + + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name3", "01011113333", "identifier3", "password!3"); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3, goalRoomRoadmapNode4)), goalRoomPendingMember2); + goalRoomRepository.save(goalRoom2); + + // when + final List goalRooms1 = goalRoomRepository.findGoalRoomsWithPendingMembersByRoadmapAndCond(roadmap, + RoadmapGoalRoomsOrderType.LATEST, null, 1); + final List goalRooms2 = goalRoomRepository.findGoalRoomsWithPendingMembersByRoadmapAndCond(roadmap, + RoadmapGoalRoomsOrderType.LATEST, goalRoom2.getId(), 10); + + assertThat(goalRooms1) + .isEqualTo(List.of(goalRoom2, goalRoom1)); + assertThat(goalRooms2) + .isEqualTo(List.of(goalRoom1)); + } + + @Test + void ๊ณจ๋ฃธ์„_๋งˆ๊ฐ์ž„๋ฐ•_์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), goalRoomPendingMember1); + goalRoomRepository.save(goalRoom1); + + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(1), TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name4", "01011114444", "identifier4", "password!4"); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3, goalRoomRoadmapNode4)), goalRoomPendingMember3); + goalRoomRepository.save(goalRoom2); + + // when + final List goalRooms1 = goalRoomRepository.findGoalRoomsWithPendingMembersByRoadmapAndCond(roadmap, + RoadmapGoalRoomsOrderType.CLOSE_TO_DEADLINE, null, 1); + final List goalRooms2 = goalRoomRepository.findGoalRoomsWithPendingMembersByRoadmapAndCond(roadmap, + RoadmapGoalRoomsOrderType.CLOSE_TO_DEADLINE, goalRoom1.getId(), 10); + + // then + assertThat(goalRooms1).isEqualTo(List.of(goalRoom1, goalRoom2)); + assertThat(goalRooms2).isEqualTo(List.of(goalRoom2)); + } + + @Test + void ๊ณจ๋ฃธ์˜_๋…ธ๋“œ์˜_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์˜ค๋Š˜์ธ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(10), TODAY.plusDays(20), + roadmapNode1); + + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1)), creator); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode2)), creator); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom3", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3)), creator); + + final GoalRoom savedGoalRoom1 = goalRoomRepository.save(goalRoom1); + final GoalRoom savedGoalRoom2 = goalRoomRepository.save(goalRoom2); + goalRoomRepository.save(goalRoom3); + + // when + final List findGoalRooms = goalRoomRepository.findAllByStartDate(LocalDate.now()); + + // then + assertThat(findGoalRooms) + .usingRecursiveComparison() + .ignoringFields("id") + .isEqualTo(List.of(savedGoalRoom1, savedGoalRoom2)); + } + + @Test + void ํˆฌ๋‘๋ฆฌ์ŠคํŠธ์™€_ํ•จ๊ป˜_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() { + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), goalRoomPendingMember); + + final LocalDate today = LocalDate.now(); + final LocalDate threeDaysAfter = today.plusDays(3); + goalRoom.addGoalRoomTodo(new GoalRoomToDo( + new GoalRoomTodoContent("ํˆฌ๋‘1"), new Period(today, threeDaysAfter) + )); + goalRoom.addGoalRoomTodo(new GoalRoomToDo( + new GoalRoomTodoContent("ํˆฌ๋‘2"), new Period(today, threeDaysAfter) + )); + goalRoomRepository.save(goalRoom); + + // when + final GoalRoom findGoalRoom = goalRoomRepository.findByIdWithTodos(goalRoom.getId()).get(); + + // then + assertThat(findGoalRoom) + .usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(goalRoom); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ๊ณผ_๋กœ๋“œ๋งต์ปจํ…์ธ _๊ณจ๋ฃธ๋…ธ๋“œ_ํˆฌ๋‘_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapNode roadmapNode = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode); + + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1)), creator); + final GoalRoomToDo goalRoomToDo1 = new GoalRoomToDo(new GoalRoomTodoContent("ํ•  ์ผ ๋ชฉ๋ก"), + new Period(TODAY, TEN_DAY_LATER)); + goalRoom1.addGoalRoomTodo(goalRoomToDo1); + final GoalRoom savedGoalRoom1 = goalRoomRepository.save(goalRoom1); + + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode2)), creator); + final GoalRoomToDo goalRoomToDo2 = new GoalRoomToDo(new GoalRoomTodoContent("์šฐ๋ฆฌ๋งŒ์˜ ํˆฌ๋‘"), + new Period(TEN_DAY_LATER, TWENTY_DAY_LAYER)); + goalRoom2.addGoalRoomTodo(goalRoomToDo2); + final GoalRoom savedGoalRoom2 = goalRoomRepository.save(goalRoom2); + + // when + final GoalRoom findGoalRoom1 = goalRoomRepository.findByIdWithContentAndTodos(goalRoom1.getId()) + .get(); + final GoalRoom findGoalRoom2 = goalRoomRepository.findByIdWithContentAndTodos(goalRoom2.getId()) + .get(); + + //then + assertAll( + () -> assertThat(findGoalRoom1) + .usingRecursiveComparison() + .ignoringFields("id") + .isEqualTo(savedGoalRoom1), + () -> assertThat(findGoalRoom2) + .usingRecursiveComparison() + .ignoringFields("id") + .isEqualTo(savedGoalRoom2) + ); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ฐธ๊ฐ€ํ•œ_๋ชจ๋“ _๊ณจ๋ฃธ๋“ค์„_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(10), TODAY.plusDays(20), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(10), TODAY.plusDays(20), + roadmapNode1); + + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1)), creator); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode2)), creator); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom3", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3)), creator); + final GoalRoom goalRoom4 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom3", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3)), creator); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("ํŒ”๋กœ์›Œ", "010-111-1111", "identifier2", "password2@"); + goalRoom1.join(member); + goalRoom2.join(member); + goalRoom3.join(member); + goalRoom2.start(); + goalRoom3.complete(); + + goalRoomRepository.save(goalRoom1); + goalRoomRepository.save(goalRoom2); + goalRoomRepository.save(goalRoom3); + goalRoomRepository.save(goalRoom4); + + //when + final List creatorMemberGoalRooms = goalRoomRepository.findByMember(creator); + final List followerMemberGoalRooms = goalRoomRepository.findByMember(member); + + //then + assertAll( + () -> assertThat(creatorMemberGoalRooms) + .usingRecursiveComparison() + .isEqualTo(List.of(goalRoom1, goalRoom2, goalRoom3, goalRoom4)), + () -> assertThat(followerMemberGoalRooms) + .usingRecursiveComparison() + .isEqualTo(List.of(goalRoom1, goalRoom2, goalRoom3)) + ); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ฐธ๊ฐ€ํ•œ_๊ณจ๋ฃธ๋“ค์„_์ƒํƒœ์—_๋”ฐ๋ผ_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(10), TODAY.plusDays(20), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(10), TODAY.plusDays(20), + roadmapNode1); + + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1)), creator); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode2)), creator); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom3", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3)), creator); + final GoalRoom goalRoom4 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom3", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3)), creator); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("ํŒ”๋กœ์›Œ", "010-111-1111", "identifier2", "password2@"); + goalRoom1.join(member); + goalRoom2.join(member); + goalRoom3.join(member); + goalRoom4.join(member); + goalRoom2.start(); + goalRoom3.complete(); + + goalRoomRepository.save(goalRoom1); + goalRoomRepository.save(goalRoom2); + goalRoomRepository.save(goalRoom3); + goalRoomRepository.save(goalRoom4); + + //when + final List memberRecruitingGoalRooms = goalRoomRepository.findByMemberAndStatus(member, + GoalRoomStatus.RECRUITING); + final List memberRunningGoalRooms = goalRoomRepository.findByMemberAndStatus(member, + GoalRoomStatus.RUNNING); + final List memberCompletedGoalRooms = goalRoomRepository.findByMemberAndStatus(member, + GoalRoomStatus.COMPLETED); + + //then + assertAll( + () -> assertThat(memberRecruitingGoalRooms) + .usingRecursiveComparison() + .isEqualTo(List.of(goalRoom1, goalRoom4)), + () -> assertThat(memberRunningGoalRooms) + .usingRecursiveComparison() + .isEqualTo(List.of(goalRoom2)), + () -> assertThat(memberCompletedGoalRooms) + .usingRecursiveComparison() + .isEqualTo(List.of(goalRoom3)) + ); + } + + @Test + void ๋…ธ๋“œ์™€_ํ•จ๊ป˜_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() { + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), goalRoomPendingMember); + goalRoomRepository.save(goalRoom); + + // when + final GoalRoom findGoalRoom = goalRoomRepository.findByIdWithNodes(goalRoom.getId()).get(); + + // then + assertThat(findGoalRoom) + .usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(goalRoom); + } + + @Test + void ๋กœ๋“œ๋งต์—_์ƒ์„ฑ๋œ_๋ชจ๋“ _๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() { + //given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค(); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapNode roadmapNode = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode)); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TEN_DAY_LATER, + roadmapNode); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TEN_DAY_LATER, TWENTY_DAY_LAYER, + roadmapNode); + + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1)), creator); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode2)), creator); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom3", 20, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1)), creator); + goalRoomRepository.save(goalRoom1); + goalRoomRepository.save(goalRoom2); + goalRoomRepository.save(goalRoom3); + + // when + final List goalRooms = goalRoomRepository.findByRoadmap(roadmap); + + // then + assertThat(goalRooms) + .isEqualTo(List.of(goalRoom1, goalRoom2, goalRoom3)); + } + + @Test + void ๋กœ๋“œ๋งต์œผ๋กœ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + + final RoadmapContent roadmapContent1 = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + final Roadmap roadmap1 = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent1); + + final RoadmapNode roadmapNode3 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ ์ž…๋‹ˆ๋‹ค.", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode4 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ ์ž…๋‹ˆ๋‹ค.", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + + final RoadmapContent roadmapContent2 = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode3, roadmapNode4)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent2); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TEN_DAY_LATER, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TWENTY_DAY_LAYER, THIRTY_DAY_LATER, + roadmapNode2); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent1, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), member); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom2", 6, roadmapContent1, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), member); + + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TEN_DAY_LATER, roadmapNode3); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TWENTY_DAY_LAYER, THIRTY_DAY_LATER, + roadmapNode4); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom3", 6, roadmapContent2, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3, goalRoomRoadmapNode4)), member); + + goalRoomRepository.saveAll(List.of(goalRoom1, goalRoom2, goalRoom3)); + + // when + final List goalRooms = goalRoomRepository.findByRoadmap(roadmap1); + + // then + assertThat(goalRooms).isEqualTo(List.of(goalRoom1, goalRoom2)); + } + + private Member ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ €์žฅํ•œ๋‹ค() { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, + LocalDate.of(1990, 1, 1), "010-1234-5678"); + final Member creator = new Member(new Identifier("cokirikiri"), + new EncryptedPassword(new Password("password1!")), new Nickname("์ฝ”๋ผ๋ฆฌ"), null, memberProfile); + return memberRepository.save(creator); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String nickname, final String phoneNumber, final String identifier, + final String password) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), + phoneNumber); + final Member creator = new Member(new Identifier(identifier), + new EncryptedPassword(new Password(password)), new Nickname(nickname), null, memberProfile); + return memberRepository.save(creator); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String name) { + final RoadmapCategory roadmapCategory = new RoadmapCategory(name); + return roadmapCategoryRepository.save(roadmapCategory); + } + + private RoadmapNode ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String title, final String content) { + return new RoadmapNode(title, content); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final Member creator, final RoadmapCategory category, + final RoadmapContent roadmapContent) { + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 30, RoadmapDifficulty.DIFFICULT, + creator, category); + roadmap.addContent(roadmapContent); + return roadmapRepository.save(roadmap); + } + + private GoalRoomRoadmapNode ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final LocalDate startDate, final LocalDate endDate, + final RoadmapNode roadmapNode) { + return new GoalRoomRoadmapNode(new Period(startDate, endDate), 1, roadmapNode); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final String name, final Integer limitedMemberCount, final RoadmapContent roadmapContent, + final GoalRoomRoadmapNodes goalRoomRoadmapNodes, final Member member) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName(name), new LimitedMemberCount(limitedMemberCount), + roadmapContent, member); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoom; + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomToDoCheckRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomToDoCheckRepositoryTest.java new file mode 100644 index 000000000..c590e95d2 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/goalroom/GoalRoomToDoCheckRepositoryTest.java @@ -0,0 +1,200 @@ +package co.kirikiri.persistence.goalroom; + +import static org.assertj.core.api.Assertions.assertThat; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.GoalRoomToDoCheck; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class GoalRoomToDoCheckRepositoryTest { + + private static final LocalDate TODAY = LocalDate.now(); + + private final MemberRepository memberRepository; + private final RoadmapRepository roadmapRepository; + private final GoalRoomRepository goalRoomRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final GoalRoomToDoCheckRepository goalRoomToDoCheckRepository; + + public GoalRoomToDoCheckRepositoryTest(final MemberRepository memberRepository, + final RoadmapRepository roadmapRepository, + final GoalRoomRepository goalRoomRepository, + final GoalRoomMemberRepository goalRoomMemberRepository, + final RoadmapCategoryRepository roadmapCategoryRepository, + final GoalRoomToDoCheckRepository goalRoomToDoCheckRepository) { + this.memberRepository = memberRepository; + this.roadmapRepository = roadmapRepository; + this.goalRoomRepository = goalRoomRepository; + this.goalRoomMemberRepository = goalRoomMemberRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + this.goalRoomToDoCheckRepository = goalRoomToDoCheckRepository; + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””์™€_ํˆฌ๋‘_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ฒดํฌ_ํ˜„ํ™ฉ์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), goalRoomPendingMember); + + final LocalDate today = LocalDate.now(); + final LocalDate threeDaysAfter = today.plusDays(3); + final GoalRoomToDo firstGoalRoomTodo = new GoalRoomToDo( + new GoalRoomTodoContent("ํˆฌ๋‘1"), new Period(today, threeDaysAfter)); + final GoalRoomToDo secondGoalRoomTodo = new GoalRoomToDo( + new GoalRoomTodoContent("ํˆฌ๋‘2"), new Period(today, threeDaysAfter)); + goalRoom.addGoalRoomTodo(firstGoalRoomTodo); + goalRoom.addGoalRoomTodo(secondGoalRoomTodo); + goalRoomRepository.save(goalRoom); + + final GoalRoomMember goalRoomMember = new GoalRoomMember( + GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + goalRoomMemberRepository.save(goalRoomMember); + + final GoalRoomToDoCheck firstGoalRoomToDoCheck = new GoalRoomToDoCheck(goalRoomMember, firstGoalRoomTodo); + final GoalRoomToDoCheck secondGoalRoomToDoCheck = new GoalRoomToDoCheck(goalRoomMember, secondGoalRoomTodo); + goalRoomToDoCheckRepository.saveAll(List.of(firstGoalRoomToDoCheck, secondGoalRoomToDoCheck)); + + // when + final GoalRoomToDoCheck findGoalRoomTodoCheck = goalRoomToDoCheckRepository.findByGoalRoomIdAndTodoAndMemberIdentifier( + goalRoom.getId(), firstGoalRoomTodo, new Identifier("identifier1")).get(); + + // then + assertThat(findGoalRoomTodoCheck) + .usingRecursiveComparison() + .isEqualTo(firstGoalRoomToDoCheck); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_ํˆฌ๋‘_์ฒดํฌ_ํ˜„ํ™ฉ์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name1", "01011111111", "identifier1", "password!1"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("์—ฌ๊ฐ€"); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator, category, roadmapContent); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY, TODAY.plusDays(10), + roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(TODAY.plusDays(11), TODAY.plusDays(20), + roadmapNode2); + final Member goalRoomPendingMember = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("name2", "01011112222", "identifier2", "password!2"); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค("goalroom1", 6, roadmapContent, + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)), goalRoomPendingMember); + + final LocalDate today = LocalDate.now(); + final LocalDate threeDaysAfter = today.plusDays(3); + final GoalRoomToDo firstGoalRoomTodo = new GoalRoomToDo( + new GoalRoomTodoContent("ํˆฌ๋‘1"), new Period(today, threeDaysAfter)); + final GoalRoomToDo secondGoalRoomTodo = new GoalRoomToDo( + new GoalRoomTodoContent("ํˆฌ๋‘2"), new Period(today, threeDaysAfter)); + goalRoom.addGoalRoomTodo(firstGoalRoomTodo); + goalRoom.addGoalRoomTodo(secondGoalRoomTodo); + goalRoomRepository.save(goalRoom); + + final GoalRoomMember goalRoomMember = new GoalRoomMember( + GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, creator); + goalRoomMemberRepository.save(goalRoomMember); + + final GoalRoomToDoCheck firstGoalRoomToDoCheck = new GoalRoomToDoCheck(goalRoomMember, firstGoalRoomTodo); + final GoalRoomToDoCheck secondGoalRoomToDoCheck = new GoalRoomToDoCheck(goalRoomMember, secondGoalRoomTodo); + goalRoomToDoCheckRepository.saveAll(List.of(firstGoalRoomToDoCheck, secondGoalRoomToDoCheck)); + + // when + final List findGoalRoomTodoCheck = goalRoomToDoCheckRepository.findByGoalRoomIdAndMemberIdentifier( + goalRoom.getId(), new Identifier("identifier1")); + + // then + assertThat(findGoalRoomTodoCheck) + .usingRecursiveComparison() + .isEqualTo(List.of(firstGoalRoomToDoCheck, secondGoalRoomToDoCheck)); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String name) { + final RoadmapCategory roadmapCategory = new RoadmapCategory(name); + return roadmapCategoryRepository.save(roadmapCategory); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String nickname, final String phoneNumber, final String identifier, + final String password) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), + phoneNumber); + final Member creator = new Member(new Identifier(identifier), + new EncryptedPassword(new Password(password)), new Nickname(nickname), null, memberProfile); + return memberRepository.save(creator); + } + + private RoadmapNode ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String title, final String content) { + return new RoadmapNode(title, content); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final Member creator, final RoadmapCategory category, + final RoadmapContent roadmapContent) { + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 30, RoadmapDifficulty.DIFFICULT, + creator, category); + roadmap.addContent(roadmapContent); + return roadmapRepository.save(roadmap); + } + + private GoalRoomRoadmapNode ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final LocalDate startDate, final LocalDate endDate, + final RoadmapNode roadmapNode) { + return new GoalRoomRoadmapNode(new Period(startDate, endDate), 1, roadmapNode); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final String name, final Integer limitedMemberCount, final RoadmapContent roadmapContent, + final GoalRoomRoadmapNodes goalRoomRoadmapNodes, final Member member) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName(name), new LimitedMemberCount(limitedMemberCount), + roadmapContent, member); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoom; + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/helper/RepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/helper/RepositoryTest.java new file mode 100644 index 000000000..3705cb9da --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/helper/RepositoryTest.java @@ -0,0 +1,22 @@ +package co.kirikiri.persistence.helper; + +import co.kirikiri.common.config.JpaConfig; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestConstructor; +import org.springframework.test.context.TestConstructor.AutowireMode; + +@DataJpaTest +@ActiveProfiles("test") +@Import({JpaConfig.class}) +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@TestConstructor(autowireMode = AutowireMode.ALL) +public @interface RepositoryTest { + +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/member/MemberRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/member/MemberRepositoryTest.java new file mode 100644 index 000000000..7d8d88b8f --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/member/MemberRepositoryTest.java @@ -0,0 +1,98 @@ +package co.kirikiri.persistence.member; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.persistence.helper.RepositoryTest; +import java.time.LocalDate; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class MemberRepositoryTest { + + private static Member member; + + private final MemberRepository memberRepository; + + public MemberRepositoryTest(final MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + @BeforeAll + static void setUp() { + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final EncryptedPassword encryptedPassword = new EncryptedPassword(password); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber); + final MemberImage memberImage = new MemberImage("originalFileName", "serverFilePath", ImageContentType.PNG); + member = new Member(identifier, encryptedPassword, nickname, memberImage, memberProfile); + } + + @Test + void ์•„์ด๋””๋กœ_์‚ฌ์šฉ์ž๋ฅผ_์ฐพ๋Š”๋‹ค() { + //given + memberRepository.save(member); + + //when + final Optional optionalMember = memberRepository.findByIdentifier(new Identifier("identifier1")); + + //then + assertThat(optionalMember).isNotEmpty(); + } + + @Test + void ์‚ฌ์šฉ์Ÿˆ์˜_์•„์ด๋””๋กœ_์‚ฌ์šฉ์ž์˜_ํ”„๋กœํ•„๊ณผ_์ด๋ฏธ์ง€๋ฅผ_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + // given + final Member savedMember = memberRepository.save(member); + + // when + final Member findMember = memberRepository.findWithMemberProfileAndImageByIdentifier( + savedMember.getIdentifier().getValue()).get(); + + // then + final MemberProfile memberProfile = findMember.getMemberProfile(); + final MemberImage memberImage = findMember.getImage(); + + assertAll( + () -> assertThat(member.getIdentifier().getValue()).isEqualTo("identifier1"), + () -> assertThat(memberProfile.getGender()).isEqualTo(Gender.MALE), + () -> assertThat(memberProfile.getPhoneNumber()).isEqualTo("010-1234-5678"), + () -> assertThat(memberProfile.getBirthday()).isEqualTo(LocalDate.now()), + () -> assertThat(memberImage.getServerFilePath()).isEqualTo("serverFilePath") + ); + } + + @Test + void ์‹๋ณ„์ž_์•„์ด๋””๋กœ_์‚ฌ์šฉ์ž์˜_ํ”„๋กœํ•„๊ณผ_์ด๋ฏธ์ง€๋ฅผ_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + // given + final Member savedMember = memberRepository.save(member); + + // when + final Member findMember = memberRepository.findWithMemberProfileAndImageById(savedMember.getId()).get(); + + // then + final MemberProfile memberProfile = findMember.getMemberProfile(); + final MemberImage memberImage = findMember.getImage(); + + assertAll( + () -> assertThat(member.getIdentifier().getValue()).isEqualTo("identifier1"), + () -> assertThat(memberProfile.getGender()).isEqualTo(Gender.MALE), + () -> assertThat(memberProfile.getPhoneNumber()).isEqualTo("010-1234-5678"), + () -> assertThat(memberProfile.getBirthday()).isEqualTo(LocalDate.now()), + () -> assertThat(memberImage.getServerFilePath()).isEqualTo("serverFilePath") + ); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapContentRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapContentRepositoryTest.java new file mode 100644 index 000000000..c102751c4 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapContentRepositoryTest.java @@ -0,0 +1,101 @@ +package co.kirikiri.persistence.roadmap; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import java.time.LocalDate; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class RoadmapContentRepositoryTest { + + private final MemberRepository memberRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + private final RoadmapRepository roadmapRepository; + private final RoadmapContentRepository roadmapContentRepository; + + public RoadmapContentRepositoryTest(final MemberRepository memberRepository, + final RoadmapCategoryRepository roadmapCategoryRepository, + final RoadmapRepository roadmapRepository, + final RoadmapContentRepository roadmapContentRepository) { + this.memberRepository = memberRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + this.roadmapRepository = roadmapRepository; + this.roadmapContentRepository = roadmapContentRepository; + } + + @Test + void ๋กœ๋“œ๋งต_์ปจํ…์ธ ๋ฅผ_๋กœ๋“œ๋งต๊ณผ_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + // given + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap savedRoadmap = roadmapRepository.save(roadmap); + final Long roadmapContentId = savedRoadmap.getContents().getValues().get(0).getId(); + + // when + final RoadmapContent roadmapContent = roadmapContentRepository.findByIdWithRoadmap(roadmapContentId).get(); + + // then + assertAll( + () -> assertThat(roadmapContent).isEqualTo(savedRoadmap.getContents().getValues().get(0)), + () -> assertThat(roadmapContent.getRoadmap()).isEqualTo(savedRoadmap) + ); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๊ฐ€์žฅ_์ตœ๊ทผ_์ปจํ…์ธ ๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + // given + final Roadmap savedRoadmap = roadmapRepository.save(๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค()); + final RoadmapContent oldRoadmapContent = roadmapContentRepository.findFirstByRoadmapOrderByCreatedAtDesc( + savedRoadmap).get(); + + final RoadmapContent newRoadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ์ œ๋ชฉ"); + savedRoadmap.addContent(newRoadmapContent); + + // when + final RoadmapContent expectedRoadmapContent = roadmapContentRepository.findFirstByRoadmapOrderByCreatedAtDesc( + savedRoadmap).get(); + + // then + assertAll( + () -> assertThat(oldRoadmapContent).isNotEqualTo(expectedRoadmapContent), + () -> assertThat(expectedRoadmapContent).isEqualTo(newRoadmapContent) + ); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค() { + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapCategory category = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent content = new RoadmapContent("๋กœ๋“œ๋งต ์ œ๋ชฉ"); + + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์„ค๋ช…", 100, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(content); + + return roadmap; + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1995, 9, 30), "010-0000-0000"); + final Member member = new Member(new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), new Nickname("์ฌ์ƒท"), null, memberProfile); + + return memberRepository.save(member); + } + + private RoadmapCategory ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapCategory category = new RoadmapCategory("์šด๋™"); + return roadmapCategoryRepository.save(category); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapRepositoryTest.java new file mode 100644 index 000000000..9ad5dfdb8 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapRepositoryTest.java @@ -0,0 +1,629 @@ +package co.kirikiri.persistence.roadmap; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.domain.roadmap.RoadmapReview; +import co.kirikiri.domain.roadmap.RoadmapStatus; +import co.kirikiri.domain.roadmap.RoadmapTag; +import co.kirikiri.domain.roadmap.RoadmapTags; +import co.kirikiri.domain.roadmap.vo.RoadmapTagName; +import co.kirikiri.persistence.dto.RoadmapOrderType; +import co.kirikiri.persistence.dto.RoadmapSearchDto; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class RoadmapRepositoryTest { + + private final MemberRepository memberRepository; + private final RoadmapRepository roadmapRepository; + private final GoalRoomRepository goalRoomRepository; + private final GoalRoomMemberRepository goalRoomMemberRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + + public RoadmapRepositoryTest(final MemberRepository memberRepository, + final RoadmapRepository roadmapRepository, + final GoalRoomRepository goalRoomRepository, + final GoalRoomMemberRepository goalRoomMemberRepository, + final RoadmapCategoryRepository roadmapCategoryRepository) { + this.memberRepository = memberRepository; + this.roadmapRepository = roadmapRepository; + this.goalRoomRepository = goalRoomRepository; + this.goalRoomMemberRepository = goalRoomMemberRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + } + + @Test + void ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + + // when + final Roadmap savedRoadmap = roadmapRepository.save(roadmap); + + // then + assertThat(savedRoadmap).usingRecursiveComparison() + .isEqualTo(roadmap); + } + + @Test + void ๋‹จ์ผ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌ๊ฐ€"); + final Roadmap savedRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต ์ œ๋ชฉ", creator, category); + + // when + final Roadmap expectedRoadmap = roadmapRepository.findRoadmapById(savedRoadmap.getId()).get(); + + assertThat(expectedRoadmap) + .usingRecursiveComparison() + .isEqualTo(savedRoadmap); + } + + @Test + void ์นดํ…Œ๊ณ ๋ฆฌ_๊ฐ’์ด_null์ด๋ผ๋ฉด_์‚ญ์ œ๋˜์ง€_์•Š์€_์ „์ฒด_๋กœ๋“œ๋งต์„_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + final Roadmap gameRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต", creator, gameCategory); + final Roadmap gameRoadmap2 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต2", creator, gameCategory); + final Roadmap travelRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต", creator, travelCategory); + ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต2", creator, travelCategory); + + final RoadmapCategory category = null; + final RoadmapOrderType orderType = RoadmapOrderType.LATEST; + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + null, 2); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(3), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(travelRoadmap, gameRoadmap2, gameRoadmap)) + ); + } + + @Test + void ์นดํ…Œ๊ณ ๋ฆฌ_๊ฐ’์œผ๋กœ_1์ด์ƒ์˜_์œ ํšจํ•œ_๊ฐ’์ด_๋“ค์–ด์˜ค๋ฉด_ํ•ด๋‹น_์นดํ…Œ๊ณ ๋ฆฌ์˜_์‚ญ์ œ๋˜์ง€_์•Š์€_๋กœ๋“œ๋งต์„_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + final Roadmap gameRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต", creator, gameCategory); + final Roadmap gameRoadmap2 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต2", creator, gameCategory); + ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต3", creator, gameCategory); + ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต4", creator, travelCategory); + + final RoadmapOrderType orderType = RoadmapOrderType.LATEST; + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCategory(gameCategory, orderType, + null, 10); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(2), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(gameRoadmap2, gameRoadmap)) + ); + } + + @Test + void ์นดํ…Œ๊ณ ๋ฆฌ_์กฐ๊ฑด_์—†์ด_์ฃผ์–ด์ง„_๋กœ๋“œ๋งต_์ด์ „์˜_๋ฐ์ดํ„ฐ๋ฅผ_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + final Roadmap gameRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต", creator, gameCategory); + final Roadmap gameRoadmap2 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต2", creator, gameCategory); + final Roadmap travelRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต", creator, travelCategory); + ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต2", creator, travelCategory); + + final RoadmapCategory category = null; + final RoadmapOrderType orderType = RoadmapOrderType.LATEST; + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + null, 2); + final List secondRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + gameRoadmap2.getId(), 10); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(3), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(travelRoadmap, gameRoadmap2, gameRoadmap)), + + () -> assertThat(secondRoadmapRequest.size()).isEqualTo(1), + () -> assertThat(secondRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(gameRoadmap)) + ); + } + + @Test + void ์นดํ…Œ๊ณ ๋ฆฌ_์กฐ๊ฑด_์—†์ด_์ฃผ์–ด์ง„_๋กœ๋“œ๋งต_์ด์ „์˜_๋ฐ์ดํ„ฐ๋ฅผ_์ƒ์„ฑ๋œ_๊ณจ๋ฃธ์ด_๋งŽ์€์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + final Roadmap gameRoadmap1 = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต", creator, gameCategory); + final Roadmap gameRoadmap2 = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต2", creator, gameCategory); + final Roadmap travelRoadmap = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต", creator, travelCategory); + ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต2", creator, travelCategory); + + // gameRoadmap1 : ๊ณจ๋ฃธ 3๊ฐœ + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(gameRoadmap1.getContents().getValues().get(0), creator); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(gameRoadmap1.getContents().getValues().get(0), creator); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(gameRoadmap1.getContents().getValues().get(0), creator); + + // gameRoadmap2 : ๊ณจ๋ฃธ 0๊ฐœ + // travelRoadmap : ๊ณจ๋ฃธ 1๊ฐœ + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(travelRoadmap.getContents().getValues().get(0), creator); + + final RoadmapCategory category = null; + final RoadmapOrderType orderType = RoadmapOrderType.GOAL_ROOM_COUNT; + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + null, 2); + final List secondRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + travelRoadmap.getId(), 10); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(3), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(gameRoadmap1, travelRoadmap, gameRoadmap2)), + + () -> assertThat(secondRoadmapRequest.size()).isEqualTo(1), + () -> assertThat(secondRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(gameRoadmap2)) + ); + } + + @Test + void ์นดํ…Œ๊ณ ๋ฆฌ_์กฐ๊ฑด_์—†์ด_์ฃผ์–ด์ง„_๋กœ๋“œ๋งต_์ด์ „์˜_๋ฐ์ดํ„ฐ๋ฅผ_์ฐธ๊ฐ€์ค‘์ธ_์ธ์›์ด_๋งŽ์€์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri2", "์ฝ”๋ผ๋ฆฌ2"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + final Roadmap gameRoadmap1 = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต", creator, gameCategory); + final Roadmap gameRoadmap2 = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต2", creator, gameCategory); + final Roadmap travelRoadmap = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต", creator, travelCategory); + ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต2", creator, travelCategory); + + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(gameRoadmap1.getContents().getValues().get(0), creator); + final GoalRoom gameRoadmap2GoalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(gameRoadmap2.getContents().getValues().get(0), creator); + final GoalRoom travelRoadmapGoalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(travelRoadmap.getContents().getValues().get(0), creator); + + // gameRoadmap1 : ์ฐธ๊ฐ€์ธ์› 0๋ช… + // gameRoadmap2 : ์ฐธ๊ฐ€์ธ์› 1๋ช… + final List gameRoadmap2GoalRoomMembers = List.of( + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), gameRoadmap2GoalRoom, creator)); + goalRoomMemberRepository.saveAll(gameRoadmap2GoalRoomMembers); + + // travelRoadmap : ์ฐธ๊ฐ€์ธ์› 2๋ช… + final List travelRoadmapGoalRoomMembers = List.of( + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), travelRoadmapGoalRoom, creator), + new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), travelRoadmapGoalRoom, follower)); + goalRoomMemberRepository.saveAll(travelRoadmapGoalRoomMembers); + + final RoadmapCategory category = null; + final RoadmapOrderType orderType = RoadmapOrderType.PARTICIPANT_COUNT; + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + null, 2); + final List secondRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + gameRoadmap2.getId(), 10); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(3), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(travelRoadmap, gameRoadmap2, gameRoadmap1)), + + () -> assertThat(secondRoadmapRequest.size()).isEqualTo(1), + () -> assertThat(secondRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(gameRoadmap1)) + ); + } + + @Test + void ์นดํ…Œ๊ณ ๋ฆฌ_์กฐ๊ฑด_์—†์ด_์ฃผ์–ด์ง„_๋กœ๋“œ๋งต_์ด์ „์˜_๋ฐ์ดํ„ฐ๋ฅผ_ํ‰์ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri2", "์ฝ”๋ผ๋ฆฌ2"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + final Roadmap gameRoadmap1 = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต", creator, gameCategory); + final Roadmap gameRoadmap2 = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„ ๋กœ๋“œ๋งต2", creator, gameCategory); + final Roadmap travelRoadmap = ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต", creator, travelCategory); + ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์—ฌํ–‰ ๋กœ๋“œ๋งต2", creator, travelCategory); + + // gameRoadmap1 : 4.5 + final RoadmapReview gameRoadmap1Review = new RoadmapReview("๋ฆฌ๋ทฐ1", 4.5, follower); + gameRoadmap1.addReview(gameRoadmap1Review); + roadmapRepository.save(gameRoadmap1); + + // gameRoadmap2 : 5.0 + final RoadmapReview gameRoadmap2Review = new RoadmapReview("๋ฆฌ๋ทฐ2", 5.0, follower); + gameRoadmap2.addReview(gameRoadmap2Review); + roadmapRepository.save(gameRoadmap2); + + // travelRoadmap : 4.0 + final RoadmapReview travelRoadmapReview = new RoadmapReview("๋ฆฌ๋ทฐ3", 4.0, follower); + travelRoadmap.addReview(travelRoadmapReview); + roadmapRepository.save(travelRoadmap); + + final RoadmapCategory category = null; + final RoadmapOrderType orderType = RoadmapOrderType.REVIEW_RATE; + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + null, 2); + final List secondRoadmapRequest = roadmapRepository.findRoadmapsByCategory(category, orderType, + gameRoadmap1.getId(), 10); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(3), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(gameRoadmap2, gameRoadmap1, travelRoadmap)), + + () -> assertThat(secondRoadmapRequest.size()).isEqualTo(1), + () -> assertThat(secondRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(travelRoadmap)) + ); + } + + @Test + void ๋กœ๋“œ๋งต์„_์ œ๋ชฉ์œผ๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌ๊ฐ€"); + + final Roadmap roadmap1 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator, category); + final Roadmap roadmap2 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์งฑ๋กœ๋“œ๋งต", creator, category); + final Roadmap roadmap3 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ ๋“œ๋งต์งฑ", creator, category); + final Roadmap roadmap4 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("์งฑ๋กœ๋“œ ๋งต์งฑ", creator, category); + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ", creator, category); + ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator, category); + + final RoadmapOrderType orderType = RoadmapOrderType.LATEST; + final RoadmapSearchDto searchRequest = RoadmapSearchDto.create(null, " ๋กœ ๋“œ ๋งต ", null); + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCond(searchRequest, orderType, + null, 2); + final List secondRoadmapRequest = roadmapRepository.findRoadmapsByCond(searchRequest, orderType, + roadmap3.getId(), 3); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(3), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(roadmap4, roadmap3, roadmap2)), + + () -> assertThat(secondRoadmapRequest.size()).isEqualTo(2), + () -> assertThat(secondRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(roadmap2, roadmap1)) + ); + } + + @Test + void ๋กœ๋“œ๋งต์„_ํฌ๋ฆฌ์—์ดํ„ฐ_๋‹‰๋„ค์ž„์œผ๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค() { + // given + final Member creator1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final Member creator2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri2", "๋ผ๋ฆฌ์ฝ”"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌ๊ฐ€"); + + final Roadmap roadmap1 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator1, category); + final Roadmap roadmap2 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator1, category); + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator2, category); + final Roadmap roadmap4 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator1, category); + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator2, category); + ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator1, category); + + final RoadmapOrderType orderType = RoadmapOrderType.LATEST; + final RoadmapSearchDto searchRequest = RoadmapSearchDto.create(creator1.getNickname().getValue(), null, null); + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCond(searchRequest, orderType, + null, 2); + final List secondRoadmapRequest = roadmapRepository.findRoadmapsByCond(searchRequest, orderType, + roadmap2.getId(), 3); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(3), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(roadmap4, roadmap2, roadmap1)), + + () -> assertThat(secondRoadmapRequest.size()).isEqualTo(1), + () -> assertThat(secondRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(roadmap1)) + ); + } + + @Test + void ๋กœ๋“œ๋งต์„_ํƒœ๊ทธ_์ด๋ฆ„์œผ๋กœ_๊ฒ€์ƒ‰ํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌ๊ฐ€"); + + final Roadmap roadmap1 = ๋กœ๋“œ๋งต์„_ํƒœ๊ทธ์™€_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator, category, + new RoadmapTags(List.of( + new RoadmapTag(new RoadmapTagName("์ž๋ฐ”")), + new RoadmapTag(new RoadmapTagName("์Šคํ”„๋ง"))))); + + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator, category); + + final Roadmap roadmap3 = ๋กœ๋“œ๋งต์„_ํƒœ๊ทธ์™€_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator, category, + new RoadmapTags(List.of( + new RoadmapTag(new RoadmapTagName("์ž๋ฐ”"))))); + + ๋กœ๋“œ๋งต์„_ํƒœ๊ทธ์™€_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator, category, new RoadmapTags(List.of( + new RoadmapTag(new RoadmapTagName("์Šคํ”„๋ง"))))); + + final RoadmapOrderType orderType = RoadmapOrderType.LATEST; + final RoadmapSearchDto searchRequest = RoadmapSearchDto.create(null, null, " ์ž ๋ฐ” "); + + // when + final List firstRoadmapRequest = roadmapRepository.findRoadmapsByCond(searchRequest, orderType, + null, 1); + final List secondRoadmapRequest = roadmapRepository.findRoadmapsByCond(searchRequest, orderType, + roadmap3.getId(), 1); + + // then + assertAll( + () -> assertThat(firstRoadmapRequest.size()).isEqualTo(2), + () -> assertThat(firstRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(roadmap3, roadmap1)), + + () -> assertThat(secondRoadmapRequest.size()).isEqualTo(1), + () -> assertThat(secondRoadmapRequest).usingRecursiveComparison() + .ignoringFields("id", "createdAt", "updatedAt") + .isEqualTo(List.of(roadmap1)) + ); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + final RoadmapCategory itCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("IT"); + + final Roadmap gameRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต1", creator, gameCategory); + final Roadmap travelRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต2", creator, travelCategory); + final Roadmap deletedGameRoadmap = ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต3", creator, itCategory); + + roadmapRepository.saveAll(List.of(gameRoadmap, travelRoadmap, deletedGameRoadmap)); + + // when + final List roadmapsFirstPage = roadmapRepository.findRoadmapsWithCategoryByMemberOrderByLatest(creator, + null, 2); + final List roadmapsSecondPage = roadmapRepository.findRoadmapsWithCategoryByMemberOrderByLatest( + creator, roadmapsFirstPage.get(1).getId(), 2); + + // then + assertAll( + () -> assertThat(roadmapsFirstPage) + .isEqualTo(List.of(deletedGameRoadmap, travelRoadmap, gameRoadmap)), + () -> assertThat(roadmapsSecondPage) + .isEqualTo(List.of(gameRoadmap)) + ); + } + + @Test + void ์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri1", "์ฝ”๋ผ๋ฆฌ1"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + final Roadmap gameRoadmap1 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต1", creator1, gameCategory); + final Roadmap travelRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต2", creator1, travelCategory); + + final Member creator2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri2", "์ฝ”๋ผ๋ฆฌ2"); + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต3", creator2, gameCategory); + + // when + final Roadmap savedRoadmap1 = roadmapRepository.findByIdAndMemberIdentifier(gameRoadmap1.getId(), "cokirikiri1") + .get(); + final Roadmap savedRoadmap2 = roadmapRepository.findByIdAndMemberIdentifier(travelRoadmap.getId(), + "cokirikiri1").get(); + + // then + assertAll( + () -> assertThat(savedRoadmap1).isEqualTo(gameRoadmap1), + () -> assertThat(savedRoadmap2).isEqualTo(travelRoadmap) + ); + } + + @Test + void ์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๋กœ๋“œ๋งต์„_์กฐํšŒ์‹œ_์—†์œผ๋ฉด_๋นˆ_๊ฐ’์„_๊ฐ์‹ธ์„œ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri1", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต1", creator1, gameCategory); + final Roadmap travelRoadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต2", creator1, travelCategory); + + final Member creator2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri2", "์ฝ”๋ผ๋ฆฌ2"); + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต3", creator2, gameCategory); + + // when + final Optional savedRoadmap = roadmapRepository.findByIdAndMemberIdentifier(travelRoadmap.getId() + 1, + "cokirikiri1"); + + // then + assertThat(savedRoadmap).isEmpty(); + } + + @Test + void ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_๋กœ๋“œ๋งต_๋ณธ๋ฌธ๊ณผ_ํ•จ๊ป˜_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("cokirikiri", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory gameCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๊ฒŒ์ž„"); + final RoadmapCategory travelCategory = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("์—ฌํ–‰"); + + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต1", creator, gameCategory); + ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต2", creator, travelCategory); + final Roadmap deletedRoadmap = ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค("๋กœ๋“œ๋งต", creator, travelCategory); + + // when + final List roadmapsByStatus = roadmapRepository.findWithRoadmapContentByStatus(RoadmapStatus.DELETED); + + // then + assertAll( + () -> assertThat(roadmapsByStatus).isEqualTo(List.of(deletedRoadmap)), + () -> assertThat(roadmapsByStatus.get(0).getContents().getValues().get(0).getContent()) + .isEqualTo("๋กœ๋“œ๋งต ๋ณธ๋ฌธ2") + ); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String identifier, final String nickname) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), "010-1234-5678"); + final MemberImage memberImage = new MemberImage("file-name", "file-path", ImageContentType.PNG); + final Member creator = new Member(new Identifier(identifier), new EncryptedPassword(new Password("password1!")), + new Nickname(nickname), memberImage, memberProfile); + return memberRepository.save(creator); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String name) { + final RoadmapCategory roadmapCategory = new RoadmapCategory(name); + return roadmapCategoryRepository.save(roadmapCategory); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(final String title, final Member creator, final RoadmapCategory category) { + final Roadmap roadmap = new Roadmap(title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ")); + return roadmapRepository.save(roadmap); + } + + private Roadmap ์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(final String title, final Member creator, final RoadmapCategory category) { + final Roadmap roadmap = new Roadmap(title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€2", 7, RoadmapDifficulty.DIFFICULT, creator, category); + roadmap.addContent(new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ2")); + roadmap.delete(); + return roadmapRepository.save(roadmap); + } + + private Roadmap ๋กœ๋“œ๋งต์„_ํƒœ๊ทธ์™€_์ €์žฅํ•œ๋‹ค(final String title, final Member creator, final RoadmapCategory category, + final RoadmapTags roadmapTags) { + final Roadmap roadmap = new Roadmap(title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addTags(roadmapTags); + return roadmapRepository.save(roadmap); + } + + private Roadmap ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final String title, final Member creator, final RoadmapCategory category) { + final Roadmap roadmap = new Roadmap(title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + roadmap.addContent(roadmapContent); + return roadmapRepository.save(roadmap); + } + + private Roadmap ๋…ธ๋“œ_์ •๋ณด๋ฅผ_ํฌํ•จํ•œ_์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(final String title, final Member creator, final RoadmapCategory category) { + final Roadmap roadmap = new Roadmap(title, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + final RoadmapNode roadmapNode1 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(List.of(roadmapNode1, roadmapNode2)); + roadmap.addContent(roadmapContent); + roadmap.delete(); + return roadmapRepository.save(roadmap); + } + + private RoadmapNode ๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String title, final String content) { + return new RoadmapNode(title, content); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapContent roadmapContent, final Member member) { + final LocalDate today = LocalDate.now(); + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(today, today.plusDays(10), + roadmapContent.getNodes().getValues().get(0)); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(today.plusDays(11), today.plusDays(20), + roadmapContent.getNodes().getValues().get(1)); + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes( + List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2)); + + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(5), roadmapContent, + member); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoomRepository.save(goalRoom); + } + + private GoalRoomRoadmapNode ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final LocalDate startDate, final LocalDate endDate, + final RoadmapNode roadmapNode) { + return new GoalRoomRoadmapNode(new Period(startDate, endDate), 1, roadmapNode); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapReviewRepositoryTest.java b/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapReviewRepositoryTest.java new file mode 100644 index 000000000..9f62efcb4 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/persistence/roadmap/RoadmapReviewRepositoryTest.java @@ -0,0 +1,175 @@ +package co.kirikiri.persistence.roadmap; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.domain.roadmap.RoadmapReview; +import co.kirikiri.persistence.helper.RepositoryTest; +import co.kirikiri.persistence.member.MemberRepository; +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; + +@RepositoryTest +class RoadmapReviewRepositoryTest { + + private final MemberRepository memberRepository; + private final RoadmapRepository roadmapRepository; + private final RoadmapReviewRepository roadmapReviewRepository; + private final RoadmapCategoryRepository roadmapCategoryRepository; + + public RoadmapReviewRepositoryTest(final MemberRepository memberRepository, + final RoadmapRepository roadmapRepository, + final RoadmapReviewRepository roadmapReviewRepository, + final RoadmapCategoryRepository roadmapCategoryRepository) { + this.memberRepository = memberRepository; + this.roadmapRepository = roadmapRepository; + this.roadmapReviewRepository = roadmapReviewRepository; + this.roadmapCategoryRepository = roadmapCategoryRepository; + } + + @Test + void ๋กœ๋“œ๋งต๊ณผ_์‚ฌ์šฉ์ž๋กœ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ •๋ณด๊ฐ€_์กด์žฌํ•˜๋ฉด_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("์ฝ”๋ผ๋ฆฌ", "cokirikiri"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(member, category); + + final RoadmapReview roadmapReview = new RoadmapReview("๋ฆฌ๋ทฐ", 1.5, member); + roadmapReview.updateRoadmap(roadmap); + roadmapReviewRepository.save(roadmapReview); + + // when + final RoadmapReview findRoadmapReview = roadmapReviewRepository.findByRoadmapAndMember(roadmap, member).get(); + + // then + assertThat(findRoadmapReview) + .isEqualTo(roadmapReview); + } + + @Test + void ๋กœ๋“œ๋งต๊ณผ_์‚ฌ์šฉ์ž๋กœ_๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ •๋ณด๊ฐ€_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_๋นˆ๊ฐ’์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("์ฝ”๋ผ๋ฆฌ", "cokirikiri"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("๋ผ๋ฆฌ์ฝ”", "kirikirico"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(member, category); + + final RoadmapReview roadmapReview = new RoadmapReview("๋ฆฌ๋ทฐ", 2.5, member); + roadmapReview.updateRoadmap(roadmap); + roadmapReviewRepository.save(roadmapReview); + + // when + final Optional findRoadmapReview = roadmapReviewRepository.findByRoadmapAndMember(roadmap, + member2); + + // then + assertThat(findRoadmapReview) + .isEmpty(); + } + + @Test + void ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๋ฆฌ๋ทฐ_์ •๋ณด๋ฅผ_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("์ฝ”๋ผ๋ฆฌ", "cokirikiri"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("๋ผ๋ฆฌ์ฝ”", "kirikirico"); + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("๋ฆฌ๋ผ์ฝ”", "rikirikico"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(member, category); + + final RoadmapReview roadmapReview1 = new RoadmapReview("๋ฆฌ๋ทฐ1", 2.5, member); + final RoadmapReview roadmapReview2 = new RoadmapReview("๋ฆฌ๋ทฐ2", 4.0, member2); + final RoadmapReview roadmapReview3 = new RoadmapReview("๋ฆฌ๋ทฐ3", 5.0, member3); + roadmapReview1.updateRoadmap(roadmap); + roadmapReview2.updateRoadmap(roadmap); + roadmapReview3.updateRoadmap(roadmap); + roadmapReviewRepository.save(roadmapReview1); + roadmapReviewRepository.save(roadmapReview2); + roadmapReviewRepository.save(roadmapReview3); + + // when + final List roadmapReviewsFirstPage = roadmapReviewRepository.findRoadmapReviewWithMemberByRoadmapOrderByLatest( + roadmap, null, 2); + + final List roadmapReviewsSecondPage = roadmapReviewRepository.findRoadmapReviewWithMemberByRoadmapOrderByLatest( + roadmap, roadmapReviewsFirstPage.get(1).getId(), 2); + + // then + assertAll( + () -> assertThat(roadmapReviewsFirstPage) + .isEqualTo(List.of(roadmapReview3, roadmapReview2)), + () -> assertThat(roadmapReviewsSecondPage) + .isEqualTo(List.of(roadmapReview1)) + ); + } + + @Test + void ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๋ฆฌ๋ทฐ_์ •๋ณด๊ฐ€_์—†์œผ๋ฉด_๋นˆ_๊ฐ’์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("์ฝ”๋ผ๋ฆฌ", "cokirikiri"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค("๋ผ๋ฆฌ์ฝ”", "kirikirico"); + final RoadmapCategory category = ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค("๊ฒŒ์ž„"); + final Roadmap roadmap1 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(member, category); + final Roadmap roadmap2 = ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(member2, category); + + final RoadmapReview roadmapReview = new RoadmapReview("๋ฆฌ๋ทฐ", 2.5, member); + roadmapReview.updateRoadmap(roadmap1); + roadmapReviewRepository.save(roadmapReview); + + // when + final List roadmapReviewsFirstPage = roadmapReviewRepository.findRoadmapReviewWithMemberByRoadmapOrderByLatest( + roadmap2, null, 1); + + // then + assertThat(roadmapReviewsFirstPage).isEmpty(); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ €์žฅํ•œ๋‹ค(final String name, final String identifier) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), "010-1234-5678"); + final MemberImage memberImage = new MemberImage("test-name", "test-path", ImageContentType.PNG); + final Member creator = new Member(new Identifier(identifier), new EncryptedPassword(new Password("password1!")), + new Nickname(name), memberImage, memberProfile); + return memberRepository.save(creator); + } + + private RoadmapCategory ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ €์žฅํ•œ๋‹ค(final String name) { + final RoadmapCategory roadmapCategory = new RoadmapCategory(name); + return roadmapCategoryRepository.save(roadmapCategory); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ €์žฅํ•œ๋‹ค(final Member creator, final RoadmapCategory category) { + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmapRepository.save(roadmap); + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/AuthServiceTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/AuthServiceTest.java new file mode 100644 index 000000000..4abad60b1 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/AuthServiceTest.java @@ -0,0 +1,183 @@ +package co.kirikiri.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + +import co.kirikiri.domain.auth.EncryptedToken; +import co.kirikiri.domain.auth.RefreshToken; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.persistence.auth.RefreshTokenRepository; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.service.dto.auth.request.LoginRequest; +import co.kirikiri.service.dto.auth.request.ReissueTokenRequest; +import co.kirikiri.service.dto.auth.response.AuthenticationResponse; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +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; + +@ExtendWith(MockitoExtension.class) +class AuthServiceTest { + + private static Member member; + + @Mock + private TokenProvider tokenProvider; + + @Mock + private MemberRepository memberRepository; + + @Mock + private RefreshTokenRepository refreshTokenRepository; + + @InjectMocks + private AuthService authService; + + @BeforeAll + static void setUp() { + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final EncryptedPassword encryptedPassword = new EncryptedPassword(password); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber); + member = new Member(identifier, encryptedPassword, nickname, null, memberProfile); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๊ทธ์ธ์„_ํ•œ๋‹ค() { + //given + final LoginRequest loginRequest = new LoginRequest("identifier1", "password1!"); + final String accessToken = "accessToken"; + final String refreshToken = "refreshToken"; + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(tokenProvider.createAccessToken(any(), any())) + .willReturn(accessToken); + given(tokenProvider.createRefreshToken(any(), any())) + .willReturn(refreshToken); + given(tokenProvider.findTokenExpiredAt(anyString())) + .willReturn(LocalDateTime.now()); + + //when + final AuthenticationResponse authenticationResponse = authService.login(loginRequest); + + //then + assertThat(authenticationResponse).isEqualTo(new AuthenticationResponse(refreshToken, accessToken)); + } + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_์•„์ด๋””๋กœ_๋กœ๊ทธ์ธ_ํ•˜๋Š”_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final LoginRequest loginRequest = new LoginRequest("identifier1", "password1!"); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.empty()); + + //when + //then + assertThatThrownBy(() -> authService.login(loginRequest)) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ์ผ์น˜ํ•˜์ง€_์•Š๋Š”_๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ_๋กœ๊ทธ์ธ_ํ•˜๋Š”_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final LoginRequest loginRequest = new LoginRequest("identifier1", "wrongpassword1!"); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + + //when + //then + assertThatThrownBy(() -> authService.login(loginRequest)) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํ† ํฐ์„_์žฌ๋ฐœํ–‰ํ•œ๋‹ค() { + //given + final String rawAccessToken = "accessToken"; + final String rawRefreshToken = "refreshToken"; + final ReissueTokenRequest reissueTokenRequest = new ReissueTokenRequest("refreshToken"); + final RefreshToken refreshToken = new RefreshToken(new EncryptedToken(rawRefreshToken), LocalDateTime.MAX, + member); + given(tokenProvider.isValidToken(any())) + .willReturn(true); + given(refreshTokenRepository.findByTokenAndIsRevokedFalse(any())) + .willReturn(Optional.of(refreshToken)); + given(tokenProvider.createAccessToken(any(), any())) + .willReturn(rawAccessToken); + given(tokenProvider.createRefreshToken(any(), any())) + .willReturn(rawRefreshToken); + given(tokenProvider.findTokenExpiredAt(anyString())) + .willReturn(LocalDateTime.now()); + + //when + final AuthenticationResponse authenticationResponse = authService.reissueToken(reissueTokenRequest); + + //then + assertThat(authenticationResponse).isEqualTo(new AuthenticationResponse(rawRefreshToken, rawAccessToken)); + } + + @Test + void ๋ฆฌํ”„๋ ˆ์‹œ_ํ† ํฐ์ด_์œ ํšจํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final String rawRefreshToken = "refreshToken"; + final ReissueTokenRequest reissueTokenRequest = new ReissueTokenRequest(rawRefreshToken); + given(tokenProvider.isValidToken(any())) + .willReturn(false); + + //when + //then + assertThatThrownBy(() -> authService.reissueToken(reissueTokenRequest)) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ๋ฆฌํ”„๋ ˆ์‹œ_ํ† ํฐ์ด_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final String rawRefreshToken = "refreshToken"; + final ReissueTokenRequest reissueTokenRequest = new ReissueTokenRequest(rawRefreshToken); + given(tokenProvider.isValidToken(any())) + .willReturn(true); + given(refreshTokenRepository.findByTokenAndIsRevokedFalse(any())) + .willReturn(Optional.empty()); + + //when + //then + assertThatThrownBy(() -> authService.reissueToken(reissueTokenRequest)) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ๋ฆฌํ”„๋ ˆ์‹œ_ํ† ํฐ์ด_๋งŒ๋ฃŒ_๋์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final String rawRefreshToken = "refreshToken"; + final ReissueTokenRequest reissueTokenRequest = new ReissueTokenRequest(rawRefreshToken); + final RefreshToken refreshToken = new RefreshToken(new EncryptedToken(rawRefreshToken), LocalDateTime.MIN, + member); + given(tokenProvider.isValidToken(any())) + .willReturn(true); + given(refreshTokenRepository.findByTokenAndIsRevokedFalse(any())) + .willReturn(Optional.of(refreshToken)); + + //when + //then + assertThatThrownBy(() -> authService.reissueToken(reissueTokenRequest)) + .isInstanceOf(AuthenticationException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomCreateServiceTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomCreateServiceTest.java new file mode 100644 index 000000000..51ee3cd17 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomCreateServiceTest.java @@ -0,0 +1,1075 @@ +package co.kirikiri.service; + +import static co.kirikiri.domain.goalroom.GoalRoomStatus.RUNNING; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.GoalRoomToDoCheck; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImage; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.domain.roadmap.RoadmapStatus; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.goalroom.CheckFeedRepository; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.goalroom.GoalRoomToDoCheckRepository; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapContentRepository; +import co.kirikiri.service.dto.goalroom.request.CheckFeedRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomCreateRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomRoadmapNodeRequest; +import co.kirikiri.service.dto.goalroom.request.GoalRoomTodoRequest; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeAll; +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 org.springframework.mock.web.MockMultipartFile; + +@ExtendWith(MockitoExtension.class) +class GoalRoomCreateServiceTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LATER = TODAY.plusDays(20); + + private static final RoadmapNode ROADMAP_NODE = new RoadmapNode(1L, "title", "content"); + private static final RoadmapContent ROADMAP_CONTENT = new RoadmapContent(1L, "content"); + private static final RoadmapContent DELETED_ROADMAP_CONTENT = new RoadmapContent(2L, "content2"); + private static final RoadmapNodes ROADMAP_CONTENTS = new RoadmapNodes(new ArrayList<>(List.of(ROADMAP_NODE))); + + private static final Member MEMBER = new Member(new Identifier("identifier2"), + new EncryptedPassword(new Password("password!2")), + new Nickname("name2"), null, + new MemberProfile(Gender.FEMALE, LocalDate.now(), "010-1111-2222")); + + private static final Roadmap ROADMAP = new Roadmap("roadmap", "introduction", 30, RoadmapDifficulty.DIFFICULT, + MEMBER, new RoadmapCategory("IT")); + + private static final Roadmap DELETED_ROADMAP = new Roadmap("roadmap", "introduction", 30, + RoadmapDifficulty.DIFFICULT, RoadmapStatus.DELETED, MEMBER, new RoadmapCategory("IT")); + + private static Member member; + + @Mock + private GoalRoomRepository goalRoomRepository; + + @Mock + private GoalRoomMemberRepository goalRoomMemberRepository; + + @Mock + private RoadmapContentRepository roadmapContentRepository; + + @Mock + private MemberRepository memberRepository; + + @Mock + private GoalRoomToDoCheckRepository goalRoomToDoCheckRepository; + + @Mock + private CheckFeedRepository checkFeedRepository; + + @Mock + private FileService fileService; + + @Mock + private FilePathGenerator filePathGenerator; + + @InjectMocks + private GoalRoomCreateService goalRoomCreateService; + + @BeforeAll + static void setUp() { + ROADMAP_CONTENT.addNodes(ROADMAP_CONTENTS); + ROADMAP.addContent(ROADMAP_CONTENT); + DELETED_ROADMAP.addContent(DELETED_ROADMAP_CONTENT); + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final EncryptedPassword encryptedPassword = new EncryptedPassword(password); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, TODAY, phoneNumber); + member = new Member(identifier, encryptedPassword, nickname, null, memberProfile); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค() { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + + given(roadmapContentRepository.findByIdWithRoadmap(anyLong())) + .willReturn(Optional.of(ROADMAP_CONTENT)); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(goalRoomRepository.save(any())) + .willReturn(new GoalRoom(1L, null, null, null, null)); + + //when + assertDoesNotThrow(() -> goalRoomCreateService.create(request, member.getIdentifier().getValue())); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์‚ญ์ œ๋œ_๋กœ๋“œ๋งต์ด๋ฉด_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + + given(roadmapContentRepository.findByIdWithRoadmap(anyLong())) + .willReturn(Optional.of(DELETED_ROADMAP_CONTENT)); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.create(request, member.getIdentifier().getValue())) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต_์ปจํ…์ธ ๊ฐ€_๋“ค์–ด์˜ฌ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + + given(roadmapContentRepository.findByIdWithRoadmap(anyLong())) + .willReturn(Optional.empty()); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.create(request, member.getIdentifier().getValue())) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต_์ปจํ…์ธ ์˜_๋…ธ๋“œ์‚ฌ์ด์ฆˆ์™€_์š”์ฒญ์˜_๋…ธ๋“œ์‚ฌ์ด์ฆˆ๊ฐ€_๋‹ค๋ฅผ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final List wrongSizeGoalRoomRoadmapNodeRequest = new ArrayList<>(List.of( + new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER), + new GoalRoomRoadmapNodeRequest(2L, 10, TODAY, TEN_DAY_LATER))); + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + wrongSizeGoalRoomRoadmapNodeRequest); + + given(roadmapContentRepository.findByIdWithRoadmap(anyLong())) + .willReturn(Optional.of(ROADMAP_CONTENT)); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.create(request, member.getIdentifier().getValue())) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_๋กœ๋“œ๋งต์—_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋…ธ๋“œ๊ฐ€_์š”์ฒญ์œผ๋กœ_๋“ค์–ด์˜ฌ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final long wrongRoadmapNodId = 2L; + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(wrongRoadmapNodId, 10, TODAY, TEN_DAY_LATER)))); + + given(roadmapContentRepository.findByIdWithRoadmap(anyLong())) + .willReturn(Optional.of(ROADMAP_CONTENT)); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.create(request, member.getIdentifier().getValue())) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ_์ƒ์„ฑ_์‹œ_์กด์žฌํ•˜์ง€_์•Š์€_ํšŒ์›์˜_Identifier๊ฐ€_๋“ค์–ด์˜ฌ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final GoalRoomCreateRequest request = new GoalRoomCreateRequest(1L, "name", + 20, new GoalRoomTodoRequest("content", TODAY, TEN_DAY_LATER), + new ArrayList<>(List.of(new GoalRoomRoadmapNodeRequest(1L, 10, TODAY, TEN_DAY_LATER)))); + + given(roadmapContentRepository.findByIdWithRoadmap(anyLong())) + .willReturn(Optional.of(ROADMAP_CONTENT)); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.empty()); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.create(request, member.getIdentifier().getValue())) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์—_์ฐธ๊ฐ€ํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์‹œ์ง„์ด", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final int limitedMemberCount = 20; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, limitedMemberCount); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier2", "password1!", "ํŒ”๋กœ์›Œ", "010-1234-5678"); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(follower)); + when(goalRoomRepository.findById(anyLong())) + .thenReturn(Optional.of(goalRoom)); + + //when + goalRoomCreateService.join("identifier2", 1L); + + //then + assertThat(goalRoom.getCurrentMemberCount()) + .isEqualTo(2); + } + + @Test + void ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ์‹œ_์œ ํšจํ•œ_์‚ฌ์šฉ์ž_์•„์ด๋””๊ฐ€_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.empty()); + + //when, then + assertThatThrownBy(() -> goalRoomCreateService.join("identifier2", 1L)) + .isInstanceOf(NotFoundException.class) + .hasMessage("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ์‹œ_์œ ํšจํ•œ_๊ณจ๋ฃธ_์•„์ด๋””๊ฐ€_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "ํŒ”๋กœ์›Œ", "010-1234-5678"); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(follower)); + when(goalRoomRepository.findById(anyLong())) + .thenReturn(Optional.empty()); + + //when, then + assertThatThrownBy(() -> goalRoomCreateService.join("identifier1", 1L)) + .isInstanceOf(NotFoundException.class) + .hasMessage("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1"); + } + + @Test + void ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ์‹œ_์ œํ•œ_์ธ์›์ด_๊ฐ€๋“_์ฐผ์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "์‹œ์ง„์ด", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final int limitedMemberCount = 1; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, limitedMemberCount); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier2", "password1!", "ํŒ”๋กœ์›Œ", "010-1234-5678"); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(follower)); + when(goalRoomRepository.findById(anyLong())) + .thenReturn(Optional.of(goalRoom)); + + //when, then + assertThatThrownBy(() -> goalRoomCreateService.join("identifier2", 1L)) + .isInstanceOf(BadRequestException.class) + .hasMessage("์ œํ•œ ์ธ์›์ด ๊ฝ‰ ์ฐฌ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ_์ฐธ๊ฐ€_์š”์ฒญ์‹œ_๋ชจ์ง‘_์ค‘์ด_์•„๋‹Œ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + //given + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "์‹œ์ง„์ด", "010-1111-1111"); + final int limitedMemberCount = 20; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, roadmapContent, limitedMemberCount); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier2", "password2!", "ํŒ”๋กœ์›Œ", "010-1111-2222"); + goalRoom.start(); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(follower)); + when(goalRoomRepository.findById(anyLong())) + .thenReturn(Optional.of(goalRoom)); + + //when, then + assertThatThrownBy(() -> goalRoomCreateService.join("identifier2", 1L)) + .isInstanceOf(BadRequestException.class) + .hasMessage("๋ชจ์ง‘ ์ค‘์ด์ง€ ์•Š์€ ๊ณจ๋ฃธ์—๋Š” ์ฐธ์—ฌํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "์‹œ์ง„์ด", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final int limitedMemberCount = 20; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, limitedMemberCount); + + goalRoom.addGoalRoomTodo( + new GoalRoomToDo(new GoalRoomTodoContent("goalRoomTodoContent"), new Period(TODAY, TEN_DAY_LATER))); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(creator)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("goalRoomContent", TODAY, + TEN_DAY_LATER); + + //when + //then + assertDoesNotThrow(() -> goalRoomCreateService.addGoalRoomTodo(1L, "identifier1", goalRoomTodoRequest)); + } + + @Test + void ๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€์‹œ_ํšŒ์›์„_์ฐพ์ง€_๋ชปํ• _๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.empty()); + + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("goalRoomContent", TODAY, + TEN_DAY_LATER); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.addGoalRoomTodo(1L, "identifier1", goalRoomTodoRequest)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€์‹œ_๊ณจ๋ฃธ์„_์ฐพ์ง€_๋ชปํ• _๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "์‹œ์ง„์ด", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final int limitedMemberCount = 20; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, limitedMemberCount); + + goalRoom.addGoalRoomTodo( + new GoalRoomToDo(new GoalRoomTodoContent("goalRoomTodoContent"), new Period(TODAY, TEN_DAY_LATER))); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(creator)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.empty()); + + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("goalRoomContent", TODAY, + TEN_DAY_LATER); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.addGoalRoomTodo(1L, "identifier1", goalRoomTodoRequest)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€์‹œ_์ข…๋ฃŒ๋œ_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "์‹œ์ง„์ด", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final int limitedMemberCount = 20; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, limitedMemberCount); + + goalRoom.addGoalRoomTodo( + new GoalRoomToDo(new GoalRoomTodoContent("goalRoomTodoContent"), new Period(TODAY, TEN_DAY_LATER))); + goalRoom.complete(); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(creator)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("goalRoomContent", TODAY, + TEN_DAY_LATER); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.addGoalRoomTodo(1L, "identifier1", goalRoomTodoRequest)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€์‹œ_๋ฆฌ๋”๊ฐ€_์•„๋‹_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "์‹œ์ง„์ด", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final int limitedMemberCount = 20; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, limitedMemberCount); + + goalRoom.addGoalRoomTodo( + new GoalRoomToDo(new GoalRoomTodoContent("goalRoomTodoContent"), new Period(TODAY, TEN_DAY_LATER))); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest("goalRoomContent", TODAY, + TEN_DAY_LATER); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.addGoalRoomTodo(1L, "identifier2", goalRoomTodoRequest)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ์—_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ถ”๊ฐ€์‹œ_๊ณจ๋ฃธ_์ปจํ…์ธ ๊ฐ€_250๊ธ€์ž๊ฐ€_๋„˜์„๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "password1!", "์‹œ์ง„์ด", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final int limitedMemberCount = 20; + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, limitedMemberCount); + + goalRoom.addGoalRoomTodo( + new GoalRoomToDo(new GoalRoomTodoContent("goalRoomTodoContent"), new Period(TODAY, TEN_DAY_LATER))); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(creator)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + + final String goalRoomTodoContent = "a".repeat(251); + final GoalRoomTodoRequest goalRoomTodoRequest = new GoalRoomTodoRequest(goalRoomTodoContent, TODAY, + TEN_DAY_LATER); + + //when + //then + assertThatThrownBy(() -> goalRoomCreateService.addGoalRoomTodo(1L, "identifier1", goalRoomTodoRequest)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(creator)); + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.of(goalRoom)); + + // when + goalRoomCreateService.startGoalRoom("cokirikiri", 1L); + + // then + assertThat(goalRoom.getStatus()).isEqualTo(RUNNING); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_์‚ฌ์šฉ์ž๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomCreateService.startGoalRoom("identifier", 1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(member)); + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomCreateService.startGoalRoom("identifier", 1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์„_์‹œ์ž‘ํ•˜๋Š”_์‚ฌ์šฉ์ž๊ฐ€_๊ณจ๋ฃธ์˜_๋ฆฌ๋”๊ฐ€_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "kirikirico", "password2!", "๋ผ๋ฆฌ์ฝ”", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(follower)); + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.of(goalRoom)); + + // expected + assertThatThrownBy(() -> goalRoomCreateService.startGoalRoom("identifier", 1L)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ_์‹œ์ž‘์‹œ_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์•„์ง_์ง€๋‚˜์ง€_์•Š์•˜์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ์‹œ์ž‘_๋‚ ์งœ๊ฐ€_๋ฏธ๋ž˜์ธ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(creator)); + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.of(goalRoom)); + + // expected + assertThatThrownBy(() -> goalRoomCreateService.startGoalRoom("cokirikiri", 1L)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์„_์š”์ฒญํ•œ๋‹ค() { + // given + final CheckFeedRequest request = ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("image/jpeg"); + + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 20); + final GoalRoomMember goalRoomLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + goalRoomMemberRepository.save(goalRoomLeader); + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final CheckFeed checkFeed = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(goalRoomRoadmapNode, goalRoomLeader); + + when(goalRoomRepository.findById(anyLong())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomLeader)); + when(checkFeedRepository.findByGoalRoomMemberAndDateTime(any(), any(), any())) + .thenReturn(Optional.empty()); + when(checkFeedRepository.countByGoalRoomMemberAndGoalRoomRoadmapNode(any(), any())) + .thenReturn(0); + when(checkFeedRepository.save(any())) + .thenReturn(checkFeed); + when(filePathGenerator.makeFilePath(any(), any())) + .thenReturn("originalFileName.jpeg"); + when(fileService.generateUrl(anyString(), any())) + .thenReturn(makeUrl("originalFileName.jpeg")); + + // when + final String response = goalRoomCreateService.createCheckFeed("identifier", 1L, request); + + // then + assertAll( + () -> assertThat(goalRoomLeader.getAccomplishmentRate()).isEqualTo(100 / (double) 10), + () -> assertThat(response).contains("originalFileName") + ); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก์‹œ_๋…ธ๋“œ_๊ธฐ๊ฐ„์—_ํ•ด๋‹นํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final CheckFeedRequest request = ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("image/jpeg"); + + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ์‹œ์ž‘_๋‚ ์งœ๊ฐ€_๋ฏธ๋ž˜์ธ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 20); + final GoalRoomMember goalRoomLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + goalRoomMemberRepository.save(goalRoomLeader); + + when(goalRoomRepository.findById(anyLong())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomLeader)); + + // expected + assertThatThrownBy( + () -> goalRoomCreateService.createCheckFeed("identifier", 1L, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("์ธ์ฆ ํ”ผ๋“œ๋Š” ๋…ธ๋“œ ๊ธฐ๊ฐ„ ๋‚ด์—๋งŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ํ•˜๋ฃจ์—_๋‘_๋ฒˆ_์ด์ƒ_์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ_์‹œ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final CheckFeedRequest request = ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("image/jpeg"); + + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 20); + final GoalRoomMember goalRoomLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + goalRoomMemberRepository.save(goalRoomLeader); + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + final CheckFeed checkFeed = ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(goalRoomRoadmapNode, goalRoomLeader); + + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomLeader)); + when(checkFeedRepository.findByGoalRoomMemberAndDateTime(any(), any(), any())) + .thenReturn(Optional.of(checkFeed)); + + //expect + assertThatThrownBy( + () -> goalRoomCreateService.createCheckFeed("identifier", 1L, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("์ด๋ฏธ ์˜ค๋Š˜ ์ธ์ฆ ํ”ผ๋“œ๋ฅผ ๋“ฑ๋กํ•˜์˜€์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ๊ณจ๋ฃธ_๋…ธ๋“œ์—์„œ_ํ—ˆ๊ฐ€๋œ_์ธ์ฆ_ํšŸ์ˆ˜๋ณด๋‹ค_๋งŽ์€_์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ_์‹œ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final CheckFeedRequest request = ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("image/jpeg"); + + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 20); + final GoalRoomMember goalRoomLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + goalRoomMemberRepository.save(goalRoomLeader); + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomLeader)); + when(checkFeedRepository.countByGoalRoomMemberAndGoalRoomRoadmapNode(any(), any())) + .thenReturn(goalRoomRoadmapNode.getCheckCount()); + + //expect + assertThatThrownBy( + () -> goalRoomCreateService.createCheckFeed("identifier", 1L, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("์ด๋ฒˆ ๋…ธ๋“œ์—๋Š” ์ตœ๋Œ€ " + goalRoomRoadmapNode.getCheckCount() + "๋ฒˆ๋งŒ ์ธ์ฆ ํ”ผ๋“œ๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ_์‹œ_ํ—ˆ์šฉ๋˜์ง€_์•Š๋Š”_ํ™•์žฅ์ž_ํ˜•์‹์ด๋ผ๋ฉด_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final CheckFeedRequest request = ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("image/gif"); + + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 20); + final GoalRoomMember goalRoomLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + goalRoomMemberRepository.save(goalRoomLeader); + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomLeader)); + + // when + assertThatThrownBy( + () -> goalRoomCreateService.createCheckFeed("identifier", 1L, request)) + .isInstanceOf(BadRequestException.class) + .hasMessage("ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ํ™•์žฅ์ž์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ_์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ผ๋ฉด_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final CheckFeedRequest request = ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("image/jpeg"); + + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 20); + final GoalRoomMember goalRoomLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + goalRoomMemberRepository.save(goalRoomLeader); + + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.empty()); + + //expect + assertThatThrownBy( + () -> goalRoomCreateService.createCheckFeed("identifier", 1L, request)) + .isInstanceOf(NotFoundException.class) + .hasMessage("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1"); + } + + @Test + void ์ธ์ฆ_ํ”ผ๋“œ_๋“ฑ๋ก_์š”์ฒญ_์‹œ_์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ด๋ผ๋ฉด_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final CheckFeedRequest request = ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("image/jpeg"); + + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 20); + + final GoalRoomMember goalRoomLeader = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + goalRoomMemberRepository.save(goalRoomLeader); + + when(goalRoomRepository.findById(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.empty()); + + //expect + assertThatThrownBy( + () -> goalRoomCreateService.createCheckFeed("identifier", 1L, request)) + .isInstanceOf(NotFoundException.class) + .hasMessage("๊ณจ๋ฃธ์— ํ•ด๋‹น ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์•„์ด๋”” = " + "identifier"); + } + + @Test + void ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์ฒดํฌํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + goalRoom.addGoalRoomTodo(new GoalRoomToDo( + 1L, new GoalRoomTodoContent("ํˆฌ๋‘ 1"), new Period(TODAY, TODAY.plusDays(3)) + )); + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + + when(goalRoomRepository.findByIdWithTodos(anyLong())) + .thenReturn(Optional.of(goalRoom)); + + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomMember)); + + when(goalRoomToDoCheckRepository.findByGoalRoomIdAndTodoAndMemberIdentifier(any(), any(), any())) + .thenReturn(Optional.empty()); + + // when + final GoalRoomToDoCheckResponse checkResponse = goalRoomCreateService.checkGoalRoomTodo(1L, 1L, "cokirikiri"); + + // then + assertThat(checkResponse) + .isEqualTo(new GoalRoomToDoCheckResponse(true)); + } + + @Test + void ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_์ฒดํฌ_์ด๋ ฅ์ด_์žˆ์œผ๋ฉด_์ œ๊ฑฐํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + final GoalRoomToDo goalRoomToDo = new GoalRoomToDo( + 1L, new GoalRoomTodoContent("ํˆฌ๋‘ 1"), new Period(TODAY, TODAY.plusDays(3))); + goalRoom.addGoalRoomTodo(goalRoomToDo); + + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + final GoalRoomToDoCheck goalRoomToDoCheck = new GoalRoomToDoCheck(goalRoomMember, goalRoomToDo); + + when(goalRoomRepository.findByIdWithTodos(anyLong())) + .thenReturn(Optional.of(goalRoom)); + + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomMember)); + + when(goalRoomToDoCheckRepository.findByGoalRoomIdAndTodoAndMemberIdentifier(any(), any(), any())) + .thenReturn(Optional.of(goalRoomToDoCheck)); + + // when + final GoalRoomToDoCheckResponse checkResponse = goalRoomCreateService.checkGoalRoomTodo(1L, 1L, "cokirikiri"); + + // then + assertThat(checkResponse) + .isEqualTo(new GoalRoomToDoCheckResponse(false)); + } + + @Test + void ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_๊ณจ๋ฃธ์ด_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(goalRoomRepository.findByIdWithTodos(anyLong())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomCreateService.checkGoalRoomTodo(1L, 1L, "cokirikiri")) + .isInstanceOf(NotFoundException.class) + .hasMessage("๊ณจ๋ฃธ์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1"); + } + + @Test + void ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_ํ•ด๋‹น_ํˆฌ๋‘๊ฐ€_์กด์žฌํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + goalRoom.addGoalRoomTodo(new GoalRoomToDo( + 1L, new GoalRoomTodoContent("ํˆฌ๋‘ 1"), new Period(TODAY, TODAY.plusDays(3)))); + + when(goalRoomRepository.findByIdWithTodos(anyLong())) + .thenReturn(Optional.of(goalRoom)); + + // expected + assertThatThrownBy(() -> goalRoomCreateService.checkGoalRoomTodo(1L, 2L, "cokirikiri")) + .isInstanceOf(NotFoundException.class) + .hasMessage("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํˆฌ๋‘์ž…๋‹ˆ๋‹ค. todoId = 2"); + } + + @Test + void ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์ฒดํฌ์‹œ_๊ณจ๋ฃธ์—_์‚ฌ์šฉ์ž๊ฐ€_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + goalRoom.addGoalRoomTodo(new GoalRoomToDo( + 1L, new GoalRoomTodoContent("ํˆฌ๋‘ 1"), new Period(TODAY, TODAY.plusDays(3)))); + + when(goalRoomRepository.findByIdWithTodos(anyLong())) + .thenReturn(Optional.of(goalRoom)); + + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomCreateService.checkGoalRoomTodo(1L, 1L, "cokirikiri")) + .isInstanceOf(NotFoundException.class) + .hasMessage("๊ณจ๋ฃธ์— ์‚ฌ์šฉ์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1 memberIdentifier = cokirikiri"); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐ„๋‹ค() { + // given + final GoalRoom goalRoom = new GoalRoom(1L, new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(3), + new RoadmapContent("content"), MEMBER); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(MEMBER)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + + // when + // then + assertDoesNotThrow(() -> goalRoomCreateService.leave("identifier2", 1L)); + + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.empty()); + + // when + // then + assertThatThrownBy(() -> goalRoomCreateService.leave("identifier2", 1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.empty()); + + // when + // then + assertThatThrownBy(() -> goalRoomCreateService.leave("identifier2", 1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_๊ณจ๋ฃธ์ด_์ง„ํ–‰์ค‘์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final GoalRoom goalRoom = new GoalRoom(1L, new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(3), + new RoadmapContent("content"), MEMBER); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + + // when + goalRoom.start(); + + // then + assertThatThrownBy(() -> goalRoomCreateService.leave("identifier2", 1L)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ์„_๋‚˜๊ฐˆ๋•Œ_๊ณจ๋ฃธ์—_๋‚จ์•„์žˆ๋Š”_์‚ฌ์šฉ์ž๊ฐ€_์—†์œผ๋ฉด_๊ณจ๋ฃธ์ด_์‚ญ์ œ๋œ๋‹ค() { + // given + final GoalRoom goalRoom = new GoalRoom(1L, new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(3), + new RoadmapContent("content"), MEMBER); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + + // when + goalRoomCreateService.leave("identifier2", 1L); + + // then + verify(goalRoomRepository, times(1)).delete(goalRoom); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final Long memberId, final String identifier, final String password, final String nickname, + final String phoneNumber) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, + LocalDate.of(1995, 9, 30), phoneNumber); + + return new Member(memberId, new Identifier(identifier), new EncryptedPassword(new Password(password)), + new Nickname(nickname), null, memberProfile); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final Member creator) { + final RoadmapCategory category = new RoadmapCategory("๊ฒŒ์ž„"); + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmap; + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + roadmapNode1.addImages(new RoadmapNodeImages(๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค())); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private List ๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of( + new RoadmapNodeImage("node-image1.png", "node-image1-save-path", ImageContentType.PNG), + new RoadmapNodeImage("node-image2.png", "node-image2-save-path", ImageContentType.PNG) + ); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final Long goalRoomId, final Member creator, final RoadmapContent roadmapContent, + final Integer limitedMemberCount) { + final GoalRoom goalRoom = new GoalRoom(goalRoomId, new GoalRoomName("๊ณจ๋ฃธ ์ด๋ฆ„"), + new LimitedMemberCount(limitedMemberCount), roadmapContent, creator); + goalRoom.addAllGoalRoomRoadmapNodes(๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(roadmapContent.getNodes())); + return goalRoom; + } + + private GoalRoom ์‹œ์ž‘_๋‚ ์งœ๊ฐ€_๋ฏธ๋ž˜์ธ_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final Long goalRoomId, final Member creator, + final RoadmapContent roadmapContent, final Integer limitedMemberCount) { + final GoalRoom goalRoom = new GoalRoom(goalRoomId, new GoalRoomName("๊ณจ๋ฃธ ์ด๋ฆ„"), + new LimitedMemberCount(limitedMemberCount), roadmapContent, creator); + final GoalRoomRoadmapNode goalRoomRoadmapNode = new GoalRoomRoadmapNode( + new Period(TEN_DAY_LATER, TWENTY_DAY_LATER), 5, roadmapContent.getNodes().getValues().get(0)); + goalRoom.addAllGoalRoomRoadmapNodes( + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode))); + return goalRoom; + } + + private GoalRoomRoadmapNodes ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapNodes roadmapNodes) { + return new GoalRoomRoadmapNodes(List.of( + new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), 5, roadmapNodes.getValues().get(0)), + new GoalRoomRoadmapNode(new Period(TEN_DAY_LATER.plusDays(1), TWENTY_DAY_LATER), 5, + roadmapNodes.getValues().get(1))) + ); + } + + private CheckFeedRequest ์ธ์ฆ_ํ”ผ๋“œ_์š”์ฒญ_DTO๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String contentType) { + return new CheckFeedRequest( + new MockMultipartFile("image", "originalFileName.jpeg", contentType, + "test image".getBytes()), "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…"); + } + + private CheckFeed ์ธ์ฆ_ํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final GoalRoomRoadmapNode goalRoomRoadmapNode, final GoalRoomMember joinedMember) { + return new CheckFeed("src/test/resources/testImage/originalFileName.jpeg", ImageContentType.JPEG, + "originalFileName.jpeg", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", goalRoomRoadmapNode, joinedMember); + } + + private URL makeUrl(final String path) { + try { + return new URL("http://example.com/" + path); + } catch (final MalformedURLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomReadServiceTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomReadServiceTest.java new file mode 100644 index 000000000..aa4156b29 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomReadServiceTest.java @@ -0,0 +1,1301 @@ +package co.kirikiri.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.CheckFeed; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.GoalRoomToDo; +import co.kirikiri.domain.goalroom.GoalRoomToDoCheck; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.GoalRoomTodoContent; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImage; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.exception.ForbiddenException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.goalroom.CheckFeedRepository; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomPendingMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.goalroom.GoalRoomToDoCheckRepository; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.service.dto.goalroom.GoalRoomMemberSortTypeDto; +import co.kirikiri.service.dto.goalroom.request.GoalRoomStatusTypeRequest; +import co.kirikiri.service.dto.goalroom.response.CheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCertifiedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomCheckFeedResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomMemberResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodeResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomRoadmapNodesResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomToDoCheckResponse; +import co.kirikiri.service.dto.goalroom.response.GoalRoomTodoResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomForListResponse; +import co.kirikiri.service.dto.member.response.MemberGoalRoomResponse; +import co.kirikiri.service.dto.member.response.MemberResponse; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +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; + +@ExtendWith(MockitoExtension.class) +class GoalRoomReadServiceTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LAYER = TODAY.plusDays(20); + private static final LocalDate THIRTY_DAY_LATER = TODAY.plusDays(30); + + @Mock + private MemberRepository memberRepository; + + @Mock + private GoalRoomRepository goalRoomRepository; + + @Mock + private GoalRoomMemberRepository goalRoomMemberRepository; + + @Mock + private GoalRoomPendingMemberRepository goalRoomPendingMemberRepository; + + @Mock + private GoalRoomToDoCheckRepository goalRoomToDoCheckRepository; + + @Mock + private CheckFeedRepository checkFeedRepository; + + @Mock + private FileService fileService; + + @InjectMocks + private GoalRoomReadService goalRoomReadService; + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + when(goalRoomRepository.findByIdWithRoadmapContent(any())) + .thenReturn(Optional.of(goalRoom)); + + // when + final GoalRoomResponse goalRoomResponse = goalRoomReadService.findGoalRoom(goalRoom.getId()); + final GoalRoomResponse expected = ์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(); + + // then + assertThat(goalRoomResponse) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์กฐํšŒ์‹œ_๊ณจ๋ฃธ_์•„์ด๋””๊ฐ€_์œ ํšจํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(goalRoomRepository.findByIdWithRoadmapContent(any())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomReadService.findGoalRoom(1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์—_๋Œ€ํ•ด์„œ_๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋Œ€๊ธฐ_๋ชฉ๋ก_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜๋Š”_์‚ฌ์šฉ์ž๋ฉด_์ฐธ์—ฌ์—ฌ๋ถ€๊ฐ€_true๋กœ_๋ฐ˜ํ™˜๋œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + final GoalRoomPendingMember goalRoomPendingMember = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), goalRoom, creator); + + when(goalRoomRepository.findByIdWithRoadmapContent(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomPendingMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomPendingMember)); + + // when + final GoalRoomCertifiedResponse goalRoomResponse = goalRoomReadService.findGoalRoom( + creator.getIdentifier().getValue(), goalRoom.getId()); + final GoalRoomCertifiedResponse expected = ์˜ˆ์ƒํ•˜๋Š”_๋กœ๊ทธ์ธ๋œ_์‚ฌ์šฉ์ž์˜_๊ณจ๋ฃธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(true, 1); + + // then + assertThat(goalRoomResponse) + .isEqualTo(expected); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์—_๋Œ€ํ•ด์„œ_๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋Œ€๊ธฐ_๋ชฉ๋ก_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š๋Š”_์‚ฌ์šฉ์ž๋ฉด_์ฐธ์—ฌ์—ฌ๋ถ€๊ฐ€_false๋กœ_๋ฐ˜ํ™˜๋œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + when(goalRoomRepository.findByIdWithRoadmapContent(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomPendingMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.empty()); + + // when + final GoalRoomCertifiedResponse goalRoomResponse = goalRoomReadService.findGoalRoom( + creator.getIdentifier().getValue(), goalRoom.getId()); + final GoalRoomCertifiedResponse expected = ์˜ˆ์ƒํ•˜๋Š”_๋กœ๊ทธ์ธ๋œ_์‚ฌ์šฉ์ž์˜_๊ณจ๋ฃธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(false, 1); + + // then + assertThat(goalRoomResponse) + .isEqualTo(expected); + } + + @Test + void ๋ชจ์ง‘์ค‘์ด์ง€_์•Š์€_๊ณจ๋ฃธ์—_๋Œ€ํ•ด์„œ_๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_๋ชฉ๋ก_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜๋Š”_์‚ฌ์šฉ์ž๋ฉด_์ฐธ์—ฌ์—ฌ๋ถ€๊ฐ€_true๋กœ_๋ฐ˜ํ™˜๋œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + goalRoom.start(); + + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, + LocalDateTime.of(2023, 7, 19, 12, 0, 0), goalRoom, creator); + + when(goalRoomRepository.findByIdWithRoadmapContent(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.of(goalRoomMember)); + + // when + final GoalRoomCertifiedResponse goalRoomResponse = goalRoomReadService.findGoalRoom( + creator.getIdentifier().getValue(), goalRoom.getId()); + final GoalRoomCertifiedResponse expected = ์˜ˆ์ƒํ•˜๋Š”_๋กœ๊ทธ์ธ๋œ_์‚ฌ์šฉ์ž์˜_๊ณจ๋ฃธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(true, 0); + + // then + assertThat(goalRoomResponse) + .isEqualTo(expected); + } + + @Test + void ๋ชจ์ง‘์ค‘์ด์ง€_์•Š์€_๊ณจ๋ฃธ์—_๋Œ€ํ•ด์„œ_๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_์‚ฌ์šฉ์ž_๋ชฉ๋ก_์กฐํšŒ์‹œ_์ฐธ์—ฌํ•˜์ง€_์•Š๋Š”_์‚ฌ์šฉ์ž๋ฉด_์ฐธ์—ฌ์—ฌ๋ถ€๊ฐ€_false๋กœ_๋ฐ˜ํ™˜๋œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + goalRoom.start(); + + when(goalRoomRepository.findByIdWithRoadmapContent(any())) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .thenReturn(Optional.empty()); + + // when + final GoalRoomCertifiedResponse goalRoomResponse = goalRoomReadService.findGoalRoom( + creator.getIdentifier().getValue(), goalRoom.getId()); + final GoalRoomCertifiedResponse expected = ์˜ˆ์ƒํ•˜๋Š”_๋กœ๊ทธ์ธ๋œ_์‚ฌ์šฉ์ž์˜_๊ณจ๋ฃธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(false, 0); + + // then + assertThat(goalRoomResponse) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ_์•„์ด๋””์™€_์‚ฌ์šฉ์ž_์•„์ด๋””๋กœ_๊ณจ๋ฃธ_๋Œ€๊ธฐ_๋ชฉ๋ก_์กฐํšŒ์‹œ_๊ณจ๋ฃธ_์•„์ด๋””๊ฐ€_์œ ํšจํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(goalRoomRepository.findByIdWithRoadmapContent(any())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomReadService.findGoalRoom("cokirikiri", 1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_์ง„ํ–‰์ค‘์ธ_๊ณจ๋ฃธ์˜_์ฐธ์—ฌ์ž๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + goalRoom.start(); + + final GoalRoomMember goalRoomMemberCreator = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), + goalRoom, creator); + final GoalRoomMember goalRoomMemberFollower = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), + goalRoom, follower); + + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomMemberRepository.findByGoalRoomIdOrderedBySortType(anyLong(), any())) + .willReturn(List.of(goalRoomMemberCreator, goalRoomMemberFollower)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + //when + final List result = goalRoomReadService.findGoalRoomMembers(1L, + GoalRoomMemberSortTypeDto.ACCOMPLISHMENT_RATE); + + //then + final GoalRoomMemberResponse expectedGoalRoomMemberResponse1 = new GoalRoomMemberResponse(1L, "name1", + "http://example.com/serverFilePath", 0.0); + final GoalRoomMemberResponse expectedGoalRoomMemberResponse2 = new GoalRoomMemberResponse(2L, "name1", + "http://example.com/serverFilePath", 0.0); + assertThat(result) + .isEqualTo(List.of(expectedGoalRoomMemberResponse1, expectedGoalRoomMemberResponse2)); + verify(goalRoomPendingMemberRepository, never()).findByGoalRoomIdOrderedBySortType(anyLong(), any()); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_์™„๋ฃŒ๋œ_๊ณจ๋ฃธ์˜_์ฐธ์—ฌ์ž๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + goalRoom.complete(); + + final GoalRoomMember goalRoomMemberCreator = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), + goalRoom, creator); + final GoalRoomMember goalRoomMemberFollower = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), + goalRoom, follower); + + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomMemberRepository.findByGoalRoomIdOrderedBySortType(anyLong(), any())) + .willReturn(List.of(goalRoomMemberCreator, goalRoomMemberFollower)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + //when + final List result = goalRoomReadService.findGoalRoomMembers(1L, + GoalRoomMemberSortTypeDto.ACCOMPLISHMENT_RATE); + + //then + final GoalRoomMemberResponse expectedGoalRoomMemberResponse1 = new GoalRoomMemberResponse(1L, "name1", + "http://example.com/serverFilePath", 0.0); + final GoalRoomMemberResponse expectedGoalRoomMemberResponse2 = new GoalRoomMemberResponse(2L, "name1", + "http://example.com/serverFilePath", 0.0); + assertThat(result) + .isEqualTo(List.of(expectedGoalRoomMemberResponse1, expectedGoalRoomMemberResponse2)); + verify(goalRoomPendingMemberRepository, never()).findByGoalRoomIdOrderedBySortType(anyLong(), any()); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์˜_์ฐธ์—ฌ์ž๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + //given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + + final GoalRoomPendingMember goalRoomMemberCreator = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), goalRoom, creator); + final GoalRoomPendingMember goalRoomMemberFollower = new GoalRoomPendingMember(GoalRoomRole.LEADER, + LocalDateTime.now(), goalRoom, follower); + + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomPendingMemberRepository.findByGoalRoomIdOrderedBySortType(anyLong(), any())) + .willReturn(List.of(goalRoomMemberCreator, goalRoomMemberFollower)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + //when + final List result = goalRoomReadService.findGoalRoomMembers(1L, + GoalRoomMemberSortTypeDto.ACCOMPLISHMENT_RATE); + + //then + final GoalRoomMemberResponse expectedGoalRoomMemberResponse1 = new GoalRoomMemberResponse(1L, "name1", + "http://example.com/serverFilePath", 0.0); + final GoalRoomMemberResponse expectedGoalRoomMemberResponse2 = new GoalRoomMemberResponse(2L, "name1", + "http://example.com/serverFilePath", 0.0); + assertThat(result) + .isEqualTo(List.of(expectedGoalRoomMemberResponse1, expectedGoalRoomMemberResponse2)); + verify(goalRoomMemberRepository, never()).findByGoalRoomIdOrderedBySortType(anyLong(), any()); + } + + @Test + void ์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + given(goalRoomRepository.findById(anyLong())) + .willReturn(Optional.empty()); + + //when + //then + assertThatThrownBy(() -> goalRoomReadService.findGoalRoomMembers(1L, + GoalRoomMemberSortTypeDto.ACCOMPLISHMENT_RATE)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ „์ฒด_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + + final GoalRoomToDo firstGoalRoomTodo = new GoalRoomToDo(1L, new GoalRoomTodoContent("ํˆฌ๋‘ 1"), + new Period(TODAY, TEN_DAY_LATER)); + final GoalRoomToDo secondGoalRoomTodo = new GoalRoomToDo(2L, new GoalRoomTodoContent("ํˆฌ๋‘ 2"), + new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER)); + goalRoom.addGoalRoomTodo(firstGoalRoomTodo); + goalRoom.addGoalRoomTodo(secondGoalRoomTodo); + + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + when(goalRoomMemberRepository.findGoalRoomMember(anyLong(), any())) + .thenReturn(Optional.of(goalRoomMember)); + when(goalRoomRepository.findByIdWithTodos(1L)) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomToDoCheckRepository.findByGoalRoomIdAndMemberIdentifier(anyLong(), any())) + .thenReturn(List.of( + new GoalRoomToDoCheck(goalRoomMember, firstGoalRoomTodo) + )); + + // when + final List responses = goalRoomReadService.findAllGoalRoomTodo(1L, "identifier"); + final List expected = List.of( + new GoalRoomTodoResponse(1L, "ํˆฌ๋‘ 1", TODAY, TEN_DAY_LATER, new GoalRoomToDoCheckResponse(true)), + new GoalRoomTodoResponse(2L, "ํˆฌ๋‘ 2", TWENTY_DAY_LAYER, THIRTY_DAY_LATER, + new GoalRoomToDoCheckResponse(false))); + + // then + assertThat(responses) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์˜_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(goalRoomRepository.findByIdWithTodos(1L)) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomReadService.findAllGoalRoomTodo(1L, "identifier")) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์˜_ํˆฌ๋‘๋ฆฌ์ŠคํŠธ_์กฐํšŒ์‹œ_๊ณจ๋ฃธ์—_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + + final GoalRoomToDo firstGoalRoomTodo = new GoalRoomToDo(1L, new GoalRoomTodoContent("ํˆฌ๋‘ 1"), + new Period(TODAY, TEN_DAY_LATER)); + final GoalRoomToDo secondGoalRoomTodo = new GoalRoomToDo(2L, new GoalRoomTodoContent("ํˆฌ๋‘ 2"), + new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER)); + goalRoom.addGoalRoomTodo(firstGoalRoomTodo); + goalRoom.addGoalRoomTodo(secondGoalRoomTodo); + + when(goalRoomRepository.findByIdWithTodos(1L)) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findGoalRoomMember(anyLong(), any())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomReadService.findAllGoalRoomTodo(1L, "identifier")) + .isInstanceOf(ForbiddenException.class); + } + + @Test + void ์ง„ํ–‰์ค‘์ธ_์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ์„_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode3 = new RoadmapNode("๋กœ๋“œ๋งต 3์ฃผ์ฐจ", "๋กœ๋“œ๋งต 3์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode4 = new RoadmapNode("๋กœ๋“œ๋งต 4์ฃผ์ฐจ", "๋กœ๋“œ๋งต 4์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNodes roadmapNodes = new RoadmapNodes( + List.of(roadmapNode1, roadmapNode2, roadmapNode3, roadmapNode4)); + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(roadmapNodes); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = new GoalRoomRoadmapNode( + new Period(TODAY, TODAY.plusDays(10)), 5, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(11), TODAY.plusDays(20)), 5, roadmapNode2); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final GoalRoom goalRoom = new GoalRoom(1L, new GoalRoomName("goalroom"), new LimitedMemberCount(10), + roadmapContent, member); + goalRoom.start(); + + goalRoom.addAllGoalRoomRoadmapNodes( + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2))); + goalRoom.addAllGoalRoomMembers( + List.of(new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, member))); + + final List checkFeeds = ์ธ์ฆ_ํ”ผ๋“œ_๋ชฉ๋ก์„_์ƒ์„ฑํ•œ๋‹ค(goalRoomRoadmapNode1, member, goalRoom); + given(goalRoomRepository.findByIdWithContentAndTodos(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(checkFeedRepository.findByRunningGoalRoomRoadmapNode(any())) + .willReturn(checkFeeds); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final MemberGoalRoomResponse expected = new MemberGoalRoomResponse(goalRoom.getName().getValue(), + goalRoom.getStatus().name(), member.getId(), goalRoom.getCurrentMemberCount(), + goalRoom.getLimitedMemberCount().getValue(), goalRoom.getStartDate(), goalRoom.getEndDate(), + roadmapContent.getId(), new GoalRoomRoadmapNodesResponse(false, true, + List.of( + new GoalRoomRoadmapNodeResponse(goalRoomRoadmapNode1.getId(), roadmapNode1.getTitle(), + goalRoomRoadmapNode1.getStartDate(), + goalRoomRoadmapNode1.getEndDate(), goalRoomRoadmapNode1.getCheckCount()), + new GoalRoomRoadmapNodeResponse(goalRoomRoadmapNode2.getId(), roadmapNode2.getTitle(), + goalRoomRoadmapNode2.getStartDate(), + goalRoomRoadmapNode2.getEndDate(), goalRoomRoadmapNode2.getCheckCount()) + )), Collections.emptyList(), + List.of( + new CheckFeedResponse(1L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()), + new CheckFeedResponse(2L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()), + new CheckFeedResponse(3L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()), + new CheckFeedResponse(4L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()) + )); + + //when + final MemberGoalRoomResponse response = goalRoomReadService.findMemberGoalRoom("identifier1", 1L); + + //then + assertThat(response) + .usingRecursiveComparison() + .ignoringFields("checkFeeds.id", "checkFeeds.createdAt") + .isEqualTo(expected); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ_์กฐํšŒ์‹œ_์ธ์ฆํ”ผ๋“œ๊ฐ€_๋นˆ_์‘๋‹ต์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode3 = new RoadmapNode("๋กœ๋“œ๋งต 3์ฃผ์ฐจ", "๋กœ๋“œ๋งต 3์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode4 = new RoadmapNode("๋กœ๋“œ๋งต 4์ฃผ์ฐจ", "๋กœ๋“œ๋งต 4์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNodes roadmapNodes = new RoadmapNodes( + List.of(roadmapNode1, roadmapNode2, roadmapNode3, roadmapNode4)); + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(roadmapNodes); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = new GoalRoomRoadmapNode( + new Period(TODAY, TODAY.plusDays(10)), 5, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(11), TODAY.plusDays(20)), 5, roadmapNode2); + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(21), TODAY.plusDays(30)), 5, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(31), TODAY.plusDays(40)), 5, roadmapNode2); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final GoalRoom goalRoom = new GoalRoom(1L, new GoalRoomName("goalroom"), new LimitedMemberCount(10), + roadmapContent, member); + goalRoom.addAllGoalRoomRoadmapNodes( + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2, goalRoomRoadmapNode3, + goalRoomRoadmapNode4))); + + given(goalRoomRepository.findByIdWithContentAndTodos(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + + final MemberGoalRoomResponse expected = new MemberGoalRoomResponse(goalRoom.getName().getValue(), + goalRoom.getStatus().name(), member.getId(), goalRoom.getCurrentMemberCount(), + goalRoom.getLimitedMemberCount().getValue(), goalRoom.getStartDate(), goalRoom.getEndDate(), + roadmapContent.getId(), new GoalRoomRoadmapNodesResponse(false, true, + List.of( + new GoalRoomRoadmapNodeResponse(goalRoomRoadmapNode1.getId(), roadmapNode1.getTitle(), + goalRoomRoadmapNode1.getStartDate(), + goalRoomRoadmapNode1.getEndDate(), goalRoomRoadmapNode1.getCheckCount()), + new GoalRoomRoadmapNodeResponse(goalRoomRoadmapNode2.getId(), roadmapNode2.getTitle(), + goalRoomRoadmapNode2.getStartDate(), + goalRoomRoadmapNode2.getEndDate(), goalRoomRoadmapNode2.getCheckCount()) + )), Collections.emptyList(), Collections.emptyList()); + + //when + final MemberGoalRoomResponse response = goalRoomReadService.findMemberGoalRoom("identifier1", 1L); + + //then + assertThat(response).isEqualTo(expected); + } + + @Test + void ์ข…๋ฃŒ๋œ_์‚ฌ์šฉ์ž_๋‹จ์ผ_๊ณจ๋ฃธ์„_์กฐํšŒ์‹œ_์ „์ฒด_์ธ์ฆํ”ผ๋“œ๋ฅผ_๋Œ€์ƒ์œผ๋กœ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws MalformedURLException { + // given + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode3 = new RoadmapNode("๋กœ๋“œ๋งต 3์ฃผ์ฐจ", "๋กœ๋“œ๋งต 3์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode4 = new RoadmapNode("๋กœ๋“œ๋งต 4์ฃผ์ฐจ", "๋กœ๋“œ๋งต 4์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNodes roadmapNodes = new RoadmapNodes( + List.of(roadmapNode1, roadmapNode2, roadmapNode3, roadmapNode4)); + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(roadmapNodes); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = new GoalRoomRoadmapNode( + new Period(TODAY, TODAY.plusDays(10)), 5, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(11), TODAY.plusDays(20)), 5, roadmapNode2); + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(21), TODAY.plusDays(30)), 5, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(31), TODAY.plusDays(40)), 5, roadmapNode2); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final GoalRoom goalRoom = new GoalRoom(1L, new GoalRoomName("goalroom"), new LimitedMemberCount(10), + roadmapContent, member); + goalRoom.start(); + goalRoom.complete(); + goalRoom.addAllGoalRoomRoadmapNodes( + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2))); + goalRoom.addAllGoalRoomMembers( + List.of(new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, member))); + + final List checkFeeds = ์ธ์ฆ_ํ”ผ๋“œ_๋ชฉ๋ก์„_์ƒ์„ฑํ•œ๋‹ค(goalRoomRoadmapNode1, member, goalRoom); + given(goalRoomRepository.findByIdWithContentAndTodos(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + given(checkFeedRepository.findByGoalRoom(any())) + .willReturn(checkFeeds); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final MemberGoalRoomResponse expected = new MemberGoalRoomResponse(goalRoom.getName().getValue(), + goalRoom.getStatus().name(), member.getId(), goalRoom.getCurrentMemberCount(), + goalRoom.getLimitedMemberCount().getValue(), goalRoom.getStartDate(), goalRoom.getEndDate(), + roadmapContent.getId(), new GoalRoomRoadmapNodesResponse(false, true, + List.of( + new GoalRoomRoadmapNodeResponse(goalRoomRoadmapNode1.getId(), roadmapNode1.getTitle(), + goalRoomRoadmapNode1.getStartDate(), + goalRoomRoadmapNode1.getEndDate(), goalRoomRoadmapNode1.getCheckCount()), + new GoalRoomRoadmapNodeResponse(goalRoomRoadmapNode2.getId(), roadmapNode2.getTitle(), + goalRoomRoadmapNode2.getStartDate(), + goalRoomRoadmapNode2.getEndDate(), goalRoomRoadmapNode2.getCheckCount()) + )), Collections.emptyList(), + List.of( + new CheckFeedResponse(1L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()), + new CheckFeedResponse(2L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()), + new CheckFeedResponse(3L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()), + new CheckFeedResponse(4L, "http://example.com/serverFilePath", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", LocalDate.now()) + )); + + //when + final MemberGoalRoomResponse response = goalRoomReadService.findMemberGoalRoom("identifier1", 1L); + + //then + assertThat(response) + .usingRecursiveComparison() + .ignoringFields("checkFeeds.id", "checkFeeds.createdAt") + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž_๋‹จ์ผ_๋ชฉ๋ก_์กฐํšŒ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ_์•„์ด๋””์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + //given + when(goalRoomRepository.findByIdWithContentAndTodos(anyLong())) + .thenThrow(new NotFoundException("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1")); + + //when, then + assertThatThrownBy(() -> goalRoomReadService.findMemberGoalRoom("identifier1", 1L)) + .isInstanceOf(NotFoundException.class) + .hasMessage("๊ณจ๋ฃธ ์ •๋ณด๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. goalRoomId = 1"); + + } + + @Test + void ์‚ฌ์šฉ์ž_๋‹จ์ผ_๋ชฉ๋ก_์กฐํšŒ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_์•„์ด๋””์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + when(goalRoomRepository.findByIdWithContentAndTodos(anyLong())) + .thenReturn(Optional.of(goalRoom)); + when(memberRepository.findByIdentifier(any())) + .thenThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + + // when, then + assertThatThrownBy(() -> goalRoomReadService.findMemberGoalRoom("identifier2", 1L)) + .isInstanceOf(NotFoundException.class) + .hasMessage("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ์‚ฌ์šฉ์ž_๋‹จ์ผ_๋ชฉ๋ก_์กฐํšŒ_์‹œ_์‚ฌ์šฉ์ž๊ฐ€_์ฐธ์—ฌํ•˜์ง€_์•Š์€_๊ณจ๋ฃธ์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + when(goalRoomRepository.findByIdWithContentAndTodos(anyLong())) + .thenReturn(Optional.of(goalRoom)); + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(member)); + + // when, then + assertThatThrownBy(() -> goalRoomReadService.findMemberGoalRoom("identifier2", 1L)) + .isInstanceOf(ForbiddenException.class) + .hasMessage("ํ•ด๋‹น ๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + goalRoom1.join(member); + goalRoom3.join(member); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(member)); + when(goalRoomRepository.findByMember(any())) + .thenReturn(List.of(goalRoom1, goalRoom3)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final List expected = List.of( + new MemberGoalRoomForListResponse(1L, "๊ณจ๋ฃธ", "RECRUITING", 2, 10, LocalDateTime.now(), TODAY, + THIRTY_DAY_LATER, new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")), + new MemberGoalRoomForListResponse(2L, "๊ณจ๋ฃธ", "RECRUITING", 2, + 10, LocalDateTime.now(), TODAY, THIRTY_DAY_LATER, + new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")) + ); + + //when + final List response = goalRoomReadService.findMemberGoalRooms("identifier1"); + + //then + assertThat(response) + .usingRecursiveComparison() + .ignoringFields("goalRoomId", "createdAt") + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_๋ชฉ๋ฃฉ_์กฐํšŒ_์ค‘_์ฐธ์—ฌํ•œ_๊ณจ๋ฃธ์ด์—†์œผ๋ฉด_๋นˆ_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(creator)); + when(goalRoomRepository.findByMember(any())) + .thenReturn(Collections.emptyList()); + + // when + final List response = goalRoomReadService.findMemberGoalRooms("identifier1"); + + // then + assertThat(response).isEmpty(); + } + + @Test + void ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_๋ชฉ๋ก_์ค‘_๋ชจ์ง‘_์ค‘์ธ_์ƒํƒœ๋งŒ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom4 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + goalRoom1.join(member); + goalRoom2.join(member); + goalRoom3.join(member); + goalRoom4.join(member); + + goalRoom3.start(); + goalRoom4.complete(); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(member)); + when(goalRoomRepository.findByMemberAndStatus(any(), any())) + .thenReturn(List.of(goalRoom1, goalRoom2)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final List expected = List.of( + new MemberGoalRoomForListResponse(1L, "๊ณจ๋ฃธ", "RECRUITING", 2, + 10, LocalDateTime.now(), TODAY, THIRTY_DAY_LATER, + new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")), + new MemberGoalRoomForListResponse(2L, "๊ณจ๋ฃธ", "RECRUITING", 2, + 10, LocalDateTime.now(), TODAY, THIRTY_DAY_LATER, + new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")) + ); + + //when + final List response = goalRoomReadService.findMemberGoalRoomsByStatusType( + "identifier2", GoalRoomStatusTypeRequest.RECRUITING); + + //then + assertThat(response) + .usingRecursiveComparison() + .ignoringFields("goalRoomId", "createdAt") + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_๋ชฉ๋ก_์ค‘_์ง„ํ–‰_์ค‘์ธ_์ƒํƒœ๋งŒ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom4 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + goalRoom1.join(member); + goalRoom2.join(member); + goalRoom3.join(member); + goalRoom4.join(member); + + goalRoom3.start(); + goalRoom4.start(); + + goalRoom3.addAllGoalRoomMembers(List.of( + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom3, creator), + new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom3, member))); + goalRoom4.addAllGoalRoomMembers(List.of( + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom3, creator), + new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom3, member))); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(member)); + when(goalRoomRepository.findByMemberAndStatus(any(), any())) + .thenReturn(List.of(goalRoom3, goalRoom4)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final List expected = List.of( + new MemberGoalRoomForListResponse(3L, "๊ณจ๋ฃธ", "RUNNING", 2, + 10, LocalDateTime.now(), TODAY, THIRTY_DAY_LATER, + new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")), + new MemberGoalRoomForListResponse(4L, "๊ณจ๋ฃธ", "RUNNING", 2, + 10, LocalDateTime.now(), TODAY, THIRTY_DAY_LATER, + new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")) + ); + + //when + final List response = goalRoomReadService.findMemberGoalRoomsByStatusType( + "identifier2", GoalRoomStatusTypeRequest.RUNNING); + + //then + assertThat(response) + .usingRecursiveComparison() + .ignoringFields("goalRoomId", "createdAt") + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž_๊ณจ๋ฃธ_๋ชฉ๋ก_์ค‘_์ข…๋ฃŒ๋œ_์ƒํƒœ๋งŒ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + final Member creator = ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom3 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + final GoalRoom goalRoom4 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, targetRoadmapContent); + + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + goalRoom1.join(member); + goalRoom2.join(member); + goalRoom3.join(member); + goalRoom4.join(member); + + goalRoom3.complete(); + goalRoom4.complete(); + + goalRoom3.addAllGoalRoomMembers(List.of( + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom3, creator), + new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom3, member))); + goalRoom4.addAllGoalRoomMembers(List.of( + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom3, creator), + new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom3, member))); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(member)); + when(goalRoomRepository.findByMemberAndStatus(any(), any())) + .thenReturn(List.of(goalRoom3, goalRoom4)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final List expected = List.of( + new MemberGoalRoomForListResponse(3L, "๊ณจ๋ฃธ", "COMPLETED", 2, + 10, LocalDateTime.now(), TODAY, THIRTY_DAY_LATER, + new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")), + new MemberGoalRoomForListResponse(4L, "๊ณจ๋ฃธ", "COMPLETED", 2, + 10, LocalDateTime.now(), TODAY, THIRTY_DAY_LATER, + new MemberResponse(creator.getId(), creator.getNickname().getValue(), + "http://example.com/serverFilePath")) + ); + + //when + final List response = goalRoomReadService.findMemberGoalRoomsByStatusType( + "identifier2", GoalRoomStatusTypeRequest.COMPLETED); + + //then + assertThat(response) + .usingRecursiveComparison() + .ignoringFields("goalRoomId", "createdAt") + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ „์ฒด_๋…ธ๋“œ๋ฅผ_์กฐํšŒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + when(goalRoomMemberRepository.findGoalRoomMember(anyLong(), any())) + .thenReturn(Optional.of(goalRoomMember)); + when(goalRoomRepository.findByIdWithNodes(1L)) + .thenReturn(Optional.of(goalRoom)); + + // when + final List responses = goalRoomReadService.findAllGoalRoomNodes(1L, "identifier"); + final List expected = List.of( + new GoalRoomRoadmapNodeResponse(1L, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ", TODAY, TEN_DAY_LATER, 10), + new GoalRoomRoadmapNodeResponse(2L, "๋กœ๋“œ๋งต 2์ฃผ์ฐจ", TWENTY_DAY_LAYER, THIRTY_DAY_LATER, 2) + ); + + // then + assertThat(responses) + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์˜_๋…ธ๋“œ_์กฐํšŒ์‹œ_๊ณจ๋ฃธ์—_์ฐธ์—ฌํ•˜์ง€_์•Š์€_์‚ฌ์šฉ์ž๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + + when(goalRoomRepository.findByIdWithNodes(1L)) + .thenReturn(Optional.of(goalRoom)); + when(goalRoomMemberRepository.findGoalRoomMember(anyLong(), any())) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomReadService.findAllGoalRoomNodes(1L, "identifier")) + .isInstanceOf(ForbiddenException.class); + } + + @Test + void ๊ณจ๋ฃธ์˜_๋…ธ๋“œ_์กฐํšŒ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(goalRoomRepository.findByIdWithNodes(1L)) + .thenReturn(Optional.empty()); + + // expected + assertThatThrownBy(() -> goalRoomReadService.findAllGoalRoomNodes(1L, "identifier")) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ์ง„ํ–‰์ค‘์ธ_๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + goalRoom.start(); + + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + follower); + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + + final CheckFeed checkFeed1 = ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath1", "description1", goalRoomRoadmapNode, + goalRoomMember1); + final CheckFeed checkFeed2 = ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath2", "description2", goalRoomRoadmapNode, + goalRoomMember1); + final CheckFeed checkFeed3 = ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath3", "description3", goalRoomRoadmapNode, + goalRoomMember2); + + given(goalRoomRepository.findByIdWithNodes(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .willReturn(Optional.of(goalRoomMember1)); + given(checkFeedRepository.findByRunningGoalRoomRoadmapNodeWithMemberAndMemberImage(any())) + .willReturn(List.of(checkFeed3, checkFeed2, checkFeed1)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + // when + final List responses = goalRoomReadService.findGoalRoomCheckFeeds("cokirikiri", 1L); + + // then + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse1 = new GoalRoomCheckFeedResponse( + new MemberResponse(1L, "name1", "http://example.com/serverFilePath"), + new CheckFeedResponse(1L, "http://example.com/serverFilePath", "description1", LocalDate.now())); + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse2 = new GoalRoomCheckFeedResponse( + new MemberResponse(1L, "name1", "http://example.com/serverFilePath"), + new CheckFeedResponse(2L, "http://example.com/serverFilePath", "description2", LocalDate.now())); + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse3 = new GoalRoomCheckFeedResponse( + new MemberResponse(2L, "name1", "http://example.com/serverFilePath"), + new CheckFeedResponse(3L, "http://example.com/serverFilePath", "description3", LocalDate.now())); + final List expected = List.of(goalRoomCheckFeedResponse3, + goalRoomCheckFeedResponse2, goalRoomCheckFeedResponse1); + + assertThat(responses).usingRecursiveComparison() + .ignoringFields("checkFeed.id", "checkFeed.createdAt") + .isEqualTo(expected); + } + + @Test + void ๋ชจ์ง‘์ค‘์ธ_๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์กฐํšŒ์‹œ_๋นˆ_๊ฐ’์„_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + final GoalRoomMember goalRoomMember = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + + given(goalRoomRepository.findByIdWithNodes(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .willReturn(Optional.of(goalRoomMember)); + + // when + final List responses = goalRoomReadService.findGoalRoomCheckFeeds("cokirikiri", 1L); + + // then + final List expected = Collections.emptyList(); + + assertThat(responses).isEqualTo(expected); + } + + @Test + void ์ข…๋ฃŒ๋œ_๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒ์‹œ_๋ชจ๋“ _๊ธฐ๊ฐ„์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_๋Œ€์ƒ์œผ๋กœ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws MalformedURLException { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + goalRoom.complete(); + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + follower); + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + + final CheckFeed checkFeed1 = ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath1", "description1", goalRoomRoadmapNode, + goalRoomMember1); + final CheckFeed checkFeed2 = ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath2", "description2", goalRoomRoadmapNode, + goalRoomMember1); + final CheckFeed checkFeed3 = ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath3", "description3", goalRoomRoadmapNode, + goalRoomMember2); + + given(goalRoomRepository.findByIdWithNodes(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .willReturn(Optional.of(goalRoomMember1)); + given(checkFeedRepository.findByGoalRoomWithMemberAndMemberImage(any())) + .willReturn(List.of(checkFeed3, checkFeed2, checkFeed1)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + // when + final List responses = goalRoomReadService.findGoalRoomCheckFeeds("cokirikiri", 1L); + + // then + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse1 = new GoalRoomCheckFeedResponse( + new MemberResponse(1L, "name1", "http://example.com/serverFilePath"), + new CheckFeedResponse(1L, "http://example.com/serverFilePath", "description1", LocalDate.now())); + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse2 = new GoalRoomCheckFeedResponse( + new MemberResponse(1L, "name1", "http://example.com/serverFilePath"), + new CheckFeedResponse(2L, "http://example.com/serverFilePath", "description2", LocalDate.now())); + final GoalRoomCheckFeedResponse goalRoomCheckFeedResponse3 = new GoalRoomCheckFeedResponse( + new MemberResponse(2L, "name1", "http://example.com/serverFilePath"), + new CheckFeedResponse(3L, "http://example.com/serverFilePath", "description3", LocalDate.now())); + final List expected = List.of(goalRoomCheckFeedResponse3, + goalRoomCheckFeedResponse2, goalRoomCheckFeedResponse1); + + assertThat(responses).usingRecursiveComparison() + .ignoringFields("checkFeed.id", "checkFeed.createdAt") + .isEqualTo(expected); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒ์‹œ_ํ˜„์žฌ_์ง„ํ–‰์ค‘์ธ_๋…ธ๋“œ๊ฐ€_์—†์œผ๋ฉด_๋นˆ_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + final Member follower = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ์ง„ํ–‰์ค‘์ธ_๋…ธ๋“œ๊ฐ€_์—†๋Š”_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + final GoalRoomMember goalRoomMember1 = new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, + creator); + final GoalRoomMember goalRoomMember2 = new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, + follower); + final GoalRoomRoadmapNode goalRoomRoadmapNode = goalRoom.getGoalRoomRoadmapNodes().getValues().get(0); + + ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath1", "description1", goalRoomRoadmapNode, goalRoomMember1); + ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath2", "description2", goalRoomRoadmapNode, goalRoomMember1); + ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค("serverFilePath3", "description3", goalRoomRoadmapNode, goalRoomMember2); + + given(goalRoomRepository.findByIdWithNodes(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomMemberRepository.findByGoalRoomAndMemberIdentifier(any(), any())) + .willReturn(Optional.of(goalRoomMember1)); + + // when + final List responses = goalRoomReadService.findGoalRoomCheckFeeds("cokirikiri", 1L); + + // then + assertThat(responses).isEmpty(); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒํ• _๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๊ณจ๋ฃธ์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + given(goalRoomRepository.findByIdWithNodes(anyLong())) + .willThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ณจ๋ฃธ์ž…๋‹ˆ๋‹ค. goalRoomId = 1")); + + // when + // then + assertThatThrownBy(() -> goalRoomReadService.findGoalRoomCheckFeeds("cokirikiri", 1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๊ณจ๋ฃธ์˜_์ธ์ฆํ”ผ๋“œ๋ฅผ_์ „์ฒด_์กฐํšŒํ• _๋•Œ_๊ณจ๋ฃธ์—_์ฐธ์—ฌํ•˜์ง€_์•Š์€_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(creator, roadmap.getContents().getValues().get(0)); + + given(goalRoomRepository.findByIdWithNodes(anyLong())) + .willReturn(Optional.of(goalRoom)); + given(goalRoomRepository.findByIdWithNodes(anyLong())) + .willThrow(new ForbiddenException("๊ณจ๋ฃธ์— ์ฐธ์—ฌํ•˜์ง€ ์•Š์€ ํšŒ์›์ž…๋‹ˆ๋‹ค.")); + + // when + // then + assertThatThrownBy(() -> goalRoomReadService.findGoalRoomCheckFeeds("cokirikiri", 1L)) + .isInstanceOf(ForbiddenException.class); + } + + private Member ํฌ๋ฆฌ์—์ดํ„ฐ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + final MemberImage memberImage = new MemberImage("originalFileName", "default-member-image", + ImageContentType.JPG); + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, LocalDate.of(1990, 1, 1), "010-1234-5678"); + return new Member(1L, new Identifier("cokirikiri"), new EncryptedPassword(new Password("password1!")), + new Nickname("์ฝ”๋ผ๋ฆฌ"), memberImage, memberProfile); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final Long id) { + return new Member(id, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1")), new Nickname("name1"), + new MemberImage("originalFileName", "serverFilePath", ImageContentType.JPEG), + new MemberProfile(Gender.FEMALE, LocalDate.of(2000, 7, 20), + "010-1111-1111")); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final Member creator) { + final RoadmapCategory category = new RoadmapCategory("๊ฒŒ์ž„"); + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmap; + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + roadmapNode1.addImages(new RoadmapNodeImages(๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค())); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private List ๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of( + new RoadmapNodeImage("node-image1.png", "node-image1-save-path", ImageContentType.PNG), + new RoadmapNodeImage("node-image2.png", "node-image2-save-path", ImageContentType.PNG) + ); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final Member member, final RoadmapContent roadmapContent) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(10), + roadmapContent, member); + final List roadmapNodes = roadmapContent.getNodes().getValues(); + + final RoadmapNode firstRoadmapNode = roadmapNodes.get(0); + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + 1L, new Period(TODAY, TEN_DAY_LATER), 10, firstRoadmapNode); + + final RoadmapNode secondRoadmapNode = roadmapNodes.get(1); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + 2L, new Period(TWENTY_DAY_LAYER, THIRTY_DAY_LATER), 2, secondRoadmapNode); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes( + List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode)); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoom; + } + + private GoalRoom ์ง„ํ–‰์ค‘์ธ_๋…ธ๋“œ๊ฐ€_์—†๋Š”_๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final Member member, final RoadmapContent roadmapContent) { + final GoalRoom goalRoom = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(10), + roadmapContent, member); + final List roadmapNodes = roadmapContent.getNodes().getValues(); + + final RoadmapNode firstRoadmapNode = roadmapNodes.get(0); + final GoalRoomRoadmapNode firstGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + 1L, new Period(TEN_DAY_LATER, TWENTY_DAY_LAYER), 10, firstRoadmapNode); + + final RoadmapNode secondRoadmapNode = roadmapNodes.get(1); + final GoalRoomRoadmapNode secondGoalRoomRoadmapNode = new GoalRoomRoadmapNode( + 2L, new Period(THIRTY_DAY_LATER, THIRTY_DAY_LATER.plusDays(10)), 2, secondRoadmapNode); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes( + List.of(firstGoalRoomRoadmapNode, secondGoalRoomRoadmapNode)); + goalRoom.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + return goalRoom; + } + + private static GoalRoomResponse ์˜ˆ์ƒํ•˜๋Š”_๊ณจ๋ฃธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค() { + final List goalRoomNodeResponses = List.of( + new GoalRoomRoadmapNodeResponse(1L, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ", TODAY, TEN_DAY_LATER, 10), + new GoalRoomRoadmapNodeResponse(2L, "๋กœ๋“œ๋งต 2์ฃผ์ฐจ", TWENTY_DAY_LAYER, THIRTY_DAY_LATER, 2)); + return new GoalRoomResponse("๊ณจ๋ฃธ", 1, 10, goalRoomNodeResponses, 31); + } + + private static GoalRoomCertifiedResponse ์˜ˆ์ƒํ•˜๋Š”_๋กœ๊ทธ์ธ๋œ_์‚ฌ์šฉ์ž์˜_๊ณจ๋ฃธ_์‘๋‹ต์„_์ƒ์„ฑํ•œ๋‹ค(final Boolean isJoined, + final int currentMemberCount) { + final List goalRoomNodeResponses = List.of( + new GoalRoomRoadmapNodeResponse(1L, "๋กœ๋“œ๋งต 1์ฃผ์ฐจ", TODAY, TEN_DAY_LATER, 10), + new GoalRoomRoadmapNodeResponse(2L, "๋กœ๋“œ๋งต 2์ฃผ์ฐจ", TWENTY_DAY_LAYER, THIRTY_DAY_LATER, 2)); + return new GoalRoomCertifiedResponse("๊ณจ๋ฃธ", currentMemberCount, 10, goalRoomNodeResponses, 31, isJoined); + } + + private CheckFeed ์ธ์ฆํ”ผ๋“œ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final String serverFilePath, final String description, + final GoalRoomRoadmapNode goalRoomRoadmapNode, final GoalRoomMember goalRoomMember) { + return new CheckFeed(serverFilePath, ImageContentType.PNG, "fileName", description, goalRoomRoadmapNode, + goalRoomMember, LocalDateTime.now()); + } + + private List ์ธ์ฆ_ํ”ผ๋“œ_๋ชฉ๋ก์„_์ƒ์„ฑํ•œ๋‹ค(final GoalRoomRoadmapNode node, final Member member, + final GoalRoom goalRoom) { + return List.of( + new CheckFeed("filePath1", ImageContentType.JPEG, "originalFileName1", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", node, + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, member), + LocalDateTime.now()), + new CheckFeed("filePath2", ImageContentType.JPEG, "originalFileName2", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", node, + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, member), + LocalDateTime.now()), + new CheckFeed("filePath3", ImageContentType.JPEG, "originalFileName3", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", node, + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, member), + LocalDateTime.now()), + new CheckFeed("filePath4", ImageContentType.JPEG, "originalFileName4", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", node, + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, member), + LocalDateTime.now()), + new CheckFeed("filePath5", ImageContentType.JPEG, "originalFileName5", "์ธ์ฆ ํ”ผ๋“œ ์„ค๋ช…", node, + new GoalRoomMember(GoalRoomRole.LEADER, LocalDateTime.now(), goalRoom, member), + LocalDateTime.now()) + ); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomSchedulerTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomSchedulerTest.java new file mode 100644 index 000000000..9b248316c --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/GoalRoomSchedulerTest.java @@ -0,0 +1,200 @@ +package co.kirikiri.service; + +import static co.kirikiri.domain.goalroom.GoalRoomStatus.RECRUITING; +import static co.kirikiri.domain.goalroom.GoalRoomStatus.RUNNING; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomPendingMember; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodeImage; +import co.kirikiri.domain.roadmap.RoadmapNodeImages; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomPendingMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +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; + +@ExtendWith(MockitoExtension.class) +public class GoalRoomSchedulerTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + private static final LocalDate TWENTY_DAY_LATER = TODAY.plusDays(20); + + @Mock + private GoalRoomRepository goalRoomRepository; + + @Mock + private GoalRoomMemberRepository goalRoomMemberRepository; + + @Mock + private GoalRoomPendingMemberRepository goalRoomPendingMemberRepository; + + @InjectMocks + private GoalRoomScheduler goalRoomScheduler; + + @Test + void ๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๊ฐ€_๋˜๋ฉด_๊ณจ๋ฃธ์˜_์ƒํƒœ๊ฐ€_์ง„ํ–‰์ค‘์œผ๋กœ_๋ณ€๊ฒฝ๋œ๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(2L, creator, targetRoadmapContent, 10); + + final Member follower1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier1", "password2!", "name1", "010-1111-1111"); + final Member follower2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(3L, "identifier2", "password3!", "name2", "010-1111-1112"); + final Member follower3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(4L, "identifier3", "password4!", "name3", "010-1111-1113"); + + final GoalRoomPendingMember goalRoomPendingMember = ๊ณจ๋ฃธ_๋Œ€๊ธฐ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(goalRoom2, creator, GoalRoomRole.FOLLOWER); + final GoalRoomPendingMember goalRoomPendingMember1 = ๊ณจ๋ฃธ_๋Œ€๊ธฐ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(goalRoom1, follower1, GoalRoomRole.FOLLOWER); + final GoalRoomPendingMember goalRoomPendingMember2 = ๊ณจ๋ฃธ_๋Œ€๊ธฐ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(goalRoom1, follower2, GoalRoomRole.FOLLOWER); + + goalRoom1.join(follower1); + goalRoom1.join(follower2); + goalRoom2.join(follower3); + + when(goalRoomRepository.findAllByStartDate(LocalDate.now())) + .thenReturn(List.of(goalRoom1)); + + // when + goalRoomScheduler.startGoalRooms(); + + // then + assertAll( + () -> assertThat(goalRoom1.getStatus()).isEqualTo(RUNNING), + () -> assertThat(goalRoom2.getStatus()).isEqualTo(RECRUITING) + ); + } + + @Test + void ๊ณจ๋ฃธ์˜_์‹œ์ž‘๋‚ ์งœ๊ฐ€_์•„์ง_์ง€๋‚˜์ง€_์•Š์•˜๋‹ค๋ฉด_๊ณจ๋ฃธ์˜_์ƒํƒœ๊ฐ€_๋ณ€๊ฒฝ๋˜์ง€_์•Š๋Š”๋‹ค() { + // given + final Member creator = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "cokirikiri", "password1!", "์ฝ”๋ผ๋ฆฌ", "010-1234-5678"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(creator); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom1 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(1L, creator, targetRoadmapContent, 10); + final GoalRoom goalRoom2 = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(2L, creator, targetRoadmapContent, 10); + + final Member follower1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier1", "password2!", "name1", "010-1111-1111"); + final Member follower2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(3L, "identifier2", "password3!", "name2", "010-1111-1112"); + final Member follower3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(4L, "identifier3", "password4!", "name3", "010-1111-1113"); + + goalRoom1.join(follower1); + goalRoom1.join(follower2); + goalRoom2.join(follower3); + + when(goalRoomRepository.findAllByStartDate(LocalDate.now())) + .thenReturn(Collections.emptyList()); + + // when + goalRoomScheduler.startGoalRooms(); + + // then + verify(goalRoomPendingMemberRepository, times(0)).findAllByGoalRoom(any()); + verify(goalRoomMemberRepository, times(0)).saveAll(anyList()); + verify(goalRoomPendingMemberRepository, times(0)).deleteAll(anyList()); + + assertAll( + () -> assertThat(goalRoom1.getStatus()).isEqualTo(RECRUITING), + () -> assertThat(goalRoom2.getStatus()).isEqualTo(RECRUITING) + ); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final Long memberId, final String identifier, final String password, final String nickname, + final String phoneNumber) { + final MemberProfile memberProfile = new MemberProfile(Gender.MALE, + LocalDate.of(1995, 9, 30), phoneNumber); + + return new Member(memberId, new Identifier(identifier), new EncryptedPassword(new Password(password)), + new Nickname(nickname), null, memberProfile); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final Member creator) { + final RoadmapCategory category = new RoadmapCategory("๊ฒŒ์ž„"); + final List roadmapNodes = ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(); + final RoadmapContent roadmapContent = ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(roadmapNodes); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 10, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(roadmapContent); + return roadmap; + } + + private List ๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + roadmapNode1.addImages(new RoadmapNodeImages(๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค())); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + return List.of(roadmapNode1, roadmapNode2); + } + + private RoadmapContent ๋กœ๋“œ๋งต_๋ณธ๋ฌธ์„_์ƒ์„ฑํ•œ๋‹ค(final List roadmapNodes) { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(new RoadmapNodes(roadmapNodes)); + return roadmapContent; + } + + private List ๋…ธ๋“œ_์ด๋ฏธ์ง€๋“ค์„_์ƒ์„ฑํ•œ๋‹ค() { + return List.of( + new RoadmapNodeImage("node-image1.png", "node-image1-save-path", ImageContentType.PNG), + new RoadmapNodeImage("node-image2.png", "node-image2-save-path", ImageContentType.PNG) + ); + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final Long goalRoomId, final Member creator, final RoadmapContent roadmapContent, + final Integer limitedMemberCount) { + final GoalRoom goalRoom = new GoalRoom(goalRoomId, new GoalRoomName("๊ณจ๋ฃธ ์ด๋ฆ„"), + new LimitedMemberCount(limitedMemberCount), roadmapContent, creator); + goalRoom.addAllGoalRoomRoadmapNodes(๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(roadmapContent.getNodes())); + return goalRoom; + } + + private GoalRoomRoadmapNodes ๊ณจ๋ฃธ_๋กœ๋“œ๋งต_๋…ธ๋“œ๋“ค์„_์ƒ์„ฑํ•œ๋‹ค(final RoadmapNodes roadmapNodes) { + return new GoalRoomRoadmapNodes(List.of( + new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), 5, roadmapNodes.getValues().get(0)), + new GoalRoomRoadmapNode(new Period(TEN_DAY_LATER.plusDays(1), TWENTY_DAY_LATER), 5, + roadmapNodes.getValues().get(1))) + ); + } + + private GoalRoomPendingMember ๊ณจ๋ฃธ_๋Œ€๊ธฐ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final GoalRoom goalRoom, final Member follower, + final GoalRoomRole role) { + return new GoalRoomPendingMember(role, LocalDateTime.of(2023, 7, 19, 12, 0, 0), goalRoom, follower); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/JwtTokenProviderTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/JwtTokenProviderTest.java new file mode 100644 index 000000000..3bc56307a --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/JwtTokenProviderTest.java @@ -0,0 +1,125 @@ +package co.kirikiri.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import co.kirikiri.exception.AuthenticationException; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class JwtTokenProviderTest { + + private static final String secretKey = "9zrOjg1kDd2gUp6KBbElGJj5GHP5BnneDs3nXEhdztHAUjKBX7l69JXUErBovPLn7TVWV0UCfejYZyxIjIMC5KPfSvBzo9C1gJ2"; + TokenProvider tokenProvider = new JwtTokenProvider(secretKey, 1_800_000L, 86_400_000L); + + @Test + void ์ •์ƒ์ ์œผ๋กœ_subject์™€_claims๋ฅผ_ํฌํ•จํ•œ_ACCESS_TOKEN์„_์ƒ์„ฑํ•œ๋‹ค() { + //given + final String subject = "subject"; + final Map claims = new HashMap<>(Map.of("test1", "test1", "test2", "test2")); + + //when + final String accessToken = tokenProvider.createAccessToken(subject, claims); + + //then + final Claims result = getClaims(accessToken); + + assertThat(result.getSubject()).isEqualTo(subject); // subject ํ™•์ธ + for (final String claimKey : claims.keySet()) { // custom claim ํ™•์ธ + final String claim = result.get(claimKey, String.class); + assertThat(claim).isEqualTo(claims.get(claimKey)); + } + + assertDoesNotThrow(result::getExpiration); + } + + @Test + void ์ •์ƒ์ ์œผ๋กœ_subject์™€_claims๋ฅผ_ํฌํ•จํ•œ_REFRESH_TOKEN์„_์ƒ์„ฑํ•œ๋‹ค() { + //given + final String subject = "subject"; + final Map claims = new HashMap<>(Map.of("test1", "test1", "test2", "test2")); + + //when + final String accessToken = tokenProvider.createRefreshToken(subject, claims); + + //then + final Claims result = getClaims(accessToken); + + assertThat(result.getSubject()).isEqualTo(subject); // subject ํ™•์ธ + for (final String claimKey : claims.keySet()) { // custom claim ํ™•์ธ + final String claim = result.get(claimKey, String.class); + assertThat(claim).isEqualTo(claims.get(claimKey)); + } + + assertDoesNotThrow(result::getExpiration); + } + + @Test + void ์ •์ƒ์ ์ธ_ํ† ํฐ์˜_์œ ํšจ์„ฑ์„_๊ฒ€์‚ฌํ•œ๋‹ค() { + //given + final String subject = "subject"; + final Map claims = new HashMap<>(Map.of("test1", "test1", "test2", "test2")); + final String accessToken = tokenProvider.createAccessToken(subject, claims); + + //when + final boolean result = tokenProvider.isValidToken(accessToken); + + //then + assertThat(result).isTrue(); + } + + @Test + void ๋งŒ๋ฃŒ๋œ_ํ† ํฐ์˜_์œ ํšจ์„ฑ์„_๊ฒ€์‚ฌํ•œ๋‹ค() { + //given + final String subject = "subject"; + final Map claims = new HashMap<>(Map.of("test1", "test1", "test2", "test2")); + final TokenProvider tokenProvider = new JwtTokenProvider(secretKey, 0L, 0L); + final String accessToken = tokenProvider.createAccessToken(subject, claims); + + //when + //then + assertThatThrownBy(() -> tokenProvider.isValidToken(accessToken)) + .isInstanceOf(AuthenticationException.class) + .hasMessage("Expired Token"); + } + + @Test + void ์œ ํšจํ•˜์ง€_์•Š์€_ํ† ํฐ์˜_์œ ํšจ์„ฑ์„_๊ฒ€์‚ฌํ•œ๋‹ค() { + //given + final String accessToken = "Invalid Token"; + + //when + //then + assertThatThrownBy(() -> tokenProvider.isValidToken(accessToken)) + .isInstanceOf(AuthenticationException.class) + .hasMessage("Invalid Token"); + } + + private Claims getClaims(final String accessToken) { + return assertDoesNotThrow(() -> // ์˜ˆ์™ธ๊ฐ€ ํ„ฐ์ง„๋‹ค๋ฉด ์„œ๋ช…์ด ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ๋งŒ๋ฃŒ๊ธฐ๊ฐ„ ์ง€๋‚œ ํ† ํฐ + Jwts.parserBuilder() + .setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes())) + .build() + .parseClaimsJws(accessToken) + .getBody()); + } + + @Test + void ํ† ํฐ์—์„œ_Subject๋ฅผ_๊ฐ€์ ธ์˜จ๋‹ค() { + //given + final String subject = "subject"; + final Map claims = new HashMap<>(Map.of("test1", "test1", "test2", "test2")); + final String accessToken = tokenProvider.createAccessToken(subject, claims); + + //when + final String result = tokenProvider.findSubject(accessToken); + + //then + assertThat(result).isEqualTo(subject); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/MemberServiceTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/MemberServiceTest.java new file mode 100644 index 000000000..04a252fe4 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/MemberServiceTest.java @@ -0,0 +1,219 @@ +package co.kirikiri.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.exception.ConflictException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.service.dto.member.request.GenderType; +import co.kirikiri.service.dto.member.request.MemberJoinRequest; +import co.kirikiri.service.dto.member.response.MemberInformationForPublicResponse; +import co.kirikiri.service.dto.member.response.MemberInformationResponse; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.LocalDate; +import java.util.Optional; +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 org.springframework.core.env.Environment; + +@ExtendWith(MockitoExtension.class) +class MemberServiceTest { + + private static final String IMAGE_DEFAULT_ORIGINAL_FILE_NAME_PROPERTY = "image.default.originalFileName"; + private static final String IMAGE_DEFAULT_SERVER_FILE_PATH_PROPERTY = "image.default.serverFilePath"; + private static final String IMAGE_DEFAULT_IMAGE_CONTENT_TYPE_PROPERTY = "image.default.imageContentType"; + + @Mock + private MemberRepository memberRepository; + + @Mock + private Environment environment; + + @Mock + private NumberGenerator numberGenerator; + + @Mock + private FileService fileService; + + @InjectMocks + private MemberService memberService; + + @Test + void ํšŒ์›๊ฐ€์ž…์„_ํ•œ๋‹ค() { + //given + final MemberJoinRequest request = new MemberJoinRequest("identifier1", "password1!", "nickname", + "010-1234-5678", GenderType.MALE, LocalDate.now()); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.empty()); + given(memberRepository.save(any())) + .willReturn(new Member(1L, null, null, null, null, null)); + given(environment.getProperty(IMAGE_DEFAULT_ORIGINAL_FILE_NAME_PROPERTY)) + .willReturn("default-member-image"); + given(environment.getProperty(IMAGE_DEFAULT_SERVER_FILE_PATH_PROPERTY)) + .willReturn("https://blog.kakaocdn.net/dn/GHYFr/btrsSwcSDQV/UQZxkayGyAXrPACyf0MaV1/img.jpg"); + given(environment.getProperty(IMAGE_DEFAULT_IMAGE_CONTENT_TYPE_PROPERTY)) + .willReturn("JPG"); + given(numberGenerator.generate()) + .willReturn(7); + + //when + //then + assertThat(memberService.join(request)) + .isEqualTo(1L); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์ด๋ฏธ_์กด์žฌํ•˜๋Š”_์•„์ด๋””๊ฐ€_์กด์žฌํ• ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final MemberJoinRequest request = new MemberJoinRequest("identifier1", "password1!", "nickname", + "010-1234-5678", GenderType.MALE, LocalDate.now()); + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + + final Member member = new Member(identifier, new EncryptedPassword(password), nickname, null, + new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber)); + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(member)); + + //when + //then + assertThatThrownBy(() -> memberService.join(request)) + .isInstanceOf(ConflictException.class); + } + + @Test + void ํšŒ์›๊ฐ€์ž…_์‹œ_์ด๋ฏธ_์กด์žฌํ•˜๋Š”_๋‹‰๋„ค์ž„_์กด์žฌํ• ๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() { + //given + final MemberJoinRequest request = new MemberJoinRequest("identifier1", "password1!", "nickname", + "010-1234-5678", GenderType.MALE, LocalDate.now()); + + given(memberRepository.findByNickname(any())) + .willReturn(Optional.of(new Member(null, null, null, null, null, null))); + + //when + //then + assertThatThrownBy(() -> memberService.join(request)) + .isInstanceOf(ConflictException.class); + } + + @Test + void ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberImage memberImage = new MemberImage("originalFileName", "serverFilePath", ImageContentType.PNG); + final Member member = new Member(1L, identifier, new EncryptedPassword(password), nickname, memberImage, + new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber)); + + given(memberRepository.findWithMemberProfileAndImageByIdentifier(any())) + .willReturn(Optional.of(member)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + // when + final MemberInformationResponse response = memberService.findMemberInformation(identifier.getValue()); + + // then + final MemberInformationResponse expected = new MemberInformationResponse(1L, "nickname", + "http://example.com/serverFilePath", + Gender.MALE.name(), + "identifier1", "010-1234-5678", LocalDate.now()); + + assertThat(response).isEqualTo(expected); + } + + @Test + void ๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž_์ž์‹ ์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ• ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Identifier identifier = new Identifier("identifier1"); + + given(memberRepository.findWithMemberProfileAndImageByIdentifier(any())) + .willReturn(Optional.empty()); + + // when + // then + assertThatThrownBy(() -> memberService.findMemberInformation(identifier.getValue())) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberImage memberImage = new MemberImage("originalFileName", "serverFilePath", ImageContentType.PNG); + final Member member = new Member(identifier, new EncryptedPassword(password), nickname, memberImage, + new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber)); + + given(memberRepository.findWithMemberProfileAndImageById(any())) + .willReturn(Optional.of(member)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + // when + final MemberInformationForPublicResponse response = memberService.findMemberInformationForPublic(1L); + + // then + final MemberInformationForPublicResponse expected = new MemberInformationForPublicResponse("nickname", + "http://example.com/serverFilePath", + Gender.MALE.name()); + + assertThat(response).isEqualTo(expected); + } + + @Test + void ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ• ๋•Œ_๋กœ๊ทธ์ธํ•œ_์‚ฌ์šฉ์ž๊ฐ€_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + // when + // then + assertThatThrownBy(() -> memberService.findMemberInformationForPublic(1L)) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ํŠน์ •_์‚ฌ์šฉ์ž์˜_์ •๋ณด๋ฅผ_์กฐํšŒํ• ๋•Œ_์กฐํšŒํ•˜๋ ค๋Š”_์‚ฌ์šฉ์ž๊ฐ€_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() throws MalformedURLException { + // given + final Identifier identifier = new Identifier("identifier1"); + final Password password = new Password("password1!"); + final Nickname nickname = new Nickname("nickname"); + final String phoneNumber = "010-1234-5678"; + final MemberImage memberImage = new MemberImage("originalFileName", "serverFilePath", ImageContentType.PNG); + final Member member = new Member(identifier, new EncryptedPassword(password), nickname, memberImage, + new MemberProfile(Gender.MALE, LocalDate.now(), phoneNumber)); + + given(memberRepository.findWithMemberProfileAndImageById(any())) + .willReturn(Optional.empty()); + + // when + // then + assertThatThrownBy(() -> memberService.findMemberInformationForPublic(1L)) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค. memberId = 1"); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapCreateEventListenerTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapCreateEventListenerTest.java new file mode 100644 index 000000000..c14d0781e --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapCreateEventListenerTest.java @@ -0,0 +1,172 @@ +package co.kirikiri.service; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ServerException; +import co.kirikiri.persistence.roadmap.RoadmapContentRepository; +import co.kirikiri.service.dto.FileInformation; +import co.kirikiri.service.dto.roadmap.RoadmapNodeSaveDto; +import co.kirikiri.service.dto.roadmap.RoadmapSaveDto; +import co.kirikiri.service.dto.roadmap.RoadmapTagSaveDto; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.event.RoadmapCreateEvent; +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 org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; +import java.io.IOException; +import java.time.LocalDate; +import java.util.List; + +@ExtendWith(MockitoExtension.class) +class RoadmapCreateEventListenerTest { + + private static final Member member = new Member(1L, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), new Nickname("๋‹‰๋„ค์ž„"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "010-1234-5678")); + + @Mock + private RoadmapContentRepository roadmapContentRepository; + + @Mock + private FilePathGenerator pathGenerator; + + @Mock + private FileService fileService; + + @InjectMocks + private RoadmapCreateEventListener roadmapCreateEventListener; + + @Test + void ์ •์ƒ์ ์œผ๋กœ_๋กœ๋“œ๋งต_๋…ธ๋“œ_์ด๋ฏธ์ง€๋ฅผ_์ €์žฅํ•œ๋‹ค() throws IOException { + final RoadmapContent roadmapContent = new RoadmapContent("roadmapContent"); + final RoadmapNode roadmapNode = new RoadmapNode("roadmapNodeTitle", "roadmapNodeContent"); + roadmapContent.addNodes(new RoadmapNodes(List.of(roadmapNode))); + + final Roadmap roadmap = new Roadmap("roadmapTitle", "inroduction", 10, + RoadmapDifficulty.DIFFICULT, member, new RoadmapCategory("category")); + + final MultipartFile imageFile = new MockMultipartFile(roadmapNode.getTitle(), + "originalFileName.jpeg", "image/jpeg", "tempImage".getBytes()); + final FileInformation fileInformation = new FileInformation(imageFile.getOriginalFilename(), + imageFile.getSize(), imageFile.getContentType(), imageFile.getInputStream()); + final RoadmapNodeSaveDto roadmapNodeSaveDto = new RoadmapNodeSaveDto(roadmapNode.getTitle(), + roadmapNode.getContent(), List.of(fileInformation)); + final RoadmapSaveDto roadmapSaveDto = new RoadmapSaveDto(1L, roadmap.getTitle(), roadmap.getIntroduction(), + roadmapContent.getContent(), RoadmapDifficultyType.DIFFICULT, 10, List.of(roadmapNodeSaveDto), + List.of(new RoadmapTagSaveDto("tag"))); + + roadmap.addContent(roadmapContent); + + final RoadmapCreateEvent roadmapCreateEvent = new RoadmapCreateEvent(roadmap, roadmapSaveDto); + + // When + roadmapCreateEventListener.handleRoadmapCreate(roadmapCreateEvent); + + // Then + verify(roadmapContentRepository, times(1)).save(roadmapContent); + } + + @Test + void ๋กœ๋“œ๋งต์—_์ปจํ…์ธ ๊ฐ€_์กด์žฌํ•˜์ง€_์•Š์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws IOException { + //given + final Roadmap roadmap = new Roadmap("roadmapTitle", "inroduction", 10, + RoadmapDifficulty.DIFFICULT, member, new RoadmapCategory("category")); + + final MultipartFile imageFile = new MockMultipartFile("roadmapNodeTitle", + "originalFileName.jpeg", "image/jpeg", "tempImage".getBytes()); + final FileInformation fileInformation = new FileInformation(imageFile.getOriginalFilename(), + imageFile.getSize(), imageFile.getContentType(), imageFile.getInputStream()); + final RoadmapNodeSaveDto roadmapNodeSaveDto = new RoadmapNodeSaveDto("roadmapNodeTitle", "roadmapNodeContent", + List.of(fileInformation)); + final RoadmapSaveDto roadmapSaveDto = new RoadmapSaveDto(1L, roadmap.getTitle(), roadmap.getIntroduction(), + "roadmapNodeContent", RoadmapDifficultyType.DIFFICULT, 10, List.of(roadmapNodeSaveDto), + List.of(new RoadmapTagSaveDto("tag"))); + + final RoadmapCreateEvent roadmapCreateEvent = new RoadmapCreateEvent(roadmap, roadmapSaveDto); + + //when + //then + assertThatThrownBy(() -> roadmapCreateEventListener.handleRoadmapCreate(roadmapCreateEvent)) + .isInstanceOf(ServerException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ œ๋ชฉ์„_๊ฐ€์ง„_๋…ธ๋“œ๊ฐ€_๋กœ๋“œ๋งต์—_์กด์žฌํ•˜์ง€_์•Š์„๋•Œ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws IOException { + //given + final RoadmapContent roadmapContent = new RoadmapContent("roadmapContent"); + final RoadmapNode roadmapNode = new RoadmapNode("roadmapNodeTitle", "roadmapNodeContent"); + roadmapContent.addNodes(new RoadmapNodes(List.of(roadmapNode))); + + final Roadmap roadmap = new Roadmap("roadmapTitle", "inroduction", 10, + RoadmapDifficulty.DIFFICULT, member, new RoadmapCategory("category")); + + final MultipartFile imageFile = new MockMultipartFile(roadmapNode.getTitle(), + "originalFileName.jpeg", "image/jpeg", "tempImage".getBytes()); + final FileInformation fileInformation = new FileInformation(imageFile.getOriginalFilename(), + imageFile.getSize(), imageFile.getContentType(), imageFile.getInputStream()); + final RoadmapNodeSaveDto roadmapNodeSaveDto = new RoadmapNodeSaveDto("Wrong Title", roadmapNode.getContent(), + List.of(fileInformation)); + final RoadmapSaveDto roadmapSaveDto = new RoadmapSaveDto(1L, roadmap.getTitle(), roadmap.getIntroduction(), + roadmapContent.getContent(), RoadmapDifficultyType.DIFFICULT, 10, List.of(roadmapNodeSaveDto), + List.of(new RoadmapTagSaveDto("tag"))); + + roadmap.addContent(roadmapContent); + + final RoadmapCreateEvent roadmapCreateEvent = new RoadmapCreateEvent(roadmap, roadmapSaveDto); + + //when + //then + assertThatThrownBy(() -> roadmapCreateEventListener.handleRoadmapCreate(roadmapCreateEvent)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋…ธ๋“œ_์ด๋ฏธ์ง€์—_์›๋ณธ_ํŒŒ์ผ_์ด๋ฆ„์ด_์—†์„_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋˜์ง„๋‹ค() throws IOException { + //given + final RoadmapContent roadmapContent = new RoadmapContent("roadmapContent"); + final RoadmapNode roadmapNode = new RoadmapNode("roadmapNodeTitle", "roadmapNodeContent"); + roadmapContent.addNodes(new RoadmapNodes(List.of(roadmapNode))); + + final Roadmap roadmap = new Roadmap("roadmapTitle", "inroduction", 10, + RoadmapDifficulty.DIFFICULT, member, new RoadmapCategory("category")); + + final MultipartFile imageFile = new MockMultipartFile(roadmapNode.getTitle(), null, + "image/jpeg", "tempImage".getBytes()); + final FileInformation fileInformation = new FileInformation(imageFile.getOriginalFilename(), + imageFile.getSize(), imageFile.getContentType(), imageFile.getInputStream()); + final RoadmapNodeSaveDto roadmapNodeSaveDto = new RoadmapNodeSaveDto("Wrong Title", roadmapNode.getContent(), + List.of(fileInformation)); + final RoadmapSaveDto roadmapSaveDto = new RoadmapSaveDto(1L, roadmap.getTitle(), roadmap.getIntroduction(), + roadmapContent.getContent(), RoadmapDifficultyType.DIFFICULT, 10, List.of(roadmapNodeSaveDto), + List.of(new RoadmapTagSaveDto("tag"))); + + roadmap.addContent(roadmapContent); + + final RoadmapCreateEvent roadmapCreateEvent = new RoadmapCreateEvent(roadmap, roadmapSaveDto); + + //when + //then + assertThatThrownBy(() -> roadmapCreateEventListener.handleRoadmapCreate(roadmapCreateEvent)) + .isInstanceOf(BadRequestException.class); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapCreateServiceTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapCreateServiceTest.java new file mode 100644 index 000000000..9908c1e0c --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapCreateServiceTest.java @@ -0,0 +1,339 @@ +package co.kirikiri.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomMember; +import co.kirikiri.domain.goalroom.GoalRoomRole; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapContents; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapReview; +import co.kirikiri.exception.AuthenticationException; +import co.kirikiri.exception.BadRequestException; +import co.kirikiri.exception.ForbiddenException; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.goalroom.GoalRoomMemberRepository; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import co.kirikiri.persistence.roadmap.RoadmapReviewRepository; +import co.kirikiri.service.dto.roadmap.request.RoadmapDifficultyType; +import co.kirikiri.service.dto.roadmap.request.RoadmapNodeSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapReviewSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSaveRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapTagSaveRequest; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +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 org.springframework.context.ApplicationEventPublisher; + +@ExtendWith(MockitoExtension.class) +class RoadmapCreateServiceTest { + + private static final Member MEMBER = new Member(1L, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), new Nickname("๋‹‰๋„ค์ž„"), + null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "010-1234-5678")); + + @Mock + private MemberRepository memberRepository; + + @Mock + private RoadmapRepository roadmapRepository; + + @Mock + private RoadmapReviewRepository roadmapReviewRepository; + + @Mock + private GoalRoomRepository goalRoomRepository; + + @Mock + private GoalRoomMemberRepository goalRoomMemberRepository; + + @Mock + private RoadmapCategoryRepository roadmapCategoryRepository; + + @Mock + private ApplicationEventPublisher applicationEventPublisher; + + @InjectMocks + private RoadmapCreateService roadmapService; + + @Test + void ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค() { + // given + final String roadmapTitle = "๋กœ๋“œ๋งต ์ œ๋ชฉ"; + final String roadmapIntroduction = "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€"; + final String roadmapContent = "๋กœ๋“œ๋งต ๋ณธ๋ฌธ"; + final RoadmapDifficultyType difficulty = RoadmapDifficultyType.DIFFICULT; + final int requiredPeriod = 30; + final RoadmapCategory category = new RoadmapCategory(1L, "์—ฌ๊ฐ€"); + + final List roadmapNodes = List.of( + new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์ œ๋ชฉ", "๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์„ค๋ช…", Collections.emptyList())); + final List roadmapTags = List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ 1")); + final RoadmapSaveRequest request = new RoadmapSaveRequest(1L, roadmapTitle, roadmapIntroduction, roadmapContent, + difficulty, requiredPeriod, roadmapNodes, roadmapTags); + + given(roadmapCategoryRepository.findById(any())) + .willReturn(Optional.of(category)); + given(roadmapRepository.save(any())) + .willReturn(new Roadmap(1L, roadmapTitle, roadmapIntroduction, requiredPeriod, + RoadmapDifficulty.valueOf(difficulty.name()), MEMBER, category)); + when(memberRepository.findByIdentifier(MEMBER.getIdentifier())) + .thenReturn(Optional.of(MEMBER)); + + // expect + assertDoesNotThrow(() -> roadmapService.create(request, "identifier1")); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์ž…๋ ฅํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final RoadmapSaveRequest request = new RoadmapSaveRequest(10L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต ๋…ธ๋“œ1", "๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์„ค๋ช…", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ 1"))); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.empty()); + + // expect + assertThatThrownBy(() -> roadmapService.create(request, "identifier1")) + .isInstanceOf(AuthenticationException.class); + } + + @Test + void ๋กœ๋“œ๋งต_์ƒ์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ž…๋ ฅํ•˜๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final RoadmapSaveRequest request = new RoadmapSaveRequest(10L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", + RoadmapDifficultyType.DIFFICULT, 30, + List.of(new RoadmapNodeSaveRequest("๋กœ๋“œ๋งต ๋…ธ๋“œ1", "๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์„ค๋ช…", Collections.emptyList())), + List.of(new RoadmapTagSaveRequest("ํƒœ๊ทธ 1"))); + + given(memberRepository.findByIdentifier(any())) + .willReturn(Optional.of(MEMBER)); + given(roadmapCategoryRepository.findById(any())) + .willReturn(Optional.empty()); + + // expect + assertThatThrownBy(() -> roadmapService.create(request, "identifier1")) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๋กœ๋“œ๋งต์—_๋Œ€ํ•œ_๋ฆฌ๋ทฐ๋ฅผ_์ถ”๊ฐ€ํ•œ๋‹ค() { + // given + final Member follower = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password1!")), new Nickname("๋‹‰๋„ค์ž„2"), + null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "010-1234-5678")); + + final RoadmapCategory category = new RoadmapCategory(1L, "์šด๋™"); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, category); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, targetRoadmapContent); + + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.of(roadmap)); + when(goalRoomMemberRepository.findByRoadmapIdAndMemberIdentifierAndGoalRoomStatus(anyLong(), any(), any())) + .thenReturn(Optional.of( + new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, follower))); + when(roadmapReviewRepository.findByRoadmapAndMember(any(), any())) + .thenReturn(Optional.empty()); + + final RoadmapReviewSaveRequest roadmapReviewSaveRequest = new RoadmapReviewSaveRequest("์ตœ๊ณ ์˜ ๋กœ๋“œ๋งต์ด๋„ค์š”", 5.0); + + // expected + assertDoesNotThrow(() -> roadmapService.createReview(1L, "identifier2", roadmapReviewSaveRequest)); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ž‘์„ฑ์‹œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต_์•„์ด๋””๋ฅผ_๋ฐ›์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.empty()); + + final RoadmapReviewSaveRequest roadmapReviewSaveRequest = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", null); + + // expected + assertThatThrownBy(() -> + roadmapService.createReview(1L, "cokirikiri", roadmapReviewSaveRequest)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ž‘์„ฑ์‹œ_์™„๋ฃŒํ•œ_๊ณจ๋ฃธ์ด_์—†์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์šด๋™"); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, category); + + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.of(roadmap)); + when(goalRoomMemberRepository.findByRoadmapIdAndMemberIdentifierAndGoalRoomStatus(anyLong(), any(), any())) + .thenReturn(Optional.empty()); + + final RoadmapReviewSaveRequest roadmapReviewSaveRequest = new RoadmapReviewSaveRequest("๋ฆฌ๋ทฐ ๋‚ด์šฉ", null); + + // expected + assertThatThrownBy(() -> + roadmapService.createReview(1L, "cokirikiri", roadmapReviewSaveRequest)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์ž‘์„ฑ์‹œ_์ด๋ฏธ_์ž‘์„ฑ์„_์™„๋ฃŒํ–ˆ์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final Member follower = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password1!")), new Nickname("๋‹‰๋„ค์ž„2"), + null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "010-1234-5678")); + + final RoadmapCategory category = new RoadmapCategory(1L, "์šด๋™"); + + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, category); + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, targetRoadmapContent); + + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.of(roadmap)); + when(goalRoomMemberRepository.findByRoadmapIdAndMemberIdentifierAndGoalRoomStatus(anyLong(), any(), any())) + .thenReturn(Optional.of( + new GoalRoomMember(GoalRoomRole.FOLLOWER, LocalDateTime.now(), goalRoom, follower))); + when(roadmapReviewRepository.findByRoadmapAndMember(any(), any())) + .thenReturn(Optional.of(new RoadmapReview("๋กœ๋“œ๋งต ์งฑ!", 5.0, MEMBER))); + + final RoadmapReviewSaveRequest roadmapReviewSaveRequest = new RoadmapReviewSaveRequest("์ตœ๊ณ ์˜ ๋กœ๋“œ๋งต์ด๋„ค์š”", 5.0); + + // expected + assertThatThrownBy(() -> roadmapService.createReview(1L, "cokirikiri", roadmapReviewSaveRequest)) + .isInstanceOf(BadRequestException.class); + } + + @Test + void ๊ณจ๋ฃธ์ด_์ƒ์„ฑ๋œ_์ ์ด_์—†๋Š”_๋กœ๋“œ๋งต์„_์‚ญ์ œํ•œ๋‹ค() { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์šด๋™"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, category); + + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.of(roadmap)); + when(roadmapRepository.findByIdAndMemberIdentifier(anyLong(), anyString())) + .thenReturn(Optional.of(roadmap)); + when(goalRoomRepository.findByRoadmap(any())) + .thenReturn(Collections.emptyList()); + + // when + // then + assertDoesNotThrow(() -> roadmapService.deleteRoadmap("identifier1", 1L)); + verify(roadmapRepository, times(1)).delete(any()); + } + + @Test + void ๊ณจ๋ฃธ์ด_์ƒ์„ฑ๋œ_์ ์ด_์žˆ๋Š”_๋กœ๋“œ๋งต์„_์‚ญ์ œํ•œ๋‹ค() { + // given + final Member follower = new Member(2L, new Identifier("identifier2"), + new EncryptedPassword(new Password("password1!")), new Nickname("๋‹‰๋„ค์ž„2"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "010-1234-5678")); + + final RoadmapCategory category = new RoadmapCategory(1L, "์šด๋™"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + final GoalRoom goalRoom = ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(follower, targetRoadmapContent); + + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.of(roadmap)); + when(roadmapRepository.findByIdAndMemberIdentifier(anyLong(), anyString())) + .thenReturn(Optional.of(roadmap)); + when(goalRoomRepository.findByRoadmap(any())) + .thenReturn(List.of(goalRoom)); + + // when + // then + assertDoesNotThrow(() -> roadmapService.deleteRoadmap("identifier1", 1L)); + assertThat(roadmap.isDeleted()).isTrue(); + verify(roadmapRepository, never()).delete(any()); + } + + @Test + void ๋กœ๋“œ๋งต์„_์‚ญ์ œํ• _๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต์ธ_๊ฒฝ์šฐ_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.empty()); + + // when + // then + assertThatThrownBy(() -> roadmapService.deleteRoadmap("identifier1", 1L)) + .isInstanceOf(NotFoundException.class) + .hasMessage("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + } + + @Test + void ๋กœ๋“œ๋งต์„_์‚ญ์ œํ• _๋•Œ_์ž์‹ ์ด_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์ด_์•„๋‹ˆ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์šด๋™"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, category); + + final RoadmapContents roadmapContents = roadmap.getContents(); + final RoadmapContent targetRoadmapContent = roadmapContents.getValues().get(0); + ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(MEMBER, targetRoadmapContent); + + when(roadmapRepository.findById(anyLong())) + .thenReturn(Optional.of(roadmap)); + when(roadmapRepository.findByIdAndMemberIdentifier(anyLong(), anyString())) + .thenReturn(Optional.empty()); + + // when + // then + assertThatThrownBy(() -> roadmapService.deleteRoadmap("identifier2", 1L)) + .isInstanceOf(ForbiddenException.class) + .hasMessage("ํ•ด๋‹น ๋กœ๋“œ๋งต์„ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค."); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final Member creator, final RoadmapCategory category) { + final RoadmapContent content = new RoadmapContent("์ฝ˜ํ…์ธ  ์ œ๋ชฉ"); + final Roadmap roadmap = new Roadmap("๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์„ค๋ช…", 100, RoadmapDifficulty.NORMAL, creator, category); + roadmap.addContent(content); + return roadmap; + } + + private GoalRoom ๊ณจ๋ฃธ์„_์ƒ์„ฑํ•œ๋‹ค(final Member member, final RoadmapContent roadmapContent) { + return new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ"), new LimitedMemberCount(10), roadmapContent, member); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapReadServiceTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapReadServiceTest.java new file mode 100644 index 000000000..655d3cab7 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapReadServiceTest.java @@ -0,0 +1,674 @@ +package co.kirikiri.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.when; + +import co.kirikiri.domain.ImageContentType; +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberImage; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.domain.roadmap.RoadmapReview; +import co.kirikiri.domain.roadmap.RoadmapTag; +import co.kirikiri.domain.roadmap.RoadmapTags; +import co.kirikiri.domain.roadmap.vo.RoadmapTagName; +import co.kirikiri.exception.NotFoundException; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsOrderType; +import co.kirikiri.persistence.member.MemberRepository; +import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository; +import co.kirikiri.persistence.roadmap.RoadmapContentRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import co.kirikiri.persistence.roadmap.RoadmapReviewRepository; +import co.kirikiri.service.dto.CustomScrollRequest; +import co.kirikiri.service.dto.member.response.MemberResponse; +import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomsOrderTypeDto; +import co.kirikiri.service.dto.roadmap.request.RoadmapOrderTypeRequest; +import co.kirikiri.service.dto.roadmap.request.RoadmapSearchRequest; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.MemberRoadmapResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapCategoryResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapContentResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponses; +import co.kirikiri.service.dto.roadmap.response.RoadmapNodeResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse; +import co.kirikiri.service.dto.roadmap.response.RoadmapTagResponse; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +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; + +@ExtendWith(MockitoExtension.class) +class RoadmapReadServiceTest { + + private static final LocalDate TODAY = LocalDate.now(); + + private final Member member = new Member(1L, new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), new Nickname("๋‹‰๋„ค์ž„"), + new MemberImage("originalFileName", "default-member-image", ImageContentType.JPG), + new MemberProfile(Gender.FEMALE, LocalDate.of(1999, 6, 8), "010-1234-5678")); + private final LocalDateTime now = LocalDateTime.now(); + + @Mock + private RoadmapRepository roadmapRepository; + + @Mock + private RoadmapCategoryRepository roadmapCategoryRepository; + + @Mock + private RoadmapContentRepository roadmapContentRepository; + + @Mock + private GoalRoomRepository goalRoomRepository; + + @Mock + private MemberRepository memberRepository; + + @Mock + private RoadmapReviewRepository roadmapReviewRepository; + + @Mock + private FileService fileService; + + @InjectMocks + private RoadmapReadService roadmapService; + + @Test + void ํŠน์ •_์•„์ด๋””๋ฅผ_๊ฐ€์ง€๋Š”_๋กœ๋“œ๋งต_๋‹จ์ผ_์กฐํšŒ์‹œ_ํ•ด๋‹น_๋กœ๋“œ๋งต์˜_์ •๋ณด๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws MalformedURLException { + //given + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "์šด๋™"); + final RoadmapContent content = ๋กœ๋“œ๋งต_์ปจํ…์ธ ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "์ฝ˜ํ…์ธ  ๋‚ด์šฉ"); + final Roadmap roadmap = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต ์ œ๋ชฉ", category); + roadmap.addContent(content); + final Long roadmapId = 1L; + + final List goalRooms = ์ƒํƒœ๋ณ„_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์ƒ์„ฑํ•œ๋‹ค(); + + when(roadmapRepository.findRoadmapById(anyLong())) + .thenReturn(Optional.of(roadmap)); + when(roadmapContentRepository.findFirstByRoadmapOrderByCreatedAtDesc(any())) + .thenReturn(Optional.of(roadmap.getContents().getValues().get(0))); + when(goalRoomRepository.findByRoadmap(any())) + .thenReturn(goalRooms); + when(fileService.generateUrl(anyString(), any())) + .thenReturn(new URL("http://example.com/serverFilePath")); + + //when + final RoadmapResponse roadmapResponse = roadmapService.findRoadmap(roadmapId); + + //then + final RoadmapResponse expectedResponse = new RoadmapResponse( + roadmapId, new RoadmapCategoryResponse(1L, "์šด๋™"), "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapContentResponse(1L, "๋กœ๋“œ๋งต ๋ณธ๋ฌธ", List.of( + new RoadmapNodeResponse(1L, "๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์ œ๋ชฉ", "๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์„ค๋ช…", Collections.emptyList()) + )), "DIFFICULT", 30, now, + List.of(new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2")), + 2L, 2L, 2L + ); + + assertThat(roadmapResponse) + .usingRecursiveComparison() + .ignoringFields("createdAt") + .isEqualTo(expectedResponse); + } + + @Test + void ๋กœ๋“œ๋งต_๋‹จ์ผ_์กฐํšŒ_์‹œ_๋กœ๋“œ๋งต_์•„์ด๋””๊ฐ€_์กด์žฌํ•˜์ง€_์•Š๋Š”_์•„์ด๋””์ผ_๊ฒฝ์šฐ_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + //when + when(roadmapRepository.findRoadmapById(anyLong())) + .thenReturn(Optional.empty()); + + //then + assertThatThrownBy(() -> roadmapService.findRoadmap(1L)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ์‹œ_์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””๊ฐ€_์œ ํšจํ•˜์ง€_์•Š์œผ๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(roadmapCategoryRepository.findById(any())) + .thenReturn(Optional.empty()); + + final Long categoryId = 1L; + final RoadmapOrderTypeRequest filterType = RoadmapOrderTypeRequest.LATEST; + final CustomScrollRequest scrollRequest = new CustomScrollRequest(null, 10); + + // expected + assertThatThrownBy(() -> roadmapService.findRoadmapsByOrderType(categoryId, filterType, scrollRequest)) + .isInstanceOf(NotFoundException.class); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ_์‹œ_ํ•„ํ„ฐ_์กฐ๊ฑด์ด_null์ด๋ฉด_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์—ฌํ–‰"); + final List roadmaps = List.of( + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category), + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category)); + + when(roadmapCategoryRepository.findById(any())) + .thenReturn(Optional.of(category)); + when(roadmapRepository.findRoadmapsByCategory(any(), any(), any(), anyInt())) + .thenReturn(roadmaps); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final Long categoryId = 1L; + final RoadmapOrderTypeRequest filterType = null; + final CustomScrollRequest scrollRequest = new CustomScrollRequest(null, 10); + + // when + final RoadmapForListResponses roadmapResponses = roadmapService.findRoadmapsByOrderType( + categoryId, filterType, scrollRequest); + + // then + final RoadmapForListResponse firstRoadmapResponse = new RoadmapForListResponse(1L, "์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final RoadmapForListResponse secondRoadmapResponse = new RoadmapForListResponse(1L, "๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final List responses = List.of(firstRoadmapResponse, secondRoadmapResponse); + final RoadmapForListResponses expected = new RoadmapForListResponses(responses, false); + + assertThat(roadmapResponses) + .usingRecursiveComparison() + .ignoringFields("responses.createdAt") + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ์‹œ_๋‹ค์Œ_์š”์†Œ๊ฐ€_์กด์žฌํ•˜๋ฉด_true๋กœ_๋ฐ˜ํ™˜ํ•œ๋‹ค() throws MalformedURLException { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์—ฌํ–‰"); + final List roadmaps = List.of( + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category), + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category)); + + when(roadmapCategoryRepository.findById(any())) + .thenReturn(Optional.of(category)); + when(roadmapRepository.findRoadmapsByCategory(any(), any(), any(), anyInt())) + .thenReturn(roadmaps); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final Long categoryId = 1L; + final RoadmapOrderTypeRequest filterType = null; + final CustomScrollRequest scrollRequest = new CustomScrollRequest(null, 1); + + // when + final RoadmapForListResponses roadmapResponses = roadmapService.findRoadmapsByOrderType( + categoryId, filterType, scrollRequest); + + // then + final RoadmapForListResponse firstRoadmapResponse = new RoadmapForListResponse( + 1L, "์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final List responses = List.of(firstRoadmapResponse); + final RoadmapForListResponses expected = new RoadmapForListResponses(responses, true); + + assertThat(roadmapResponses) + .usingRecursiveComparison() + .ignoringFields("responses.createdAt") + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_๋ชฉ๋ก_์กฐํšŒ_์‹œ_์นดํ…Œ๊ณ ๋ฆฌ_์กฐ๊ฑด์ด_null์ด๋ฉด_์ „์ฒด_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_๋Œ€์ƒ์œผ๋กœ_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์—ฌํ–‰"); + final List roadmaps = List.of(๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category), ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category)); + + when(roadmapRepository.findRoadmapsByCategory(any(), any(), any(), anyInt())) + .thenReturn(roadmaps); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final Long categoryId = null; + final RoadmapOrderTypeRequest filterType = RoadmapOrderTypeRequest.LATEST; + final CustomScrollRequest scrollRequest = new CustomScrollRequest(null, 10); + + // when + final RoadmapForListResponses roadmapResponses = roadmapService.findRoadmapsByOrderType( + categoryId, filterType, scrollRequest); + + // then + final RoadmapForListResponse firstRoadmapResponse = new RoadmapForListResponse(1L, "์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final RoadmapForListResponse secondRoadmapResponse = new RoadmapForListResponse(1L, "๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final RoadmapForListResponses expected = new RoadmapForListResponses( + List.of(firstRoadmapResponse, secondRoadmapResponse), false); + + assertThat(roadmapResponses) + .usingRecursiveComparison() + .ignoringFields("responses.createdAt") + .isEqualTo(expected); + } + + @Test + void ์นดํ…Œ๊ณ ๋ฆฌ_์•„์ด๋””์™€_ํ•„ํ„ฐ๋ง_์กฐ๊ฑด์„_ํ†ตํ•ด_๋กœ๋“œ๋งต_๋ชฉ๋ก์„_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์—ฌํ–‰"); + final List roadmaps = List.of(๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category)); + + when(roadmapCategoryRepository.findById(any())) + .thenReturn(Optional.of(new RoadmapCategory("์—ฌํ–‰"))); + when(roadmapRepository.findRoadmapsByCategory(any(), any(), any(), anyInt())) + .thenReturn(roadmaps); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final Long categoryId = 1L; + final RoadmapOrderTypeRequest filterType = RoadmapOrderTypeRequest.LATEST; + final CustomScrollRequest scrollRequest = new CustomScrollRequest(null, 10); + + // when + final RoadmapForListResponses roadmapResponses = roadmapService.findRoadmapsByOrderType( + categoryId, filterType, scrollRequest); + + // then + final RoadmapForListResponse roadmapResponse = new RoadmapForListResponse(1L, "์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final RoadmapForListResponses expected = new RoadmapForListResponses(List.of(roadmapResponse), false); + + assertThat(roadmapResponses) + .usingRecursiveComparison() + .ignoringFields("responses.createdAt") + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต_์ „์ฒด_์นดํ…Œ๊ณ ๋ฆฌ_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + final List roadmapCategories = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(); + when(roadmapCategoryRepository.findAll()) + .thenReturn(roadmapCategories); + + // when + final List categoryResponses = roadmapService.findAllRoadmapCategories(); + + // then + final List expected = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค(); + assertThat(categoryResponses) + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต์„_๊ฒ€์ƒ‰ํ•œ๋‹ค() throws MalformedURLException { + // given + final RoadmapCategory category = new RoadmapCategory(1L, "์—ฌํ–‰"); + final List roadmaps = List.of( + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category), + ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", category)); + + when(roadmapRepository.findRoadmapsByCond(any(), any(), any(), anyInt())) + .thenReturn(roadmaps); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + final RoadmapSearchRequest roadmapSearchRequest = new RoadmapSearchRequest("๋กœ๋“œ๋งต", "๋‹‰๋„ค์ž„", "ํƒœ๊ทธ"); + final RoadmapOrderTypeRequest filterType = RoadmapOrderTypeRequest.LATEST; + final CustomScrollRequest scrollRequest = new CustomScrollRequest(null, 10); + + // when + final RoadmapForListResponses roadmapResponses = roadmapService.search( + filterType, roadmapSearchRequest, scrollRequest); + + // then + final RoadmapForListResponse firstRoadmapResponse = new RoadmapForListResponse(1L, "์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final RoadmapForListResponse secondRoadmapResponse = new RoadmapForListResponse(1L, "๋‘ ๋ฒˆ์งธ ๋กœ๋“œ๋งต", "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", + "DIFFICULT", 30, LocalDateTime.now(), + new MemberResponse(1L, "๋‹‰๋„ค์ž„", "http://example.com/serverFilePath"), + new RoadmapCategoryResponse(1, "์—ฌํ–‰"), + List.of( + new RoadmapTagResponse(1L, "ํƒœ๊ทธ1"), + new RoadmapTagResponse(2L, "ํƒœ๊ทธ2"))); + + final RoadmapForListResponses expected = new RoadmapForListResponses( + List.of(firstRoadmapResponse, secondRoadmapResponse), false); + + assertThat(roadmapResponses) + .usingRecursiveComparison() + .ignoringFields("responses.createdAt") + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ•œ๋‹ค() { + // given + final Member member = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "์ฝ”๋ผ๋ฆฌ"); + final RoadmapCategory category1 = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "์šด๋™"); + final RoadmapCategory category2 = ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "์—ฌ๊ฐ€"); + final Roadmap roadmap1 = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต1", category1); + final Roadmap roadmap2 = ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค("๋กœ๋“œ๋งต2", category2); + + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.of(member)); + when(roadmapRepository.findRoadmapsWithCategoryByMemberOrderByLatest(any(), any(), anyInt())) + .thenReturn(List.of(roadmap2, roadmap1)); + + // when + final MemberRoadmapResponses memberRoadmapResponse = roadmapService.findAllMemberRoadmaps( + "identifier1", new CustomScrollRequest(null, 10)); + + // then + final MemberRoadmapResponses expected = new MemberRoadmapResponses(List.of( + new MemberRoadmapResponse(2L, "๋กœ๋“œ๋งต2", RoadmapDifficulty.DIFFICULT.name(), LocalDateTime.now(), + new RoadmapCategoryResponse(2L, "์—ฌ๊ฐ€")), + new MemberRoadmapResponse(1L, "๋กœ๋“œ๋งต1", RoadmapDifficulty.DIFFICULT.name(), LocalDateTime.now(), + new RoadmapCategoryResponse(1L, "์šด๋™"))), false); + + assertThat(memberRoadmapResponse) + .usingRecursiveComparison() + .ignoringFields("responses.roadmapId", "responses.createdAt") + .isEqualTo(expected); + } + + @Test + void ์‚ฌ์šฉ์ž๊ฐ€_์ƒ์„ฑํ•œ_๋กœ๋“œ๋งต์„_์กฐํšŒํ• ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_ํšŒ์›์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + when(memberRepository.findByIdentifier(any())) + .thenReturn(Optional.empty()); + + // when + // then + assertThatThrownBy(() -> roadmapService.findAllMemberRoadmaps("identifier1", + new CustomScrollRequest(null, 10))).isInstanceOf(NotFoundException.class) + .hasMessageContaining("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "name1"); + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNodes roadmapNodes = new RoadmapNodes(List.of(roadmapNode1, roadmapNode2)); + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(roadmapNodes); + final Roadmap roadmap = new Roadmap(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์„ค๋ช…", 100, RoadmapDifficulty.DIFFICULT, member1, + new RoadmapCategory("it")); + + final GoalRoomRoadmapNode goalRoomRoadmapNode1 = new GoalRoomRoadmapNode(new Period(TODAY, TODAY.plusDays(10)), + 1, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode2 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(11), TODAY.plusDays(20)), 1, roadmapNode2); + final GoalRoomRoadmapNode goalRoomRoadmapNode3 = new GoalRoomRoadmapNode(new Period(TODAY, TODAY.plusDays(10)), + 1, roadmapNode1); + final GoalRoomRoadmapNode goalRoomRoadmapNode4 = new GoalRoomRoadmapNode( + new Period(TODAY.plusDays(11), TODAY.plusDays(20)), 1, roadmapNode2); + + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier2", "name2"); + final GoalRoom goalRoom1 = new GoalRoom(1L, new GoalRoomName("goalroom1"), new LimitedMemberCount(10), + roadmapContent, member2); + goalRoom1.addAllGoalRoomRoadmapNodes( + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode1, goalRoomRoadmapNode2))); + + final Member member3 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(3L, "identifier2", "name3"); + final GoalRoom goalRoom2 = new GoalRoom(2L, new GoalRoomName("goalroom2"), new LimitedMemberCount(10), + roadmapContent, member3); + goalRoom2.addAllGoalRoomRoadmapNodes( + new GoalRoomRoadmapNodes(List.of(goalRoomRoadmapNode3, goalRoomRoadmapNode4))); + + final List goalRooms = List.of(goalRoom2, goalRoom1); + given(roadmapRepository.findRoadmapById(anyLong())) + .willReturn(Optional.of(roadmap)); + given(goalRoomRepository.findGoalRoomsWithPendingMembersByRoadmapAndCond(roadmap, + RoadmapGoalRoomsOrderType.LATEST, null, 10)) + .willReturn(goalRooms); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + // when + final RoadmapGoalRoomResponses result = roadmapService.findRoadmapGoalRoomsByOrderType(1L, + RoadmapGoalRoomsOrderTypeDto.LATEST, new CustomScrollRequest(null, 10)); + + final RoadmapGoalRoomResponses expected = + new RoadmapGoalRoomResponses(List.of( + new RoadmapGoalRoomResponse(2L, "goalroom2", 1, 10, LocalDateTime.now(), + TODAY, TODAY.plusDays(20), + new MemberResponse(member3.getId(), member3.getNickname().getValue(), + "http://example.com/serverFilePath")), + new RoadmapGoalRoomResponse(1L, "goalroom1", 1, 10, LocalDateTime.now(), + TODAY, TODAY.plusDays(20), + new MemberResponse(member2.getId(), member2.getNickname().getValue(), + "http://example.com/serverFilePath"))), false); + + assertThat(result) + .usingRecursiveComparison() + .ignoringFields("responses.createdAt") + .isEqualTo(expected); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์กฐํšŒํ• ๋•Œ_์กด์žฌํ•˜์ง€_์•Š๋Š”_๋กœ๋“œ๋งต์ด๋ฉด_์˜ˆ์™ธ๊ฐ€_๋ฐœ์ƒํ•œ๋‹ค() { + // given + given(roadmapRepository.findRoadmapById(anyLong())) + .willThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")); + + // when + // then + assertThatThrownBy( + () -> roadmapService.findRoadmapGoalRoomsByOrderType(1L, + RoadmapGoalRoomsOrderTypeDto.LATEST, new CustomScrollRequest(null, 10))) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + } + + @Test + void ๋กœ๋“œ๋งต์˜_๋ฆฌ๋ทฐ_๋ชฉ๋ก์„_์ตœ์‹ ์ˆœ์œผ๋กœ_์กฐํšŒํ•œ๋‹ค() throws MalformedURLException { + // given + final Member member1 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(1L, "identifier1", "๋ฆฌ๋ทฐ์–ด1"); + final Member member2 = ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(2L, "identifier2", "๋ฆฌ๋ทฐ์–ด2"); + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต 1์ฃผ์ฐจ", "๋กœ๋“œ๋งต 1์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNode roadmapNode2 = new RoadmapNode("๋กœ๋“œ๋งต 2์ฃผ์ฐจ", "๋กœ๋“œ๋งต 2์ฃผ์ฐจ ๋‚ด์šฉ"); + final RoadmapNodes roadmapNodes = new RoadmapNodes(List.of(roadmapNode1, roadmapNode2)); + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + roadmapContent.addNodes(roadmapNodes); + final Roadmap roadmap = new Roadmap(1L, "๋กœ๋“œ๋งต ์ œ๋ชฉ", "๋กœ๋“œ๋งต ์„ค๋ช…", 100, RoadmapDifficulty.DIFFICULT, member1, + new RoadmapCategory("it")); + + final RoadmapReview roadmapReview1 = new RoadmapReview("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0, member1); + final RoadmapReview roadmapReview2 = new RoadmapReview("๋ฆฌ๋ทฐ ๋‚ด์šฉ", 4.5, member2); + roadmapReview1.updateRoadmap(roadmap); + roadmapReview2.updateRoadmap(roadmap); + + when(roadmapRepository.findRoadmapById(anyLong())).thenReturn(Optional.of(roadmap)); + when(roadmapReviewRepository.findRoadmapReviewWithMemberByRoadmapOrderByLatest(any(), any(), anyInt())) + .thenReturn(List.of(roadmapReview2, roadmapReview1)); + given(fileService.generateUrl(anyString(), any())) + .willReturn(new URL("http://example.com/serverFilePath")); + + // when + final List response = roadmapService.findRoadmapReviews(1L, + new CustomScrollRequest(null, 10)); + + final List expect = List.of( + new RoadmapReviewResponse(2L, new MemberResponse(2L, "๋ฆฌ๋ทฐ์–ด2", "http://example.com/serverFilePath"), + LocalDateTime.now(), "๋ฆฌ๋ทฐ ๋‚ด์šฉ", 4.5), + new RoadmapReviewResponse(1L, new MemberResponse(1L, "๋ฆฌ๋ทฐ์–ด1", "http://example.com/serverFilePath"), + LocalDateTime.now(), "๋ฆฌ๋ทฐ ๋‚ด์šฉ", 5.0)); + + // then + assertThat(response) + .usingRecursiveComparison() + .ignoringFields("id", "member.imageUrl", "createdAt") + .isEqualTo(expect); + } + + @Test + void ๋กœ๋“œ๋งต_๋ฆฌ๋ทฐ_์กฐํšŒ_์‹œ_์œ ํšจํ•˜์ง€_์•Š์€_๋กœ๋“œ๋งต_์•„์ด๋””๋ผ๋ฉด_์˜ˆ์™ธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + // given + when(roadmapRepository.findRoadmapById(anyLong())) + .thenThrow(new NotFoundException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1")); + + // when, then + assertThatThrownBy(() -> roadmapService.findRoadmapReviews(1L, new CustomScrollRequest(null, 2))) + .isInstanceOf(NotFoundException.class) + .hasMessageContaining("์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋กœ๋“œ๋งต์ž…๋‹ˆ๋‹ค. roadmapId = 1"); + } + + private Member ์‚ฌ์šฉ์ž๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final Long id, final String identifier, final String nickname) { + return new Member(id, new Identifier(identifier), + new EncryptedPassword(new Password("password1!")), + new Nickname(nickname), + new MemberImage("originalFileName", "default-profile-image", ImageContentType.JPG), + new MemberProfile(Gender.FEMALE, LocalDate.of(2000, 7, 20), "010-1111-1111")); + } + + private Roadmap ๋กœ๋“œ๋งต์„_์ƒ์„ฑํ•œ๋‹ค(final String roadmapTitle, final RoadmapCategory category) { + final Roadmap roadmap = new Roadmap(1L, roadmapTitle, "๋กœ๋“œ๋งต ์†Œ๊ฐœ๊ธ€", 30, + RoadmapDifficulty.valueOf("DIFFICULT"), member, category); + + final RoadmapTags roadmapTags = new RoadmapTags( + List.of(new RoadmapTag(1L, new RoadmapTagName("ํƒœ๊ทธ1")), + new RoadmapTag(2L, new RoadmapTagName("ํƒœ๊ทธ2")))); + roadmap.addTags(roadmapTags); + + final RoadmapContent roadmapContent = new RoadmapContent(1L, "๋กœ๋“œ๋งต ๋ณธ๋ฌธ"); + final RoadmapNodes roadmapNodes = new RoadmapNodes( + List.of(new RoadmapNode(1L, "๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์ œ๋ชฉ", "๋กœ๋“œ๋งต ๋…ธ๋“œ1 ์„ค๋ช…"))); + roadmapContent.addNodes(roadmapNodes); + roadmap.addContent(roadmapContent); + + return roadmap; + } + + private RoadmapCategory ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final Long id, final String title) { + return new RoadmapCategory(id, title); + } + + private RoadmapContent ๋กœ๋“œ๋งต_์ปจํ…์ธ ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค(final Long id, final String content) { + return new RoadmapContent(id, content); + } + + private List ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + final RoadmapCategory category1 = new RoadmapCategory(1L, "์–ดํ•™"); + final RoadmapCategory category2 = new RoadmapCategory(2L, "IT"); + final RoadmapCategory category3 = new RoadmapCategory(3L, "์‹œํ—˜"); + final RoadmapCategory category4 = new RoadmapCategory(4L, "์šด๋™"); + final RoadmapCategory category5 = new RoadmapCategory(5L, "๊ฒŒ์ž„"); + final RoadmapCategory category6 = new RoadmapCategory(6L, "์Œ์•…"); + final RoadmapCategory category7 = new RoadmapCategory(7L, "๋ผ์ดํ”„"); + final RoadmapCategory category8 = new RoadmapCategory(8L, "์—ฌ๊ฐ€"); + final RoadmapCategory category9 = new RoadmapCategory(9L, "๊ธฐํƒ€"); + return List.of(category1, category2, category3, category4, category5, + category6, category7, category8, category9); + } + + private List ๋กœ๋“œ๋งต_์นดํ…Œ๊ณ ๋ฆฌ_์‘๋‹ต_๋ฆฌ์ŠคํŠธ๋ฅผ_๋ฐ˜ํ™˜ํ•œ๋‹ค() { + final RoadmapCategoryResponse category1 = new RoadmapCategoryResponse(1L, "์–ดํ•™"); + final RoadmapCategoryResponse category2 = new RoadmapCategoryResponse(2L, "IT"); + final RoadmapCategoryResponse category3 = new RoadmapCategoryResponse(3L, "์‹œํ—˜"); + final RoadmapCategoryResponse category4 = new RoadmapCategoryResponse(4L, "์šด๋™"); + final RoadmapCategoryResponse category5 = new RoadmapCategoryResponse(5L, "๊ฒŒ์ž„"); + final RoadmapCategoryResponse category6 = new RoadmapCategoryResponse(6L, "์Œ์•…"); + final RoadmapCategoryResponse category7 = new RoadmapCategoryResponse(7L, "๋ผ์ดํ”„"); + final RoadmapCategoryResponse category8 = new RoadmapCategoryResponse(8L, "์—ฌ๊ฐ€"); + final RoadmapCategoryResponse category9 = new RoadmapCategoryResponse(9L, "๊ธฐํƒ€"); + return List.of(category1, category2, category3, category4, category5, + category6, category7, category8, category9); + } + + private List ์ƒํƒœ๋ณ„_๊ณจ๋ฃธ_๋ชฉ๋ก์„_์ƒ์„ฑํ•œ๋‹ค() { + final RoadmapContent roadmapContent = new RoadmapContent("๋กœ๋“œ๋งต ๋‚ด์šฉ"); + final GoalRoom recruitedGoalRoom1 = new GoalRoom(new GoalRoomName("๋ชจ์ง‘ ์ค‘ ๊ณจ๋ฃธ 1"), + new LimitedMemberCount(20), roadmapContent, member); + final GoalRoom recruitedGoalRoom2 = new GoalRoom(new GoalRoomName("๋ชจ์ง‘ ์ค‘ ๊ณจ๋ฃธ 2"), + new LimitedMemberCount(20), roadmapContent, member); + final GoalRoom runningGoalRoom1 = new GoalRoom(new GoalRoomName("์ง„ํ–‰ ์ค‘ ๊ณจ๋ฃธ 1"), + new LimitedMemberCount(20), roadmapContent, member); + final GoalRoom runningGoalRoom2 = new GoalRoom(new GoalRoomName("์ง„ํ–‰ ์ค‘ ๊ณจ๋ฃธ 2"), + new LimitedMemberCount(20), roadmapContent, member); + final GoalRoom completedGoalRoom1 = new GoalRoom(new GoalRoomName("์™„๋ฃŒ๋œ ๊ณจ๋ฃธ 1"), + new LimitedMemberCount(20), roadmapContent, member); + final GoalRoom completedGoalRoom2 = new GoalRoom(new GoalRoomName("์™„๋ฃŒ๋œ ๊ณจ๋ฃธ 2"), + new LimitedMemberCount(20), roadmapContent, member); + + runningGoalRoom1.start(); + runningGoalRoom2.start(); + completedGoalRoom1.complete(); + completedGoalRoom2.complete(); + + return List.of(recruitedGoalRoom1, recruitedGoalRoom2, runningGoalRoom1, runningGoalRoom2, + completedGoalRoom1, completedGoalRoom2); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapSchedulerTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapSchedulerTest.java new file mode 100644 index 000000000..6487784dd --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/RoadmapSchedulerTest.java @@ -0,0 +1,172 @@ +package co.kirikiri.service; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import co.kirikiri.domain.goalroom.GoalRoom; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNode; +import co.kirikiri.domain.goalroom.GoalRoomRoadmapNodes; +import co.kirikiri.domain.goalroom.vo.GoalRoomName; +import co.kirikiri.domain.goalroom.vo.LimitedMemberCount; +import co.kirikiri.domain.goalroom.vo.Period; +import co.kirikiri.domain.member.EncryptedPassword; +import co.kirikiri.domain.member.Gender; +import co.kirikiri.domain.member.Member; +import co.kirikiri.domain.member.MemberProfile; +import co.kirikiri.domain.member.vo.Identifier; +import co.kirikiri.domain.member.vo.Nickname; +import co.kirikiri.domain.member.vo.Password; +import co.kirikiri.domain.roadmap.Roadmap; +import co.kirikiri.domain.roadmap.RoadmapCategory; +import co.kirikiri.domain.roadmap.RoadmapContent; +import co.kirikiri.domain.roadmap.RoadmapDifficulty; +import co.kirikiri.domain.roadmap.RoadmapNode; +import co.kirikiri.domain.roadmap.RoadmapNodes; +import co.kirikiri.persistence.goalroom.GoalRoomRepository; +import co.kirikiri.persistence.roadmap.RoadmapRepository; +import java.time.LocalDate; +import java.util.Collections; +import java.util.List; +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; + +@ExtendWith(MockitoExtension.class) +class RoadmapSchedulerTest { + + private static final LocalDate TODAY = LocalDate.now(); + private static final LocalDate TEN_DAY_LATER = TODAY.plusDays(10); + + @Mock + private RoadmapRepository roadmapRepository; + + @Mock + private GoalRoomRepository goalRoomRepository; + + @InjectMocks + private RoadmapScheduler roadmapScheduler; + + @Test + void ์‚ญ์ œ๋œ_์ƒํƒœ์˜_๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_์ข…๋ฃŒ๋˜์ง€_์•Š์€_๊ณจ๋ฃธ์ด_์žˆ์œผ๋ฉด_์‚ญ์ œ๋˜์ง€_์•Š๋Š”๋‹ค() { + // given + final Member member1 = new Member(new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), new Nickname("name1"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1900, 1, 1), "010-1111-1111")); + final Member member2 = new Member(new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), new Nickname("name2"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1900, 1, 1), "010-1111-2222")); + + final RoadmapCategory category = new RoadmapCategory("์—ฌํ–‰"); + final RoadmapContent roadmapContent1_1 = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ2"); + final RoadmapContent roadmapContent1_2 = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ2 - ์ˆ˜์ •๋ณธ"); + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต1 ๋…ธ๋“œ", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ"); + roadmapContent1_1.addNodes(new RoadmapNodes(List.of(roadmapNode1))); + roadmapContent1_2.addNodes(new RoadmapNodes(List.of(roadmapNode1))); + final Roadmap roadmap1 = new Roadmap("๋กœ๋“œ๋งต2", "๋กœ๋“œ๋งต ์„ค๋ช…2", 30, RoadmapDifficulty.DIFFICULT, member1, category); + roadmap1.addContent(roadmapContent1_1); + roadmap1.addContent(roadmapContent1_2); + + final GoalRoom goalRoom1_1 = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ2"), new LimitedMemberCount(10), + roadmapContent1_1, member2); + final GoalRoom goalRoom1_2 = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ2-1"), new LimitedMemberCount(10), + roadmapContent1_2, member2); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes1 = new GoalRoomRoadmapNodes(List.of( + new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), 5, roadmapNode1))); + goalRoom1_1.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes1); + goalRoom1_2.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes1); + + given(roadmapRepository.findWithRoadmapContentByStatus(any())) + .willReturn(List.of(roadmap1)); + given(goalRoomRepository.findByRoadmap(roadmap1)) + .willReturn(List.of(goalRoom1_1, goalRoom1_2)); + + // when + roadmap1.delete(); + goalRoom1_1.complete(); + + // then + assertDoesNotThrow(() -> roadmapScheduler.deleteRoadmaps()); + verify(goalRoomRepository, never()).deleteAll(any()); + verify(roadmapRepository, never()).delete(any()); + } + + @Test + void ์‚ญ์ œ๋œ_์ƒํƒœ์˜_๋กœ๋“œ๋งต_์‚ญ์ œ์‹œ_๊ณจ๋ฃธ์ด_์ข…๋ฃŒ๋œ์ง€_3๊ฐœ์›”์ด_์ง€๋‚˜์ง€_์•Š์œผ๋ฉด_์‚ญ์ œ๋˜์ง€_์•Š๋Š”๋‹ค() { + // given + final Member member1 = new Member(new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), new Nickname("name1"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1900, 1, 1), "010-1111-1111")); + final Member member2 = new Member(new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), new Nickname("name2"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1900, 1, 1), "010-1111-2222")); + + final RoadmapCategory category = new RoadmapCategory("์—ฌํ–‰"); + final RoadmapContent roadmapContent1 = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ1"); + final RoadmapNode roadmapNode1 = new RoadmapNode("๋กœ๋“œ๋งต1 ๋…ธ๋“œ", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ"); + roadmapContent1.addNodes(new RoadmapNodes(List.of(roadmapNode1))); + + final Roadmap roadmap1 = new Roadmap("๋กœ๋“œ๋งต1", "๋กœ๋“œ๋งต ์„ค๋ช…1", 30, RoadmapDifficulty.DIFFICULT, member1, category); + roadmap1.addContent(roadmapContent1); + + final GoalRoom goalRoom1 = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ1"), new LimitedMemberCount(10), roadmapContent1, + member2); + final GoalRoomRoadmapNodes goalRoomRoadmapNodes1 = new GoalRoomRoadmapNodes(List.of( + new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), 5, roadmapNode1))); + goalRoom1.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes1); + + given(roadmapRepository.findWithRoadmapContentByStatus(any())) + .willReturn(List.of(roadmap1)); + given(goalRoomRepository.findByRoadmap(roadmap1)) + .willReturn(List.of(goalRoom1)); + + // when + roadmap1.delete(); + goalRoom1.complete(); + + // then + assertDoesNotThrow(() -> roadmapScheduler.deleteRoadmaps()); + verify(goalRoomRepository, never()).deleteAll(any()); + verify(roadmapRepository, never()).delete(any()); + } + + @Test + void ์‚ญ์ œ๋œ_์ƒํƒœ์˜_๋กœ๋“œ๋งต์ด_์—†๋Š”_๊ฒฝ์šฐ_์‚ญ์ œ๋˜์ง€_์•Š๋Š”๋‹ค() { + // given + final Member member1 = new Member(new Identifier("identifier1"), + new EncryptedPassword(new Password("password1!")), new Nickname("name1"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1900, 1, 1), "010-1111-1111")); + final Member member2 = new Member(new Identifier("identifier2"), + new EncryptedPassword(new Password("password2!")), new Nickname("name2"), null, + new MemberProfile(Gender.FEMALE, LocalDate.of(1900, 1, 1), "010-1111-2222")); + + final RoadmapCategory category = new RoadmapCategory("์—ฌํ–‰"); + final RoadmapContent roadmapContent1 = new RoadmapContent("๋กœ๋“œ๋งต ๋ณธ๋ฌธ1"); + final RoadmapNode roadmapNode = new RoadmapNode("๋กœ๋“œ๋งต ๋…ธ๋“œ", "๋กœ๋“œ๋งต ๋…ธ๋“œ ๋‚ด์šฉ"); + final Roadmap roadmap1 = new Roadmap("๋กœ๋“œ๋งต1", "๋กœ๋“œ๋งต ์„ค๋ช…1", 30, RoadmapDifficulty.DIFFICULT, member1, category); + roadmapContent1.addNodes(new RoadmapNodes(List.of(roadmapNode))); + roadmap1.addContent(roadmapContent1); + + final GoalRoom goalRoom1 = new GoalRoom(new GoalRoomName("๊ณจ๋ฃธ1"), new LimitedMemberCount(10), roadmapContent1, + member2); + + final GoalRoomRoadmapNodes goalRoomRoadmapNodes = new GoalRoomRoadmapNodes(List.of( + new GoalRoomRoadmapNode(new Period(TODAY, TEN_DAY_LATER), 5, roadmapNode))); + goalRoom1.addAllGoalRoomRoadmapNodes(goalRoomRoadmapNodes); + goalRoom1.complete(); + + given(roadmapRepository.findWithRoadmapContentByStatus(any())) + .willReturn(Collections.emptyList()); + + // when + // then + assertDoesNotThrow(() -> roadmapScheduler.deleteRoadmaps()); + verify(goalRoomRepository, never()).findByRoadmap(any()); + verify(roadmapRepository, never()).deleteAll(any()); + } +} diff --git a/backend/kirikiri/src/test/java/co/kirikiri/service/UUIDFilePathGeneratorTest.java b/backend/kirikiri/src/test/java/co/kirikiri/service/UUIDFilePathGeneratorTest.java new file mode 100644 index 000000000..39a036b81 --- /dev/null +++ b/backend/kirikiri/src/test/java/co/kirikiri/service/UUIDFilePathGeneratorTest.java @@ -0,0 +1,27 @@ +package co.kirikiri.service; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class UUIDFilePathGeneratorTest { + + private final FilePathGenerator filePathGenerator = new UUIDFilePathGenerator(); + + @Test + void ์ •์ƒ์ ์œผ๋กœ_ํŒŒ์ผ_๊ฒฝ๋กœ๋ฅผ_์ƒ์„ฑํ•œ๋‹ค() { + //given + final ImageDirType imageDirType = ImageDirType.ROADMAP_NODE; + final String originalFileName = "originalFileName.png"; + + //when + final String filePath = filePathGenerator.makeFilePath(imageDirType, originalFileName); + + //then + assertAll( + () -> assertTrue(filePath.contains(imageDirType.getDirName())), + () -> assertTrue(filePath.contains(originalFileName)) + ); + } +} diff --git a/backend/kirikiri/src/test/resources/application.yml b/backend/kirikiri/src/test/resources/application.yml new file mode 100644 index 000000000..c36e03cde --- /dev/null +++ b/backend/kirikiri/src/test/resources/application.yml @@ -0,0 +1,63 @@ +spring: + datasource: + url: jdbc:h2:mem:test;MODE=MYSQL + driver-class-name: org.h2.Driver + jpa: + properties: + hibernate: + format_sql: true + show-sql: true + hibernate: + ddl-auto: create-drop + open-in-view: false + servlet: + multipart: + max-file-size: 10MB + flyway: + enabled: false + +logging: + level: + org: + hibernate: + sql: debug + orm: + jdbc: + bind: TRACE + file-path: ./logs + file-name: test-name + custom-pattern: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%thread] [%logger{36}] - %msg%n' + + slack: + webhook-url: test-url + +server: + servlet: + contextPath: /api + port: 8080 + +jwt: + secret-key: 9zrOjg1kDd2gUp6KBbElGJj5GHP5BnneDs3nXEhdztHAUjKBX7l69JXUErBovPLn7TVWV0UCfejYZyxIjIMC5KPfSvBzo9C1gJ2 + access-token-validity-in-seconds: 86400 + refresh-token-validity-in-seconds: 86400 + +image: + default: + originalFileName: default-member-image + serverFilePath: /test/member/profile/default/default-member-image + imageContentType: PNG + extension: .png + +cloud: + aws: + region: + static: ap-northeast-2 + stack: + auto: false + credentials: + instanceProfile: true + s3: + bucket: 2023-team-project + root-directory: 2023-co-kirikiri + sub-directory: prod + url-expiration: 60000 diff --git a/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/path-parameters.snippet b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/path-parameters.snippet new file mode 100644 index 000000000..77d2294bd --- /dev/null +++ b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/path-parameters.snippet @@ -0,0 +1,8 @@ +|=== +|Parameter|Required|Description +{{#parameters}} +|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{^optional}}false{{/optional}}{{#optional}}true{{/optional}}{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} +{{/parameters}} +|=== \ No newline at end of file diff --git a/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/query-parameters.snippet b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/query-parameters.snippet new file mode 100644 index 000000000..7d13df35e --- /dev/null +++ b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/query-parameters.snippet @@ -0,0 +1,8 @@ +|=== +|Parameter|Required|Description +{{#parameters}} +|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{^optional}}true{{/optional}}{{#optional}}false{{/optional}}{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} +{{/parameters}} +|=== diff --git a/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-fields.snippet b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-fields.snippet new file mode 100644 index 000000000..c3073fe26 --- /dev/null +++ b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-fields.snippet @@ -0,0 +1,10 @@ +|=== +|Field|Type|Description|Restrict|Required +{{#fields}} +|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}} +|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} +|{{#tableCellContent}}{{^restrict}}์ œํ•œ ์—†์Œ{{/restrict}}{{#restrict}}{{.}}{{/restrict}}{{/tableCellContent}} +|{{#tableCellContent}}{{^optional}}true{{/optional}}{{#optional}}false{{/optional}}{{/tableCellContent}} +{{/fields}} +|=== diff --git a/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-parameters.snippet b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-parameters.snippet new file mode 100644 index 000000000..8561f998c --- /dev/null +++ b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-parameters.snippet @@ -0,0 +1,10 @@ +|=== +|Parameter|Type|Description|Restrict|Required +{{#parameters}} +|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}} +|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} +|{{#tableCellContent}}{{^restrict}}์ œํ•œ ์—†์Œ{{/restrict}}{{#restrict}}{{.}}{{/restrict}}{{/tableCellContent}} +|{{#tableCellContent}}{{^optional}}true{{/optional}}{{#optional}}false{{/optional}}{{/tableCellContent}} +{{/parameters}} +|=== diff --git a/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet new file mode 100644 index 000000000..9596447c8 --- /dev/null +++ b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/request-parts.snippet @@ -0,0 +1,9 @@ +|=== +|Part|Description + +{{#parts}} +|{{#tableCellContent}}`+{{name}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} + +{{/parts}} +|=== \ No newline at end of file diff --git a/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/response-fields.snippet b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/response-fields.snippet new file mode 100644 index 000000000..e03756f8b --- /dev/null +++ b/backend/kirikiri/src/test/resources/org/springframework/restdocs/templates/response-fields.snippet @@ -0,0 +1,8 @@ +|=== +|Field|Type|Description +{{#fields}} +|{{#tableCellContent}}`+{{path}}+`{{/tableCellContent}} +|{{#tableCellContent}}`+{{type}}+`{{/tableCellContent}} +|{{#tableCellContent}}{{description}}{{/tableCellContent}} +{{/fields}} +|===