mirror of
https://github.com/IRS-Public/direct-file.git
synced 2025-06-28 04:25:52 +00:00
Merge pull request #1 from cjhskippy/remove-submit-app
Remove submit and status apps
This commit is contained in:
commit
ffde0cfbcd
238 changed files with 0 additions and 15592 deletions
|
@ -313,21 +313,8 @@ Most of the project dependencies can be installed using [SDKMAN!](https://sdkman
|
||||||
export LOCAL_WRAPPING_KEY="9mteZFY+gIVfMFywgvpLpyVl+8UIcNoIWpGaHX4jDFU="
|
export LOCAL_WRAPPING_KEY="9mteZFY+gIVfMFywgvpLpyVl+8UIcNoIWpGaHX4jDFU="
|
||||||
export MEF_SOFTWARE_ID="[mef-software-id]"
|
export MEF_SOFTWARE_ID="[mef-software-id]"
|
||||||
export MEF_SOFTWARE_VERSION_NUM="2023.0.1"
|
export MEF_SOFTWARE_VERSION_NUM="2023.0.1"
|
||||||
export STATUS_ASID="[status-asid]"
|
|
||||||
export STATUS_EFIN="[status-efin]"
|
|
||||||
export STATUS_ETIN="[status-etin]"
|
|
||||||
export SUBMIT_ASID=$STATUS_ASID
|
|
||||||
export SUBMIT_EFIN=$STATUS_EFIN
|
|
||||||
export SUBMIT_ETIN=$STATUS_ETIN
|
|
||||||
export DF_TIN_VALIDATION_ENABLED=false
|
export DF_TIN_VALIDATION_ENABLED=false
|
||||||
export DF_EMAIL_VALIDATION_ENABLED=false
|
export DF_EMAIL_VALIDATION_ENABLED=false
|
||||||
export STATUS_KEYSTOREALIAS="[keystore-alias]"
|
|
||||||
export STATUS_KEYSTOREBASE64="[base64-encoded-keystore]"
|
|
||||||
export STATUS_KEYSTOREPASSWORD="[keystore-password]"
|
|
||||||
export SUBMIT_KEYSTORE_KEYSTOREALIAS=$STATUS_KEYSTOREALIAS
|
|
||||||
export SUBMIT_KEYSTORE_KEYSTOREBASE64=$STATUS_KEYSTOREBASE64
|
|
||||||
export SUBMIT_KEYSTORE_KEYSTOREPASSWORD=$STATUS_KEYSTOREPASSWORD
|
|
||||||
export SUBMIT_ID_VAR_CHARS="zz"
|
|
||||||
export GIT_COMMIT_HASH="$(cd /path/to/direct-file && git rev-parse --short main)"
|
export GIT_COMMIT_HASH="$(cd /path/to/direct-file && git rev-parse --short main)"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
**/application-local.*
|
|
||||||
.env*
|
|
||||||
.git/
|
|
||||||
Dockerfile*
|
|
43
direct-file/status/.gitignore
vendored
43
direct-file/status/.gitignore
vendored
|
@ -1,43 +0,0 @@
|
||||||
HELP.md
|
|
||||||
target/
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
*.jar
|
|
||||||
/src/main/resources/spotbugs/output/spotbugs.xml
|
|
||||||
|
|
||||||
### STS ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
### Special ###
|
|
||||||
/src/main/resources/application-local.*
|
|
||||||
src/test/resources/private.p12
|
|
||||||
src/test/resources/private.p12
|
|
||||||
|
|
||||||
### Gradle ###
|
|
||||||
/.gradle/
|
|
||||||
/build/
|
|
|
@ -1,5 +0,0 @@
|
||||||
changeLogFile=db/changelog.yaml
|
|
||||||
url=jdbc:postgresql://localhost:32768/directfile-status
|
|
||||||
username=postgres
|
|
||||||
password=postgres
|
|
||||||
changesetAuthor=directfile
|
|
|
@ -1,19 +0,0 @@
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you 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
|
|
||||||
#
|
|
||||||
# http://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.
|
|
||||||
wrapperVersion=3.3.2
|
|
||||||
distributionType=only-script
|
|
||||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.7/apache-maven-3.9.7-bin.zip
|
|
|
@ -1,56 +0,0 @@
|
||||||
#syntax=docker/dockerfile:1.7-labs
|
|
||||||
# build factgraph since it will be a dependency in share-libs-builder
|
|
||||||
FROM sbtscala/scala-sbt:eclipse-temurin-alpine-21.0.2_13_1.9.9_3.3.3 AS factgraph-builder
|
|
||||||
WORKDIR /build/
|
|
||||||
COPY --from=factgraph-repo js/src/ js/src/
|
|
||||||
COPY --from=factgraph-repo jvm/src/ jvm/src/
|
|
||||||
COPY --from=factgraph-repo project/build.properties project/plugins.sbt project/
|
|
||||||
COPY --from=factgraph-repo shared/ shared/
|
|
||||||
COPY --from=factgraph-repo build.sbt .
|
|
||||||
RUN sbt compile package publishM2
|
|
||||||
|
|
||||||
# build shared dependencies
|
|
||||||
FROM eclipse-temurin:21-jdk-alpine AS shared-dependencies-builder
|
|
||||||
COPY --from=factgraph-builder /root/.m2/repository/gov/irs/factgraph/fact-graph_3/ /root/.m2/repository/gov/irs/factgraph/fact-graph_3/
|
|
||||||
ARG MAVEN_OPTS=""
|
|
||||||
WORKDIR /build/
|
|
||||||
COPY --from=config . ./config/
|
|
||||||
COPY --from=boms . ./boms/
|
|
||||||
WORKDIR /build/libs/
|
|
||||||
COPY --from=shared-libs .mvn/wrapper/maven-wrapper.properties .mvn/wrapper/
|
|
||||||
COPY --from=shared-libs mvnw ./
|
|
||||||
COPY --from=shared-libs --parents **/pom.xml ./
|
|
||||||
RUN ./mvnw dependency:resolve -P resolve
|
|
||||||
COPY --from=shared-libs starters/ ./starters/
|
|
||||||
COPY --from=shared-libs data-models/ ./data-models/
|
|
||||||
RUN ./mvnw install
|
|
||||||
|
|
||||||
|
|
||||||
# build mef-status
|
|
||||||
FROM shared-dependencies-builder AS mef-status-builder
|
|
||||||
ARG MAVEN_OPTS=""
|
|
||||||
ENV MEF_REPO /mef-client-sdk
|
|
||||||
ENV A2A_TOOLKIT_HOME /${MEF_REPO}/MeF_Client_SDK/Java/source/
|
|
||||||
ENV LOCALSTACK_INTEGRATION_TESTS_ENABLED false
|
|
||||||
COPY --from=mef-sdk-repo MeF_Client_SDK/ /${MEF_REPO}/MeF_Client_SDK/
|
|
||||||
COPY --from=config . /config/
|
|
||||||
WORKDIR /build/
|
|
||||||
COPY --from=scripts install-mef-sdk.sh ./
|
|
||||||
COPY mvnw pom.xml ./
|
|
||||||
COPY .mvn/wrapper/maven-wrapper.properties .mvn/wrapper/
|
|
||||||
RUN ./install-mef-sdk.sh
|
|
||||||
RUN ./mvnw dependency:resolve
|
|
||||||
COPY src/ src/
|
|
||||||
RUN ./mvnw package
|
|
||||||
|
|
||||||
FROM eclipse-temurin:21-jre-alpine
|
|
||||||
ENV LOCAL_WRAPPING_KEY "${LOCAL_WRAPPING_KEY:-oE3Pm+fr1I+YbX2ZxEe/n9INqJjy00KSl7oXXW4p5Xw=}"
|
|
||||||
COPY --from=mef-status-builder /build/target/mef-status-0.0.1-SNAPSHOT.jar /app.jar
|
|
||||||
COPY --from=mef-sdk-repo MeF_Client_SDK/Java/source/ /mef-client-sdk-src/
|
|
||||||
# Run from dir that allows mef-sdk to write it's files to the working directory (next iteration: configure mef-sdk)
|
|
||||||
RUN adduser --system --no-create-home jar-runner && \
|
|
||||||
mkdir -p /jar-run && \
|
|
||||||
chown jar-runner /jar-run
|
|
||||||
WORKDIR /jar-run
|
|
||||||
USER jar-runner
|
|
||||||
CMD ["java", "-jar", "/app.jar"]
|
|
|
@ -1,86 +0,0 @@
|
||||||
# MEF Status
|
|
||||||
|
|
||||||
## About MeF Status
|
|
||||||
The MeF Status application's job is to:
|
|
||||||
- Regularly poll MeF to learn about the status of each submitted tax return, until we recieve a final status. A final status is one that will not change: Accepted, Rejected, or an error that will not get resolved without intervention.
|
|
||||||
- Save the final status for each tax return where it can be accessed by the backend application
|
|
||||||
|
|
||||||
### How it works
|
|
||||||
|
|
||||||
- At the time a tax return is submitted, the mef-submit app creates a submission ID and notifies the status application via message queue that there is a new tax return to begin polling for.
|
|
||||||
- MeF status periodically queries the status database to find a list of pending tax returns.
|
|
||||||
- MeF status (this application) then queries MeF (the external API) for batches of those returns. When it receives a final response from MeF (generally "accepted" or "rejected") for any one of those returns, it saves the results to the status database. Returns that remain in pending status will be polled for at the next interval.
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> For setup please see the most up-to-date instructions which are found in the [Onboarding docs](../../ONBOARDING.md).
|
|
||||||
|
|
||||||
### MeF SDK
|
|
||||||
|
|
||||||
2. Once you have that variable set, run the
|
|
||||||
build-project.sh script from the
|
|
||||||
`submit` folder of the direct_file project.
|
|
||||||
|
|
||||||
|
|
||||||
### Proxy
|
|
||||||
If you use a proxy, first see `MAVEN_OPTS` in [the project readme](../README.md#important-configuration-variables) and [the OMB Connect readme](../README-omb-connect.md) for information about ensuring your proxy settings are passed to all build steps.
|
|
||||||
|
|
||||||
## Docker
|
|
||||||
|
|
||||||
Ensure you have the environment variables set (see [Environment](#environment) below).
|
|
||||||
You may be able to run with only `STATUS_ETIN` set, using the test value from the [submit README](../backend/README.md).
|
|
||||||
|
|
||||||
Build the application:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose build
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run it:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d mef-status
|
|
||||||
```
|
|
||||||
|
|
||||||
The app probably failed for you due to lack of configuration. You can look at the reason why it failed to start with:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose logs mef-status
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Running locally
|
|
||||||
|
|
||||||
### Environment
|
|
||||||
|
|
||||||
Set the following environment variables in your local environment which will facilitate running both the applications as well as the docker containers. On macbooks, placing the export statements below in the `.zshrc` (gets run and evaluated everytime a shell instance is started) or `.zprofile` (gets run and evaluated when a user logs in) file will accomplish this. If using the bash shell, placing them in `.bashrc` should do (and effectively behave similar to `.zshrc`).
|
|
||||||
|
|
||||||
```
|
|
||||||
# Get the keystore alias from a fellow developer and replace the value in between quotes with the actual value
|
|
||||||
export STATUS_KEYSTOREALIAS="[keystore-alias]"
|
|
||||||
|
|
||||||
# Get the base64 encoded keystore from a fellow developer and replace the value in between quotes with the actual value
|
|
||||||
export STATUS_KEYSTOREBASE64="[base64-encoded-keystore]"
|
|
||||||
|
|
||||||
# Get the keystore password from a fellow developer and replace the value in between quotes with the actual value
|
|
||||||
export STATUS_KEYSTOREPASSWORD="[keystore-password]"
|
|
||||||
|
|
||||||
# Get the ASID value for the status application from a fellow developer and replace the value in between quotes with the actual value
|
|
||||||
export STATUS_ASID="[status-asid]"
|
|
||||||
|
|
||||||
# Get the EFIN value for the status application from a fellow developer and replace the value in between quotes with the actual value
|
|
||||||
export STATUS_EFIN="[status-efin]"
|
|
||||||
|
|
||||||
# Get the ETIN value for the status application from a fellow developer and replace the value in between quotes with the actual value
|
|
||||||
export STATUS_ETIN="[status-etin]"
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll also need to set up the `LOCAL_WRAPPING_KEY` following the instructions in the [backend README](../backend/README.md#initial-setup)
|
|
||||||
```
|
|
||||||
export LOCAL_WRAPPING_KEY="[local-wrapping-key]"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Static Analysis: Spot Bugs and PMD
|
|
||||||
For notes and usage on spotbugs see the [Backend API README Spot Bugs section](../submit/README.md#static-analysis)
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
cd target
|
|
||||||
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8001 -jar mef-status-0.0.1-SNAPSHOT.jar
|
|
259
direct-file/status/mvnw
vendored
259
direct-file/status/mvnw
vendored
|
@ -1,259 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you 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
|
|
||||||
#
|
|
||||||
# http://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.
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
# Apache Maven Wrapper startup batch script, version 3.3.2
|
|
||||||
#
|
|
||||||
# Optional ENV vars
|
|
||||||
# -----------------
|
|
||||||
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
|
|
||||||
# MVNW_REPOURL - repo url base for downloading maven distribution
|
|
||||||
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
|
||||||
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
|
|
||||||
# ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
set -euf
|
|
||||||
[ "${MVNW_VERBOSE-}" != debug ] || set -x
|
|
||||||
|
|
||||||
# OS specific support.
|
|
||||||
native_path() { printf %s\\n "$1"; }
|
|
||||||
case "$(uname)" in
|
|
||||||
CYGWIN* | MINGW*)
|
|
||||||
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
|
|
||||||
native_path() { cygpath --path --windows "$1"; }
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# set JAVACMD and JAVACCMD
|
|
||||||
set_java_home() {
|
|
||||||
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
|
|
||||||
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"
|
|
||||||
JAVACCMD="$JAVA_HOME/jre/sh/javac"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
JAVACCMD="$JAVA_HOME/bin/javac"
|
|
||||||
|
|
||||||
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
|
|
||||||
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
|
|
||||||
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="$(
|
|
||||||
'set' +e
|
|
||||||
'unset' -f command 2>/dev/null
|
|
||||||
'command' -v java
|
|
||||||
)" || :
|
|
||||||
JAVACCMD="$(
|
|
||||||
'set' +e
|
|
||||||
'unset' -f command 2>/dev/null
|
|
||||||
'command' -v javac
|
|
||||||
)" || :
|
|
||||||
|
|
||||||
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
|
|
||||||
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# hash string like Java String::hashCode
|
|
||||||
hash_string() {
|
|
||||||
str="${1:-}" h=0
|
|
||||||
while [ -n "$str" ]; do
|
|
||||||
char="${str%"${str#?}"}"
|
|
||||||
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
|
|
||||||
str="${str#?}"
|
|
||||||
done
|
|
||||||
printf %x\\n $h
|
|
||||||
}
|
|
||||||
|
|
||||||
verbose() { :; }
|
|
||||||
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
|
|
||||||
|
|
||||||
die() {
|
|
||||||
printf %s\\n "$1" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
trim() {
|
|
||||||
# MWRAPPER-139:
|
|
||||||
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
|
|
||||||
# Needed for removing poorly interpreted newline sequences when running in more
|
|
||||||
# exotic environments such as mingw bash on Windows.
|
|
||||||
printf "%s" "${1}" | tr -d '[:space:]'
|
|
||||||
}
|
|
||||||
|
|
||||||
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
|
|
||||||
while IFS="=" read -r key value; do
|
|
||||||
case "${key-}" in
|
|
||||||
distributionUrl) distributionUrl=$(trim "${value-}") ;;
|
|
||||||
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
|
|
||||||
esac
|
|
||||||
done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
|
||||||
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
|
|
||||||
|
|
||||||
case "${distributionUrl##*/}" in
|
|
||||||
maven-mvnd-*bin.*)
|
|
||||||
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
|
|
||||||
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
|
|
||||||
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
|
|
||||||
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
|
|
||||||
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
|
|
||||||
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
|
|
||||||
*)
|
|
||||||
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
|
|
||||||
distributionPlatform=linux-amd64
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
|
|
||||||
;;
|
|
||||||
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
|
|
||||||
*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
|
||||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
|
||||||
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
|
|
||||||
distributionUrlName="${distributionUrl##*/}"
|
|
||||||
distributionUrlNameMain="${distributionUrlName%.*}"
|
|
||||||
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
|
|
||||||
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
|
|
||||||
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
|
|
||||||
|
|
||||||
exec_maven() {
|
|
||||||
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
|
|
||||||
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -d "$MAVEN_HOME" ]; then
|
|
||||||
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
|
||||||
exec_maven "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "${distributionUrl-}" in
|
|
||||||
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
|
|
||||||
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# prepare tmp dir
|
|
||||||
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
|
|
||||||
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
|
|
||||||
trap clean HUP INT TERM EXIT
|
|
||||||
else
|
|
||||||
die "cannot create temp dir"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p -- "${MAVEN_HOME%/*}"
|
|
||||||
|
|
||||||
# Download and Install Apache Maven
|
|
||||||
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
|
||||||
verbose "Downloading from: $distributionUrl"
|
|
||||||
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
|
||||||
|
|
||||||
# select .zip or .tar.gz
|
|
||||||
if ! command -v unzip >/dev/null; then
|
|
||||||
distributionUrl="${distributionUrl%.zip}.tar.gz"
|
|
||||||
distributionUrlName="${distributionUrl##*/}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# verbose opt
|
|
||||||
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
|
|
||||||
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
|
|
||||||
|
|
||||||
# normalize http auth
|
|
||||||
case "${MVNW_PASSWORD:+has-password}" in
|
|
||||||
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
|
||||||
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
|
|
||||||
verbose "Found wget ... using wget"
|
|
||||||
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
|
|
||||||
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
|
|
||||||
verbose "Found curl ... using curl"
|
|
||||||
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
|
|
||||||
elif set_java_home; then
|
|
||||||
verbose "Falling back to use Java to download"
|
|
||||||
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
|
|
||||||
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
|
|
||||||
cat >"$javaSource" <<-END
|
|
||||||
public class Downloader extends java.net.Authenticator
|
|
||||||
{
|
|
||||||
protected java.net.PasswordAuthentication getPasswordAuthentication()
|
|
||||||
{
|
|
||||||
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
|
|
||||||
}
|
|
||||||
public static void main( String[] args ) throws Exception
|
|
||||||
{
|
|
||||||
setDefault( new Downloader() );
|
|
||||||
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
END
|
|
||||||
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
|
|
||||||
verbose " - Compiling Downloader.java ..."
|
|
||||||
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
|
|
||||||
verbose " - Running Downloader.java ..."
|
|
||||||
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
|
||||||
if [ -n "${distributionSha256Sum-}" ]; then
|
|
||||||
distributionSha256Result=false
|
|
||||||
if [ "$MVN_CMD" = mvnd.sh ]; then
|
|
||||||
echo "Checksum validation is not supported for maven-mvnd." >&2
|
|
||||||
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
|
||||||
exit 1
|
|
||||||
elif command -v sha256sum >/dev/null; then
|
|
||||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
|
|
||||||
distributionSha256Result=true
|
|
||||||
fi
|
|
||||||
elif command -v shasum >/dev/null; then
|
|
||||||
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
|
|
||||||
distributionSha256Result=true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
|
|
||||||
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ $distributionSha256Result = false ]; then
|
|
||||||
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
|
|
||||||
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# unzip and move
|
|
||||||
if command -v unzip >/dev/null; then
|
|
||||||
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
|
|
||||||
else
|
|
||||||
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
|
|
||||||
fi
|
|
||||||
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
|
|
||||||
mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
|
|
||||||
|
|
||||||
clean || :
|
|
||||||
exec_maven "$@"
|
|
149
direct-file/status/mvnw.cmd
vendored
149
direct-file/status/mvnw.cmd
vendored
|
@ -1,149 +0,0 @@
|
||||||
<# : batch portion
|
|
||||||
@REM ----------------------------------------------------------------------------
|
|
||||||
@REM Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
@REM or more contributor license agreements. See the NOTICE file
|
|
||||||
@REM distributed with this work for additional information
|
|
||||||
@REM regarding copyright ownership. The ASF licenses this file
|
|
||||||
@REM to you under the Apache License, Version 2.0 (the
|
|
||||||
@REM "License"); you may not use this file except in compliance
|
|
||||||
@REM with the License. You may obtain a copy of the License at
|
|
||||||
@REM
|
|
||||||
@REM http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
@REM
|
|
||||||
@REM Unless required by applicable law or agreed to in writing,
|
|
||||||
@REM software distributed under the License is distributed on an
|
|
||||||
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
@REM KIND, either express or implied. See the License for the
|
|
||||||
@REM specific language governing permissions and limitations
|
|
||||||
@REM under the License.
|
|
||||||
@REM ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
@REM ----------------------------------------------------------------------------
|
|
||||||
@REM Apache Maven Wrapper startup batch script, version 3.3.2
|
|
||||||
@REM
|
|
||||||
@REM Optional ENV vars
|
|
||||||
@REM MVNW_REPOURL - repo url base for downloading maven distribution
|
|
||||||
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
|
|
||||||
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
|
|
||||||
@REM ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
|
|
||||||
@SET __MVNW_CMD__=
|
|
||||||
@SET __MVNW_ERROR__=
|
|
||||||
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
|
|
||||||
@SET PSModulePath=
|
|
||||||
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
|
|
||||||
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
|
|
||||||
)
|
|
||||||
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
|
|
||||||
@SET __MVNW_PSMODULEP_SAVE=
|
|
||||||
@SET __MVNW_ARG0_NAME__=
|
|
||||||
@SET MVNW_USERNAME=
|
|
||||||
@SET MVNW_PASSWORD=
|
|
||||||
@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*)
|
|
||||||
@echo Cannot start maven from wrapper >&2 && exit /b 1
|
|
||||||
@GOTO :EOF
|
|
||||||
: end batch / begin powershell #>
|
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
|
||||||
if ($env:MVNW_VERBOSE -eq "true") {
|
|
||||||
$VerbosePreference = "Continue"
|
|
||||||
}
|
|
||||||
|
|
||||||
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
|
|
||||||
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
|
|
||||||
if (!$distributionUrl) {
|
|
||||||
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
|
|
||||||
"maven-mvnd-*" {
|
|
||||||
$USE_MVND = $true
|
|
||||||
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
|
|
||||||
$MVN_CMD = "mvnd.cmd"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
default {
|
|
||||||
$USE_MVND = $false
|
|
||||||
$MVN_CMD = $script -replace '^mvnw','mvn'
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# apply MVNW_REPOURL and calculate MAVEN_HOME
|
|
||||||
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
|
|
||||||
if ($env:MVNW_REPOURL) {
|
|
||||||
$MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" }
|
|
||||||
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')"
|
|
||||||
}
|
|
||||||
$distributionUrlName = $distributionUrl -replace '^.*/',''
|
|
||||||
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
|
|
||||||
$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain"
|
|
||||||
if ($env:MAVEN_USER_HOME) {
|
|
||||||
$MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain"
|
|
||||||
}
|
|
||||||
$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
|
|
||||||
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
|
|
||||||
|
|
||||||
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
|
|
||||||
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
|
|
||||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
|
||||||
exit $?
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
|
|
||||||
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
|
|
||||||
}
|
|
||||||
|
|
||||||
# prepare tmp dir
|
|
||||||
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
|
|
||||||
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
|
|
||||||
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
|
|
||||||
trap {
|
|
||||||
if ($TMP_DOWNLOAD_DIR.Exists) {
|
|
||||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
|
||||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
|
|
||||||
|
|
||||||
# Download and Install Apache Maven
|
|
||||||
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
|
|
||||||
Write-Verbose "Downloading from: $distributionUrl"
|
|
||||||
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
|
|
||||||
|
|
||||||
$webclient = New-Object System.Net.WebClient
|
|
||||||
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
|
|
||||||
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
|
|
||||||
}
|
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
||||||
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
|
|
||||||
|
|
||||||
# If specified, validate the SHA-256 sum of the Maven distribution zip file
|
|
||||||
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
|
|
||||||
if ($distributionSha256Sum) {
|
|
||||||
if ($USE_MVND) {
|
|
||||||
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
|
|
||||||
}
|
|
||||||
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
|
|
||||||
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
|
|
||||||
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# unzip and move
|
|
||||||
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
|
|
||||||
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null
|
|
||||||
try {
|
|
||||||
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
|
|
||||||
} catch {
|
|
||||||
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
|
|
||||||
Write-Error "fail to move MAVEN_HOME"
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
|
|
||||||
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
|
|
|
@ -1,174 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<parent>
|
|
||||||
<groupId>gov.irs.directfile.boot</groupId>
|
|
||||||
<artifactId>irs-spring-boot-starter-parent</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
<relativePath>../boms/irs-spring-boot-starter-parent</relativePath>
|
|
||||||
</parent>
|
|
||||||
<groupId>gov.irs.directfile.status</groupId>
|
|
||||||
<artifactId>mef-status</artifactId>
|
|
||||||
<version>0.0.1-SNAPSHOT</version>
|
|
||||||
<name>MeF status</name>
|
|
||||||
<description>Status checking system for MeF</description>
|
|
||||||
<properties>
|
|
||||||
<!-- overrides for properties defined in irs-spring-boot-starter-parent -->
|
|
||||||
<config-folder.path>${project.basedir}/../config</config-folder.path>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.postgresql</groupId>
|
|
||||||
<artifactId>postgresql</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-validation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.xml.ws</groupId>
|
|
||||||
<artifactId>jakarta.xml.ws-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.sun.xml.bind</groupId>
|
|
||||||
<artifactId>jaxb-impl</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.sun.xml.ws</groupId>
|
|
||||||
<artifactId>jaxws-rt</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>software.amazon.awssdk</groupId>
|
|
||||||
<artifactId>sns</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>software.amazon.awssdk</groupId>
|
|
||||||
<artifactId>sqs</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>software.amazon.awssdk</groupId>
|
|
||||||
<artifactId>s3</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>software.amazon.awssdk</groupId>
|
|
||||||
<artifactId>sts</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>commons-logging</groupId>
|
|
||||||
<artifactId>commons-logging</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gov.irs.directfile</groupId>
|
|
||||||
<artifactId>data-models</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.liquibase</groupId>
|
|
||||||
<artifactId>liquibase-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.amazonaws</groupId>
|
|
||||||
<artifactId>amazon-sqs-java-messaging-lib</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>software.amazon.encryption.s3</groupId>
|
|
||||||
<artifactId>amazon-s3-encryption-client-java</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.logstash.logback</groupId>
|
|
||||||
<artifactId>logstash-logback-encoder</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.spotbugs</groupId>
|
|
||||||
<artifactId>spotbugs-annotations</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-site-plugin</artifactId>
|
|
||||||
<!-- Configures mvn site:run to run on port 9898 -->
|
|
||||||
<configuration>
|
|
||||||
<port>9898</port>
|
|
||||||
<tempWebappDirectory>${basedir}/target/site/tempdir</tempWebappDirectory>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<argLine>-XX:+EnableDynamicAgentLoading ${argLine}</argLine>
|
|
||||||
<excludedEnvironmentVariables>
|
|
||||||
<!-- exclude active profiles so tests work from cli even if this var is set -->
|
|
||||||
<excludedEnvironmentVariable>SPRING_PROFILES_ACTIVE</excludedEnvironmentVariable>
|
|
||||||
</excludedEnvironmentVariables>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
|
@ -1,37 +0,0 @@
|
||||||
package gov.irs.directfile.status;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
|
||||||
|
|
||||||
import gov.irs.mef.services.msi.LoginClient;
|
|
||||||
import gov.irs.mef.services.msi.LogoutClient;
|
|
||||||
import gov.irs.mef.services.transmitter.mtom.GetAcksMTOMClient;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
@ConfigurationPropertiesScan
|
|
||||||
public class StatusApplication {
|
|
||||||
@Bean
|
|
||||||
@Scope("prototype")
|
|
||||||
public LoginClient loginClient() {
|
|
||||||
return new LoginClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Scope("prototype")
|
|
||||||
public GetAcksMTOMClient ackClient() {
|
|
||||||
return new GetAcksMTOMClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@Scope("prototype")
|
|
||||||
public LogoutClient logoutClient() {
|
|
||||||
return new LogoutClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
SpringApplication.run(StatusApplication.class, args);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,212 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
|
|
||||||
import gov.irs.directfile.audit.AuditEventData;
|
|
||||||
import gov.irs.directfile.audit.AuditLogElement;
|
|
||||||
import gov.irs.directfile.audit.AuditService;
|
|
||||||
import gov.irs.directfile.audit.events.Event;
|
|
||||||
import gov.irs.directfile.audit.events.EventId;
|
|
||||||
import gov.irs.directfile.audit.events.EventStatus;
|
|
||||||
import gov.irs.directfile.audit.events.SystemEventPrincipal;
|
|
||||||
import gov.irs.directfile.models.RejectedStatus;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.domain.AcknowledgementStatus;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"CRLF_INJECTION_LOGS"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@RestController
|
|
||||||
@Validated
|
|
||||||
@Slf4j
|
|
||||||
@RequestMapping("/status")
|
|
||||||
public class AcknowledgementController {
|
|
||||||
|
|
||||||
private static String X_FORWARDED_FOR = "X-Forwarded-For";
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"EI_EXPOSE_REP2"},
|
|
||||||
justification = "constructor injection")
|
|
||||||
public AcknowledgementController(AcknowledgementService acknowledgementService) {
|
|
||||||
this.acknowledgementService = acknowledgementService;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final AcknowledgementService acknowledgementService;
|
|
||||||
private static final AuditService auditService = new AuditService();
|
|
||||||
|
|
||||||
@GetMapping()
|
|
||||||
public ResponseEntity<AcknowledgementStatus> get(
|
|
||||||
@RequestParam(name = "id") UUID taxReturnId, HttpServletRequest request) {
|
|
||||||
AuditEventData eventData = new AuditEventData();
|
|
||||||
String submissionId = null;
|
|
||||||
try {
|
|
||||||
MDC.put(AuditLogElement.taxReturnId.toString(), taxReturnId.toString());
|
|
||||||
log.info(String.format("Request for taxReturnId %s", taxReturnId));
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
submissionId =
|
|
||||||
acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(taxReturnId);
|
|
||||||
AcknowledgementStatus acknowledgementStatus =
|
|
||||||
acknowledgementService.GetAcknowledgement(taxReturnId, submissionId);
|
|
||||||
|
|
||||||
submissionId = setSubmissionIdToUnknownStringIfItIsNullSoThatLogMessagesWillBeMoreClear(submissionId);
|
|
||||||
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
log.info(String.format("Retrieved submissionId %s", submissionId));
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
if (acknowledgementStatus == null) {
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.mefSubmissionId, submissionId);
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.taxReturnId, taxReturnId.toString());
|
|
||||||
addValuesToEventData(
|
|
||||||
eventData, AuditLogElement.responseStatusCode, String.valueOf(HttpStatus.NOT_FOUND.value()));
|
|
||||||
|
|
||||||
auditService.performLogFromEvent(
|
|
||||||
Event.builder()
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.build(),
|
|
||||||
eventData);
|
|
||||||
return new ResponseEntity<AcknowledgementStatus>(HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
// this will get logged everytime /status is hit, regardless of whether submissionId is found
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.mefSubmissionId, submissionId);
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.taxReturnId, taxReturnId.toString());
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.responseStatusCode, String.valueOf(HttpStatus.OK.value()));
|
|
||||||
|
|
||||||
auditService.performLogFromEvent(
|
|
||||||
Event.builder()
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventStatus(EventStatus.SUCCESS)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.build(),
|
|
||||||
eventData);
|
|
||||||
return new ResponseEntity<>(acknowledgementStatus, HttpStatus.OK);
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
|
||||||
eventData.put(AuditLogElement.eventErrorMessage, ex.getClass().getName());
|
|
||||||
eventData.putDetail("errorMessage", ex.getMessage());
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.mefSubmissionId, submissionId);
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.taxReturnId, taxReturnId.toString());
|
|
||||||
addValuesToEventData(
|
|
||||||
eventData, AuditLogElement.responseStatusCode, String.valueOf(HttpStatus.BAD_REQUEST.value()));
|
|
||||||
|
|
||||||
auditService.performLogFromEvent(
|
|
||||||
Event.builder()
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.build(),
|
|
||||||
eventData);
|
|
||||||
MDC.put(AuditLogElement.taxReturnId.toString(), taxReturnId.toString());
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
log.error(String.format("Error handling submission id %s", taxReturnId), ex);
|
|
||||||
MDC.clear();
|
|
||||||
return new ResponseEntity<AcknowledgementStatus>(HttpStatus.BAD_REQUEST);
|
|
||||||
} finally {
|
|
||||||
MDC.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/rejection-codes")
|
|
||||||
public ResponseEntity<List<RejectedStatus>> getRejectionCodes(
|
|
||||||
@RequestParam(name = "submissionId") String submissionId, HttpServletRequest request) {
|
|
||||||
AuditEventData eventData = new AuditEventData();
|
|
||||||
try {
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
List<RejectedStatus> rejectionCodes;
|
|
||||||
try {
|
|
||||||
rejectionCodes = acknowledgementService.getRejectionCodesForSubmissionId(submissionId);
|
|
||||||
} catch (EntityNotFoundException e) {
|
|
||||||
log.error(String.format("Could not find record for submission ID %s", submissionId), e);
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.mefSubmissionId, submissionId);
|
|
||||||
addValuesToEventData(
|
|
||||||
eventData, AuditLogElement.responseStatusCode, String.valueOf(HttpStatus.NOT_FOUND.value()));
|
|
||||||
|
|
||||||
auditService.performLogFromEvent(
|
|
||||||
Event.builder()
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.build(),
|
|
||||||
eventData);
|
|
||||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
// this will get logged everytime /status is hit, regardless of whether submissionId is found
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.mefSubmissionId, submissionId);
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.responseStatusCode, String.valueOf(HttpStatus.OK.value()));
|
|
||||||
|
|
||||||
auditService.performLogFromEvent(
|
|
||||||
Event.builder()
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventStatus(EventStatus.SUCCESS)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.build(),
|
|
||||||
eventData);
|
|
||||||
return new ResponseEntity<>(rejectionCodes, HttpStatus.OK);
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
|
||||||
eventData.put(AuditLogElement.eventErrorMessage, ex.getClass().getName());
|
|
||||||
eventData.putDetail("errorMessage", ex.getMessage());
|
|
||||||
addValuesToEventData(eventData, AuditLogElement.mefSubmissionId, submissionId);
|
|
||||||
addValuesToEventData(
|
|
||||||
eventData, AuditLogElement.responseStatusCode, String.valueOf(HttpStatus.BAD_REQUEST.value()));
|
|
||||||
|
|
||||||
auditService.performLogFromEvent(
|
|
||||||
Event.builder()
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.build(),
|
|
||||||
eventData);
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
log.error(String.format("Error handling submission id %s", submissionId), ex);
|
|
||||||
MDC.clear();
|
|
||||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
|
||||||
} finally {
|
|
||||||
MDC.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addValuesToEventData(AuditEventData auditEventData, AuditLogElement key, String value) {
|
|
||||||
if (value != null) {
|
|
||||||
auditEventData.put(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a bit of workaround to make our log messages more clear.
|
|
||||||
// If submissionId is null, that means the status app could not find a submission associated with the given
|
|
||||||
// taxreturn in the TaxReturnSubmission table.
|
|
||||||
// If no submission was found in the TaxReturnSubmission, that likely means that the status app is still waiting for
|
|
||||||
// a message from the pending submission queue.
|
|
||||||
// There is currently some logic based on a config property in getAcknowledgementStatus. This logic causes
|
|
||||||
// GetAcknowledgement to return PENDING if submissionId is null,
|
|
||||||
// and the statusEndpointReturnsPendingByDefaultEnabled property is true (which it currently is in PROD).
|
|
||||||
// Without this workaround, submissionId will not appear in our logs, which was causing confusion.
|
|
||||||
// I am setting submissionId to NOT_YET_KNOWN so that we can have a more clear understanding of what is happening
|
|
||||||
// when we see our logs.
|
|
||||||
private String setSubmissionIdToUnknownStringIfItIsNullSoThatLogMessagesWillBeMoreClear(String submissionId) {
|
|
||||||
if (submissionId == null) {
|
|
||||||
return "NOT_YET_KNOWN";
|
|
||||||
} else {
|
|
||||||
return submissionId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,593 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.common.math.IntMath;
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
|
||||||
import jakarta.transaction.Transactional;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.slf4j.MDC;
|
|
||||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.mef.exception.ServiceException;
|
|
||||||
import gov.irs.mef.exception.ToolkitException;
|
|
||||||
import gov.irs.mef.services.ServiceContext;
|
|
||||||
|
|
||||||
import gov.irs.directfile.audit.AuditLogElement;
|
|
||||||
import gov.irs.directfile.models.RejectedStatus;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.domain.AcknowledgementStatus;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.domain.Status;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.*;
|
|
||||||
import gov.irs.directfile.status.domain.Error;
|
|
||||||
import gov.irs.directfile.status.error.ErrorRepository;
|
|
||||||
import gov.irs.directfile.status.error.ToolkitErrorRepository;
|
|
||||||
import gov.irs.directfile.status.mef.client.MeFAcksMTOMClientService;
|
|
||||||
import gov.irs.directfile.status.mef.client.MeFLoginClientService;
|
|
||||||
import gov.irs.directfile.status.mef.client.MeFLogoutClientService;
|
|
||||||
import gov.irs.directfile.status.repository.PodIdentifierRepository;
|
|
||||||
import gov.irs.directfile.status.services.StatusChangeMessageService;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"CRLF_INJECTION_LOGS", "NM_METHOD_NAMING_CONVENTION"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@Service
|
|
||||||
@EnableScheduling
|
|
||||||
@Transactional
|
|
||||||
@Slf4j
|
|
||||||
@SuppressWarnings({
|
|
||||||
"PMD.SimpleDateFormatNeedsLocale",
|
|
||||||
"PMD.ExcessiveParameterList",
|
|
||||||
"PMD.AvoidDuplicateLiterals",
|
|
||||||
"PMD.LiteralsFirstInComparisons",
|
|
||||||
"PMD.UselessParentheses"
|
|
||||||
})
|
|
||||||
public class AcknowledgementService {
|
|
||||||
private final CompletedAcknowledgementRepository completedRepo;
|
|
||||||
private final PendingAcknowledgementRepository pendingRepo;
|
|
||||||
private final TaxReturnSubmissionRepository taxReturnSubmissionRepository;
|
|
||||||
private final ErrorRepository errorRepo;
|
|
||||||
private final PodIdentifierRepository podIdentifierRepository;
|
|
||||||
|
|
||||||
private final ToolkitErrorRepository toolkitErrorRepo;
|
|
||||||
private final StatusProperties statusProperties;
|
|
||||||
private ServiceContext serviceContext;
|
|
||||||
|
|
||||||
private final StatusChangeMessageService statusChangeMessageService;
|
|
||||||
|
|
||||||
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm:ss");
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"EI_EXPOSE_REP2"},
|
|
||||||
justification = "constructor injection")
|
|
||||||
public AcknowledgementService(
|
|
||||||
CompletedAcknowledgementRepository completedRepo,
|
|
||||||
PendingAcknowledgementRepository pendingRepo,
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepository,
|
|
||||||
ErrorRepository errorRepo,
|
|
||||||
ToolkitErrorRepository toolkitErrorRepo,
|
|
||||||
StatusProperties statusProperties,
|
|
||||||
StatusChangeMessageService statusChangeMessageService,
|
|
||||||
MeFAcksMTOMClientService getAcksClientService,
|
|
||||||
MeFLoginClientService loginClientService,
|
|
||||||
MeFLogoutClientService logoutClientService,
|
|
||||||
PodIdentifierRepository podIdentifierRepository) {
|
|
||||||
this.completedRepo = completedRepo;
|
|
||||||
this.pendingRepo = pendingRepo;
|
|
||||||
this.taxReturnSubmissionRepository = taxReturnSubmissionRepository;
|
|
||||||
this.errorRepo = errorRepo;
|
|
||||||
this.toolkitErrorRepo = toolkitErrorRepo;
|
|
||||||
this.statusProperties = statusProperties;
|
|
||||||
this.statusChangeMessageService = statusChangeMessageService;
|
|
||||||
this.getAcksClientService = getAcksClientService;
|
|
||||||
this.loginClientService = loginClientService;
|
|
||||||
this.logoutClientService = logoutClientService;
|
|
||||||
this.podIdentifierRepository = podIdentifierRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
// changed from protected to public, called by TaxReturnXmlServiceImpl (which would be separated into its own
|
|
||||||
// microservice later)
|
|
||||||
public String getLatestSubmissionIdByTaxReturnId(UUID taxReturnId) {
|
|
||||||
log.info("getLatestSubmissionIdByTaxReturnId for tax-return-id {}", taxReturnId);
|
|
||||||
Optional<String> submissionId = taxReturnSubmissionRepository.getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
return submissionId.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(UUID taxReturnId) {
|
|
||||||
log.info("Getting most relevant submission Id for taxReturnId {}", taxReturnId);
|
|
||||||
|
|
||||||
Optional<String> latestAcceptedSubmissionId =
|
|
||||||
taxReturnSubmissionRepository.getLatestAcceptedSubmissionIdForTaxReturnId(taxReturnId);
|
|
||||||
|
|
||||||
if (latestAcceptedSubmissionId.isPresent()) {
|
|
||||||
String submissionId = latestAcceptedSubmissionId.get();
|
|
||||||
log.info("Using {} as the most relevant submissionId for taxReturnId {}", submissionId, taxReturnId);
|
|
||||||
return submissionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(
|
|
||||||
"Falling back to retrieving the latest submissionId, regardless of status, for tax return {}",
|
|
||||||
taxReturnId);
|
|
||||||
return getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Useful for navigating race conditions where a non-accepted submission that is more recent than an accepted
|
|
||||||
* submission exists, where the accepted submission should be the
|
|
||||||
*
|
|
||||||
* @param requestedSubmissionId a submission that (ideally) belongs to a tax return submission
|
|
||||||
* @return the latest accepted submissionId, if present
|
|
||||||
*/
|
|
||||||
public Optional<String> getLatestAcceptedSubmissionIdOfParentTaxReturn(String requestedSubmissionId) {
|
|
||||||
// Note: Cannot log method name alongside submissionId as it implies status
|
|
||||||
log.info("checking for more relevant submissionId of tax return with submissionId {}", requestedSubmissionId);
|
|
||||||
return taxReturnSubmissionRepository.getLatestAcceptedSubmissionIdOfParentTaxReturn(requestedSubmissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<Completed> getCompletedBySubmissionId(String submissionId) {
|
|
||||||
return completedRepo.GetCompletedSubmission(submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<RejectedStatus> getRejectionCodesForSubmissionId(String submissionId) {
|
|
||||||
Optional<Completed> optCompleted = getCompletedBySubmissionId(submissionId);
|
|
||||||
|
|
||||||
// If submission ID does not have a completed record, throw an exception.
|
|
||||||
if (optCompleted.isEmpty()) {
|
|
||||||
throw new EntityNotFoundException("Could not find completed record for submission ID: " + submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have a completed submission. Convert to a List<RejectedStatus> and return the list (if it's
|
|
||||||
// not a rejected submission, the returned list should be empty).
|
|
||||||
Completed completed = optCompleted.get();
|
|
||||||
return createRejectedReasonList(completed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AcknowledgementStatus GetAcknowledgement(UUID taxReturnId) {
|
|
||||||
String submissionId = getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
|
|
||||||
return getAcknowledgementStatus(taxReturnId, submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AcknowledgementStatus GetAcknowledgement(UUID taxReturnId, String submissionId) {
|
|
||||||
return getAcknowledgementStatus(taxReturnId, submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AcknowledgementStatus getAcknowledgementStatus(UUID taxReturnId, String submissionId) {
|
|
||||||
if (submissionId == null && statusProperties.statusEndpointReturnsPendingByDefaultEnabled) {
|
|
||||||
// if statusProperties.createPendingUponGetStatus is true, return Pending status as we previously did
|
|
||||||
// The difference is, we are no longer saving a Pending object in the DB.
|
|
||||||
log.atInfo()
|
|
||||||
.setMessage("Unable to find a submission associated with taxReturnId in TaxReturnSubmission table")
|
|
||||||
.addKeyValue(AuditLogElement.taxReturnId.toString(), taxReturnId)
|
|
||||||
.log();
|
|
||||||
|
|
||||||
return new AcknowledgementStatus(
|
|
||||||
Status.Pending, CreateTranslationKey("status", "pending"), List.of(), new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (submissionId == null && !statusProperties.statusEndpointReturnsPendingByDefaultEnabled) {
|
|
||||||
// tax return was likely not submitted to MeF
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
MDC.put(AuditLogElement.taxReturnId.toString(), taxReturnId.toString());
|
|
||||||
log.info(String.format("Attempting to find submission id %s in completed database", submissionId));
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
Optional<Completed> completed = completedRepo.GetCompletedSubmission(submissionId);
|
|
||||||
// this is a completed return
|
|
||||||
if (completed.isPresent()) {
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
MDC.put(AuditLogElement.taxReturnId.toString(), taxReturnId.toString());
|
|
||||||
log.info("Completed record found");
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
return getCompletedStatus(completed.get());
|
|
||||||
}
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
MDC.put(AuditLogElement.taxReturnId.toString(), taxReturnId.toString());
|
|
||||||
log.info(String.format("Did not find %s in completed, checking pending", submissionId));
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
Optional<Pending> pending = pendingRepo.GetPendingSubmission(submissionId);
|
|
||||||
if (pending.isPresent()) {
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
MDC.put(AuditLogElement.taxReturnId.toString(), taxReturnId.toString());
|
|
||||||
log.info(String.format("Found %s in pending, will recheck status on next pass", submissionId));
|
|
||||||
MDC.clear();
|
|
||||||
|
|
||||||
return new AcknowledgementStatus(
|
|
||||||
Status.Pending,
|
|
||||||
CreateTranslationKey("status", "pending"),
|
|
||||||
List.of(),
|
|
||||||
pending.get().getCreatedAt());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Scheduled(fixedRateString = "${status.ack-poll-in-milliseconds}", initialDelay = 1000)
|
|
||||||
public void ProcessPendingTable() {
|
|
||||||
if (!statusProperties.isStatusPollingEnabled()) {
|
|
||||||
log.info("Status polling is disabled in this environment");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
log.info("Timer called: performing ack check");
|
|
||||||
LookupSubmissions();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Iterable<Pending> getAllPending() {
|
|
||||||
return pendingRepo.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Iterable<Error> getAllError() {
|
|
||||||
return errorRepo.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Iterable<Completed> getAllCompleted() {
|
|
||||||
return completedRepo.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Set<Pending>> batchPendings(Iterable<Pending> pendings) {
|
|
||||||
List<Set<Pending>> batches = new ArrayList<>();
|
|
||||||
Set<Pending> current = new HashSet<>();
|
|
||||||
log.info(String.format("Estimated count: %s", pendings.spliterator().estimateSize()));
|
|
||||||
// This surprised me, but if you access it from pending every time
|
|
||||||
// the iterator will never move to next.
|
|
||||||
Iterator<Pending> iterator = pendings.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Pending pending = iterator.next();
|
|
||||||
if (current.size() < 100) {
|
|
||||||
current.add(pending);
|
|
||||||
} else {
|
|
||||||
log.info("100 Pendings in current batch, creating new batch");
|
|
||||||
batches.add(current);
|
|
||||||
current = new HashSet<>();
|
|
||||||
current.add(pending);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
batches.add(current);
|
|
||||||
log.info(String.format("%s batches created", batches.size()));
|
|
||||||
return batches;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void LookupSubmissions() {
|
|
||||||
String podId = statusProperties.getApplicationId();
|
|
||||||
log.info("Getting all pending submission ids for podId {}", podId);
|
|
||||||
Iterable<Pending> pendings = pendingRepo.findAllByPodId(podId);
|
|
||||||
// we will either get the exact size or a 0 here.
|
|
||||||
if (pendings.spliterator().getExactSizeIfKnown() == 0) {
|
|
||||||
log.info("No pending submission ids for podId {}", podId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// The MeF system has a limit of 100 submission ids checked per attempt
|
|
||||||
List<Set<Pending>> batchedPendings = batchPendings(pendings);
|
|
||||||
|
|
||||||
log.info("Creating ack client for podId {}", podId);
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
Date date = new Date(startTime);
|
|
||||||
log.info("Logging in at {} for podId {}", simpleDateFormat.format(date), podId);
|
|
||||||
batchedPendings.forEach(batch -> {
|
|
||||||
try {
|
|
||||||
log.info("Getting acks from MeF for batch for podId {}", podId);
|
|
||||||
getGetAcksResult(batch);
|
|
||||||
// It might one day be necessary to purge submissionIds
|
|
||||||
// It shouldn't be necessary with this service being only available
|
|
||||||
// to our internal system.
|
|
||||||
} catch (ToolkitException e) {
|
|
||||||
// TODO: if a batch fails, find the bad one and report the problem to some other system
|
|
||||||
log.error("Toolkit error getting ack on poll: {}", e.getMessage(), e);
|
|
||||||
|
|
||||||
if (batch.size() == 1) {
|
|
||||||
createToolkitError(batch.iterator().next(), e);
|
|
||||||
} else {
|
|
||||||
partitionBatch(batch);
|
|
||||||
}
|
|
||||||
} catch (ServiceException e) {
|
|
||||||
log.error("Service error getting ack on poll: {}", e.getMessage(), e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
long endTime = System.currentTimeMillis();
|
|
||||||
date = new Date(endTime);
|
|
||||||
log.info(
|
|
||||||
"Logging out at {}, elapsed time in milliseconds: {}",
|
|
||||||
simpleDateFormat.format(date),
|
|
||||||
(endTime - startTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getGetAcksResult(Set<Pending> pendings) throws ToolkitException, ServiceException {
|
|
||||||
Set<String> submissionIds =
|
|
||||||
pendings.stream().map(Pending::getSubmissionId).collect(Collectors.toSet());
|
|
||||||
GetAcksResultWrapper acknowledgements = getAcksClientService.getAcks(serviceContext, submissionIds);
|
|
||||||
// to enable parallel processing of each batch of 100 submissions, we handle each batch of acknowledgements in a
|
|
||||||
// separate thread
|
|
||||||
// once we have fetched them from MeF
|
|
||||||
new Thread(() -> bulkUpdateRecordsFromAckResultAndEnqueueStatusChangeMessages(acknowledgements, pendings))
|
|
||||||
.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void bulkUpdateRecordsFromAckResultAndEnqueueStatusChangeMessages(
|
|
||||||
GetAcksResultWrapper acksResult, Iterable<Pending> pendings) {
|
|
||||||
/*
|
|
||||||
* We start with a list of ackResults and the original Pending records in the database
|
|
||||||
* All batching logic is handle as a map of a mefSubmissionId key to an arbitrary value
|
|
||||||
* This allows us to make O(1) look ups between the various batching functions when creating new maps
|
|
||||||
* There are several steps for map and transform steps before we are ready to save/write database records
|
|
||||||
* and enqueue the SQS message back to the Backend service
|
|
||||||
*
|
|
||||||
* 1. createStatusSubmissionIdMap()
|
|
||||||
* - initializes a Map of ackStatus (accepted, rejected, pending) to an empty list
|
|
||||||
* - returns: {"accepted":[],"rejected":[],"pending":[]}
|
|
||||||
* 2. Loop through the acks and:
|
|
||||||
* a) populate the submissionIdToValidationErrorMap map submission Id to a list of lists of strings representing each part of the validationErrorGroup
|
|
||||||
* - returns {"sub_id_1" :[["R0000-904-03","Reject and Stop","Software ID in the Return Header must have passed testing for the form family and ‘TaxYr’."],
|
|
||||||
* ["F1040-525-03","Reject and Stop","If 'PINTypeCd' in the Return Header has ..."]],"sub_id_2":[[...],[...]]}
|
|
||||||
* b) populate the statusSubmissionIdMap
|
|
||||||
* - returns: {"accepted":["sub_id_3"],"rejected":["sub_id_2",],"pending":["sub_id_1"]}
|
|
||||||
*
|
|
||||||
* 3. createNewCompleteds()
|
|
||||||
* - Prepare the new Completed entities *but do not save them yet*
|
|
||||||
*
|
|
||||||
* 4. Map the Completed and Pending entities to respective maps of submissionId:Completed and submissionId:Pending
|
|
||||||
*
|
|
||||||
* 5. bulkUpdateEntities()
|
|
||||||
* - bulkGetOrCreateErrorsToRejectedAcknowledgements()
|
|
||||||
* - Create the Error entities based on the submissionIdToValidationErrorMap and save them to the database
|
|
||||||
* - at this point, the Error entities are *not* related to the Completed entities, because
|
|
||||||
* - Completed entities haven't been saved
|
|
||||||
* - returns submissionIdToError(), which is a map of submission Ids to Errors (newly created)
|
|
||||||
* - addErrorsToRejectedAcknowledgementsAndDeletePendingRecords()
|
|
||||||
* - pass the three maps (submissionIdToError,submissionIdToCompleted,submissionIdToPending) as args
|
|
||||||
* - iterate through the submissionIdToCompleted and:
|
|
||||||
* - if Errors exist, relate them to the completed
|
|
||||||
* - if the Pending exists, add it to the batch of Pendings to delete
|
|
||||||
* - in all cases, add the Completed to a batch of Completeds to persist
|
|
||||||
* - Save all Completeds in the batch to create
|
|
||||||
* - Delete all Pendings in the batch to delete
|
|
||||||
* 6. Remove pending submissions from the map of statusSubmissionIds to produce finalStatusSubmissionIds
|
|
||||||
* 7. Enqueue the finalStatusSubmissionIds to SQS and call statusChangeMessageService.publishStatusChangePayloadV1(finalStatusSubmissionIds)
|
|
||||||
* */
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = createStatusSubmissionIdMap();
|
|
||||||
Map<String, List<List<String>>> submissionIdToValidationErrorMap = new HashMap<>();
|
|
||||||
Map<String, Completed> submissionIdToCompletedMap = new HashMap<>();
|
|
||||||
Map<String, Pending> submissionIdToPendingdMap = new HashMap<>();
|
|
||||||
|
|
||||||
acksResult.getAcknowledgementsListWrapper().getAcknowledgements().forEach(acknowledgement -> {
|
|
||||||
String status = acknowledgement.getAcceptanceStatusTxt().toLowerCase();
|
|
||||||
String submissionId = acknowledgement.getSubmissionId();
|
|
||||||
submissionIdToValidationErrorMap.put(submissionId, new ArrayList<>());
|
|
||||||
if (status.equals("rejected")) {
|
|
||||||
acknowledgement.getValidationErrorList().forEach(validationErrorGrp -> {
|
|
||||||
List<String> errorMap = new ArrayList<>();
|
|
||||||
errorMap.add(validationErrorGrp.getRuleNum());
|
|
||||||
errorMap.add(validationErrorGrp.getSeverityCd());
|
|
||||||
errorMap.add(validationErrorGrp.getErrorMessageTxt());
|
|
||||||
submissionIdToValidationErrorMap.get(submissionId).add(errorMap);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
addToSubmissionIdMap(status, submissionId, statusSubmissionIdMap);
|
|
||||||
});
|
|
||||||
|
|
||||||
Iterable<Completed> completeds = createNewCompleteds(statusSubmissionIdMap);
|
|
||||||
completeds.forEach(completed -> submissionIdToCompletedMap.put(completed.getSubmissionId(), completed));
|
|
||||||
pendings.forEach(pending -> submissionIdToPendingdMap.put(pending.getSubmissionId(), pending));
|
|
||||||
|
|
||||||
bulkUpdateEntities(submissionIdToValidationErrorMap, submissionIdToCompletedMap, submissionIdToPendingdMap);
|
|
||||||
Map<String, List<String>> finalStatusSubmissionIdMap =
|
|
||||||
stripPendingAcknowledgementsFromStatusSubmissionIdMap(statusSubmissionIdMap);
|
|
||||||
|
|
||||||
if (!finalStatusSubmissionIdMap.get("rejected").isEmpty()
|
|
||||||
|| !finalStatusSubmissionIdMap.get("accepted").isEmpty()) {
|
|
||||||
statusChangeMessageService.publishStatusChangePayloadV1(finalStatusSubmissionIdMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Map<String, List<String>> stripPendingAcknowledgementsFromStatusSubmissionIdMap(
|
|
||||||
Map<String, List<String>> statusSubmssionIdMap) {
|
|
||||||
statusSubmssionIdMap.remove("pending");
|
|
||||||
return statusSubmssionIdMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Map<String, List<String>> createStatusSubmissionIdMap() {
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = new HashMap<>();
|
|
||||||
|
|
||||||
statusSubmissionIdMap.put("accepted", new ArrayList<>());
|
|
||||||
statusSubmissionIdMap.put("rejected", new ArrayList<>());
|
|
||||||
statusSubmissionIdMap.put("pending", new ArrayList<>());
|
|
||||||
return statusSubmissionIdMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Iterable<Completed> createNewCompleteds(Map<String, List<String>> statusSubmissionIdMap) {
|
|
||||||
List<Completed> completedsToCreate = new ArrayList<>();
|
|
||||||
statusSubmissionIdMap.forEach((status, submissionIdSet) -> {
|
|
||||||
if (status.equals("pending")) {
|
|
||||||
log.info("The following subIds are still pending {}", submissionIdSet.toString());
|
|
||||||
} else {
|
|
||||||
submissionIdSet.forEach(submissionId -> {
|
|
||||||
Completed completed = new Completed();
|
|
||||||
completed.setSubmissionId(submissionId);
|
|
||||||
completed.setStatus(status);
|
|
||||||
completedsToCreate.add(completed);
|
|
||||||
log.info("{} acknowledgement received from MeF", status);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return completedsToCreate;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addToSubmissionIdMap(
|
|
||||||
String status, String submissionId, Map<String, List<String>> statusSubmissionIdMap) {
|
|
||||||
MDC.put(AuditLogElement.mefSubmissionId.toString(), submissionId);
|
|
||||||
if (statusSubmissionIdMap.containsKey(status)) {
|
|
||||||
log.info(
|
|
||||||
"Acknowledgement with submissionId {} has status changed, adding to statusSubmissionIdMap",
|
|
||||||
submissionId);
|
|
||||||
statusSubmissionIdMap.get(status).add(submissionId);
|
|
||||||
} else {
|
|
||||||
// default case where the status is not present or not one we expect
|
|
||||||
// TODO: handle the exception status case when/if necessary
|
|
||||||
log.error("Missing a status type: {}", status);
|
|
||||||
}
|
|
||||||
MDC.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bulkUpdateEntities(
|
|
||||||
Map<String, List<List<String>>> validationErrorMap,
|
|
||||||
Map<String, Completed> submissionIdToCompleted,
|
|
||||||
Map<String, Pending> submissionIdToPending) {
|
|
||||||
Map<String, List<Error>> submissionIdToError =
|
|
||||||
bulkGetOrCreateErrorsToRejectedAcknowledgements(validationErrorMap);
|
|
||||||
addErrorsToRejectedAcknowledgementsAndDeletePendingRecords(
|
|
||||||
submissionIdToError, submissionIdToCompleted, submissionIdToPending);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Map<String, List<Error>> bulkGetOrCreateErrorsToRejectedAcknowledgements(
|
|
||||||
Map<String, List<List<String>>> validationErrorMap) {
|
|
||||||
|
|
||||||
List<Error> errorList = new ArrayList<>();
|
|
||||||
Map<String, List<Error>> submissionIdToError = new HashMap<>();
|
|
||||||
|
|
||||||
validationErrorMap.forEach((submissionId, validationErrorGrp) -> {
|
|
||||||
submissionIdToError.put(submissionId, new ArrayList<>());
|
|
||||||
validationErrorGrp.forEach(validationError -> {
|
|
||||||
String ruleNum = validationError.get(0);
|
|
||||||
String severityCd = validationError.get(1);
|
|
||||||
String errorMessageTxt = validationError.get(2);
|
|
||||||
var databaseError = errorRepo.findById(ruleNum);
|
|
||||||
if (databaseError.isPresent()) {
|
|
||||||
log.info(String.format("Found reject reason %s", ruleNum));
|
|
||||||
Error existingError = databaseError.get();
|
|
||||||
errorList.add(existingError);
|
|
||||||
submissionIdToError.get(submissionId).add(existingError);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log.warn(String.format("New reject reason found: %s. New translation required", ruleNum));
|
|
||||||
Error newError = new Error();
|
|
||||||
newError.setMefErrorCode(ruleNum);
|
|
||||||
newError.setErrorCodeTranslationKey(CreateTranslationKey("reject", ruleNum));
|
|
||||||
newError.setMefErrorCategory(severityCd);
|
|
||||||
newError.setErrorMessage(errorMessageTxt);
|
|
||||||
log.info(String.format("Saving new reject reason %s", ruleNum));
|
|
||||||
errorList.add(newError);
|
|
||||||
submissionIdToError.get(submissionId).add(newError);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
errorRepo.saveAll(errorList);
|
|
||||||
return submissionIdToError;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addErrorsToRejectedAcknowledgementsAndDeletePendingRecords(
|
|
||||||
Map<String, List<Error>> submissionIdToError,
|
|
||||||
Map<String, Completed> submissionIdToCompleted,
|
|
||||||
Map<String, Pending> submissionIdToPending) {
|
|
||||||
List<Completed> completedToSave = new ArrayList<>();
|
|
||||||
List<Pending> pendingToDelete = new ArrayList<>();
|
|
||||||
submissionIdToCompleted.forEach((submissionId, completed) -> {
|
|
||||||
List<Error> errorsToPersist = submissionIdToError.get(submissionId);
|
|
||||||
Optional<Pending> pending = Optional.ofNullable(submissionIdToPending.get(submissionId));
|
|
||||||
if (errorsToPersist != null
|
|
||||||
&& !errorsToPersist.isEmpty()
|
|
||||||
&& completed.getStatus().toLowerCase().compareTo("rejected") == 0) {
|
|
||||||
completed.setErrors(errorsToPersist);
|
|
||||||
}
|
|
||||||
completedToSave.add(completed);
|
|
||||||
if (pending.isPresent()) {
|
|
||||||
Pending p = pending.get();
|
|
||||||
pendingToDelete.add(p);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
log.info(String.format("Creating %s completed objects", completedToSave.size()));
|
|
||||||
completedRepo.saveAll(completedToSave);
|
|
||||||
log.info(String.format("Deleting %s pending objects", pendingToDelete.size()));
|
|
||||||
pendingRepo.deleteAll(pendingToDelete);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void createToolkitError(Pending pending, Exception e) {
|
|
||||||
String submissionId = pending.getSubmissionId();
|
|
||||||
ToolkitError tke = new ToolkitError();
|
|
||||||
tke.setSubmissionId(submissionId);
|
|
||||||
tke.setErrorName(e.getClass().getName());
|
|
||||||
tke.setErrorMessage(e.toString());
|
|
||||||
|
|
||||||
toolkitErrorRepo.save(tke);
|
|
||||||
|
|
||||||
// delete the corresponding pending record
|
|
||||||
try {
|
|
||||||
deletePendingRecord(submissionId);
|
|
||||||
} catch (EntityNotFoundException notFoundException) {
|
|
||||||
log.error(notFoundException.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deletePendingRecord(String submissionId) {
|
|
||||||
Pending p = pendingRepo
|
|
||||||
.findById(submissionId)
|
|
||||||
.orElseThrow(() -> new EntityNotFoundException(
|
|
||||||
String.format("Submission with id [%s] was not found in the database!", submissionId)));
|
|
||||||
pendingRepo.delete(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AcknowledgementStatus getCompletedStatus(Completed c) {
|
|
||||||
if (c.getStatus().toLowerCase().compareTo("accepted") == 0) {
|
|
||||||
return new AcknowledgementStatus(
|
|
||||||
Status.Accepted, CreateTranslationKey("status", "accepted"), List.of(), c.getCreatedAt());
|
|
||||||
} else if (c.getStatus().toLowerCase().compareTo("rejected") == 0) {
|
|
||||||
return new AcknowledgementStatus(
|
|
||||||
Status.Rejected,
|
|
||||||
CreateTranslationKey("status", "rejected"),
|
|
||||||
createRejectedReasonList(c),
|
|
||||||
c.getCreatedAt());
|
|
||||||
} else {
|
|
||||||
throw new RuntimeException("Missing status type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<RejectedStatus> createRejectedReasonList(Completed c) {
|
|
||||||
List<RejectedStatus> statuses = new ArrayList<>();
|
|
||||||
if (c.getErrors() != null) {
|
|
||||||
c.getErrors()
|
|
||||||
.forEach(x -> statuses.add(new RejectedStatus(
|
|
||||||
x.getMefErrorCode(), x.getErrorCodeTranslationKey(), x.getErrorMessage())));
|
|
||||||
}
|
|
||||||
|
|
||||||
return statuses;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String CreateTranslationKey(String type, String name) {
|
|
||||||
return String.join(
|
|
||||||
statusProperties.getTranslationKeySplitter(), statusProperties.getRootTranslationKey(), type, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void partitionBatch(Set<Pending> pBatch) {
|
|
||||||
Iterable<List<Pending>> partitions =
|
|
||||||
Iterables.partition(pBatch, IntMath.divide(pBatch.size(), 2, RoundingMode.CEILING));
|
|
||||||
|
|
||||||
partitions.forEach(partition -> {
|
|
||||||
try {
|
|
||||||
getGetAcksResult(new HashSet<>(partition));
|
|
||||||
} catch (ToolkitException tke) {
|
|
||||||
if (partition.size() == 1) {
|
|
||||||
// report and flag bad data to db
|
|
||||||
createToolkitError(partition.get(0), tke);
|
|
||||||
} else {
|
|
||||||
partitionBatch(new HashSet<>(partition));
|
|
||||||
}
|
|
||||||
} catch (ServiceException se) {
|
|
||||||
if (partition.size() == 1) {
|
|
||||||
log.warn("ServiceException - " + se);
|
|
||||||
} else {
|
|
||||||
partitionBatch(new HashSet<>(partition));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.Completed;
|
|
||||||
|
|
||||||
public interface CompletedAcknowledgementRepository extends CrudRepository<Completed, String> {
|
|
||||||
|
|
||||||
@Query(value = "SELECT * FROM completed WHERE submission_id = :submissionId LIMIT 1", nativeQuery = true)
|
|
||||||
Optional<Completed> GetCompletedSubmission(String submissionId);
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
|
|
||||||
public interface PendingAcknowledgementRepository extends CrudRepository<Pending, String> {
|
|
||||||
|
|
||||||
@Query(value = "SELECT * FROM pending WHERE submission_id = :submissionId LIMIT 1", nativeQuery = true)
|
|
||||||
Optional<Pending> GetPendingSubmission(String submissionId);
|
|
||||||
|
|
||||||
@Query(value = "SELECT * FROM pending WHERE pod_id = :podId ORDER BY created_at asc", nativeQuery = true)
|
|
||||||
List<Pending> findAllByPodId(String podId);
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.TaxReturnSubmission;
|
|
||||||
|
|
||||||
public interface TaxReturnSubmissionRepository extends CrudRepository<TaxReturnSubmission, Long> {
|
|
||||||
@Query(
|
|
||||||
value =
|
|
||||||
"SELECT submission_id FROM tax_return_submission WHERE tax_return_id = :taxReturnId ORDER BY CREATED_AT DESC LIMIT 1",
|
|
||||||
nativeQuery = true)
|
|
||||||
Optional<String> getLatestSubmissionIdByTaxReturnId(UUID taxReturnId);
|
|
||||||
|
|
||||||
@Query(
|
|
||||||
value =
|
|
||||||
"""
|
|
||||||
SELECT trs.submission_id
|
|
||||||
FROM tax_return_submission trs
|
|
||||||
JOIN completed c ON trs.submission_id = c.submission_id
|
|
||||||
WHERE trs.tax_return_id = :taxReturnId
|
|
||||||
AND LOWER(c.status) = 'accepted'
|
|
||||||
ORDER BY c.created_at DESC LIMIT 1
|
|
||||||
""",
|
|
||||||
nativeQuery = true)
|
|
||||||
Optional<String> getLatestAcceptedSubmissionIdForTaxReturnId(UUID taxReturnId);
|
|
||||||
|
|
||||||
@Query(
|
|
||||||
value =
|
|
||||||
"""
|
|
||||||
SELECT trs.submission_id
|
|
||||||
FROM tax_return_submission trs
|
|
||||||
JOIN completed c ON trs.submission_id = c.submission_id
|
|
||||||
WHERE
|
|
||||||
trs.tax_return_id = (
|
|
||||||
SELECT tax_return_id
|
|
||||||
FROM tax_return_submission
|
|
||||||
WHERE submission_id = :submissionId
|
|
||||||
)
|
|
||||||
AND LOWER(c.status) = 'accepted'
|
|
||||||
ORDER BY c.created_at DESC LIMIT 1
|
|
||||||
""",
|
|
||||||
nativeQuery = true)
|
|
||||||
Optional<String> getLatestAcceptedSubmissionIdOfParentTaxReturn(String submissionId);
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement.domain;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.RejectedStatus;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AcknowledgementStatus {
|
|
||||||
private Status status;
|
|
||||||
private String translationKey;
|
|
||||||
private List<RejectedStatus> rejectionCodes;
|
|
||||||
private Date createdAt;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement.domain;
|
|
||||||
|
|
||||||
public enum Status {
|
|
||||||
Pending,
|
|
||||||
Accepted,
|
|
||||||
Rejected,
|
|
||||||
Error,
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "aws")
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Getter
|
|
||||||
public class AWSClientConfiguration {
|
|
||||||
private String accessKey;
|
|
||||||
private String secretKey;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@AllArgsConstructor
|
|
||||||
@EnableConfigurationProperties(AWSClientConfiguration.class)
|
|
||||||
public class AWSCredentialsConfiguration {
|
|
||||||
private final AWSClientConfiguration awsClientConfiguration;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnProperty(
|
|
||||||
name = "aws.default-credentials-provider-chain-enabled",
|
|
||||||
havingValue = "false",
|
|
||||||
matchIfMissing = true)
|
|
||||||
public AwsCredentialsProvider staticAWSCredentialsProvider() {
|
|
||||||
return StaticCredentialsProvider.create(AwsBasicCredentials.create(
|
|
||||||
awsClientConfiguration.getAccessKey(), awsClientConfiguration.getSecretKey()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnProperty(name = "aws.default-credentials-provider-chain-enabled", havingValue = "true")
|
|
||||||
public AwsCredentialsProvider defaultAWSCredentialsProvider() {
|
|
||||||
return DefaultCredentialsProvider.create();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.Base64;
|
|
||||||
import javax.crypto.SecretKey;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.regions.Region;
|
|
||||||
import software.amazon.awssdk.services.kms.KmsClient;
|
|
||||||
import software.amazon.encryption.s3.materials.CryptographicMaterialsManager;
|
|
||||||
import software.amazon.encryption.s3.materials.DefaultCryptoMaterialsManager;
|
|
||||||
import software.amazon.encryption.s3.materials.KmsKeyring;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@AllArgsConstructor
|
|
||||||
@EnableConfigurationProperties(EncryptionConfiguration.class)
|
|
||||||
public class EncryptionClientConfiguration {
|
|
||||||
private final EncryptionConfiguration encryptionConfig;
|
|
||||||
private final AwsCredentialsProvider awsCredentialsProvider;
|
|
||||||
|
|
||||||
public CryptographicMaterialsManager kmsCrypto(@NonNull String kmsWrappingKeyArn) {
|
|
||||||
return DefaultCryptoMaterialsManager.builder()
|
|
||||||
.keyring(KmsKeyring.builder()
|
|
||||||
.kmsClient(regionalKmsClient())
|
|
||||||
.wrappingKeyId(kmsWrappingKeyArn)
|
|
||||||
.build())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public SecretKey getLocalAesWrappingKey() {
|
|
||||||
return new SecretKeySpec(Base64.getDecoder().decode(encryptionConfig.getLocalWrappingKey()), "AES");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected KmsClient regionalKmsClient() {
|
|
||||||
return KmsClient.builder()
|
|
||||||
.region(Region.of(encryptionConfig.getRegion()))
|
|
||||||
.credentialsProvider(awsCredentialsProvider)
|
|
||||||
.endpointOverride(URI.create(encryptionConfig.getKmsEndpoint()))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Getter
|
|
||||||
@ConfigurationProperties
|
|
||||||
public class EncryptionConfiguration {
|
|
||||||
@Value("${aws.kmsEndpoint:#{null}}")
|
|
||||||
private String kmsEndpoint;
|
|
||||||
|
|
||||||
@Value("${aws.region:#{null}}")
|
|
||||||
private String region;
|
|
||||||
|
|
||||||
@Value("${direct-file.local-encryption.local-wrapping-key:#{null}}")
|
|
||||||
private String localWrappingKey;
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.hibernate.validator.constraints.URL;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
|
|
||||||
@Validated
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Getter
|
|
||||||
// See https://stackoverflow.com/a/67994421 for why we use kebab case here (message-queue)
|
|
||||||
// when we're using camel case (messageQueue) in the source.
|
|
||||||
@ConfigurationProperties("status.message-queue")
|
|
||||||
public class MessageQueueConfiguration {
|
|
||||||
@NotBlank
|
|
||||||
@URL
|
|
||||||
private final String endpoint;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String statusChangeQueue;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String pendingSubmissionQueue;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String dlqPendingSubmissionQueue;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String region;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String accessKey;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String secretKey;
|
|
||||||
|
|
||||||
private final boolean sqsMessageHandlingEnabled;
|
|
||||||
|
|
||||||
private final boolean statusChangePublishEnabled;
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.regions.Region;
|
|
||||||
import software.amazon.awssdk.services.sns.SnsClient;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnProperty(value = "status.sns.status-change-publish-enabled", havingValue = "true")
|
|
||||||
@EnableConfigurationProperties(SnsConfiguration.class)
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SnsClientConfiguration {
|
|
||||||
private final AwsCredentialsProvider awsCredentialsProvider;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SnsClient snsClient(SnsConfiguration snsConfiguration) {
|
|
||||||
return SnsClient.builder()
|
|
||||||
.region(Region.of(snsConfiguration.getRegion()))
|
|
||||||
.credentialsProvider(awsCredentialsProvider)
|
|
||||||
.endpointOverride(URI.create(snsConfiguration.getEndpoint()))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.hibernate.validator.constraints.URL;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
|
|
||||||
@Validated
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Getter
|
|
||||||
@ConfigurationProperties("status.sns")
|
|
||||||
public class SnsConfiguration {
|
|
||||||
@NotBlank
|
|
||||||
@URL
|
|
||||||
private final String endpoint;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String statusChangeTopicArn;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String region;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String accessKey;
|
|
||||||
|
|
||||||
@NotBlank
|
|
||||||
private final String secretKey;
|
|
||||||
|
|
||||||
private final boolean statusChangePublishEnabled;
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.regions.Region;
|
|
||||||
import software.amazon.awssdk.services.sqs.SqsClient;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableConfigurationProperties(MessageQueueConfiguration.class)
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SqsClientConfiguration {
|
|
||||||
private final AwsCredentialsProvider awsCredentialsProvider;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SqsClient sqsClient(MessageQueueConfiguration messageQueueConfiguration) {
|
|
||||||
return SqsClient.builder()
|
|
||||||
.region(Region.of(messageQueueConfiguration.getRegion()))
|
|
||||||
.credentialsProvider(awsCredentialsProvider)
|
|
||||||
.endpointOverride(URI.create(messageQueueConfiguration.getEndpoint()))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"NM_FIELD_NAMING_CONVENTION"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Getter
|
|
||||||
@Validated
|
|
||||||
@ConfigurationProperties(prefix = "status")
|
|
||||||
public class StatusProperties {
|
|
||||||
@NotBlank
|
|
||||||
private String applicationId;
|
|
||||||
|
|
||||||
private String keystoreBase64;
|
|
||||||
private String keystorePassword;
|
|
||||||
private String keystoreAlias;
|
|
||||||
private String etin;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private String asid;
|
|
||||||
|
|
||||||
private String efin;
|
|
||||||
private boolean unitTesting;
|
|
||||||
private boolean prod;
|
|
||||||
private String rootTranslationKey;
|
|
||||||
private String translationKeySplitter;
|
|
||||||
public Long AckPollInMilliseconds;
|
|
||||||
public boolean statusEndpointReturnsPendingByDefaultEnabled;
|
|
||||||
private String toolkit;
|
|
||||||
private boolean statusPollingEnabled;
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import gov.irs.mef.AcknowledgementList;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class AcknowledgementWrapper {
|
|
||||||
private final String submissionId;
|
|
||||||
private final String receiptId;
|
|
||||||
private final String acceptanceStatusTxt;
|
|
||||||
private final List<ValidationErrorGrpWrapper> validationErrorList;
|
|
||||||
|
|
||||||
public AcknowledgementWrapper(String submissionId, String receiptId, String acceptanceStatusTxt) {
|
|
||||||
this(submissionId, receiptId, acceptanceStatusTxt, List.of());
|
|
||||||
}
|
|
||||||
|
|
||||||
public AcknowledgementWrapper(
|
|
||||||
String submissionId,
|
|
||||||
String receiptId,
|
|
||||||
String acceptanceStatusTxt,
|
|
||||||
List<ValidationErrorGrpWrapper> validationErrorList) {
|
|
||||||
this.submissionId = submissionId;
|
|
||||||
this.receiptId = receiptId;
|
|
||||||
this.acceptanceStatusTxt = acceptanceStatusTxt;
|
|
||||||
this.validationErrorList = List.copyOf(validationErrorList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AcknowledgementWrapper fromMefAcknowledgement(AcknowledgementList.Acknowledgement acknowledgement) {
|
|
||||||
if (acknowledgement.getValidationErrorList() == null) {
|
|
||||||
return new AcknowledgementWrapper(
|
|
||||||
acknowledgement.getSubmissionId(),
|
|
||||||
acknowledgement.getReceiptId(),
|
|
||||||
acknowledgement.getAcceptanceStatusTxt(),
|
|
||||||
new ArrayList<>());
|
|
||||||
} else {
|
|
||||||
List<ValidationErrorGrpWrapper> validationErrors =
|
|
||||||
acknowledgement.getValidationErrorList().getValidationErrorGrp().stream()
|
|
||||||
.map(ValidationErrorGrpWrapper::fromMefValidationErrorGrp)
|
|
||||||
.toList();
|
|
||||||
return new AcknowledgementWrapper(
|
|
||||||
acknowledgement.getSubmissionId(),
|
|
||||||
acknowledgement.getReceiptId(),
|
|
||||||
acknowledgement.getAcceptanceStatusTxt(),
|
|
||||||
validationErrors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import gov.irs.mef.AcknowledgementList;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class AcknowledgementsListWrapper {
|
|
||||||
private final List<AcknowledgementWrapper> acknowledgements;
|
|
||||||
|
|
||||||
public AcknowledgementsListWrapper(AcknowledgementList acknowledgementList) {
|
|
||||||
this.acknowledgements = List.copyOf(acknowledgementList.getAcknowledgements().stream()
|
|
||||||
.map(AcknowledgementWrapper::fromMefAcknowledgement)
|
|
||||||
.collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public AcknowledgementsListWrapper(List<AcknowledgementWrapper> acknowledgementWrappers) {
|
|
||||||
this.acknowledgements = List.copyOf(acknowledgementWrappers);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@Entity(name = "Completed")
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class Completed {
|
|
||||||
@Id
|
|
||||||
@Column(length = 20)
|
|
||||||
private String submissionId;
|
|
||||||
|
|
||||||
@Column(length = 20)
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "DEFAULT CURRENT_TIMESTAMP")
|
|
||||||
@CreationTimestamp
|
|
||||||
private Date createdAt;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@ManyToMany(fetch = FetchType.EAGER)
|
|
||||||
@JoinTable(
|
|
||||||
name = "completed-errors",
|
|
||||||
joinColumns = {
|
|
||||||
@JoinColumn(
|
|
||||||
name = "submissionId",
|
|
||||||
referencedColumnName = "submissionId",
|
|
||||||
foreignKey = @ForeignKey(name = "completed_error_submission_id_fk"))
|
|
||||||
},
|
|
||||||
inverseJoinColumns = {
|
|
||||||
@JoinColumn(
|
|
||||||
name = "mefErrorCode",
|
|
||||||
referencedColumnName = "meferror_code",
|
|
||||||
foreignKey = @ForeignKey(name = "completed_error_mef_error_code_fk"))
|
|
||||||
})
|
|
||||||
private List<Error> errors;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.ToString;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
|
||||||
|
|
||||||
@Entity(name = "Error")
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@ToString(doNotUseGetters = true)
|
|
||||||
public class Error {
|
|
||||||
@Id
|
|
||||||
@Column(name = "meferror_code", length = 25)
|
|
||||||
private String mefErrorCode;
|
|
||||||
|
|
||||||
@Column(name = "error_message", columnDefinition = "TEXT")
|
|
||||||
private String errorMessage;
|
|
||||||
|
|
||||||
@Column(name = "meferror_category")
|
|
||||||
private String mefErrorCategory;
|
|
||||||
|
|
||||||
private String errorCodeTranslationKey;
|
|
||||||
|
|
||||||
@Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "DEFAULT CURRENT_TIMESTAMP")
|
|
||||||
@CreationTimestamp
|
|
||||||
private LocalDate createdAt;
|
|
||||||
|
|
||||||
@ManyToMany(mappedBy = "errors")
|
|
||||||
@JsonBackReference
|
|
||||||
private List<Completed> completed;
|
|
||||||
|
|
||||||
public List<Completed> getCompleted() {
|
|
||||||
return List.copyOf(completed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCompleted(List<Completed> completed) {
|
|
||||||
this.completed = List.copyOf(completed);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import gov.irs.mef.services.transmitter.mtom.GetAcksResult;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class GetAcksResultWrapper {
|
|
||||||
private AcknowledgementsListWrapper acknowledgementsListWrapper;
|
|
||||||
|
|
||||||
public GetAcksResultWrapper(GetAcksResult getAcksResult) {
|
|
||||||
this.acknowledgementsListWrapper = new AcknowledgementsListWrapper(getAcksResult.getAcknowledgementList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public GetAcksResultWrapper(AcknowledgementsListWrapper acknowledgementsListWrapper) {
|
|
||||||
this.acknowledgementsListWrapper = acknowledgementsListWrapper;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
|
||||||
import org.hibernate.annotations.JdbcTypeCode;
|
|
||||||
import org.hibernate.type.SqlTypes;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2", "NM_FIELD_NAMING_CONVENTION"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@Entity(name = "Pending")
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class Pending {
|
|
||||||
@Id
|
|
||||||
@Column(length = 20)
|
|
||||||
private String submissionId;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "DEFAULT CURRENT_TIMESTAMP")
|
|
||||||
@CreationTimestamp
|
|
||||||
private Date createdAt;
|
|
||||||
|
|
||||||
@JdbcTypeCode(SqlTypes.VARCHAR)
|
|
||||||
@Column(columnDefinition = "varchar", name = "pod_id", length = 255)
|
|
||||||
private String podId;
|
|
||||||
|
|
||||||
public Pending() {}
|
|
||||||
|
|
||||||
public Pending(final String submissionId) {
|
|
||||||
this.submissionId = submissionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pending(String submissionId, String podId) {
|
|
||||||
this.submissionId = submissionId;
|
|
||||||
this.podId = podId;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.annotations.JdbcTypeCode;
|
|
||||||
import org.hibernate.type.SqlTypes;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@Entity(name = "PodIdentifier")
|
|
||||||
@Table(name = "pod_identifier")
|
|
||||||
public class PodIdentifier {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@JdbcTypeCode(SqlTypes.VARCHAR)
|
|
||||||
@Column(columnDefinition = "varchar", name = "asid", length = 50)
|
|
||||||
private String asid;
|
|
||||||
|
|
||||||
@JdbcTypeCode(SqlTypes.VARCHAR)
|
|
||||||
@Column(columnDefinition = "varchar", name = "region", length = 50)
|
|
||||||
private String region;
|
|
||||||
|
|
||||||
@JdbcTypeCode(SqlTypes.VARCHAR)
|
|
||||||
@Column(columnDefinition = "varchar", name = "pod_id", length = 255)
|
|
||||||
private String podId;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@Entity(name = "TaxReturnSubmission")
|
|
||||||
@Table(name = "tax_return_submission")
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class TaxReturnSubmission {
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private UUID taxReturnId;
|
|
||||||
|
|
||||||
@Column(length = 20)
|
|
||||||
private String submissionId;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "DEFAULT CURRENT_TIMESTAMP")
|
|
||||||
@CreationTimestamp
|
|
||||||
private Date createdAt;
|
|
||||||
|
|
||||||
public TaxReturnSubmission(UUID taxReturnId, String submissionId) {
|
|
||||||
this.taxReturnId = taxReturnId;
|
|
||||||
this.submissionId = submissionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TaxReturnSubmission() {}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
|
||||||
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"NM_FIELD_NAMING_CONVENTION", "EI_EXPOSE_REP", "EI_EXPOSE_REP2"},
|
|
||||||
justification = "Initial SpotBugs Setup")
|
|
||||||
@Entity
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class ToolkitError {
|
|
||||||
@Id
|
|
||||||
private String submissionId;
|
|
||||||
|
|
||||||
@NotNull private String errorMessage;
|
|
||||||
|
|
||||||
@NotNull private String errorName;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Column(name = "created_at", nullable = false, updatable = false, columnDefinition = "DEFAULT CURRENT_TIMESTAMP")
|
|
||||||
@CreationTimestamp
|
|
||||||
private Date createdAt;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package gov.irs.directfile.status.domain;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import gov.irs.efile.ValidationErrorListType;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class ValidationErrorGrpWrapper {
|
|
||||||
private String ruleNum;
|
|
||||||
private String severityCd;
|
|
||||||
private String errorMessageTxt;
|
|
||||||
|
|
||||||
public static ValidationErrorGrpWrapper fromMefValidationErrorGrp(
|
|
||||||
ValidationErrorListType.ValidationErrorGrp validationErrorGrp) {
|
|
||||||
return new ValidationErrorGrpWrapper(
|
|
||||||
validationErrorGrp.getRuleNum(),
|
|
||||||
validationErrorGrp.getSeverityCd(),
|
|
||||||
validationErrorGrp.getErrorMessageTxt());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package gov.irs.directfile.status.error;
|
|
||||||
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.Error;
|
|
||||||
|
|
||||||
public interface ErrorRepository extends CrudRepository<Error, String> {}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package gov.irs.directfile.status.error;
|
|
||||||
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
import org.springframework.stereotype.Repository;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.ToolkitError;
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
public interface ToolkitErrorRepository extends CrudRepository<ToolkitError, String> {}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package gov.irs.directfile.status.mef.client;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import gov.irs.mef.services.ServiceContext;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@SuppressFBWarnings(
|
|
||||||
value = {"EI_EXPOSE_REP", "EI_EXPOSE_REP2"},
|
|
||||||
justification = "The Getter and Setter are auto-generated by Lombox.")
|
|
||||||
public class ServiceContextWrapper {
|
|
||||||
private final ServiceContext serviceContext;
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package gov.irs.directfile.status.repository;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.PodIdentifier;
|
|
||||||
|
|
||||||
public interface PodIdentifierRepository extends CrudRepository<PodIdentifier, Long> {
|
|
||||||
|
|
||||||
@Query(value = "SELECT asid from pod_identifier WHERE pod_id = :pod_id", nativeQuery = true)
|
|
||||||
Optional<String> findAsidByPodId(String pod_id);
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import jakarta.jms.Message;
|
|
||||||
import jakarta.jms.MessageListener;
|
|
||||||
import jakarta.jms.TextMessage;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
import gov.irs.directfile.models.message.pending.VersionedPendingSubmissionMessage;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.AbstractPendingSubmissionPayload;
|
|
||||||
import gov.irs.directfile.status.config.MessageQueueConfiguration;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@ConditionalOnProperty(value = "status.messageQueue.sqs-message-handling-enabled", havingValue = "true")
|
|
||||||
@EnableConfigurationProperties(MessageQueueConfiguration.class)
|
|
||||||
public class MessageQueueListenerService implements MessageListener {
|
|
||||||
private final String pendingSubmissionQueue;
|
|
||||||
private final PendingSubmissionMessageRouter pendingSubmissionMessageRouter;
|
|
||||||
private final SubmissionConfirmationMessageRouter submissionConfirmationMessageRouter;
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
MessageQueueListenerService(
|
|
||||||
MessageQueueConfiguration messageQueueConfiguration,
|
|
||||||
PendingSubmissionMessageRouter pendingSubmissionMessageRouter,
|
|
||||||
SubmissionConfirmationMessageRouter submissionConfirmationMessageRouter) {
|
|
||||||
this.pendingSubmissionQueue = messageQueueConfiguration.getPendingSubmissionQueue();
|
|
||||||
this.pendingSubmissionMessageRouter = pendingSubmissionMessageRouter;
|
|
||||||
this.submissionConfirmationMessageRouter = submissionConfirmationMessageRouter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMessage(Message message) {
|
|
||||||
log.info("onMessage called ({})", pendingSubmissionQueue);
|
|
||||||
|
|
||||||
String rawText = "";
|
|
||||||
try {
|
|
||||||
rawText = ((TextMessage) message).getText();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// First try to deserialize as a VersionedPendingSubmissionMessage (what SQS would send)
|
|
||||||
log.info("Trying to deserialize message to VersionedPendingSubmissionMessage");
|
|
||||||
VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> versionedPendingSubmissionMessage =
|
|
||||||
objectMapper.readValue(rawText, new TypeReference<>() {});
|
|
||||||
pendingSubmissionMessageRouter.handlePendingSubmissionMessage(versionedPendingSubmissionMessage);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
// Otherwise, try to deserialize as a VersionedSubmissionConfirmationMessage (what SNS would send)
|
|
||||||
log.info("Trying to deserialize message to VersionedSubmissionConfirmationMessage");
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload>
|
|
||||||
versionedSubmissionConfirmationMessage =
|
|
||||||
objectMapper.readValue(rawText, new TypeReference<>() {});
|
|
||||||
submissionConfirmationMessageRouter.handleSubmissionConfirmationMessage(
|
|
||||||
versionedSubmissionConfirmationMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
message.acknowledge();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error(
|
|
||||||
"Error saving Pending objects in database. Re-queueing list of submissionIds: {}. Error: {}",
|
|
||||||
rawText,
|
|
||||||
e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.exception.UnsupportedVersionException;
|
|
||||||
import gov.irs.directfile.models.message.pending.PendingSubmissionMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.pending.VersionedPendingSubmissionMessage;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.AbstractPendingSubmissionPayload;
|
|
||||||
import gov.irs.directfile.status.services.handlers.pending.PendingSubmissionHandler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.pending.PendingSubmissionV1Handler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.pending.UnsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class PendingSubmissionMessageRouter {
|
|
||||||
private final Map<PendingSubmissionMessageVersion, PendingSubmissionHandler> handlers = new HashMap<>();
|
|
||||||
private final UnsupportedMessageVersionHandler unsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
public PendingSubmissionMessageRouter(
|
|
||||||
UnsupportedMessageVersionHandler unsupportedMessageVersionHandler,
|
|
||||||
PendingSubmissionV1Handler pendingSubmissionV1Handler) {
|
|
||||||
this.unsupportedMessageVersionHandler = unsupportedMessageVersionHandler;
|
|
||||||
this.handlers.put(PendingSubmissionMessageVersion.V1, pendingSubmissionV1Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handlePendingSubmissionMessage(
|
|
||||||
VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> message) {
|
|
||||||
QueueMessageHeaders headers = message.getHeaders();
|
|
||||||
Optional<String> versionOptional = headers.getAttribute(MessageHeaderAttribute.VERSION);
|
|
||||||
|
|
||||||
// We can assume a version number is present here since a VersionedPendingSubmissionMessage
|
|
||||||
// mandates that on construction.
|
|
||||||
|
|
||||||
// Get enum for this version (may throw UnsupportedVersionException which we should handle and
|
|
||||||
// rethrow to get message back on queue/DLQ).
|
|
||||||
PendingSubmissionMessageVersion version;
|
|
||||||
try {
|
|
||||||
version = PendingSubmissionMessageVersion.getEnum(versionOptional.get());
|
|
||||||
} catch (UnsupportedVersionException e) {
|
|
||||||
unsupportedMessageVersionHandler.handlePendingSubmissionMessage(message);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get handler. If not found, we have an unsupported version so handle and throw exception.
|
|
||||||
PendingSubmissionHandler handler = handlers.get(version);
|
|
||||||
if (handler == null) {
|
|
||||||
unsupportedMessageVersionHandler.handlePendingSubmissionMessage(message);
|
|
||||||
throw new UnsupportedVersionException(
|
|
||||||
String.format("No handler found for PendingSubmissionMessageVersion (%s)", version.getVersion()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should have a good handler, so handle the message.
|
|
||||||
handler.handlePendingSubmissionMessage(message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import com.amazon.sqs.javamessaging.ProviderConfiguration;
|
|
||||||
import com.amazon.sqs.javamessaging.SQSConnection;
|
|
||||||
import com.amazon.sqs.javamessaging.SQSConnectionFactory;
|
|
||||||
import com.amazon.sqs.javamessaging.SQSSession;
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|
||||||
import jakarta.annotation.PreDestroy;
|
|
||||||
import jakarta.jms.JMSException;
|
|
||||||
import jakarta.jms.MessageConsumer;
|
|
||||||
import jakarta.jms.Queue;
|
|
||||||
import jakarta.jms.Session;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import software.amazon.awssdk.services.sqs.SqsClient;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.config.MessageQueueConfiguration;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@ConditionalOnProperty(value = "status.messageQueue.sqs-message-handling-enabled", havingValue = "true")
|
|
||||||
@Slf4j
|
|
||||||
@SuppressFBWarnings(value = "CT_CONSTRUCTOR_THROW", justification = "Java 21 update")
|
|
||||||
@SuppressWarnings({"PMD.CloseResource", "PMD.UnusedPrivateMethod"})
|
|
||||||
@EnableConfigurationProperties(MessageQueueConfiguration.class)
|
|
||||||
public class SqsConnectionSetupService {
|
|
||||||
private final SqsClient sqsClient;
|
|
||||||
private final String pendingSubmissionQueue;
|
|
||||||
private final MessageQueueListenerService messageQueueListenerService;
|
|
||||||
private SQSConnection connection;
|
|
||||||
|
|
||||||
SqsConnectionSetupService(
|
|
||||||
SqsClient sqsClient,
|
|
||||||
MessageQueueConfiguration messageQueueConfiguration,
|
|
||||||
MessageQueueListenerService messageQueueListenerService)
|
|
||||||
throws JMSException {
|
|
||||||
this.sqsClient = sqsClient;
|
|
||||||
this.pendingSubmissionQueue = messageQueueConfiguration.getPendingSubmissionQueue();
|
|
||||||
this.messageQueueListenerService = messageQueueListenerService;
|
|
||||||
|
|
||||||
initializeSQSConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeSQSConnection() throws JMSException {
|
|
||||||
SQSConnectionFactory connectionFactory = new SQSConnectionFactory(new ProviderConfiguration(), sqsClient);
|
|
||||||
connection = connectionFactory.createConnection();
|
|
||||||
|
|
||||||
Session session = connection.createSession(false, SQSSession.UNORDERED_ACKNOWLEDGE);
|
|
||||||
Queue queue = session.createQueue(pendingSubmissionQueue);
|
|
||||||
MessageConsumer consumer = session.createConsumer(queue);
|
|
||||||
consumer.setMessageListener(messageQueueListenerService);
|
|
||||||
|
|
||||||
connection.start();
|
|
||||||
log.info("CONNECTED TO SQS");
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreDestroy
|
|
||||||
private void cleanup() throws JMSException {
|
|
||||||
if (connection != null) {
|
|
||||||
connection.stop();
|
|
||||||
log.info("SQS connection stopped");
|
|
||||||
connection.close();
|
|
||||||
log.info("SQS connection closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.PublisherException;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.status.StatusChangeMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.status.VersionedStatusChangeMessage;
|
|
||||||
import gov.irs.directfile.models.message.status.payload.AbstractStatusChangePayload;
|
|
||||||
import gov.irs.directfile.models.message.status.payload.StatusChangePayloadV1;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
public class StatusChangeMessageService {
|
|
||||||
private final List<StatusChangePublisher> publishers;
|
|
||||||
private final ObjectMapper mapper;
|
|
||||||
|
|
||||||
public StatusChangeMessageService(List<StatusChangePublisher> publishers, ObjectMapper mapper) {
|
|
||||||
this.publishers = publishers;
|
|
||||||
this.mapper = mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void publishStatusChangePayloadV1(Map<String, List<String>> statusSubmissionIdMap) {
|
|
||||||
AbstractStatusChangePayload payload = new StatusChangePayloadV1(statusSubmissionIdMap);
|
|
||||||
publishStatusChangePayload(payload, StatusChangeMessageVersion.V1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void publishStatusChangePayload(AbstractStatusChangePayload payload, StatusChangeMessageVersion version) {
|
|
||||||
if (publishers == null || publishers.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
VersionedStatusChangeMessage<AbstractStatusChangePayload> message = new VersionedStatusChangeMessage<>(
|
|
||||||
payload, new QueueMessageHeaders().addHeader(MessageHeaderAttribute.VERSION, version.getVersion()));
|
|
||||||
|
|
||||||
String jsonString;
|
|
||||||
try {
|
|
||||||
jsonString = mapper.writeValueAsString(message);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
String errorMessage = "Exception calling writeValueAsString";
|
|
||||||
log.error(errorMessage, e);
|
|
||||||
throw new PublisherException(errorMessage, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> errors = new ArrayList<>();
|
|
||||||
for (StatusChangePublisher publisher : publishers) {
|
|
||||||
try {
|
|
||||||
publisher.publish(jsonString);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Exception calling publish", e);
|
|
||||||
errors.add(e.getMessage() + " (" + publisher.getClass().getSimpleName() + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!errors.isEmpty()) {
|
|
||||||
String errorMessage = StringUtils.join(errors, "; ");
|
|
||||||
log.error(errorMessage);
|
|
||||||
throw new PublisherException(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.Publisher;
|
|
||||||
|
|
||||||
public interface StatusChangePublisher extends Publisher {
|
|
||||||
// Just a marker interface to allow Spring to inject all the publishers for this message type
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import software.amazon.awssdk.services.sns.SnsClient;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.SnsPublisher;
|
|
||||||
import gov.irs.directfile.status.config.SnsConfiguration;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@ConditionalOnProperty(value = "status.sns.status-change-publish-enabled", havingValue = "true")
|
|
||||||
@EnableConfigurationProperties(SnsConfiguration.class)
|
|
||||||
public class StatusChangeSnsPublisher extends SnsPublisher implements StatusChangePublisher {
|
|
||||||
public StatusChangeSnsPublisher(SnsClient snsClient, SnsConfiguration snsConfiguration) {
|
|
||||||
super(snsClient, snsConfiguration.getStatusChangeTopicArn());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import software.amazon.awssdk.services.sqs.SqsClient;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.SqsPublisher;
|
|
||||||
import gov.irs.directfile.status.config.MessageQueueConfiguration;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@ConditionalOnProperty(value = "status.messageQueue.status-change-publish-enabled", havingValue = "true")
|
|
||||||
@EnableConfigurationProperties(MessageQueueConfiguration.class)
|
|
||||||
public class StatusChangeSqsPublisher extends SqsPublisher implements StatusChangePublisher {
|
|
||||||
public StatusChangeSqsPublisher(SqsClient sqsClient, MessageQueueConfiguration messageQueueConfiguration) {
|
|
||||||
super(sqsClient, messageQueueConfiguration.getStatusChangeQueue());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.SubmissionConfirmationMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
import gov.irs.directfile.models.message.exception.UnsupportedVersionException;
|
|
||||||
import gov.irs.directfile.status.services.handlers.confirmation.SubmissionConfirmationHandler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.confirmation.SubmissionConfirmationV1Handler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.confirmation.SubmissionConfirmationV2Handler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.confirmation.UnsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
public class SubmissionConfirmationMessageRouter {
|
|
||||||
private final Map<SubmissionConfirmationMessageVersion, SubmissionConfirmationHandler> handlers = new HashMap<>();
|
|
||||||
private final UnsupportedMessageVersionHandler unsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
public SubmissionConfirmationMessageRouter(
|
|
||||||
UnsupportedMessageVersionHandler unsupportedMessageVersionHandler,
|
|
||||||
SubmissionConfirmationV1Handler submissionConfirmationV1Handler,
|
|
||||||
SubmissionConfirmationV2Handler submissionConfirmationV2Handler) {
|
|
||||||
this.unsupportedMessageVersionHandler = unsupportedMessageVersionHandler;
|
|
||||||
this.handlers.put(SubmissionConfirmationMessageVersion.V1, submissionConfirmationV1Handler);
|
|
||||||
this.handlers.put(SubmissionConfirmationMessageVersion.V2, submissionConfirmationV2Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handleSubmissionConfirmationMessage(
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> message) {
|
|
||||||
QueueMessageHeaders headers = message.getHeaders();
|
|
||||||
Optional<String> versionOptional = headers.getAttribute(MessageHeaderAttribute.VERSION);
|
|
||||||
|
|
||||||
// We can assume a version number is present here since a VersionedSubmissionConfirmationMessage
|
|
||||||
// mandates that on construction.
|
|
||||||
|
|
||||||
// Get enum for this version (may throw UnsupportedVersionException which we should handle and
|
|
||||||
// rethrow to get message back on queue/DLQ).
|
|
||||||
SubmissionConfirmationMessageVersion version;
|
|
||||||
try {
|
|
||||||
version = SubmissionConfirmationMessageVersion.getEnum(versionOptional.get());
|
|
||||||
} catch (UnsupportedVersionException e) {
|
|
||||||
unsupportedMessageVersionHandler.handleSubmissionConfirmationMessage(message);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get handler. If not found, we have an unsupported version so handle and throw exception.
|
|
||||||
SubmissionConfirmationHandler handler = handlers.get(version);
|
|
||||||
if (handler == null) {
|
|
||||||
unsupportedMessageVersionHandler.handleSubmissionConfirmationMessage(message);
|
|
||||||
throw new UnsupportedVersionException(String.format(
|
|
||||||
"No handler found for SubmissionConfirmationMessageVersion (%s)", version.getVersion()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should have a good handler, so handle the message.
|
|
||||||
handler.handleSubmissionConfirmationMessage(message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.confirmation;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
|
|
||||||
public interface SubmissionConfirmationHandler {
|
|
||||||
void handleSubmissionConfirmationMessage(
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> message);
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.confirmation;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.TaxReturnSubmissionReceipt;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.SubmissionConfirmationPayloadV1;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.PendingAcknowledgementRepository;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.TaxReturnSubmissionRepository;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
import gov.irs.directfile.status.domain.TaxReturnSubmission;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated V1 messages are no longer sent, but keeping handlers until we are sure queues are V1-free
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
public class SubmissionConfirmationV1Handler implements SubmissionConfirmationHandler {
|
|
||||||
private final PendingAcknowledgementRepository pendingRepo;
|
|
||||||
private final TaxReturnSubmissionRepository taxReturnSubmissionRepo;
|
|
||||||
private final StatusProperties statusProperties;
|
|
||||||
|
|
||||||
public SubmissionConfirmationV1Handler(
|
|
||||||
PendingAcknowledgementRepository pendingRepo,
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepo,
|
|
||||||
StatusProperties statusProperties) {
|
|
||||||
|
|
||||||
this.pendingRepo = pendingRepo;
|
|
||||||
this.taxReturnSubmissionRepo = taxReturnSubmissionRepo;
|
|
||||||
this.statusProperties = statusProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleSubmissionConfirmationMessage(
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> message) {
|
|
||||||
SubmissionConfirmationPayloadV1 payload = (SubmissionConfirmationPayloadV1) message.getPayload();
|
|
||||||
List<TaxReturnSubmissionReceipt> taxReturnSubmissionReceipts = payload.getReceipts();
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Received submission confirmation V1 message for tax return ids:");
|
|
||||||
taxReturnSubmissionReceipts.forEach(
|
|
||||||
taxReturnSubmissionReceipt -> sb.append(" ").append(taxReturnSubmissionReceipt.getTaxReturnId()));
|
|
||||||
log.info(sb.toString());
|
|
||||||
|
|
||||||
List<Pending> pendings = taxReturnSubmissionReceipts.stream()
|
|
||||||
.map(taxReturnSubmissionReceipt ->
|
|
||||||
new Pending(taxReturnSubmissionReceipt.getSubmissionId(), statusProperties.getApplicationId()))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
List<TaxReturnSubmission> taxReturnSubmissions = taxReturnSubmissionReceipts.stream()
|
|
||||||
.map(taxReturnSubmissionReceipt -> new TaxReturnSubmission(
|
|
||||||
taxReturnSubmissionReceipt.getTaxReturnId(), taxReturnSubmissionReceipt.getSubmissionId()))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
log.info(String.format("Saving %s pendings", pendings.size()));
|
|
||||||
pendingRepo.saveAll(pendings);
|
|
||||||
taxReturnSubmissionRepo.saveAll(taxReturnSubmissions);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.confirmation;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.TaxReturnSubmissionReceipt;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.SubmissionConfirmationPayloadV2;
|
|
||||||
import gov.irs.directfile.models.message.event.SubmissionEventTypeEnum;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.PendingAcknowledgementRepository;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.TaxReturnSubmissionRepository;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
import gov.irs.directfile.status.domain.TaxReturnSubmission;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SubmissionConfirmationV2Handler implements SubmissionConfirmationHandler {
|
|
||||||
private final PendingAcknowledgementRepository pendingRepo;
|
|
||||||
private final TaxReturnSubmissionRepository taxReturnSubmissionRepo;
|
|
||||||
private final StatusProperties statusProperties;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleSubmissionConfirmationMessage(
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> message) {
|
|
||||||
SubmissionConfirmationPayloadV2 payload = (SubmissionConfirmationPayloadV2) message.getPayload();
|
|
||||||
|
|
||||||
// Note that for the pending submission queue, we only need to process SUBMITTED tax return
|
|
||||||
// events. FAILED events are also sent via the submission confirmation SNS topic subscription,
|
|
||||||
// but can be ignored here since they aren't considered pending submissions.
|
|
||||||
List<TaxReturnSubmissionReceipt> submittedTaxReturnSubmissionReceipts = new ArrayList<>();
|
|
||||||
payload.getEntries().forEach(entry -> {
|
|
||||||
if (SubmissionEventTypeEnum.SUBMITTED.equals(entry.getEventType())) {
|
|
||||||
submittedTaxReturnSubmissionReceipts.add(entry.getTaxReturnSubmissionReceipt());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// If we did not get any SUBMITTED returns, then we're done.
|
|
||||||
if (submittedTaxReturnSubmissionReceipts.isEmpty()) return;
|
|
||||||
|
|
||||||
// Otherwise, save the database records for the SUBMITTED returns.
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Received SUBMITTED submission confirmation V2 message for tax return ids:");
|
|
||||||
submittedTaxReturnSubmissionReceipts.forEach(
|
|
||||||
taxReturnSubmissionReceipt -> sb.append(" ").append(taxReturnSubmissionReceipt.getTaxReturnId()));
|
|
||||||
log.info(sb.toString());
|
|
||||||
|
|
||||||
List<Pending> pendings = submittedTaxReturnSubmissionReceipts.stream()
|
|
||||||
.map(taxReturnSubmissionReceipt ->
|
|
||||||
new Pending(taxReturnSubmissionReceipt.getSubmissionId(), statusProperties.getApplicationId()))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
List<TaxReturnSubmission> taxReturnSubmissions = submittedTaxReturnSubmissionReceipts.stream()
|
|
||||||
.map(taxReturnSubmissionReceipt -> new TaxReturnSubmission(
|
|
||||||
taxReturnSubmissionReceipt.getTaxReturnId(), taxReturnSubmissionReceipt.getSubmissionId()))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
log.info(String.format("Saving %s pendings", pendings.size()));
|
|
||||||
pendingRepo.saveAll(pendings);
|
|
||||||
taxReturnSubmissionRepo.saveAll(taxReturnSubmissions);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.confirmation;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
|
|
||||||
@Service("SubmissionConfirmationUnsupportedMessageVersionHandler")
|
|
||||||
@Slf4j
|
|
||||||
public class UnsupportedMessageVersionHandler implements SubmissionConfirmationHandler {
|
|
||||||
@Override
|
|
||||||
public void handleSubmissionConfirmationMessage(
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> payload) {
|
|
||||||
log.error("Unable to process Submission Confirmation Message. Headers: {} ", payload.getHeaders());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.pending;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.pending.VersionedPendingSubmissionMessage;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.AbstractPendingSubmissionPayload;
|
|
||||||
|
|
||||||
public interface PendingSubmissionHandler {
|
|
||||||
void handlePendingSubmissionMessage(VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> message);
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.pending;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.TaxReturnIdAndSubmissionId;
|
|
||||||
import gov.irs.directfile.models.message.pending.VersionedPendingSubmissionMessage;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.AbstractPendingSubmissionPayload;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.PendingSubmissionPayloadV1;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.PendingAcknowledgementRepository;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.TaxReturnSubmissionRepository;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
import gov.irs.directfile.status.domain.TaxReturnSubmission;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
public class PendingSubmissionV1Handler implements PendingSubmissionHandler {
|
|
||||||
private final PendingAcknowledgementRepository pendingRepo;
|
|
||||||
private final TaxReturnSubmissionRepository taxReturnSubmissionRepo;
|
|
||||||
private final StatusProperties statusProperties;
|
|
||||||
|
|
||||||
public PendingSubmissionV1Handler(
|
|
||||||
PendingAcknowledgementRepository pendingRepo,
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepo,
|
|
||||||
StatusProperties statusProperties) {
|
|
||||||
this.pendingRepo = pendingRepo;
|
|
||||||
this.taxReturnSubmissionRepo = taxReturnSubmissionRepo;
|
|
||||||
this.statusProperties = statusProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handlePendingSubmissionMessage(
|
|
||||||
VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> message) {
|
|
||||||
PendingSubmissionPayloadV1 payload = (PendingSubmissionPayloadV1) message.getPayload();
|
|
||||||
List<TaxReturnIdAndSubmissionId> taxReturnIdAndSubmissionIds = payload.getPendings();
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Received pending submission V1 message for tax return ids:");
|
|
||||||
taxReturnIdAndSubmissionIds.forEach(
|
|
||||||
taxReturnIdAndSubmissionId -> sb.append(" ").append(taxReturnIdAndSubmissionId.getTaxReturnId()));
|
|
||||||
log.info(sb.toString());
|
|
||||||
|
|
||||||
List<Pending> pendings = taxReturnIdAndSubmissionIds.stream()
|
|
||||||
.map(taxReturnIdAndSubmissionId -> {
|
|
||||||
Pending pending = new Pending();
|
|
||||||
pending.setSubmissionId(taxReturnIdAndSubmissionId.getSubmissionId());
|
|
||||||
pending.setPodId(statusProperties.getApplicationId());
|
|
||||||
return pending;
|
|
||||||
})
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
List<TaxReturnSubmission> taxReturnSubmissions = taxReturnIdAndSubmissionIds.stream()
|
|
||||||
.map(taxReturnIdAndSubmissionId -> new TaxReturnSubmission(
|
|
||||||
taxReturnIdAndSubmissionId.getTaxReturnId(), taxReturnIdAndSubmissionId.getSubmissionId()))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
log.info(String.format("Saving %s pendings", pendings.size()));
|
|
||||||
pendingRepo.saveAll(pendings);
|
|
||||||
taxReturnSubmissionRepo.saveAll(taxReturnSubmissions);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.pending;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.pending.VersionedPendingSubmissionMessage;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.AbstractPendingSubmissionPayload;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Slf4j
|
|
||||||
public class UnsupportedMessageVersionHandler implements PendingSubmissionHandler {
|
|
||||||
@Override
|
|
||||||
public void handlePendingSubmissionMessage(
|
|
||||||
VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> payload) {
|
|
||||||
log.error("Unable to process Pending Submission Message. Headers: {} ", payload.getHeaders());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
status:
|
|
||||||
status-endpoint-returns-pending-by-default-enabled: false
|
|
||||||
messageQueue:
|
|
||||||
sqs-message-handling-enabled: true
|
|
||||||
|
|
||||||
direct-file:
|
|
||||||
local-encryption:
|
|
||||||
local-wrapping-key: ${LOCAL_WRAPPING_KEY}
|
|
||||||
|
|
||||||
server:
|
|
||||||
port: 8082
|
|
|
@ -1,19 +0,0 @@
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
url: jdbc:postgresql://mef-apps-db:5432/directfile-status
|
|
||||||
|
|
||||||
status:
|
|
||||||
toolkit: /mef-client-sdk-src
|
|
||||||
status-endpoint-returns-pending-by-default-enabled: false
|
|
||||||
messageQueue:
|
|
||||||
endpoint: http://localstack:4566
|
|
||||||
sqs-message-handling-enabled: true
|
|
||||||
sns:
|
|
||||||
endpoint: http://localstack:4566
|
|
||||||
documentstore:
|
|
||||||
endpoint: http://localstack:4566/
|
|
||||||
|
|
||||||
# these defaults are to match the backend (update/remove once we're fully onto sqs)
|
|
||||||
direct-file:
|
|
||||||
local-encryption:
|
|
||||||
local-wrapping-key: ${LOCAL_WRAPPING_KEY}
|
|
|
@ -1,98 +0,0 @@
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
username: postgres
|
|
||||||
password: postgres
|
|
||||||
url: jdbc:postgresql://localhost:${MEF_APPS_DB_PORT:32768}/directfile-status
|
|
||||||
jpa:
|
|
||||||
hibernate:
|
|
||||||
ddl-auto: none
|
|
||||||
properties:
|
|
||||||
hibernate:
|
|
||||||
dialect: org.hibernate.dialect.PostgreSQLDialect
|
|
||||||
# Batching insert/update/delete
|
|
||||||
# https://docs.jboss.org/hibernate/orm/6.4/userguide/html_single/Hibernate_User_Guide.html#batch
|
|
||||||
jdbc:
|
|
||||||
batch_size: 30 # Hibernate docs recommend a value between 10 and 50
|
|
||||||
# Not turning on order_inserts or order_updates since we already generally save as a group
|
|
||||||
# Hibernate disables batching for entities having an identity PK, so tax_return_submission won't batch
|
|
||||||
liquibase:
|
|
||||||
change-log: classpath:db/changelog.yaml
|
|
||||||
url: ${spring.datasource.url}
|
|
||||||
user: ${spring.datasource.username}
|
|
||||||
password: ${spring.datasource.password}
|
|
||||||
hikari:
|
|
||||||
maximum-pool-size: 50
|
|
||||||
max-lifetime: 450000
|
|
||||||
minimum-idle: 30
|
|
||||||
connection-timeout: 15000
|
|
||||||
|
|
||||||
server:
|
|
||||||
shutdown: graceful
|
|
||||||
|
|
||||||
status:
|
|
||||||
# base64-encode the DER-formatted keystore and pass as `keystore-base64`
|
|
||||||
keystore-base64: MISSING
|
|
||||||
keystore-password: MISSING
|
|
||||||
keystore-alias: MISSING
|
|
||||||
application-id: ${POD_NAME:dfsys-mef-status-deployment-0}-${DF_AWS_REGION:us-gov-east-1}
|
|
||||||
etin: ${STATUS_ETIN:99999}
|
|
||||||
asid: 000
|
|
||||||
efin: 000
|
|
||||||
prod: false
|
|
||||||
unit-testing: false
|
|
||||||
root-translation-key: status
|
|
||||||
translation-key-splitter: .
|
|
||||||
ack-poll-in-milliseconds: 60000
|
|
||||||
# this field controls whether a Pending Response is returned from the /status endpoint when no submisionId is found.
|
|
||||||
# we will want to disable this in the future (likely when SQS communication is enabled).
|
|
||||||
status-endpoint-returns-pending-by-default-enabled: true
|
|
||||||
status-polling-enabled: true
|
|
||||||
messageQueue:
|
|
||||||
endpoint: http://localhost:4566
|
|
||||||
status-change-queue: status-change-queue
|
|
||||||
pending-submission-queue: pending-submission-queue
|
|
||||||
dlq-pending-submission-queue: dlq-pending-submission-queue
|
|
||||||
region: us-west-2
|
|
||||||
accessKey: accessKey
|
|
||||||
secretKey: secretKey
|
|
||||||
sqs-message-handling-enabled: false
|
|
||||||
status-change-publish-enabled: false
|
|
||||||
sns:
|
|
||||||
endpoint: http://localhost:4566
|
|
||||||
status-change-topic-arn: arn:aws:sns:us-west-2:000000000000:status-change-topic
|
|
||||||
region: us-west-2
|
|
||||||
accessKey: accessKey
|
|
||||||
secretKey: secretKey
|
|
||||||
status-change-publish-enabled: true
|
|
||||||
documentstore:
|
|
||||||
region: us-west-2
|
|
||||||
accessKey: accessKey
|
|
||||||
secretKey: secretKey
|
|
||||||
assume-role-arn: assume-role-arn-placeholder
|
|
||||||
assume-role-duration-seconds: 1800
|
|
||||||
assume-role-session-name: "df-status"
|
|
||||||
endpoint: http://localhost:4566/
|
|
||||||
bucket: direct-file-taxreturns
|
|
||||||
prefix:
|
|
||||||
|
|
||||||
aws:
|
|
||||||
enabled: false
|
|
||||||
default-credentials-provider-chain-enabled: false
|
|
||||||
access-key: accessKey
|
|
||||||
secret-key: secretKey
|
|
||||||
|
|
||||||
direct-file:
|
|
||||||
local-encryption:
|
|
||||||
local-wrapping-key: ${LOCAL_WRAPPING_KEY:-}
|
|
||||||
|
|
||||||
management:
|
|
||||||
endpoint:
|
|
||||||
health:
|
|
||||||
enabled: true
|
|
||||||
endpoints:
|
|
||||||
enabled-by-default: false
|
|
||||||
web:
|
|
||||||
discovery:
|
|
||||||
enabled: false
|
|
||||||
exposure:
|
|
||||||
include: health
|
|
|
@ -1,32 +0,0 @@
|
||||||
@@@@
|
|
||||||
(..@ ( @ .@@@@ @@@@/*@#@@@. .@@(@&@@/&@ * * * .
|
|
||||||
. @ @@@@@@@@@ &@@@(@@@@@@ .@/@@@@@@./@@@*@(@@@. ,
|
|
||||||
. @& &@&/@%@@@ ,&&@@&#@@@@ &%@@&. (@@@@(@@#@@(&
|
|
||||||
@@&@@#%& /@@@&@(@@% @@@@@@@@( @@@@@ @/&@@ #@@@@&&@
|
|
||||||
@%@#%%@@@ @@@&&@@(&#%% . %&#(@& @@@@@( @@&@@
|
|
||||||
@@&%@@#@@ @@%%@@ / # . %##@@@ @&&@@ %@@&@ &%@#@
|
|
||||||
#&@%/@@%@ #&@ . @@@&@(#@&#@@@ @&@&#@@&&#(@&& #/@&@ ,@@@(#
|
|
||||||
@(@#(@@@ @& %@/*&( ,&%(@*@ #@%@@* @@@@(@*@@@( @@&@&
|
|
||||||
((, @ @@&@ @@@@@@ @&(&/@&&@@@@/ , @&&% @&(@& @@@%@@@@%/ %@@(@
|
|
||||||
,@@@ @@ #@@@@@#@@ @@&@. , .*@. @/@#@ .@@@@@@@@@ (#@*@ (/@@@
|
|
||||||
@@(@&/ @@%@&/@%@@* #@@@%@@/*#@&@@ @@#@@, @@/@@ @/# @@@@@,@@@@@
|
|
||||||
@*@(@@@% @@@(@@@@(@ . &@@@ @ @@(@@. @.&@&* *#@& &(@@@ #@@*@
|
|
||||||
@@@/@/@@*@@@#@@@@ /@@@ &@@@* %@&@#. @@&@,,&@@@& @&(@
|
|
||||||
@(@&@@@@@@@&@/ @ @ @@@@, * @@*/&%@@,@@( *@@/@@ @@@@@ @@@@
|
|
||||||
&@@@@%@&%@ % . (@@# *@&*@(@&@@@ * @@@&@ &&#&@ &@@@
|
|
||||||
@@@&@@@ &@@&@ ( &(@% * @#@#@@&%@ &@@@%, .@@@@@ #@@@
|
|
||||||
*@@% ##@%@@ * @#@% ( / #@%&@&@ (#@#%@ #@&@@@ %@@@@
|
|
||||||
@%& @ &@&@@@&@ @%@@&@@@&%@@%@&#@%@@%(&@ @@%@&@ (@@@@@% %#&&%# /#@@@@
|
|
||||||
@#@@@ #@@&#(@@&( @&@#&#@(&&&@@@%%(#@@&&#%%@ @ ( &#%&% @@%@@@ %@@%@
|
|
||||||
@@@(&&( @@&@@/@@@ @(@@@@@@ @@&@ @#@&@@@& &@%&/% &@@(@, @(*@*
|
|
||||||
(@#@@@@@@@@@@(@@ ,@&(@@.#@@&& &@@@ @#@@@@@@@& , @@@@( /@/@#( @@@@&
|
|
||||||
*@%@@@@@@&@&@@. @@#%@ @@@,@ ,@@#% @(%,@ . @@@@, @/,@(@ @@@@*
|
|
||||||
.(&&@/@%/@&@ @ @@@@@ @&@@@ (. @*@@ #@@@& ,(@@@, &@@@@# @@(@@
|
|
||||||
&*@@@@@@@@# &@@@# . &@@%@ @*@@( .@@*@@ *@@@@@ @*@@( @#@@@
|
|
||||||
/@@@&&@#& #@@&@%( @@@@* %@@@@# @@%@@ @@@@@& ,/@
|
|
||||||
@@@@, /@@*@( /(&&@, &@@@@ @ @@&@( , @@@@@ .
|
|
||||||
. &(@%@@@@&@@&&&@@@&*@@@@@@*@@&&@@&#/@@@@@@ @&@/ .
|
|
||||||
( &#@%#@#@%%# #@@@@#@&&#@ #
|
|
||||||
|
|
||||||
${application.title} (${application.version})
|
|
||||||
Spring Boot ${spring-boot.version}
|
|
|
@ -1,7 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- preConditions:
|
|
||||||
onFail: HALT
|
|
||||||
onError: HALT
|
|
||||||
- includeAll:
|
|
||||||
path: migrations/
|
|
||||||
relativeToChangelogFile: true
|
|
|
@ -1,196 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-1
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: completed
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: completed_pkey
|
|
||||||
name: submission_id
|
|
||||||
type: VARCHAR(20)
|
|
||||||
- column:
|
|
||||||
name: status
|
|
||||||
type: VARCHAR(20)
|
|
||||||
- column:
|
|
||||||
name: tax_return_id
|
|
||||||
type: VARCHAR(255)
|
|
||||||
tableName: completed
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-2
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: completed-errors
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
name: submission_id
|
|
||||||
type: VARCHAR(20)
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
name: mef_error_code
|
|
||||||
type: VARCHAR(25)
|
|
||||||
tableName: completed-errors
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-3
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: error
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: error_pkey
|
|
||||||
name: meferror_code
|
|
||||||
type: VARCHAR(25)
|
|
||||||
- column:
|
|
||||||
name: error_code_translation_key
|
|
||||||
type: VARCHAR(255)
|
|
||||||
- column:
|
|
||||||
name: meferror_category
|
|
||||||
type: VARCHAR(255)
|
|
||||||
- column:
|
|
||||||
name: meferror_message
|
|
||||||
type: BLOB
|
|
||||||
tableName: error
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-4
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: pending
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: pending_pkey
|
|
||||||
name: submission_id
|
|
||||||
type: VARCHAR(20)
|
|
||||||
- column:
|
|
||||||
name: error_message
|
|
||||||
type: VARCHAR(255)
|
|
||||||
- column:
|
|
||||||
name: status
|
|
||||||
type: VARCHAR(20)
|
|
||||||
tableName: pending
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-5
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: tax_return_identifier
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: tax_return_identifier_pkey
|
|
||||||
name: tax_return_id
|
|
||||||
type: UUID
|
|
||||||
- column:
|
|
||||||
name: submission_id
|
|
||||||
type: VARCHAR(20)
|
|
||||||
tableName: tax_return_identifier
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-6
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: toolkit_error
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: toolkit_error_pkey
|
|
||||||
name: submission_id
|
|
||||||
type: VARCHAR(255)
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
name: error_message
|
|
||||||
type: VARCHAR(255)
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
name: error_name
|
|
||||||
type: VARCHAR(255)
|
|
||||||
tableName: toolkit_error
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-7
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: completed
|
|
||||||
- tableExists:
|
|
||||||
- tableName: completed-errors
|
|
||||||
changes:
|
|
||||||
- addForeignKeyConstraint:
|
|
||||||
baseColumnNames: submission_id
|
|
||||||
baseTableName: completed-errors
|
|
||||||
constraintName: fkd6wcrt7yp7rypmyf365wlrely
|
|
||||||
deferrable: false
|
|
||||||
initiallyDeferred: false
|
|
||||||
onDelete: NO ACTION
|
|
||||||
onUpdate: NO ACTION
|
|
||||||
referencedColumnNames: submission_id
|
|
||||||
referencedTableName: completed
|
|
||||||
validate: true
|
|
||||||
- changeSet:
|
|
||||||
id: 1704409188607-8
|
|
||||||
author: irs-123 (generated)
|
|
||||||
preConditions:
|
|
||||||
- onFail: MARK_RAN
|
|
||||||
- not:
|
|
||||||
- tableExists:
|
|
||||||
- tableName: error
|
|
||||||
- tableExists:
|
|
||||||
- tableName: completed-errors
|
|
||||||
changes:
|
|
||||||
- addForeignKeyConstraint:
|
|
||||||
baseColumnNames: mef_error_code
|
|
||||||
baseTableName: completed-errors
|
|
||||||
constraintName: fkhq7kqsddr2k6uauh9gg47bfis
|
|
||||||
deferrable: false
|
|
||||||
initiallyDeferred: false
|
|
||||||
onDelete: NO ACTION
|
|
||||||
onUpdate: NO ACTION
|
|
||||||
referencedColumnNames: meferror_code
|
|
||||||
referencedTableName: error
|
|
||||||
validate: true
|
|
|
@ -1,77 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: add-created_at
|
|
||||||
author: irs-123
|
|
||||||
comment: add createdAt columns for various tables
|
|
||||||
changes:
|
|
||||||
- addColumn:
|
|
||||||
tableName: pending
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
type: TIMESTAMP WITHOUT TIME ZONE
|
|
||||||
defaultValueComputed: CURRENT_TIMESTAMP
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
- addColumn:
|
|
||||||
tableName: completed
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
type: TIMESTAMP WITHOUT TIME ZONE
|
|
||||||
defaultValueComputed: CURRENT_TIMESTAMP
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
- addColumn:
|
|
||||||
tableName: toolkit_error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
type: TIMESTAMP WITHOUT TIME ZONE
|
|
||||||
defaultValueComputed: CURRENT_TIMESTAMP
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
- addColumn:
|
|
||||||
tableName: error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
type: TIMESTAMP WITHOUT TIME ZONE
|
|
||||||
defaultValueComputed: CURRENT_TIMESTAMP
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
- addColumn:
|
|
||||||
tableName: tax_return_identifier
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
type: TIMESTAMP WITHOUT TIME ZONE
|
|
||||||
defaultValueComputed: CURRENT_TIMESTAMP
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
rollback:
|
|
||||||
- dropColumn:
|
|
||||||
tableName: error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
- dropColumn:
|
|
||||||
tableName: completed
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
- dropColumn:
|
|
||||||
tableName: pending
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
- dropColumn:
|
|
||||||
tableName: toolkit_error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
- dropColumn:
|
|
||||||
tableName: tax_return_identifier
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
|
@ -1,18 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: add-error-message
|
|
||||||
author: irs-123
|
|
||||||
comment: add error_message field to error table
|
|
||||||
changes:
|
|
||||||
- addColumn:
|
|
||||||
tableName: error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: error_message
|
|
||||||
type: TEXT
|
|
||||||
rollback:
|
|
||||||
- dropColumn:
|
|
||||||
tableName: error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: error_message
|
|
|
@ -1,18 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: add-error-message
|
|
||||||
author: irs-123
|
|
||||||
comment: delete meferror_message field from error table
|
|
||||||
changes:
|
|
||||||
- dropColumn:
|
|
||||||
tableName: error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: meferror_message
|
|
||||||
rollback:
|
|
||||||
- addColumn:
|
|
||||||
tableName: error
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: meferror_message
|
|
||||||
type: BLOB
|
|
|
@ -1,31 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: add-taxreturn-submission-table
|
|
||||||
author: irs-123
|
|
||||||
comment: create tax_return_submission join table
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: id
|
|
||||||
type: serial
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: tax_return_id_submission_id_pkey
|
|
||||||
- column:
|
|
||||||
name: tax_return_id
|
|
||||||
type: UUID
|
|
||||||
- column:
|
|
||||||
name: submission_id
|
|
||||||
type: VARCHAR(20)
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
type: TIMESTAMP WITHOUT TIME ZONE
|
|
||||||
defaultValueComputed: CURRENT_TIMESTAMP
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
tableName: tax_return_submission
|
|
||||||
rollback:
|
|
||||||
- dropTable:
|
|
||||||
tableName: tax_return_submission
|
|
|
@ -1,40 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: add-indices-status-app
|
|
||||||
author: irs-123
|
|
||||||
comment: add indices to status app
|
|
||||||
|
|
||||||
changes:
|
|
||||||
- createIndex:
|
|
||||||
indexName: completed_tax_return_id_idx
|
|
||||||
tableName: completed
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: tax_return_id
|
|
||||||
- createIndex:
|
|
||||||
indexName: tax_return_submission_tax_return_id_idx
|
|
||||||
tableName: tax_return_submission
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: tax_return_id
|
|
||||||
- createIndex:
|
|
||||||
indexName: completed_errors_submission_id_idx
|
|
||||||
tableName: completed-errors
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: submission_id
|
|
||||||
- createIndex:
|
|
||||||
indexName: completed_errors_mef_error_code_idx
|
|
||||||
tableName: completed-errors
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: mef_error_code
|
|
||||||
rollback:
|
|
||||||
- dropIndex:
|
|
||||||
indexName: completed_tax_return_id_idx
|
|
||||||
- dropIndex:
|
|
||||||
indexName: tax_return_submission_tax_return_id_idx
|
|
||||||
- dropIndex:
|
|
||||||
indexName: completed_error_submission_id_idx
|
|
||||||
- dropIndex:
|
|
||||||
indexName: completed_error_mef_error_code_idx
|
|
|
@ -1,36 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: fk-completed-error
|
|
||||||
author: irs-123
|
|
||||||
comment: add foreign key constraint on m2m join between completed and error tables
|
|
||||||
changes:
|
|
||||||
changes:
|
|
||||||
- addForeignKeyConstraint:
|
|
||||||
baseColumnNames: submission_id
|
|
||||||
baseTableName: completed-errors
|
|
||||||
constraintName: completed_error_submission_id_fk
|
|
||||||
deferrable: false
|
|
||||||
initiallyDeferred: false
|
|
||||||
onDelete: NO ACTION
|
|
||||||
onUpdate: NO ACTION
|
|
||||||
referencedColumnNames: submission_id
|
|
||||||
referencedTableName: completed
|
|
||||||
validate: true
|
|
||||||
- addForeignKeyConstraint:
|
|
||||||
baseColumnNames: mef_error_code
|
|
||||||
baseTableName: completed-errors
|
|
||||||
constraintName: completed_error_mef_error_code_fk
|
|
||||||
deferrable: false
|
|
||||||
initiallyDeferred: false
|
|
||||||
onDelete: NO ACTION
|
|
||||||
onUpdate: NO ACTION
|
|
||||||
referencedColumnNames: meferror_code
|
|
||||||
referencedTableName: error
|
|
||||||
validate: true
|
|
||||||
rollback:
|
|
||||||
- dropForeignKeyConstraint:
|
|
||||||
baseTableName: completed-errors
|
|
||||||
constraintName: completed_error_submission_id_fk
|
|
||||||
- dropForeignKeyConstraint:
|
|
||||||
baseTableName: completed-errors
|
|
||||||
constraintName: completed_error_mef_error_code_fk
|
|
|
@ -1,63 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: drop-unused-columns-from-completed-and-pending-tables-and-drop-tax-return-identifier-table
|
|
||||||
author: irs-123
|
|
||||||
comment: drop tax_return_id column from completed, drop error_message and status columns from pending, drop tax_return_identifier table
|
|
||||||
changes:
|
|
||||||
- dropIndex:
|
|
||||||
indexName: completed_tax_return_id_idx
|
|
||||||
- dropColumn:
|
|
||||||
tableName: completed
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: tax_return_id
|
|
||||||
- dropColumn:
|
|
||||||
tableName: pending
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: error_message
|
|
||||||
- column:
|
|
||||||
name: status
|
|
||||||
- dropTable:
|
|
||||||
tableName: tax_return_identifier
|
|
||||||
rollback:
|
|
||||||
- addColumn:
|
|
||||||
tableName: completed
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: tax_return_id
|
|
||||||
type: VARCHAR(255)
|
|
||||||
- createIndex:
|
|
||||||
indexName: completed_tax_return_id_idx
|
|
||||||
tableName: completed
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: tax_return_id
|
|
||||||
- addColumn:
|
|
||||||
tableName: pending
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: error_message
|
|
||||||
type: TEXT
|
|
||||||
- column:
|
|
||||||
name: status
|
|
||||||
type: TEXT
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: tax_return_identifier_pkey
|
|
||||||
name: tax_return_id
|
|
||||||
type: UUID
|
|
||||||
- column:
|
|
||||||
name: submission_id
|
|
||||||
type: VARCHAR(20)
|
|
||||||
- column:
|
|
||||||
name: created_at
|
|
||||||
type: TIMESTAMP WITHOUT TIME ZONE
|
|
||||||
defaultValueComputed: CURRENT_TIMESTAMP
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
tableName: tax_return_identifier
|
|
|
@ -1,29 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: pod-identifier-table
|
|
||||||
author: 123 (generated)
|
|
||||||
comment: create pod_identifier table
|
|
||||||
|
|
||||||
changes:
|
|
||||||
- createTable:
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: id
|
|
||||||
type: serial
|
|
||||||
constraints:
|
|
||||||
nullable: false
|
|
||||||
primaryKey: true
|
|
||||||
primaryKeyName: pod_identifier_id_pkey
|
|
||||||
- column:
|
|
||||||
name: asid
|
|
||||||
type: VARCHAR(50)
|
|
||||||
- column:
|
|
||||||
name: region
|
|
||||||
type: VARCHAR(50)
|
|
||||||
- column:
|
|
||||||
name: pod_id
|
|
||||||
type: VARCHAR(255)
|
|
||||||
tableName: pod_identifier
|
|
||||||
rollback:
|
|
||||||
- dropTable:
|
|
||||||
tableName: pod_identifier
|
|
|
@ -1,18 +0,0 @@
|
||||||
databaseChangeLog:
|
|
||||||
- changeSet:
|
|
||||||
id: add-pod-id-column-pending
|
|
||||||
author: 123 (generated)
|
|
||||||
comment: add pod_id column to pending table
|
|
||||||
changes:
|
|
||||||
- addColumn:
|
|
||||||
tableName: pending
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: pod_id
|
|
||||||
type: VARCHAR(255)
|
|
||||||
rollback:
|
|
||||||
- dropColumn:
|
|
||||||
tableName: pending
|
|
||||||
columns:
|
|
||||||
- column:
|
|
||||||
name: pod_id
|
|
|
@ -1,22 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<!DOCTYPE configuration>
|
|
||||||
<configuration>
|
|
||||||
<appender name="ConsoleJSON" class="ch.qos.logback.core.ConsoleAppender">
|
|
||||||
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
|
|
||||||
<fieldNames>
|
|
||||||
<timestamp>timestamp</timestamp>
|
|
||||||
<thread>[ignore]</thread>
|
|
||||||
<version>[ignore]</version>
|
|
||||||
<levelValue>[ignore]</levelValue>
|
|
||||||
</fieldNames>
|
|
||||||
<timestampPattern>yyyy-MM-dd'T'HH:mm:ss.SSS'Z'</timestampPattern>
|
|
||||||
<timeZone>UTC</timeZone>
|
|
||||||
<customFields>{"system":"DIRECTFILE","eventType":"STATUS","version":"${GIT_COMMIT_HASH}"}}</customFields>
|
|
||||||
<throwableConverter class="gov.irs.directfile.audit.NoMessageStackTraceConverter" />
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<root level="INFO">
|
|
||||||
<appender-ref ref="ConsoleJSON" />
|
|
||||||
</root>
|
|
||||||
</configuration>
|
|
|
@ -1,423 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
|
||||||
|
|
||||||
import gov.irs.directfile.audit.AuditLogElement;
|
|
||||||
import gov.irs.directfile.audit.AuditService;
|
|
||||||
import gov.irs.directfile.audit.events.*;
|
|
||||||
import gov.irs.directfile.models.RejectedStatus;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.domain.AcknowledgementStatus;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.domain.Status;
|
|
||||||
import gov.irs.directfile.status.config.SnsClientTestConfiguration;
|
|
||||||
import gov.irs.directfile.status.extension.LoggerExtension;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
|
||||||
|
|
||||||
@SpringBootTest
|
|
||||||
@AutoConfigureMockMvc
|
|
||||||
@TestPropertySource(properties = {"status.xml-headers-to-be-removed="})
|
|
||||||
@Import(SnsClientTestConfiguration.class)
|
|
||||||
class AcknowledgementControllerTest {
|
|
||||||
@Autowired
|
|
||||||
private MockMvc mockMvc;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private AcknowledgementService acknowledgementService;
|
|
||||||
|
|
||||||
@RegisterExtension
|
|
||||||
public static LoggerExtension logVerifier = new LoggerExtension(Level.INFO, AuditService.class.getName());
|
|
||||||
|
|
||||||
private static String X_FORWARDED_FOR = "X-Forwarded-For";
|
|
||||||
private static final String TEST_IP_ADDR1 = "10.1.2.1";
|
|
||||||
private static final String TEST_IP_ADDR2 = "10.1.2.2";
|
|
||||||
private static final String REMOTE_IP_ADDR = "10.1.2.3";
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void status_whenAcknowledgementServiceReturnsPendingStatus_endpointReturnsOkResponse() throws Exception {
|
|
||||||
AcknowledgementStatus acknowledgementStatus =
|
|
||||||
new AcknowledgementStatus(Status.Pending, "", List.of(), new Date());
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
when(acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(eq(taxReturnId)))
|
|
||||||
.thenReturn("1234567890");
|
|
||||||
when(acknowledgementService.GetAcknowledgement(eq(taxReturnId), eq("1234567890")))
|
|
||||||
.thenReturn(acknowledgementStatus);
|
|
||||||
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status")
|
|
||||||
.with(r -> {
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("id", taxReturnId.toString()))
|
|
||||||
.andExpect(status().isOk());
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{}")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.SUCCESS)
|
|
||||||
.mefSubmissionId("1234567890")
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.taxReturnId,
|
|
||||||
taxReturnId.toString(),
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.OK.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
REMOTE_IP_ADDR,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void status_whenAcknowledgementServiceReturnsNull_endpointReturnsNotFoundResponse() throws Exception {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
when(acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(eq(taxReturnId)))
|
|
||||||
.thenReturn("1234567890");
|
|
||||||
when(acknowledgementService.GetAcknowledgement(eq(taxReturnId), eq("1234567890")))
|
|
||||||
.thenReturn(null);
|
|
||||||
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status")
|
|
||||||
.with(r -> {
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("id", taxReturnId.toString()))
|
|
||||||
.andExpect(status().isNotFound());
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{}")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.taxReturnId,
|
|
||||||
taxReturnId.toString(),
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.NOT_FOUND.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
REMOTE_IP_ADDR,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void status_whenAcknowledgementServiceThrowsException_endpointReturnsBadRequestResponse() throws Exception {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
when(acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(eq(taxReturnId)))
|
|
||||||
.thenReturn("1234567890");
|
|
||||||
when(acknowledgementService.GetAcknowledgement(eq(taxReturnId), eq("1234567890")))
|
|
||||||
.thenThrow(new NullPointerException("Error occurred"));
|
|
||||||
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status")
|
|
||||||
.with(r -> {
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("id", taxReturnId.toString()))
|
|
||||||
.andExpect(status().isBadRequest());
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{errorMessage=Error occurred}")
|
|
||||||
.eventErrorMessage("java.lang.NullPointerException")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.taxReturnId,
|
|
||||||
taxReturnId.toString(),
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.BAD_REQUEST.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
REMOTE_IP_ADDR,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void status_endpointHitWithInvalidUUID_endpointReturnsBadRequestResponse() throws Exception {
|
|
||||||
String invalidUUIDString = "12323123231321";
|
|
||||||
|
|
||||||
this.mockMvc.perform(get("/status").param("id", invalidUUIDString)).andExpect(status().isBadRequest());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRemoteIpAddress_OneIpInX_Forwarded_For() throws Exception {
|
|
||||||
AcknowledgementStatus acknowledgementStatus =
|
|
||||||
new AcknowledgementStatus(Status.Pending, "", List.of(), new Date());
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
when(acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(eq(taxReturnId)))
|
|
||||||
.thenReturn("1234567890");
|
|
||||||
when(acknowledgementService.GetAcknowledgement(eq(taxReturnId), eq("1234567890")))
|
|
||||||
.thenReturn(acknowledgementStatus);
|
|
||||||
|
|
||||||
// 1 ip address in x-forwarded-for
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status")
|
|
||||||
.with(r -> {
|
|
||||||
r.addHeader(X_FORWARDED_FOR, TEST_IP_ADDR1);
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("id", taxReturnId.toString()))
|
|
||||||
.andExpect(status().isOk());
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{}")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.SUCCESS)
|
|
||||||
.mefSubmissionId("1234567890")
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.taxReturnId,
|
|
||||||
taxReturnId.toString(),
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.OK.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
TEST_IP_ADDR1,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRemoteIpAddress_TwoIpInX_Forwarded_For() throws Exception {
|
|
||||||
AcknowledgementStatus acknowledgementStatus =
|
|
||||||
new AcknowledgementStatus(Status.Pending, "", List.of(), new Date());
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
when(acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(eq(taxReturnId)))
|
|
||||||
.thenReturn("1234567890");
|
|
||||||
when(acknowledgementService.GetAcknowledgement(eq(taxReturnId), eq("1234567890")))
|
|
||||||
.thenReturn(acknowledgementStatus);
|
|
||||||
|
|
||||||
// 2 ip addresses in x-forwarded-for
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status")
|
|
||||||
.with(r -> {
|
|
||||||
r.addHeader(X_FORWARDED_FOR, TEST_IP_ADDR2 + "," + TEST_IP_ADDR1);
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("id", taxReturnId.toString()))
|
|
||||||
.andExpect(status().isOk());
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{}")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.SUCCESS)
|
|
||||||
.mefSubmissionId("1234567890")
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.taxReturnId,
|
|
||||||
taxReturnId.toString(),
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.OK.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
TEST_IP_ADDR2,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void rejectionCodes_whenAcknowledgementServiceReturnsRejectionCodes_endpointReturnsOkResponse()
|
|
||||||
throws Exception {
|
|
||||||
List<RejectedStatus> rejectionCodes = List.of(
|
|
||||||
new RejectedStatus("code1", "key1", "description1"),
|
|
||||||
new RejectedStatus("code2", "key2", "description2"));
|
|
||||||
|
|
||||||
String submissionId = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
when(acknowledgementService.getRejectionCodesForSubmissionId(submissionId))
|
|
||||||
.thenReturn(rejectionCodes);
|
|
||||||
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status/rejection-codes")
|
|
||||||
.with(r -> {
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("submissionId", submissionId))
|
|
||||||
.andExpect(status().isOk());
|
|
||||||
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{}")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.SUCCESS)
|
|
||||||
.mefSubmissionId(submissionId)
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.mefSubmissionId,
|
|
||||||
submissionId,
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.OK.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
REMOTE_IP_ADDR,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void rejectionCodes_whenAcknowledgementServiceThrowsNotFoundException_endpointReturnsNotFoundResponse()
|
|
||||||
throws Exception {
|
|
||||||
String submissionId = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
when(acknowledgementService.getRejectionCodesForSubmissionId(submissionId))
|
|
||||||
.thenThrow(EntityNotFoundException.class);
|
|
||||||
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status/rejection-codes")
|
|
||||||
.with(r -> {
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("submissionId", submissionId))
|
|
||||||
.andExpect(status().isNotFound());
|
|
||||||
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{}")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.mefSubmissionId(submissionId)
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.mefSubmissionId,
|
|
||||||
submissionId,
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.NOT_FOUND.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
REMOTE_IP_ADDR,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void rejectionCodes_whenAcknowledgementServiceThrowsException_endpointReturnsBadRequestResponse()
|
|
||||||
throws Exception {
|
|
||||||
String submissionId = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
when(acknowledgementService.getRejectionCodesForSubmissionId(submissionId))
|
|
||||||
.thenThrow(new NullPointerException("Error occurred"));
|
|
||||||
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status/rejection-codes")
|
|
||||||
.with(r -> {
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("submissionId", submissionId))
|
|
||||||
.andExpect(status().isBadRequest());
|
|
||||||
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{errorMessage=Error occurred}")
|
|
||||||
.eventErrorMessage("java.lang.NullPointerException")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.FAILURE)
|
|
||||||
.mefSubmissionId(submissionId)
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.mefSubmissionId,
|
|
||||||
submissionId,
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.BAD_REQUEST.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
REMOTE_IP_ADDR,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Stream<Arguments> getRejectionCodesXForwardedForParameters() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.of(TEST_IP_ADDR1, TEST_IP_ADDR1),
|
|
||||||
Arguments.of(TEST_IP_ADDR2 + "," + TEST_IP_ADDR1, TEST_IP_ADDR2));
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@MethodSource("getRejectionCodesXForwardedForParameters")
|
|
||||||
public void rejectionCodes_whenXForwardedFor_endpointReturnsOkResponse(
|
|
||||||
String xForwardedForValue, String expectedRemoteAddress) throws Exception {
|
|
||||||
List<RejectedStatus> rejectionCodes = List.of(
|
|
||||||
new RejectedStatus("code1", "key1", "description1"),
|
|
||||||
new RejectedStatus("code2", "key2", "description2"));
|
|
||||||
|
|
||||||
String submissionId = UUID.randomUUID().toString();
|
|
||||||
|
|
||||||
when(acknowledgementService.getRejectionCodesForSubmissionId(submissionId))
|
|
||||||
.thenReturn(rejectionCodes);
|
|
||||||
|
|
||||||
this.mockMvc
|
|
||||||
.perform(get("/status/rejection-codes")
|
|
||||||
.with(r -> {
|
|
||||||
r.addHeader(X_FORWARDED_FOR, xForwardedForValue);
|
|
||||||
r.setRemoteAddr(REMOTE_IP_ADDR);
|
|
||||||
return r;
|
|
||||||
})
|
|
||||||
.param("submissionId", submissionId))
|
|
||||||
.andExpect(status().isOk());
|
|
||||||
|
|
||||||
// verify audit log message
|
|
||||||
logVerifier.verifyLogEvent(
|
|
||||||
Event.builder()
|
|
||||||
.detail("{}")
|
|
||||||
.eventId(EventId.CHECK)
|
|
||||||
.eventPrincipal(new SystemEventPrincipal())
|
|
||||||
.eventStatus(EventStatus.SUCCESS)
|
|
||||||
.mefSubmissionId(submissionId)
|
|
||||||
.build(),
|
|
||||||
Map.of(
|
|
||||||
AuditLogElement.mefSubmissionId,
|
|
||||||
submissionId,
|
|
||||||
AuditLogElement.responseStatusCode,
|
|
||||||
HttpStatus.OK.value(),
|
|
||||||
AuditLogElement.remoteAddress,
|
|
||||||
expectedRemoteAddress,
|
|
||||||
AuditLogElement.cyberOnly,
|
|
||||||
true));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,859 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
|
||||||
import org.junit.jupiter.api.*;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.*;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
||||||
|
|
||||||
import gov.irs.a2a.mef.mefheader.TestCdType;
|
|
||||||
import gov.irs.mef.exception.ServiceException;
|
|
||||||
import gov.irs.mef.exception.ToolkitException;
|
|
||||||
import gov.irs.mef.services.ServiceContext;
|
|
||||||
import gov.irs.mef.services.transmitter.mtom.GetAcksResult;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.RejectedStatus;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.domain.Status;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.*;
|
|
||||||
import gov.irs.directfile.status.domain.Error;
|
|
||||||
import gov.irs.directfile.status.error.ErrorRepository;
|
|
||||||
import gov.irs.directfile.status.error.ToolkitErrorRepository;
|
|
||||||
import gov.irs.directfile.status.mef.client.MeFAcksMTOMClientService;
|
|
||||||
import gov.irs.directfile.status.mef.client.MeFLoginClientService;
|
|
||||||
import gov.irs.directfile.status.mef.client.MeFLogoutClientService;
|
|
||||||
import gov.irs.directfile.status.mef.client.ServiceContextWrapper;
|
|
||||||
import gov.irs.directfile.status.repository.PodIdentifierRepository;
|
|
||||||
import gov.irs.directfile.status.services.StatusChangeMessageService;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.anySet;
|
|
||||||
import static org.mockito.ArgumentMatchers.isNull;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@EnableConfigurationProperties(StatusProperties.class)
|
|
||||||
@ImportAutoConfiguration(classes = SecurityAutoConfiguration.class)
|
|
||||||
@DataJpaTest
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class AcknowledgementServiceTest {
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() throws ServiceException, ToolkitException {
|
|
||||||
when(mockLoginClientService.loginWithDefaultAsid()).thenReturn(new ServiceContextWrapper(null));
|
|
||||||
|
|
||||||
acknowledgementService = new AcknowledgementService(
|
|
||||||
completedRepo,
|
|
||||||
pendingRepo,
|
|
||||||
taxReturnSubmissionRepository,
|
|
||||||
errorRepository,
|
|
||||||
toolkitErrorRepo,
|
|
||||||
statusProperties,
|
|
||||||
statusChangeMessageService,
|
|
||||||
mockGetAcksClientService,
|
|
||||||
mockLoginClientService,
|
|
||||||
mockLogoutClientService,
|
|
||||||
podIdentifierRepository);
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
public static void setupSystemProperties() {
|
|
||||||
String userDirectory = System.getProperty("user.dir");
|
|
||||||
System.setProperty("A2A_TOOLKIT_HOME", userDirectory + "/src/test/resources/");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
public static void cleanupSystemProperties() {
|
|
||||||
System.clearProperty("A2A_TOOLKIT_HOME");
|
|
||||||
}
|
|
||||||
|
|
||||||
String ASID = "asid1235";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
CompletedAcknowledgementRepository completedRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
ErrorRepository errorRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
PendingAcknowledgementRepository pendingRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
ToolkitErrorRepository toolkitErrorRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
PodIdentifierRepository podIdentifierRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
StatusProperties statusProperties;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private StatusChangeMessageService statusChangeMessageService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
MeFAcksMTOMClientService mockGetAcksClientService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
MeFLoginClientService mockLoginClientService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
MeFLogoutClientService mockLogoutClientService;
|
|
||||||
|
|
||||||
AcknowledgementService acknowledgementService;
|
|
||||||
|
|
||||||
public PodIdentifier createPodIdentifer(String region, String asid, int index) {
|
|
||||||
PodIdentifier p = new PodIdentifier();
|
|
||||||
p.setAsid(asid);
|
|
||||||
p.setRegion(region);
|
|
||||||
p.setPodId("dfsys-mef-status-deployment-" + index + "-" + region);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void GetAcknowledgementWithACompleted() {
|
|
||||||
String submissionId = "1234562023021500001";
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, submissionId));
|
|
||||||
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId(submissionId);
|
|
||||||
c.setStatus("Accepted");
|
|
||||||
completedRepo.save(c);
|
|
||||||
|
|
||||||
var accepted = acknowledgementService.GetAcknowledgement(taxReturnId);
|
|
||||||
assertEquals(Status.Accepted, accepted.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void GetAcknowledgementWithARejection() {
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId("12345620230215000001");
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation.reject.XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject and Stop");
|
|
||||||
c.setErrors(List.of(e));
|
|
||||||
errorRepository.save(e);
|
|
||||||
completedRepo.save(c);
|
|
||||||
|
|
||||||
String submissionId = "12345620230215000001";
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, submissionId));
|
|
||||||
|
|
||||||
var rejected = acknowledgementService.GetAcknowledgement(taxReturnId);
|
|
||||||
assertEquals(Status.Rejected, rejected.getStatus());
|
|
||||||
assertEquals(1, rejected.getRejectionCodes().size());
|
|
||||||
assertEquals("XML-123-4567-006", rejected.getRejectionCodes().getFirst().MeFErrorCode);
|
|
||||||
assertEquals("You messed up!", rejected.getRejectionCodes().getFirst().MeFDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void GetAcknowledgementWithMultipleRejections() {
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId("12345620230215000001");
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject");
|
|
||||||
Error e2 = new Error();
|
|
||||||
e2.setMefErrorCode("REJC-00001");
|
|
||||||
e2.setErrorMessage("This was a huge problem");
|
|
||||||
e2.setErrorCodeTranslationKey("translation/reject/REJC-00001");
|
|
||||||
e2.setMefErrorCategory("Reject");
|
|
||||||
c.setErrors(List.of(e, e2));
|
|
||||||
errorRepository.saveAll(List.of(e, e2));
|
|
||||||
completedRepo.save(c);
|
|
||||||
|
|
||||||
String submissionId = "12345620230215000001";
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, submissionId));
|
|
||||||
|
|
||||||
var rejected = acknowledgementService.GetAcknowledgement(taxReturnId);
|
|
||||||
assertEquals(Status.Rejected, rejected.getStatus());
|
|
||||||
assertEquals(2, rejected.getRejectionCodes().size());
|
|
||||||
assertEquals("XML-123-4567-006", rejected.getRejectionCodes().get(0).MeFErrorCode);
|
|
||||||
assertEquals("You messed up!", rejected.getRejectionCodes().get(0).MeFDescription);
|
|
||||||
assertEquals("REJC-00001", rejected.getRejectionCodes().get(1).MeFErrorCode);
|
|
||||||
assertEquals("This was a huge problem", rejected.getRejectionCodes().get(1).MeFDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled("This test has been flaking")
|
|
||||||
void GetAcknowledgementWithRejectionAndAcceptedReturnsLatestCompleted() {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
String submissionId = "1234562023021500001";
|
|
||||||
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId(submissionId);
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation.reject.XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject and Stop");
|
|
||||||
c.setErrors(List.of(e));
|
|
||||||
errorRepository.save(e);
|
|
||||||
completedRepo.save(c);
|
|
||||||
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, submissionId));
|
|
||||||
|
|
||||||
submissionId = "1234562023021500002";
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, submissionId));
|
|
||||||
|
|
||||||
Completed c1 = new Completed();
|
|
||||||
c1.setSubmissionId(submissionId);
|
|
||||||
c1.setStatus("Accepted");
|
|
||||||
completedRepo.save(c1);
|
|
||||||
|
|
||||||
var accepted = acknowledgementService.GetAcknowledgement(taxReturnId);
|
|
||||||
assertEquals(Status.Accepted, accepted.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void
|
|
||||||
GetAcknowledgementWithNoTaxReturnSubmissionReturnsPendingIfStatusEndpointReturnsPendingByDefaultEnabledIsTrue() {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
String submissionId = "1234562023021500001";
|
|
||||||
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId(submissionId);
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation.reject.XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject and Stop");
|
|
||||||
c.setErrors(List.of(e));
|
|
||||||
errorRepository.save(e);
|
|
||||||
completedRepo.save(c);
|
|
||||||
|
|
||||||
var result = acknowledgementService.GetAcknowledgement(taxReturnId);
|
|
||||||
assertEquals(Status.Pending, result.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void GetAcknowledgementWithPending() {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000001");
|
|
||||||
pendingRepo.save(p);
|
|
||||||
|
|
||||||
var pending = acknowledgementService.GetAcknowledgement(taxReturnId);
|
|
||||||
assertEquals(Status.Pending, pending.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void
|
|
||||||
GetAcknowledgementWithNoPreviousLookup_ifCreatePendingUponLookupIsTrue_ReturnsPendingStatusButDoesNotSaveObjectInDB() {
|
|
||||||
UUID taxReturnId = UUID.fromString("e111c2c4-5de7-465d-8a00-b0e80caeedbc");
|
|
||||||
var nothing = acknowledgementService.GetAcknowledgement(taxReturnId);
|
|
||||||
assertEquals(Status.Pending, nothing.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Set<String>> createBatchSubmissionIds(List<Pending> argument)
|
|
||||||
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
|
|
||||||
Method method = AcknowledgementService.class.getDeclaredMethod("batchPendings", Iterable.class);
|
|
||||||
method.setAccessible(true);
|
|
||||||
return (List<Set<String>>) method.invoke(acknowledgementService, argument);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void batchSubmissionIdsReturnsASingleBatchForOneSubmissionId() {
|
|
||||||
try {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000001");
|
|
||||||
var test = createBatchSubmissionIds(List.of(p));
|
|
||||||
assertEquals(1, test.size());
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void batchSubmissionIdsReturns10BatchesFor1000Ids() {
|
|
||||||
try {
|
|
||||||
List<Pending> pendings = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 1000; i++) {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000" + i);
|
|
||||||
pendings.add(p);
|
|
||||||
}
|
|
||||||
var test = createBatchSubmissionIds(pendings);
|
|
||||||
assertEquals(10, test.size());
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void batchSubmissionIdsReturns2BatchesFor101Ids() {
|
|
||||||
try {
|
|
||||||
List<Pending> pendings = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 101; i++) {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000" + i);
|
|
||||||
pendings.add(p);
|
|
||||||
}
|
|
||||||
var test = createBatchSubmissionIds(pendings);
|
|
||||||
assertEquals(2, test.size());
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void batchSubmissionIdsReturns1BatchFor0() {
|
|
||||||
try {
|
|
||||||
List<Pending> pendings = new ArrayList<>();
|
|
||||||
var test = createBatchSubmissionIds(pendings);
|
|
||||||
assertEquals(1, test.size());
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void CreateToolkitErrorDeletesPendingRecordForSubmissionId() {
|
|
||||||
String submissionId = "12345678900987654321";
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId(submissionId);
|
|
||||||
pendingRepo.save(p);
|
|
||||||
ToolkitException tke = new ToolkitException("invalid request parameters");
|
|
||||||
acknowledgementService.createToolkitError(p, tke);
|
|
||||||
Optional<Pending> deletedPendingRecord = pendingRepo.findById(submissionId);
|
|
||||||
assertEquals(Optional.empty(), deletedPendingRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void CreateToolkitErrorCreatesTheRecordWithTheSubmissionIdAndError() {
|
|
||||||
String submissionId = "21423423423424423234";
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId(submissionId);
|
|
||||||
p.setPodId(getDefaultPodIdentifierFromProperties(0, "us-gov-east-1"));
|
|
||||||
pendingRepo.save(p);
|
|
||||||
|
|
||||||
ToolkitException tke = new ToolkitException("invalid request parameters");
|
|
||||||
acknowledgementService.createToolkitError(p, tke);
|
|
||||||
|
|
||||||
Optional<ToolkitError> toolkitErrorRecord = toolkitErrorRepo.findById(submissionId);
|
|
||||||
|
|
||||||
assertEquals(submissionId, toolkitErrorRecord.get().getSubmissionId());
|
|
||||||
assertEquals(
|
|
||||||
"gov.irs.mef.exception.ToolkitException",
|
|
||||||
toolkitErrorRecord.get().getErrorName());
|
|
||||||
assertEquals(
|
|
||||||
"gov.irs.mef.exception.ToolkitException: invalid request parameters",
|
|
||||||
toolkitErrorRecord.get().getErrorMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled
|
|
||||||
void lookupSubmissionsAddsToolkitErrorRecordsOnToolkitExceptions() throws ServiceException, ToolkitException {
|
|
||||||
MockitoAnnotations.openMocks(this);
|
|
||||||
String meFClientErrorString = "MeFClientSDK000039: Invalid request parameters";
|
|
||||||
pendingRepo.save(new Pending("12345"));
|
|
||||||
ToolkitException tke = new ToolkitException(meFClientErrorString);
|
|
||||||
when(mockGetAcksClientService.getAcks(isNull(), anySet())).thenThrow(tke);
|
|
||||||
acknowledgementService.LookupSubmissions();
|
|
||||||
|
|
||||||
Optional<Pending> pendingRecord = pendingRepo.findById("12345");
|
|
||||||
Optional<ToolkitError> toolkitError = toolkitErrorRepo.findById("12345");
|
|
||||||
assertEquals(Optional.empty(), pendingRecord);
|
|
||||||
assertEquals(
|
|
||||||
"gov.irs.mef.exception.ToolkitException", toolkitError.get().getErrorName());
|
|
||||||
assertEquals(
|
|
||||||
"gov.irs.mef.exception.ToolkitException: " + meFClientErrorString,
|
|
||||||
toolkitError.get().getErrorMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled
|
|
||||||
void lookupSubmissionsHandlesToolkitExceptions() throws ServiceException, ToolkitException {
|
|
||||||
MockitoAnnotations.openMocks(this);
|
|
||||||
for (int i = 0; i < 100; i++) {
|
|
||||||
String genString = RandomStringUtils.random(20, true, true);
|
|
||||||
Pending p = new Pending(genString);
|
|
||||||
pendingRepo.save(p);
|
|
||||||
}
|
|
||||||
assertEquals(100, pendingRepo.count());
|
|
||||||
|
|
||||||
ToolkitException tke = new ToolkitException("Invalid request parameters");
|
|
||||||
|
|
||||||
GetAcksResult acksResult = mock(GetAcksResult.class);
|
|
||||||
|
|
||||||
// We do this to mimic the expected behavior of the MeF client SDK on batch calls that have an issue with one
|
|
||||||
// piece of data in the batch.
|
|
||||||
// throw ToolkitException 7 times on a batch of size 100
|
|
||||||
when(mockGetAcksClientService.getAcks(isNull(), anySet()))
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenThrow(tke)
|
|
||||||
.thenReturn(new GetAcksResultWrapper(new AcknowledgementsListWrapper(new ArrayList<>())));
|
|
||||||
|
|
||||||
acknowledgementService.LookupSubmissions();
|
|
||||||
|
|
||||||
// This is to test the expected binary search pattern
|
|
||||||
verify(mockGetAcksClientService, times(15)).getAcks(isNull(), anySet());
|
|
||||||
|
|
||||||
// since we threw ToolkitException 7 times in a batch of size 100, we only expect one pending record to be
|
|
||||||
// deleted and then created as a toolkit error record in the database,
|
|
||||||
// because we use binary search pattern to divide the set until we find the single cause of the exception (100/2
|
|
||||||
// 50/2 25/2 13/2 7/2 3/2 2/2 1/1)
|
|
||||||
assertEquals(1, toolkitErrorRepo.count());
|
|
||||||
assertEquals(99, pendingRepo.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getDefaultPodIdentifierFromProperties(int index, String region) {
|
|
||||||
return "dfsys-mef-status-deployment-" + index + "-" + region;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, List<String>> getStatusSubmissionIdMap() {
|
|
||||||
PodIdentifier pi = createPodIdentifer("us-gov-east-1", statusProperties.getAsid(), 0);
|
|
||||||
podIdentifierRepository.save(pi);
|
|
||||||
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = acknowledgementService.createStatusSubmissionIdMap();
|
|
||||||
List<String> statuses = new ArrayList<>();
|
|
||||||
statuses.add("accepted");
|
|
||||||
statuses.add("rejected");
|
|
||||||
statuses.add("pending");
|
|
||||||
statuses.forEach(status -> {
|
|
||||||
String submissionId = UUID.randomUUID().toString().substring(0, 20);
|
|
||||||
if (Objects.equals(status, "pending")) {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId(submissionId);
|
|
||||||
p.setPodId(pi.getPodId());
|
|
||||||
pendingRepo.save(p);
|
|
||||||
}
|
|
||||||
acknowledgementService.addToSubmissionIdMap(status, submissionId, statusSubmissionIdMap);
|
|
||||||
});
|
|
||||||
return statusSubmissionIdMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ValidationMapCompleted getValidationErrorMap() {
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = getStatusSubmissionIdMap();
|
|
||||||
Map<String, List<List<String>>> validationErrorMap = new HashMap<>();
|
|
||||||
statusSubmissionIdMap.forEach((status, submissionIdList) -> {
|
|
||||||
if (status.equals("rejected")) {
|
|
||||||
String submissionId = submissionIdList.get(0);
|
|
||||||
validationErrorMap.put(submissionId, new ArrayList<>());
|
|
||||||
List<String> errorList1 = new ArrayList<>();
|
|
||||||
List<String> errorList2 = new ArrayList<>();
|
|
||||||
String ruleNum = "R0000-904-03";
|
|
||||||
String severityCd = "Reject and Stop";
|
|
||||||
String errorMessageTxt =
|
|
||||||
"Software ID in the Return Header must have passed testing for the form family and ‘TaxYr’.";
|
|
||||||
errorList1.add(ruleNum);
|
|
||||||
errorList1.add(severityCd);
|
|
||||||
errorList1.add(errorMessageTxt);
|
|
||||||
validationErrorMap.get(submissionId).add(errorList1);
|
|
||||||
ruleNum = "F1040-525-03";
|
|
||||||
severityCd = "Reject and Stop";
|
|
||||||
errorMessageTxt =
|
|
||||||
"If 'PINTypeCd' in the Return Header has the value \"Self-Select On-Line\" and the filing status of the return is married filing jointly and Form 1040, [ 'SpecialProcessingLiteralCd' and 'CombatZoneCd' and 'SpecialProcessingCodeTxt' and 'PrimaryDeathDt' ] do not have values, then 'PrimaryBirthDt' in the Return Header must match the e-File database.";
|
|
||||||
errorList2.add(ruleNum);
|
|
||||||
errorList2.add(severityCd);
|
|
||||||
errorList2.add(errorMessageTxt);
|
|
||||||
validationErrorMap.get(submissionId).add(errorList2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Iterable<Completed> completeds = acknowledgementService.createNewCompleteds(statusSubmissionIdMap);
|
|
||||||
return new ValidationMapCompleted(validationErrorMap, completeds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void stripPendingAcknowledgementsFromStatusSubmissionIdMap() {
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = getStatusSubmissionIdMap();
|
|
||||||
Map<String, List<String>> newMap =
|
|
||||||
acknowledgementService.stripPendingAcknowledgementsFromStatusSubmissionIdMap(statusSubmissionIdMap);
|
|
||||||
assertNull(newMap.get("pending"));
|
|
||||||
assertEquals(newMap.get("rejected").size(), 1);
|
|
||||||
assertEquals(newMap.get("accepted").size(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void addToSubmissionIdMapErrorDoesNotMutateSubmissionIdMap() {
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = getStatusSubmissionIdMap();
|
|
||||||
String status = "error";
|
|
||||||
String submissionId = UUID.randomUUID().toString().substring(0, 20);
|
|
||||||
|
|
||||||
acknowledgementService.addToSubmissionIdMap(status, submissionId, statusSubmissionIdMap);
|
|
||||||
assertNull(statusSubmissionIdMap.get("error"));
|
|
||||||
assertEquals(statusSubmissionIdMap.get("rejected").size(), 1);
|
|
||||||
assertEquals(statusSubmissionIdMap.get("accepted").size(), 1);
|
|
||||||
assertEquals(statusSubmissionIdMap.get("pending").size(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void createNewCompletedsCreatesExpectedEntities() {
|
|
||||||
assertEquals(acknowledgementService.getAllPending().spliterator().getExactSizeIfKnown(), 0);
|
|
||||||
assertEquals(acknowledgementService.getAllCompleted().spliterator().getExactSizeIfKnown(), 0);
|
|
||||||
Map<String, List<String>> statusSubmssionIdMap = getStatusSubmissionIdMap();
|
|
||||||
Iterable<Completed> completeds = acknowledgementService.createNewCompleteds(statusSubmssionIdMap);
|
|
||||||
completedRepo.saveAll(completeds);
|
|
||||||
// one pending is created, two completed (rejected and accepted)
|
|
||||||
assertEquals(acknowledgementService.getAllPending().spliterator().getExactSizeIfKnown(), 1);
|
|
||||||
assertEquals(acknowledgementService.getAllCompleted().spliterator().getExactSizeIfKnown(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void bulkUpdateEntitiesWithNewErrors() {
|
|
||||||
assertEquals(acknowledgementService.getAllPending().spliterator().getExactSizeIfKnown(), 0);
|
|
||||||
assertEquals(acknowledgementService.getAllError().spliterator().getExactSizeIfKnown(), 0);
|
|
||||||
assertEquals(acknowledgementService.getAllCompleted().spliterator().getExactSizeIfKnown(), 0);
|
|
||||||
|
|
||||||
ValidationMapCompleted validationMapCompleted = getValidationErrorMap();
|
|
||||||
Map<String, List<List<String>>> validationErrorMap = validationMapCompleted.validationErrorMap;
|
|
||||||
Iterable<Completed> c = validationMapCompleted.completeds;
|
|
||||||
Map<String, Completed> cmap = new HashMap<>();
|
|
||||||
Map<String, Pending> pmap = new HashMap<>();
|
|
||||||
c.forEach(completed -> cmap.put(completed.getSubmissionId(), completed));
|
|
||||||
|
|
||||||
String podId = getDefaultPodIdentifierFromProperties(0, "us-gov-east-1");
|
|
||||||
Iterable<Pending> p = pendingRepo.findAllByPodId(podId);
|
|
||||||
p.forEach(pending -> pmap.put(pending.getSubmissionId(), pending));
|
|
||||||
|
|
||||||
acknowledgementService.bulkUpdateEntities(validationErrorMap, cmap, pmap);
|
|
||||||
|
|
||||||
String rejectedSubmissionId =
|
|
||||||
validationErrorMap.entrySet().iterator().next().getKey();
|
|
||||||
Completed rejectedAck = acknowledgementService
|
|
||||||
.getCompletedBySubmissionId(rejectedSubmissionId)
|
|
||||||
.get();
|
|
||||||
|
|
||||||
Pending pending = acknowledgementService.getAllPending().iterator().next();
|
|
||||||
Iterator<Completed> completeds =
|
|
||||||
acknowledgementService.getAllCompleted().iterator();
|
|
||||||
|
|
||||||
assertEquals(acknowledgementService.getAllCompleted().spliterator().getExactSizeIfKnown(), 2);
|
|
||||||
assertEquals(acknowledgementService.getAllError().spliterator().getExactSizeIfKnown(), 2);
|
|
||||||
assertEquals(rejectedAck.getSubmissionId(), rejectedSubmissionId);
|
|
||||||
assertNotNull(rejectedAck.getErrors());
|
|
||||||
|
|
||||||
// the pending object that corresponded to the rejected completed is deleted, the one that remains
|
|
||||||
// is still pending from the standpoint of MeF so it was not deleted
|
|
||||||
assertEquals(acknowledgementService.getAllPending().spliterator().getExactSizeIfKnown(), 1);
|
|
||||||
completeds.forEachRemaining(completed -> {
|
|
||||||
assertNotEquals(pending.getSubmissionId(), completed.getSubmissionId());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void bulkUpdateEntitiesWithPreexistingErrors() {
|
|
||||||
ValidationMapCompleted validationMapCompleted = getValidationErrorMap();
|
|
||||||
Map<String, List<List<String>>> validationErrorMap1 = validationMapCompleted.validationErrorMap;
|
|
||||||
Iterable<Completed> c = validationMapCompleted.completeds;
|
|
||||||
Map<String, Completed> cmap = new HashMap<>();
|
|
||||||
Map<String, Pending> pmap = new HashMap<>();
|
|
||||||
c.forEach(completed -> cmap.put(completed.getSubmissionId(), completed));
|
|
||||||
|
|
||||||
String podId = getDefaultPodIdentifierFromProperties(0, "us-gov-east-1");
|
|
||||||
Iterable<Pending> p = pendingRepo.findAllByPodId(podId);
|
|
||||||
p.forEach(pending -> pmap.put(pending.getSubmissionId(), pending));
|
|
||||||
|
|
||||||
acknowledgementService.bulkUpdateEntities(validationErrorMap1, cmap, pmap);
|
|
||||||
|
|
||||||
String rejectedSubmissionId =
|
|
||||||
validationErrorMap1.entrySet().iterator().next().getKey();
|
|
||||||
Completed rejectedAck = acknowledgementService
|
|
||||||
.getCompletedBySubmissionId(rejectedSubmissionId)
|
|
||||||
.get();
|
|
||||||
Pending pending = acknowledgementService.getAllPending().iterator().next();
|
|
||||||
Iterator<Completed> completeds =
|
|
||||||
acknowledgementService.getAllCompleted().iterator();
|
|
||||||
|
|
||||||
assertEquals(acknowledgementService.getAllCompleted().spliterator().getExactSizeIfKnown(), 2);
|
|
||||||
assertEquals(acknowledgementService.getAllError().spliterator().getExactSizeIfKnown(), 2);
|
|
||||||
assertEquals(rejectedAck.getSubmissionId(), rejectedSubmissionId);
|
|
||||||
assertNotNull(rejectedAck.getErrors());
|
|
||||||
assertEquals(acknowledgementService.getAllPending().spliterator().getExactSizeIfKnown(), 1);
|
|
||||||
completeds.forEachRemaining(completed -> {
|
|
||||||
assertNotEquals(pending.getSubmissionId(), completed.getSubmissionId());
|
|
||||||
});
|
|
||||||
|
|
||||||
// mimic polling MeF again for the same errors but different submissions
|
|
||||||
// we would expect the rejected ack in the second batch to still have associated errors
|
|
||||||
ValidationMapCompleted validationMapCompleted2 = getValidationErrorMap();
|
|
||||||
Map<String, List<List<String>>> validationErrorMap2 = validationMapCompleted2.validationErrorMap;
|
|
||||||
Iterable<Completed> c2 = validationMapCompleted2.completeds;
|
|
||||||
Map<String, Completed> cmap2 = new HashMap<>();
|
|
||||||
c2.forEach(completed -> cmap2.put(completed.getSubmissionId(), completed));
|
|
||||||
|
|
||||||
acknowledgementService.bulkUpdateEntities(validationErrorMap2, cmap2, pmap);
|
|
||||||
String rejectedSubmissionId2 =
|
|
||||||
validationErrorMap2.entrySet().iterator().next().getKey();
|
|
||||||
Completed rejectedAck2 = acknowledgementService
|
|
||||||
.getCompletedBySubmissionId(rejectedSubmissionId2)
|
|
||||||
.get();
|
|
||||||
Pending updatedPendings =
|
|
||||||
acknowledgementService.getAllPending().iterator().next();
|
|
||||||
Iterator<Completed> updatedCompleteds =
|
|
||||||
acknowledgementService.getAllCompleted().iterator();
|
|
||||||
|
|
||||||
// added another rejected and accepted submission object on top of the 2 in the first batch
|
|
||||||
assertEquals(acknowledgementService.getAllCompleted().spliterator().getExactSizeIfKnown(), 4);
|
|
||||||
// error count is the same because each error in the db is unique
|
|
||||||
assertEquals(acknowledgementService.getAllError().spliterator().getExactSizeIfKnown(), 2);
|
|
||||||
|
|
||||||
assertEquals(rejectedAck2.getSubmissionId(), rejectedSubmissionId2);
|
|
||||||
// errors are still persisted
|
|
||||||
assertNotNull(rejectedAck2.getErrors());
|
|
||||||
assertEquals(acknowledgementService.getAllPending().spliterator().getExactSizeIfKnown(), 2);
|
|
||||||
updatedCompleteds.forEachRemaining(completed -> {
|
|
||||||
assertNotEquals(updatedPendings.getSubmissionId(), completed.getSubmissionId());
|
|
||||||
});
|
|
||||||
assertEquals(
|
|
||||||
rejectedAck2.getErrors().getFirst().getErrorMessage(),
|
|
||||||
rejectedAck.getErrors().getFirst().getErrorMessage());
|
|
||||||
assertEquals(
|
|
||||||
rejectedAck2.getErrors().getLast().getErrorMessage(),
|
|
||||||
rejectedAck.getErrors().getLast().getErrorMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission_returnsAcceptedSubmissionEvenIfNotTheLatest() {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
String olderAcceptedSubmissionId = "accepted";
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, olderAcceptedSubmissionId));
|
|
||||||
|
|
||||||
String latestSubmissionId = "latest";
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, latestSubmissionId));
|
|
||||||
|
|
||||||
Completed acceptedCompleted = new Completed();
|
|
||||||
acceptedCompleted.setSubmissionId(olderAcceptedSubmissionId);
|
|
||||||
acceptedCompleted.setStatus("accepted");
|
|
||||||
completedRepo.save(acceptedCompleted);
|
|
||||||
|
|
||||||
Completed latestCompleted = new Completed();
|
|
||||||
latestCompleted.setSubmissionId(latestSubmissionId);
|
|
||||||
latestCompleted.setStatus("rejected");
|
|
||||||
completedRepo.save(latestCompleted);
|
|
||||||
|
|
||||||
var submissionId =
|
|
||||||
acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(taxReturnId);
|
|
||||||
assertEquals(olderAcceptedSubmissionId, submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void
|
|
||||||
getLatestAcceptedSubmissionIdOfParentTaxReturn_getsTheLatestAcceptedSubmissionIdOfTheParentTaxReturnEvenIfNotTheLatest() {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
String olderAcceptedSubmissionId = "accepted";
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, olderAcceptedSubmissionId));
|
|
||||||
|
|
||||||
String latestSubmissionId = "latest";
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, latestSubmissionId));
|
|
||||||
|
|
||||||
Completed acceptedCompleted = new Completed();
|
|
||||||
acceptedCompleted.setSubmissionId(olderAcceptedSubmissionId);
|
|
||||||
acceptedCompleted.setStatus("accepted");
|
|
||||||
completedRepo.save(acceptedCompleted);
|
|
||||||
|
|
||||||
Completed latestCompleted = new Completed();
|
|
||||||
latestCompleted.setSubmissionId(latestSubmissionId);
|
|
||||||
latestCompleted.setStatus("rejected");
|
|
||||||
completedRepo.save(latestCompleted);
|
|
||||||
|
|
||||||
var submissionId =
|
|
||||||
acknowledgementService.getLatestAcceptedSubmissionIdOfParentTaxReturn(olderAcceptedSubmissionId);
|
|
||||||
assertTrue(submissionId.isPresent());
|
|
||||||
assertEquals(olderAcceptedSubmissionId, submissionId.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getRejectionCodesForSubmissionId_returnsRejectionCodes() {
|
|
||||||
Error error1 = new Error();
|
|
||||||
error1.setMefErrorCode("code1");
|
|
||||||
error1.setErrorCodeTranslationKey("key1");
|
|
||||||
error1.setMefErrorCategory("category1");
|
|
||||||
error1.setErrorMessage("message1");
|
|
||||||
error1 = errorRepository.save(error1);
|
|
||||||
|
|
||||||
Completed completedRejection = new Completed();
|
|
||||||
String submissionId = "rejected";
|
|
||||||
completedRejection.setSubmissionId(submissionId);
|
|
||||||
completedRejection.setStatus("rejected");
|
|
||||||
completedRejection.setErrors(List.of(error1));
|
|
||||||
completedRepo.save(completedRejection);
|
|
||||||
|
|
||||||
List<RejectedStatus> rejectionCodes = acknowledgementService.getRejectionCodesForSubmissionId(submissionId);
|
|
||||||
|
|
||||||
assertEquals(1, rejectionCodes.size());
|
|
||||||
RejectedStatus rejectedStatus = rejectionCodes.getFirst();
|
|
||||||
assertEquals(error1.getMefErrorCode(), rejectedStatus.MeFErrorCode);
|
|
||||||
assertEquals(error1.getErrorCodeTranslationKey(), rejectedStatus.TranslationKey);
|
|
||||||
assertEquals(error1.getErrorMessage(), rejectedStatus.MeFDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getRejectionCodesForSubmissionId_returnsEmptyListWhenCompletedIsNotRejected() {
|
|
||||||
Completed completedAccepted = new Completed();
|
|
||||||
String submissionId = "accepted";
|
|
||||||
completedAccepted.setSubmissionId(submissionId);
|
|
||||||
completedAccepted.setStatus("accepted");
|
|
||||||
completedRepo.save(completedAccepted);
|
|
||||||
|
|
||||||
List<RejectedStatus> rejectionCodes = acknowledgementService.getRejectionCodesForSubmissionId(submissionId);
|
|
||||||
|
|
||||||
assertEquals(0, rejectionCodes.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getRejectionCodesForSubmissionId_throwsExceptionWhenNoCompletedRecord() {
|
|
||||||
String submissionId = "missing";
|
|
||||||
EntityNotFoundException thrown = assertThrows(
|
|
||||||
EntityNotFoundException.class,
|
|
||||||
() -> acknowledgementService.getRejectionCodesForSubmissionId(submissionId));
|
|
||||||
|
|
||||||
assertEquals("Could not find completed record for submission ID: " + submissionId, thrown.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenCreateServiceContextWrapper_WithPodIdentifiers_ThenReturnsAsidFromDatabase() {
|
|
||||||
PodIdentifier p = createPodIdentifer("us-gov-east-1", statusProperties.getAsid(), 0);
|
|
||||||
podIdentifierRepository.save(p);
|
|
||||||
|
|
||||||
String asid = podIdentifierRepository.findAsidByPodId(p.getPodId()).get();
|
|
||||||
|
|
||||||
ServiceContextWrapper serviceContextWrapper = acknowledgementService.createServiceContextWrapper();
|
|
||||||
ServiceContext serviceContext = serviceContextWrapper.getServiceContext();
|
|
||||||
assertNotNull(serviceContextWrapper);
|
|
||||||
assertNotNull(serviceContextWrapper.getServiceContext());
|
|
||||||
assertEquals(serviceContext.getAppSysID(), statusProperties.getAsid());
|
|
||||||
assertEquals(serviceContext.getAppSysID(), asid);
|
|
||||||
assertEquals(serviceContext.getEtin().toString(), statusProperties.getEtin());
|
|
||||||
assertEquals(serviceContext.getTestCdType(), TestCdType.T);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenCreateServiceContextWrapper_WithMultiplePodIdentifiers_ThenReturnsCorrectAsid() {
|
|
||||||
PodIdentifier p1 = createPodIdentifer("us-gov-east-1", ASID, 2);
|
|
||||||
PodIdentifier p2 = createPodIdentifer("us-gov-east-1", ASID + "2", 1);
|
|
||||||
PodIdentifier p3 = createPodIdentifer("us-gov-east-1", statusProperties.getAsid(), 0);
|
|
||||||
podIdentifierRepository.save(p1);
|
|
||||||
podIdentifierRepository.save(p2);
|
|
||||||
podIdentifierRepository.save(p3);
|
|
||||||
|
|
||||||
String correctAsid =
|
|
||||||
podIdentifierRepository.findAsidByPodId(p3.getPodId()).get();
|
|
||||||
|
|
||||||
ServiceContextWrapper serviceContextWrapper = acknowledgementService.createServiceContextWrapper();
|
|
||||||
ServiceContext serviceContext = serviceContextWrapper.getServiceContext();
|
|
||||||
assertNotNull(serviceContextWrapper);
|
|
||||||
assertNotNull(serviceContextWrapper.getServiceContext());
|
|
||||||
assertEquals(serviceContext.getAppSysID(), statusProperties.getAsid());
|
|
||||||
assertEquals(serviceContext.getAppSysID(), correctAsid);
|
|
||||||
assertEquals(serviceContext.getEtin().toString(), statusProperties.getEtin());
|
|
||||||
assertEquals(serviceContext.getTestCdType(), TestCdType.T);
|
|
||||||
}
|
|
||||||
|
|
||||||
private record ValidationMapCompleted(
|
|
||||||
Map<String, List<List<String>>> validationErrorMap, Iterable<Completed> completeds) {}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenRejectedStatusChangeMessages_DoPublish() {
|
|
||||||
List<AcknowledgementWrapper> acksList = new ArrayList<>();
|
|
||||||
PodIdentifier pi = createPodIdentifer("us-gov-east-1", statusProperties.getAsid(), 0);
|
|
||||||
podIdentifierRepository.save(pi);
|
|
||||||
Pending pending = new Pending("submissionId", pi.getPodId());
|
|
||||||
pendingRepo.save(pending);
|
|
||||||
acksList.add(new AcknowledgementWrapper("submissionId", "reeee", "rejected"));
|
|
||||||
GetAcksResultWrapper acksResult = new GetAcksResultWrapper(new AcknowledgementsListWrapper(acksList));
|
|
||||||
acknowledgementService.bulkUpdateRecordsFromAckResultAndEnqueueStatusChangeMessages(
|
|
||||||
acksResult, List.of(pending));
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = new HashMap<>();
|
|
||||||
statusSubmissionIdMap.put("accepted", List.of());
|
|
||||||
statusSubmissionIdMap.put("rejected", List.of("submissionId"));
|
|
||||||
verify(statusChangeMessageService, times(1)).publishStatusChangePayloadV1(statusSubmissionIdMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenAcceptedStatusChangeMessages_DoPublish() {
|
|
||||||
List<AcknowledgementWrapper> acksList = new ArrayList<>();
|
|
||||||
PodIdentifier pi = createPodIdentifer("us-gov-east-1", statusProperties.getAsid(), 0);
|
|
||||||
podIdentifierRepository.save(pi);
|
|
||||||
Pending pending = new Pending("submissionId3", pi.getPodId());
|
|
||||||
pendingRepo.save(pending);
|
|
||||||
acksList.add(new AcknowledgementWrapper("submissionId3", "beeee", "accepted"));
|
|
||||||
GetAcksResultWrapper acksResult = new GetAcksResultWrapper(new AcknowledgementsListWrapper(acksList));
|
|
||||||
acknowledgementService.bulkUpdateRecordsFromAckResultAndEnqueueStatusChangeMessages(
|
|
||||||
acksResult, List.of(pending));
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = new HashMap<>();
|
|
||||||
statusSubmissionIdMap.put("accepted", List.of("submissionId3"));
|
|
||||||
statusSubmissionIdMap.put("rejected", List.of());
|
|
||||||
verify(statusChangeMessageService, times(1)).publishStatusChangePayloadV1(statusSubmissionIdMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenAcceptedandRejectedStatusChangeMessages_DoPublish() {
|
|
||||||
List<AcknowledgementWrapper> acksList = new ArrayList<>();
|
|
||||||
PodIdentifier pi = createPodIdentifer("us-gov-east-1", statusProperties.getAsid(), 0);
|
|
||||||
podIdentifierRepository.save(pi);
|
|
||||||
Pending pending = new Pending("subId3", pi.getPodId());
|
|
||||||
Pending pending2 = new Pending("subId", pi.getPodId());
|
|
||||||
pendingRepo.save(pending);
|
|
||||||
pendingRepo.save(pending2);
|
|
||||||
acksList.add(new AcknowledgementWrapper("subId3", "yerp", "accepted"));
|
|
||||||
acksList.add(new AcknowledgementWrapper("subId", "nerp", "rejected"));
|
|
||||||
GetAcksResultWrapper acksResult = new GetAcksResultWrapper(new AcknowledgementsListWrapper(acksList));
|
|
||||||
acknowledgementService.bulkUpdateRecordsFromAckResultAndEnqueueStatusChangeMessages(
|
|
||||||
acksResult, List.of(pending, pending2));
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = new HashMap<>();
|
|
||||||
statusSubmissionIdMap.put("accepted", List.of("subId3"));
|
|
||||||
statusSubmissionIdMap.put("rejected", List.of("subId"));
|
|
||||||
verify(statusChangeMessageService, times(1)).publishStatusChangePayloadV1(statusSubmissionIdMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenNoStatusChangeMessages_NoPublish() {
|
|
||||||
List<AcknowledgementWrapper> acksList = new ArrayList<>();
|
|
||||||
GetAcksResultWrapper acksResult = new GetAcksResultWrapper(new AcknowledgementsListWrapper(acksList));
|
|
||||||
acknowledgementService.bulkUpdateRecordsFromAckResultAndEnqueueStatusChangeMessages(
|
|
||||||
acksResult, new ArrayList<>());
|
|
||||||
Map<String, List<String>> statusSubmissionIdMap = new HashMap<>();
|
|
||||||
statusSubmissionIdMap.put("accepted", List.of());
|
|
||||||
statusSubmissionIdMap.put("rejected", List.of());
|
|
||||||
verify(statusChangeMessageService, times(0)).publishStatusChangePayloadV1(statusSubmissionIdMap);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
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 static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
|
|
||||||
// AcknowledgementServiceTest is a @SpringBootTest
|
|
||||||
// This test uses mocks for lighter weight tests that don't need to test integration details as heavily.
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class AcknowledgementServiceWithMocksTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private TaxReturnSubmissionRepository taxReturnSubmissionRepository;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private CompletedAcknowledgementRepository completedRepo;
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
AcknowledgementService acknowledgementService;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission_returnsNullIfNoSubmissionIdsExist() {
|
|
||||||
// Given
|
|
||||||
var taxReturnId = UUID.randomUUID();
|
|
||||||
|
|
||||||
when(taxReturnSubmissionRepository.getLatestAcceptedSubmissionIdForTaxReturnId(taxReturnId))
|
|
||||||
.thenReturn(Optional.empty());
|
|
||||||
when(taxReturnSubmissionRepository.getLatestSubmissionIdByTaxReturnId(taxReturnId))
|
|
||||||
.thenReturn(Optional.empty());
|
|
||||||
|
|
||||||
// When
|
|
||||||
String submissionId =
|
|
||||||
acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(taxReturnId);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
verify(taxReturnSubmissionRepository, times(1)).getLatestAcceptedSubmissionIdForTaxReturnId(taxReturnId);
|
|
||||||
verify(taxReturnSubmissionRepository, times(1)).getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
assertNull(submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void
|
|
||||||
getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission_justGetsTheLatestSubmissionIdIfNoAcceptedSubmissionIsFound() {
|
|
||||||
// Given
|
|
||||||
var taxReturnId = UUID.randomUUID();
|
|
||||||
var latestSubmissionId = "theLatestSubmissionId";
|
|
||||||
|
|
||||||
when(taxReturnSubmissionRepository.getLatestAcceptedSubmissionIdForTaxReturnId(taxReturnId))
|
|
||||||
.thenReturn(Optional.empty());
|
|
||||||
when(taxReturnSubmissionRepository.getLatestSubmissionIdByTaxReturnId(taxReturnId))
|
|
||||||
.thenReturn(Optional.of(latestSubmissionId));
|
|
||||||
|
|
||||||
// When
|
|
||||||
String submissionId =
|
|
||||||
acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(taxReturnId);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
verify(taxReturnSubmissionRepository, times(1)).getLatestAcceptedSubmissionIdForTaxReturnId(taxReturnId);
|
|
||||||
verify(taxReturnSubmissionRepository, times(1)).getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
assertEquals(latestSubmissionId, submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void
|
|
||||||
getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission_getsTheLatestAcceptedSubmissionIdEvenIfItIsNotTheLatest() {
|
|
||||||
// Given
|
|
||||||
var taxReturnId = UUID.randomUUID();
|
|
||||||
var latestAcceptedSubmissionId = "theLatestAcceptedSubmissionId";
|
|
||||||
|
|
||||||
when(taxReturnSubmissionRepository.getLatestAcceptedSubmissionIdForTaxReturnId(taxReturnId))
|
|
||||||
.thenReturn(Optional.of(latestAcceptedSubmissionId));
|
|
||||||
|
|
||||||
// When
|
|
||||||
String submissionId =
|
|
||||||
acknowledgementService.getLatestSubmissionIdByTaxReturnIdPreferringAcceptedSubmission(taxReturnId);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
verify(taxReturnSubmissionRepository, times(1)).getLatestAcceptedSubmissionIdForTaxReturnId(taxReturnId);
|
|
||||||
verify(taxReturnSubmissionRepository, times(0)).getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
assertEquals(latestAcceptedSubmissionId, submissionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getLatestAcceptedSubmissionIdOfParentTaxReturn_returnsEmptyIfNoAcceptedSubmissionFound() {
|
|
||||||
// Given
|
|
||||||
var requestedSubmissionId = "requestedSubmissionId";
|
|
||||||
|
|
||||||
when(taxReturnSubmissionRepository.getLatestAcceptedSubmissionIdOfParentTaxReturn(requestedSubmissionId))
|
|
||||||
.thenReturn(Optional.empty());
|
|
||||||
|
|
||||||
// When
|
|
||||||
Optional<String> latestAcceptedSubmissionId =
|
|
||||||
acknowledgementService.getLatestAcceptedSubmissionIdOfParentTaxReturn(requestedSubmissionId);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
verify(taxReturnSubmissionRepository, times(1))
|
|
||||||
.getLatestAcceptedSubmissionIdOfParentTaxReturn(requestedSubmissionId);
|
|
||||||
assertTrue(latestAcceptedSubmissionId.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getLatestAcceptedSubmissionIdOfParentTaxReturn_returnsTheAcceptedSubmissionId() {
|
|
||||||
// Given
|
|
||||||
var requestedSubmissionId = "requestedSubmissionId";
|
|
||||||
var acceptedSubmissionId = "acceptedSubmissionId";
|
|
||||||
|
|
||||||
when(taxReturnSubmissionRepository.getLatestAcceptedSubmissionIdOfParentTaxReturn(requestedSubmissionId))
|
|
||||||
.thenReturn(Optional.of(acceptedSubmissionId));
|
|
||||||
|
|
||||||
// When
|
|
||||||
Optional<String> latestAcceptedSubmissionId =
|
|
||||||
acknowledgementService.getLatestAcceptedSubmissionIdOfParentTaxReturn(requestedSubmissionId);
|
|
||||||
|
|
||||||
// Then
|
|
||||||
verify(taxReturnSubmissionRepository, times(1))
|
|
||||||
.getLatestAcceptedSubmissionIdOfParentTaxReturn(requestedSubmissionId);
|
|
||||||
assertTrue(latestAcceptedSubmissionId.isPresent());
|
|
||||||
assertEquals(acceptedSubmissionId, latestAcceptedSubmissionId.get());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,156 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import org.hibernate.engine.jdbc.batch.JdbcBatchLogging;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.Completed;
|
|
||||||
import gov.irs.directfile.status.domain.Error;
|
|
||||||
import gov.irs.directfile.status.error.ErrorRepository;
|
|
||||||
import gov.irs.directfile.status.extension.BatchUtil;
|
|
||||||
import gov.irs.directfile.status.extension.LoggerExtension;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@ImportAutoConfiguration(classes = SecurityAutoConfiguration.class)
|
|
||||||
@DataJpaTest(properties = "spring.main.web-application-type=servlet")
|
|
||||||
class CompletedAcknowledgementRepositoryTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
CompletedAcknowledgementRepository completedRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
ErrorRepository errorRepository;
|
|
||||||
|
|
||||||
@RegisterExtension
|
|
||||||
private static final LoggerExtension batchLogVerifier = new LoggerExtension(Level.TRACE, JdbcBatchLogging.NAME);
|
|
||||||
|
|
||||||
@Value("${spring.jpa.properties.hibernate.jdbc.batch_size}")
|
|
||||||
private int batchSize;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddAnAccepted() {
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId("12345620230215000001");
|
|
||||||
c.setStatus("Accepted");
|
|
||||||
completedRepo.save(c);
|
|
||||||
var completed =
|
|
||||||
completedRepo.GetCompletedSubmission("12345620230215000001").get();
|
|
||||||
assertEquals("Accepted", completed.getStatus());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Completed.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddARejected() {
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId("12345620230215000001");
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject and Stop");
|
|
||||||
c.setErrors(List.of(e));
|
|
||||||
// must add error to database first!
|
|
||||||
errorRepository.save(e);
|
|
||||||
completedRepo.save(c);
|
|
||||||
var completed =
|
|
||||||
completedRepo.GetCompletedSubmission("12345620230215000001").get();
|
|
||||||
assertEquals("Rejected", completed.getStatus());
|
|
||||||
assertEquals("XML-123-4567-006", completed.getErrors().get(0).getMefErrorCode());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Error.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Completed.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(BatchUtil.buildBatchMessage(
|
|
||||||
1, batchSize, Completed.class.getName() + ".errors", BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddARejectedWithMultipleErrors() {
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId("12345620230215000001");
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject");
|
|
||||||
Error e2 = new Error();
|
|
||||||
e2.setMefErrorCode("REJC-00001");
|
|
||||||
e2.setErrorMessage("This was a huge problem");
|
|
||||||
e2.setErrorCodeTranslationKey("translation/reject/REJC-00001");
|
|
||||||
e2.setMefErrorCategory("Reject");
|
|
||||||
c.setErrors(List.of(e, e2));
|
|
||||||
errorRepository.saveAll(List.of(e, e2));
|
|
||||||
completedRepo.save(c);
|
|
||||||
|
|
||||||
var completed =
|
|
||||||
completedRepo.GetCompletedSubmission("12345620230215000001").get();
|
|
||||||
assertEquals("Rejected", completed.getStatus());
|
|
||||||
assertEquals("XML-123-4567-006", completed.getErrors().get(0).getMefErrorCode());
|
|
||||||
assertEquals("REJC-00001", completed.getErrors().get(1).getMefErrorCode());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(2, batchSize, Error.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Completed.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(BatchUtil.buildBatchMessage(
|
|
||||||
2, batchSize, Completed.class.getName() + ".errors", BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanQueryForANonExistentSubmissionId() {
|
|
||||||
var completed = completedRepo.GetCompletedSubmission("12345620230215000001");
|
|
||||||
assertTrue(completed.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddTheSameErrorToTwoDifferentCompletedRecords() {
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject and Stop");
|
|
||||||
errorRepository.save(e);
|
|
||||||
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId("12345620230215000001");
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
c.setErrors(List.of(e));
|
|
||||||
completedRepo.save(c);
|
|
||||||
|
|
||||||
Completed c2 = new Completed();
|
|
||||||
c2.setSubmissionId("12345620230215000002");
|
|
||||||
c2.setStatus("Rejected");
|
|
||||||
c2.setErrors(List.of(e));
|
|
||||||
completedRepo.save(c2);
|
|
||||||
|
|
||||||
assertEquals(1, errorRepository.findAll().spliterator().getExactSizeIfKnown());
|
|
||||||
assertEquals(2, completedRepo.findAll().spliterator().getExactSizeIfKnown());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Error.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(2, batchSize, Completed.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(BatchUtil.buildBatchMessage(
|
|
||||||
2, batchSize, Completed.class.getName() + ".errors", BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,143 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import org.hibernate.engine.jdbc.batch.JdbcBatchLogging;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
import gov.irs.directfile.status.extension.BatchUtil;
|
|
||||||
import gov.irs.directfile.status.extension.LoggerExtension;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@ImportAutoConfiguration(classes = SecurityAutoConfiguration.class)
|
|
||||||
@DataJpaTest(properties = "spring.main.web-application-type=servlet")
|
|
||||||
public class PendingAcknowledgementRepositoryTest {
|
|
||||||
@Autowired
|
|
||||||
PendingAcknowledgementRepository pendingRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TestEntityManager testEntityManager;
|
|
||||||
|
|
||||||
@RegisterExtension
|
|
||||||
private static final LoggerExtension batchLogVerifier = new LoggerExtension(Level.TRACE, JdbcBatchLogging.NAME);
|
|
||||||
|
|
||||||
@Value("${spring.jpa.properties.hibernate.jdbc.batch_size}")
|
|
||||||
private int batchSize;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddASubmissionIdToTheTable() {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000010");
|
|
||||||
pendingRepo.save(p);
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
testEntityManager.flush();
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Pending.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddMultipleSubmissionsToTheTable() {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000001");
|
|
||||||
pendingRepo.save(p);
|
|
||||||
Pending p2 = new Pending();
|
|
||||||
p2.setSubmissionId("12345620230215000002");
|
|
||||||
pendingRepo.save(p2);
|
|
||||||
Pending p3 = new Pending();
|
|
||||||
Pending p4 = new Pending();
|
|
||||||
p3.setSubmissionId("12345620230215000003");
|
|
||||||
p4.setSubmissionId("12345620230215000004");
|
|
||||||
var multiple = List.of(p3, p4);
|
|
||||||
pendingRepo.saveAll(multiple);
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
testEntityManager.flush();
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(4, batchSize, Pending.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanRetrieveFromPendingTable() {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000001");
|
|
||||||
pendingRepo.save(p);
|
|
||||||
var pending = pendingRepo.GetPendingSubmission("12345620230215000001");
|
|
||||||
assertEquals(p.getSubmissionId(), pending.get().getSubmissionId());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Pending.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanDeleteFromPendingTable() {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000001");
|
|
||||||
pendingRepo.save(p);
|
|
||||||
Pending p2 = new Pending();
|
|
||||||
p2.setSubmissionId("12345620230215000001");
|
|
||||||
pendingRepo.delete(p2);
|
|
||||||
var option = pendingRepo.GetPendingSubmission("12345620230215000001");
|
|
||||||
assertTrue(option.isEmpty());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Pending.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Pending.class.getName(), BatchUtil.BatchType.DELETE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CannotEnterTwoOfTheSameSubmissionIdsIntoThePendingTable() {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("12345620230215000001");
|
|
||||||
pendingRepo.save(p);
|
|
||||||
Pending p2 = new Pending();
|
|
||||||
p2.setSubmissionId("12345620230215000001");
|
|
||||||
pendingRepo.save(p2);
|
|
||||||
var all = pendingRepo.findAll();
|
|
||||||
var size = all.spliterator().getExactSizeIfKnown();
|
|
||||||
assertEquals(1, size);
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Pending.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanQueryForANonExistentPendingWithNoResults() {
|
|
||||||
var empty = pendingRepo.GetPendingSubmission("12345620230215000001");
|
|
||||||
assertTrue(empty.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CannotEnterASubmissionIdThatIsTooLong() {
|
|
||||||
Pending p = new Pending();
|
|
||||||
p.setSubmissionId("123456202302150000001");
|
|
||||||
assertEquals(0, pendingRepo.findAll().spliterator().getExactSizeIfKnown());
|
|
||||||
// I wish I knew why this saves
|
|
||||||
// TODO: make this throw...
|
|
||||||
pendingRepo.save(p);
|
|
||||||
|
|
||||||
assertThrows(org.springframework.dao.DataIntegrityViolationException.class, () -> {
|
|
||||||
assertEquals(0, pendingRepo.findAll().spliterator().getExactSizeIfKnown());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Pending.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package gov.irs.directfile.status.acknowledgement;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.TaxReturnSubmission;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@DataJpaTest
|
|
||||||
class TaxReturnSubmissionRepositoryTest {
|
|
||||||
@Autowired
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepository;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void canSaveAndRetrieveTaxReturnSubmissions() {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
String submissionId = "12345678901234567890";
|
|
||||||
taxReturnSubmissionRepository.save(new TaxReturnSubmission(taxReturnId, submissionId));
|
|
||||||
|
|
||||||
Optional<String> result = taxReturnSubmissionRepository.getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
|
|
||||||
assertTrue(result.isPresent());
|
|
||||||
assertEquals(result.get(), submissionId);
|
|
||||||
|
|
||||||
// Note: Hibernate disables batching for entities having an identity PK, so no batching to test for here
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void returnsEmptyOptionalWhenTryingToFindSubmissionIdOfTaxReturnThatDoesNotExist() {
|
|
||||||
UUID taxReturnId = UUID.randomUUID();
|
|
||||||
Optional<String> result = taxReturnSubmissionRepository.getLatestSubmissionIdByTaxReturnId(taxReturnId);
|
|
||||||
|
|
||||||
assertTrue(result.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
class AWSCredentialsConfigurationTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void staticCredentialProviderCreatedWhenApplicablePropertySetToFalse() {
|
|
||||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
|
||||||
.withPropertyValues(
|
|
||||||
"aws.accessKey=test",
|
|
||||||
"aws.secretKey=test",
|
|
||||||
"aws.default-credentials-provider-chain-enabled=false")
|
|
||||||
.withUserConfiguration(AWSCredentialsConfiguration.class);
|
|
||||||
applicationContextRunner.run((context) -> {
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isNotNull();
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isInstanceOf(StaticCredentialsProvider.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void staticCredentialProviderCreatedWhenApplicablePropertyIsNotSet() {
|
|
||||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
|
||||||
.withPropertyValues("aws.accessKey=test", "aws.secretKey=test")
|
|
||||||
.withUserConfiguration(AWSCredentialsConfiguration.class);
|
|
||||||
applicationContextRunner.run((context) -> {
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isNotNull();
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isInstanceOf(StaticCredentialsProvider.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void defaultCredentialProviderCreatedWhenApplicablePropertySetToTrue() {
|
|
||||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
|
||||||
.withPropertyValues(
|
|
||||||
"aws.accessKey=test",
|
|
||||||
"aws.secretKey=test",
|
|
||||||
"aws.default-credentials-provider-chain-enabled=true")
|
|
||||||
.withUserConfiguration(AWSCredentialsConfiguration.class);
|
|
||||||
applicationContextRunner.run((context) -> {
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isNotNull();
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isInstanceOf(DefaultCredentialsProvider.class);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import software.amazon.awssdk.services.kms.KmsClient;
|
|
||||||
import software.amazon.encryption.s3.materials.CryptographicMaterialsManager;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@SpringBootTest(
|
|
||||||
classes = {EncryptionClientConfiguration.class, AWSCredentialsConfiguration.class},
|
|
||||||
webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
|
||||||
class EncryptionClientConfigurationTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
EncryptionClientConfiguration encryptionClientConfiguration;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void regionalKmsClientIsNotNull() {
|
|
||||||
KmsClient kmsClient = encryptionClientConfiguration.regionalKmsClient();
|
|
||||||
assertNotNull(kmsClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void kmsCryptoIsNotNull() {
|
|
||||||
String testKmsKeyArn = "test-kms-arn";
|
|
||||||
CryptographicMaterialsManager cryptographicMaterialsManager =
|
|
||||||
encryptionClientConfiguration.kmsCrypto(testKmsKeyArn);
|
|
||||||
assertNotNull(cryptographicMaterialsManager);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
class SnsClientConfigurationTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void snsClientBeanCreatedWhenStaticCredentialProviderEnabled() {
|
|
||||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
|
||||||
.withPropertyValues(
|
|
||||||
"aws.accessKey=test",
|
|
||||||
"aws.secretKey=test",
|
|
||||||
"status.sns.endpoint=http://directfile.test",
|
|
||||||
"status.sns.status-change-topic-arn=test-topic-arn",
|
|
||||||
"status.sns.region=us-west-2",
|
|
||||||
"status.sns.accessKey=test",
|
|
||||||
"status.sns.secretKey=test",
|
|
||||||
"status.sns.status-change-publish-enabled=true",
|
|
||||||
"aws.default-credentials-provider-chain-enabled=false")
|
|
||||||
.withUserConfiguration(AWSCredentialsConfiguration.class, SnsClientConfiguration.class);
|
|
||||||
applicationContextRunner.run((context) -> {
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isInstanceOf(StaticCredentialsProvider.class);
|
|
||||||
assertThat(context.getBean(SnsClientConfiguration.class)).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void snsClientBeanCreatedWhenDefaultCredentialProviderEnabled() {
|
|
||||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
|
||||||
.withPropertyValues(
|
|
||||||
"status.sns.endpoint=http://directfile.test",
|
|
||||||
"status.sns.status-change-topic-arn=test-topic-arn",
|
|
||||||
"status.sns.region=us-west-2",
|
|
||||||
"status.sns.accessKey=test",
|
|
||||||
"status.sns.secretKey=test",
|
|
||||||
"status.sns.status-change-publish-enabled=true",
|
|
||||||
"aws.default-credentials-provider-chain-enabled=true")
|
|
||||||
.withUserConfiguration(AWSCredentialsConfiguration.class, SnsClientConfiguration.class);
|
|
||||||
applicationContextRunner.run((context) -> {
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isInstanceOf(DefaultCredentialsProvider.class);
|
|
||||||
assertThat(context.getBean(SnsClientConfiguration.class)).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.boot.test.context.TestConfiguration;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
import software.amazon.awssdk.services.sns.SnsClient;
|
|
||||||
import software.amazon.awssdk.services.sns.model.ListSubscriptionsByTopicRequest;
|
|
||||||
import software.amazon.awssdk.services.sns.model.ListSubscriptionsByTopicResponse;
|
|
||||||
import software.amazon.awssdk.services.sns.model.Subscription;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@TestConfiguration
|
|
||||||
public class SnsClientTestConfiguration {
|
|
||||||
@Bean
|
|
||||||
@Primary
|
|
||||||
public SnsClient testSnsClient() {
|
|
||||||
ListSubscriptionsByTopicResponse listSubscriptionsByTopicResponse =
|
|
||||||
mock(ListSubscriptionsByTopicResponse.class);
|
|
||||||
List<Subscription> subscriptions = new ArrayList<>();
|
|
||||||
subscriptions.add(mock(Subscription.class));
|
|
||||||
when(listSubscriptionsByTopicResponse.subscriptions()).thenReturn(subscriptions);
|
|
||||||
|
|
||||||
SnsClient snsClient = mock(SnsClient.class);
|
|
||||||
when(snsClient.listSubscriptionsByTopic(any(ListSubscriptionsByTopicRequest.class)))
|
|
||||||
.thenReturn(listSubscriptionsByTopicResponse);
|
|
||||||
return snsClient;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package gov.irs.directfile.status.config;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|
||||||
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
|
|
||||||
import software.amazon.awssdk.services.sqs.SqsClient;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
class SqsClientConfigurationTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void sqsClientBeanCreatedWhenStaticCredentialProviderEnabled() {
|
|
||||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
|
||||||
.withPropertyValues(
|
|
||||||
"aws.accessKey=test",
|
|
||||||
"aws.secretKey=test",
|
|
||||||
"status.message-queue.endpoint=http://directfile.test",
|
|
||||||
"status.message-queue.status-change-queue=test-queue-01",
|
|
||||||
"status.message-queue.pending-submission-queue=test-queue-02",
|
|
||||||
"status.message-queue.dlq-pending-submission-queue=test-queue-03",
|
|
||||||
"status.message-queue.region=us-west-2",
|
|
||||||
"status.message-queue.accessKey=test",
|
|
||||||
"status.message-queue.secretKey=test",
|
|
||||||
"aws.default-credentials-provider-chain-enabled=false")
|
|
||||||
.withUserConfiguration(AWSCredentialsConfiguration.class, SqsClientConfiguration.class);
|
|
||||||
applicationContextRunner.run((context) -> {
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isInstanceOf(StaticCredentialsProvider.class);
|
|
||||||
assertThat(context.getBean(SqsClient.class)).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void sqsClientBeanCreatedWhenDefaultCredentialProviderEnabled() {
|
|
||||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
|
||||||
.withPropertyValues(
|
|
||||||
"status.message-queue.endpoint=http://directfile.test",
|
|
||||||
"status.message-queue.status-change-queue=test-queue-01",
|
|
||||||
"status.message-queue.pending-submission-queue=test-queue-02",
|
|
||||||
"status.message-queue.dlq-pending-submission-queue=test-queue-03",
|
|
||||||
"status.message-queue.region=us-west-2",
|
|
||||||
"status.message-queue.accessKey=test",
|
|
||||||
"status.message-queue.secretKey=test",
|
|
||||||
"aws.default-credentials-provider-chain-enabled=true")
|
|
||||||
.withUserConfiguration(AWSCredentialsConfiguration.class, SqsClientConfiguration.class);
|
|
||||||
applicationContextRunner.run((context) -> {
|
|
||||||
assertThat(context.getBean(AwsCredentialsProvider.class)).isInstanceOf(DefaultCredentialsProvider.class);
|
|
||||||
assertThat(context.getBean(SqsClient.class)).isNotNull();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
package gov.irs.directfile.status.error;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import org.hibernate.engine.jdbc.batch.JdbcBatchLogging;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.acknowledgement.CompletedAcknowledgementRepository;
|
|
||||||
import gov.irs.directfile.status.domain.Completed;
|
|
||||||
import gov.irs.directfile.status.domain.Error;
|
|
||||||
import gov.irs.directfile.status.extension.BatchUtil;
|
|
||||||
import gov.irs.directfile.status.extension.LoggerExtension;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
// For right now, Errors only exist as information on
|
|
||||||
// the Reject. It doesn't need a direct access right now.
|
|
||||||
// It may/will in the future.
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@ImportAutoConfiguration(classes = SecurityAutoConfiguration.class)
|
|
||||||
@DataJpaTest(properties = "spring.main.web-application-type=servlet")
|
|
||||||
class ErrorRepositoryTest {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
CompletedAcknowledgementRepository completedRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
ErrorRepository errorRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TestEntityManager testEntityManager;
|
|
||||||
|
|
||||||
@RegisterExtension
|
|
||||||
private static final LoggerExtension batchLogVerifier = new LoggerExtension(Level.TRACE, JdbcBatchLogging.NAME);
|
|
||||||
|
|
||||||
@Value("${spring.jpa.properties.hibernate.jdbc.batch_size}")
|
|
||||||
private int batchSize;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddABasicError() {
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject");
|
|
||||||
errorRepository.save(e);
|
|
||||||
Error retrieved = errorRepository.findById("XML-123-4567-006").get();
|
|
||||||
assertEquals(e.getErrorCodeTranslationKey(), retrieved.getErrorCodeTranslationKey());
|
|
||||||
assertEquals(e.getMefErrorCode(), retrieved.getMefErrorCode());
|
|
||||||
assertEquals(e.getErrorMessage(), retrieved.getErrorMessage());
|
|
||||||
assertEquals(e.getMefErrorCategory(), retrieved.getMefErrorCategory());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
testEntityManager.flush();
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Error.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CanAddAnErrorToACompletedRecord() {
|
|
||||||
// you should never do it this way!
|
|
||||||
// Errors should be created first
|
|
||||||
Completed c = new Completed();
|
|
||||||
c.setSubmissionId("12345620230215000001");
|
|
||||||
c.setStatus("Rejected");
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject");
|
|
||||||
e.setCompleted(List.of(c));
|
|
||||||
completedRepo.save(c);
|
|
||||||
errorRepository.save(e);
|
|
||||||
Error retrieved = errorRepository.findById("XML-123-4567-006").get();
|
|
||||||
assertEquals("12345620230215000001", retrieved.getCompleted().get(0).getSubmissionId());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
testEntityManager.flush();
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Completed.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Error.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void CallingSaveOnAKnownIDWithNewInformationUpdatesTheRecord() {
|
|
||||||
Error e = new Error();
|
|
||||||
e.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e.setErrorMessage("You messed up!");
|
|
||||||
e.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e.setMefErrorCategory("Reject");
|
|
||||||
errorRepository.save(e);
|
|
||||||
Error e2 = new Error();
|
|
||||||
e2.setMefErrorCode("XML-123-4567-006");
|
|
||||||
e2.setErrorMessage("This is bad");
|
|
||||||
e2.setErrorCodeTranslationKey("translation/reject/XML-123-4567-006");
|
|
||||||
e2.setMefErrorCategory("Reject");
|
|
||||||
errorRepository.save(e2);
|
|
||||||
|
|
||||||
Error retrieved = errorRepository.findById("XML-123-4567-006").get();
|
|
||||||
assertEquals(e.getErrorCodeTranslationKey(), retrieved.getErrorCodeTranslationKey());
|
|
||||||
assertEquals(e.getMefErrorCode(), retrieved.getMefErrorCode());
|
|
||||||
assertEquals(e2.getErrorMessage(), retrieved.getErrorMessage());
|
|
||||||
assertEquals(e.getMefErrorCategory(), retrieved.getMefErrorCategory());
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
testEntityManager.flush();
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Error.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, Error.class.getName(), BatchUtil.BatchType.UPDATE));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
package gov.irs.directfile.status.error;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import jakarta.validation.ConstraintViolationException;
|
|
||||||
import org.hibernate.engine.jdbc.batch.JdbcBatchLogging;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
import org.springframework.transaction.TransactionSystemException;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.domain.ToolkitError;
|
|
||||||
import gov.irs.directfile.status.extension.BatchUtil;
|
|
||||||
import gov.irs.directfile.status.extension.LoggerExtension;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@ImportAutoConfiguration(classes = SecurityAutoConfiguration.class)
|
|
||||||
@Transactional(propagation = Propagation.NOT_SUPPORTED) // Allows CrudRepository Transactional scope to work as intended
|
|
||||||
@DataJpaTest
|
|
||||||
public class ToolkitErrorRepositoryTest {
|
|
||||||
@Autowired
|
|
||||||
ToolkitErrorRepository toolkitErrorRepo;
|
|
||||||
|
|
||||||
@RegisterExtension
|
|
||||||
private static final LoggerExtension batchLogVerifier = new LoggerExtension(Level.TRACE, JdbcBatchLogging.NAME);
|
|
||||||
|
|
||||||
@Value("${spring.jpa.properties.hibernate.jdbc.batch_size}")
|
|
||||||
private int batchSize;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void DoesNotAllowNullErrorName() {
|
|
||||||
ToolkitError tke = new ToolkitError();
|
|
||||||
tke.setSubmissionId("12345620230215000010");
|
|
||||||
tke.setErrorMessage("something");
|
|
||||||
TransactionSystemException tse = assertThrows(TransactionSystemException.class, () -> {
|
|
||||||
toolkitErrorRepo.save(tke);
|
|
||||||
});
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
ConstraintViolationException.class, tse.getMostSpecificCause().getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void DoesNotAllowNullErrorMessage() {
|
|
||||||
ToolkitError tke = new ToolkitError();
|
|
||||||
tke.setSubmissionId("12345678900987654321");
|
|
||||||
tke.setErrorName("ToolkitException");
|
|
||||||
TransactionSystemException tse = assertThrows(TransactionSystemException.class, () -> {
|
|
||||||
toolkitErrorRepo.save(tke);
|
|
||||||
});
|
|
||||||
assertEquals(
|
|
||||||
ConstraintViolationException.class, tse.getMostSpecificCause().getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void SavesWithValidFields() {
|
|
||||||
ToolkitError tke = new ToolkitError();
|
|
||||||
tke.setSubmissionId("12345678900987654321");
|
|
||||||
tke.setErrorName("ToolkitException");
|
|
||||||
tke.setErrorMessage("Something went wrong!");
|
|
||||||
|
|
||||||
toolkitErrorRepo.save(tke);
|
|
||||||
|
|
||||||
assert (toolkitErrorRepo.findById(tke.getSubmissionId())).isPresent();
|
|
||||||
|
|
||||||
// Verify JDBC batching
|
|
||||||
batchLogVerifier.verifyLogContainsMessage(
|
|
||||||
BatchUtil.buildBatchMessage(1, batchSize, ToolkitError.class.getName(), BatchUtil.BatchType.INSERT));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package gov.irs.directfile.status.extension;
|
|
||||||
|
|
||||||
public final class BatchUtil {
|
|
||||||
private BatchUtil() {
|
|
||||||
// no instantiation allowed
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum BatchType {
|
|
||||||
INSERT,
|
|
||||||
UPDATE,
|
|
||||||
DELETE
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String buildBatchMessage(int count, int batchSize, String entityName, BatchType type) {
|
|
||||||
return String.format("Executing JDBC batch (%d / %d) - `%s#%s`", count, batchSize, entityName, type);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
package gov.irs.directfile.status.extension;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import ch.qos.logback.classic.Level;
|
|
||||||
import ch.qos.logback.classic.Logger;
|
|
||||||
import ch.qos.logback.classic.LoggerContext;
|
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
||||||
import ch.qos.logback.core.read.ListAppender;
|
|
||||||
import org.junit.jupiter.api.extension.AfterEachCallback;
|
|
||||||
import org.junit.jupiter.api.extension.BeforeEachCallback;
|
|
||||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.slf4j.event.KeyValuePair;
|
|
||||||
|
|
||||||
import gov.irs.directfile.audit.AuditLogElement;
|
|
||||||
import gov.irs.directfile.audit.events.Event;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
public class LoggerExtension implements BeforeEachCallback, AfterEachCallback {
|
|
||||||
private Logger logger;
|
|
||||||
private ListAppender<ILoggingEvent> appender;
|
|
||||||
private final String loggerName;
|
|
||||||
private final Level level;
|
|
||||||
|
|
||||||
public LoggerExtension(Level level, String loggerName) {
|
|
||||||
this.loggerName = loggerName;
|
|
||||||
this.level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void beforeEach(ExtensionContext context) {
|
|
||||||
logger = (Logger) LoggerFactory.getLogger(loggerName);
|
|
||||||
appender = new ListAppender<>();
|
|
||||||
appender.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
|
|
||||||
logger.setLevel(level);
|
|
||||||
logger.addAppender(appender);
|
|
||||||
appender.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterEach(ExtensionContext context) {
|
|
||||||
logger.detachAppender(appender);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifyLogEvent(Event event) {
|
|
||||||
verifyLogEvent(event, 0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifyLogEvent(Event event, Map<AuditLogElement, Object> logPropertiesToAssert) {
|
|
||||||
verifyLogEvent(event, 0, logPropertiesToAssert);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifyLogEvent(Event event, int index) {
|
|
||||||
verifyLogEvent(event, index, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifyLogEvent(Event event, int index, Map<AuditLogElement, Object> logPropertiesToAssert) {
|
|
||||||
ILoggingEvent loggingEvent = appender.list.get(index);
|
|
||||||
|
|
||||||
List<KeyValuePair> keyValuePairs = loggingEvent.getKeyValuePairs();
|
|
||||||
Map<String, String> mdcPropertyMap = loggingEvent.getMDCPropertyMap();
|
|
||||||
|
|
||||||
HashMap<String, String> combinedMap = new HashMap<>(mdcPropertyMap);
|
|
||||||
ListIterator<KeyValuePair> keyValuePairListIterator = keyValuePairs.listIterator();
|
|
||||||
while (keyValuePairListIterator.hasNext()) {
|
|
||||||
KeyValuePair next = keyValuePairListIterator.next();
|
|
||||||
// a collision here causes logback to silently exclude all keyValuePairs from json output
|
|
||||||
assertFalse(combinedMap.containsKey(next.key));
|
|
||||||
combinedMap.put(next.key, next.value == null ? null : next.value.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(combinedMap.get(AuditLogElement.cyberOnly.toString()), "true", "cyberOnly not set (XXXX flag)");
|
|
||||||
assertEquals(event.getEventStatus().toString(), combinedMap.get(AuditLogElement.eventStatus.toString()));
|
|
||||||
assertEquals(event.getEventId().toString(), combinedMap.get(AuditLogElement.eventId.toString()));
|
|
||||||
assertEquals(
|
|
||||||
event.getEventPrincipal().getUserType().toString(),
|
|
||||||
combinedMap.get(AuditLogElement.userType.toString()));
|
|
||||||
assertEquals(event.getEventErrorMessage(), combinedMap.get(AuditLogElement.eventErrorMessage.toString()));
|
|
||||||
assertEquals(event.getDetail(), combinedMap.get(AuditLogElement.detail.toString()));
|
|
||||||
|
|
||||||
if (logPropertiesToAssert != null) {
|
|
||||||
for (Map.Entry<AuditLogElement, Object> entry : logPropertiesToAssert.entrySet()) {
|
|
||||||
assertEquals(
|
|
||||||
entry.getValue().toString(),
|
|
||||||
combinedMap.get(entry.getKey().toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void verifyLogContainsMessage(String message) {
|
|
||||||
boolean foundMessage = false;
|
|
||||||
for (ILoggingEvent loggingEvent : appender.list) {
|
|
||||||
if (loggingEvent.getMessage().equals(message)) {
|
|
||||||
foundMessage = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assertTrue(foundMessage, String.format("log message not found: %s", message));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import com.amazon.sqs.javamessaging.message.SQSTextMessage;
|
|
||||||
import jakarta.jms.JMSException;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
import gov.irs.directfile.status.config.MessageQueueConfiguration;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class MessageQueueListenerServiceTest {
|
|
||||||
@Mock
|
|
||||||
private MessageQueueConfiguration messageQueueConfiguration;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private PendingSubmissionMessageRouter pendingSubmissionMessageRouter;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private SubmissionConfirmationMessageRouter submissionConfirmationMessageRouter;
|
|
||||||
|
|
||||||
private MessageQueueListenerService messageQueueListenerService;
|
|
||||||
|
|
||||||
String pendingSubmissionMessageJson =
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"payload": {
|
|
||||||
"@type": "PendingSubmissionPayloadV1",
|
|
||||||
"pendings": [
|
|
||||||
{
|
|
||||||
"taxReturnId": "00000000-0000-1111-1111-000000000000",
|
|
||||||
"submissionId": "11111111"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"taxReturnId": "00000000-0000-2222-2222-000000000000",
|
|
||||||
"submissionId": "22222222"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"headers": {
|
|
||||||
"headers": {
|
|
||||||
"VERSION": "1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
|
|
||||||
String submissionConfirmationMessageJson =
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"payload": {
|
|
||||||
"@type": "SubmissionConfirmationPayloadV1",
|
|
||||||
"receipts": [
|
|
||||||
{
|
|
||||||
"taxReturnId": "f6cdd8d9-2606-4acc-a331-28554f9bc72b",
|
|
||||||
"submissionId": "submissionId1",
|
|
||||||
"receiptId": "receiptId1",
|
|
||||||
"submissionReceivedAt": 1721754334033
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"taxReturnId": "248fcc48-b362-497e-8927-e3c88b653009",
|
|
||||||
"submissionId": "submissionId2",
|
|
||||||
"receiptId": "receiptId2",
|
|
||||||
"submissionReceivedAt": 1721754334033
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"headers": {
|
|
||||||
"headers": {
|
|
||||||
"VERSION": "1.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setup() {
|
|
||||||
messageQueueListenerService = new MessageQueueListenerService(
|
|
||||||
messageQueueConfiguration, pendingSubmissionMessageRouter, submissionConfirmationMessageRouter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onMessage_success_pendingSubmissionMessage() throws JMSException {
|
|
||||||
SQSTextMessage mockMessage = mock(SQSTextMessage.class);
|
|
||||||
when(mockMessage.getText()).thenReturn(pendingSubmissionMessageJson);
|
|
||||||
|
|
||||||
assertDoesNotThrow(() -> {
|
|
||||||
messageQueueListenerService.onMessage(mockMessage);
|
|
||||||
|
|
||||||
// Verify that only the pending submission handler is called and message acknowledged
|
|
||||||
verify(pendingSubmissionMessageRouter, times(1)).handlePendingSubmissionMessage(any());
|
|
||||||
verify(submissionConfirmationMessageRouter, never()).handleSubmissionConfirmationMessage(any());
|
|
||||||
verify(mockMessage, times(1)).acknowledge();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onMessage_success_submissionConfirmationMessage() throws JMSException {
|
|
||||||
SQSTextMessage mockMessage = mock(SQSTextMessage.class);
|
|
||||||
when(mockMessage.getText()).thenReturn(submissionConfirmationMessageJson);
|
|
||||||
|
|
||||||
assertDoesNotThrow(() -> {
|
|
||||||
messageQueueListenerService.onMessage(mockMessage);
|
|
||||||
|
|
||||||
// Verify that only the submission confirmation handler is called and message acknowledged
|
|
||||||
verify(pendingSubmissionMessageRouter, never()).handlePendingSubmissionMessage(any());
|
|
||||||
verify(submissionConfirmationMessageRouter, times(1)).handleSubmissionConfirmationMessage(any());
|
|
||||||
verify(mockMessage, times(1)).acknowledge();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onMessage_exceptionThrown() throws JMSException {
|
|
||||||
SQSTextMessage mockMessage = mock(SQSTextMessage.class);
|
|
||||||
when(mockMessage.getText())
|
|
||||||
.thenReturn(
|
|
||||||
"""
|
|
||||||
{"some_key":"some_val_without_a_closing_string}\s
|
|
||||||
""");
|
|
||||||
|
|
||||||
messageQueueListenerService.onMessage(mockMessage);
|
|
||||||
|
|
||||||
// Verify that handlers and message.acknowledge() are not called
|
|
||||||
verify(pendingSubmissionMessageRouter, never()).handlePendingSubmissionMessage(any());
|
|
||||||
verify(submissionConfirmationMessageRouter, never()).handleSubmissionConfirmationMessage(any());
|
|
||||||
verify(mockMessage, never()).acknowledge();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.exception.UnsupportedVersionException;
|
|
||||||
import gov.irs.directfile.models.message.pending.PendingSubmissionMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.pending.VersionedPendingSubmissionMessage;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.AbstractPendingSubmissionPayload;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.PendingSubmissionPayloadV1;
|
|
||||||
import gov.irs.directfile.status.services.handlers.pending.PendingSubmissionV1Handler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.pending.UnsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class PendingSubmissionMessageRouterTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
public PendingSubmissionV1Handler pendingSubmissionV1Handler;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
public UnsupportedMessageVersionHandler unsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
private PendingSubmissionMessageRouter pendingSubmissionMessageRouter;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setup() {
|
|
||||||
pendingSubmissionMessageRouter =
|
|
||||||
new PendingSubmissionMessageRouter(unsupportedMessageVersionHandler, pendingSubmissionV1Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void itGetsHandlerWhenProvidedAValidPendingSubmissionMessageVersion() {
|
|
||||||
// Arrange: Create a VersionedPendingSubmissionMessage, with a header specifying V1
|
|
||||||
AbstractPendingSubmissionPayload payload = new PendingSubmissionPayloadV1(new ArrayList<>());
|
|
||||||
VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> queueMessage =
|
|
||||||
new VersionedPendingSubmissionMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(
|
|
||||||
MessageHeaderAttribute.VERSION,
|
|
||||||
PendingSubmissionMessageVersion.V1.getVersion()));
|
|
||||||
|
|
||||||
// Act: Call handlePendingSubmissionMessage()
|
|
||||||
assertDoesNotThrow(() -> {
|
|
||||||
pendingSubmissionMessageRouter.handlePendingSubmissionMessage(queueMessage);
|
|
||||||
|
|
||||||
// Assert: Expect that an exception was not thrown, and that the
|
|
||||||
// PendingSubmissionV1Handler.handlePendingSubmissionMessage() was called
|
|
||||||
verify(pendingSubmissionV1Handler, times(1)).handlePendingSubmissionMessage(any());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void itHandlesUnsupportedVersions() {
|
|
||||||
// Arrange: Create a VersionedPendingSubmissionMessage, with a header specifying an unsupported version
|
|
||||||
AbstractPendingSubmissionPayload payload = new PendingSubmissionPayloadV1(new ArrayList<>());
|
|
||||||
String unsupportedVersion = "9.0.EGG";
|
|
||||||
|
|
||||||
VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> messageWithUnsupportedVersion =
|
|
||||||
new VersionedPendingSubmissionMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders().addHeader(MessageHeaderAttribute.VERSION, unsupportedVersion));
|
|
||||||
|
|
||||||
// Act: call handlePendingSubmissionMessage()
|
|
||||||
assertThrows(UnsupportedVersionException.class, () -> {
|
|
||||||
pendingSubmissionMessageRouter.handlePendingSubmissionMessage(messageWithUnsupportedVersion);
|
|
||||||
|
|
||||||
// Assert: Check that we called the UnsupportedVersionHandler
|
|
||||||
verify(unsupportedMessageVersionHandler, times(1)).handlePendingSubmissionMessage(any());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,108 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
|
||||||
import org.junit.jupiter.params.provider.NullAndEmptySource;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.PublisherException;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.status.StatusChangeMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.status.VersionedStatusChangeMessage;
|
|
||||||
import gov.irs.directfile.models.message.status.payload.AbstractStatusChangePayload;
|
|
||||||
import gov.irs.directfile.models.message.status.payload.StatusChangePayloadV1;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
import static org.mockito.Mockito.doThrow;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
class StatusChangeMessageServiceTest {
|
|
||||||
private StatusChangeMessageService statusChangeMessageService;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private StatusChangeSqsPublisher sqsPublisher;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private StatusChangeSnsPublisher snsPublisher;
|
|
||||||
|
|
||||||
private static final Map<String, List<String>> v1Object;
|
|
||||||
private static final String v1Json;
|
|
||||||
|
|
||||||
static {
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
v1Object = Map.of(
|
|
||||||
"accepted", List.of("11111111", "33333333"),
|
|
||||||
"rejected", List.of("22222222", "44444444"));
|
|
||||||
|
|
||||||
VersionedStatusChangeMessage<AbstractStatusChangePayload> v1VersionedObject =
|
|
||||||
new VersionedStatusChangeMessage<>(
|
|
||||||
new StatusChangePayloadV1(v1Object),
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(MessageHeaderAttribute.VERSION, StatusChangeMessageVersion.V1.getVersion()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
v1Json = objectMapper.writeValueAsString(v1VersionedObject);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setup() {
|
|
||||||
statusChangeMessageService =
|
|
||||||
new StatusChangeMessageService(List.of(sqsPublisher, snsPublisher), new ObjectMapper());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void publishStatusChangePayloadV1_success() {
|
|
||||||
statusChangeMessageService.publishStatusChangePayloadV1(v1Object);
|
|
||||||
|
|
||||||
ArgumentCaptor<String> sqsPublishArgumentCaptor = ArgumentCaptor.forClass(String.class);
|
|
||||||
verify(sqsPublisher, times(1)).publish(sqsPublishArgumentCaptor.capture());
|
|
||||||
assertEquals(v1Json, sqsPublishArgumentCaptor.getValue());
|
|
||||||
|
|
||||||
ArgumentCaptor<String> snsPublishArgumentCaptor = ArgumentCaptor.forClass(String.class);
|
|
||||||
verify(snsPublisher, times(1)).publish(snsPublishArgumentCaptor.capture());
|
|
||||||
assertEquals(v1Json, snsPublishArgumentCaptor.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@NullAndEmptySource
|
|
||||||
public void publishStatusChangePayloadV1_nullOrEmptyPublishers(List<StatusChangePublisher> publishers) {
|
|
||||||
StatusChangeMessageService noPublishersService = new StatusChangeMessageService(publishers, new ObjectMapper());
|
|
||||||
noPublishersService.publishStatusChangePayloadV1(v1Object);
|
|
||||||
verify(sqsPublisher, never()).publish(any());
|
|
||||||
verify(snsPublisher, never()).publish(any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void publishSubmissionConfirmationPayloadV1_writeValueAsStringFails() throws JsonProcessingException {
|
|
||||||
ObjectMapper mockMapper = Mockito.mock(ObjectMapper.class);
|
|
||||||
StatusChangeMessageService testService =
|
|
||||||
new StatusChangeMessageService(List.of(sqsPublisher, snsPublisher), mockMapper);
|
|
||||||
doThrow(new JsonProcessingException("bad json") {}).when(mockMapper).writeValueAsString(any());
|
|
||||||
|
|
||||||
assertThrows(PublisherException.class, () -> testService.publishStatusChangePayloadV1(v1Object));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void publishStatusChangePayloadV1_publishFails() {
|
|
||||||
doThrow(new PublisherException("could not publish")).when(snsPublisher).publish(any());
|
|
||||||
|
|
||||||
assertThrows(PublisherException.class, () -> statusChangeMessageService.publishStatusChangePayloadV1(v1Object));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
package gov.irs.directfile.status.services;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.SubmissionConfirmationMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.SubmissionConfirmationPayloadV1;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.SubmissionConfirmationPayloadV2;
|
|
||||||
import gov.irs.directfile.models.message.exception.UnsupportedVersionException;
|
|
||||||
import gov.irs.directfile.status.services.handlers.confirmation.SubmissionConfirmationV1Handler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.confirmation.SubmissionConfirmationV2Handler;
|
|
||||||
import gov.irs.directfile.status.services.handlers.confirmation.UnsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.mockito.ArgumentMatchers.*;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class SubmissionConfirmationMessageRouterTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
public SubmissionConfirmationV1Handler submissionConfirmationV1Handler;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
public SubmissionConfirmationV2Handler submissionConfirmationV2Handler;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
public UnsupportedMessageVersionHandler unsupportedMessageVersionHandler;
|
|
||||||
|
|
||||||
private SubmissionConfirmationMessageRouter submissionConfirmationMessageRouter;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setup() {
|
|
||||||
submissionConfirmationMessageRouter = new SubmissionConfirmationMessageRouter(
|
|
||||||
unsupportedMessageVersionHandler, submissionConfirmationV1Handler, submissionConfirmationV2Handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void itGetsHandlerWhenProvidedAValidConfirmationMessageVersion() {
|
|
||||||
// Arrange: Create a VersionedSubmissionConfirmationMessage, with a header specifying V1
|
|
||||||
AbstractSubmissionConfirmationPayload payload = new SubmissionConfirmationPayloadV1(List.of());
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> queueMessage =
|
|
||||||
new VersionedSubmissionConfirmationMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(
|
|
||||||
MessageHeaderAttribute.VERSION,
|
|
||||||
SubmissionConfirmationMessageVersion.V1.getVersion()));
|
|
||||||
|
|
||||||
// Act: Call handleSubmissionConfirmationMessage()
|
|
||||||
assertDoesNotThrow(() -> {
|
|
||||||
submissionConfirmationMessageRouter.handleSubmissionConfirmationMessage(queueMessage);
|
|
||||||
|
|
||||||
// Assert: Expect that an exception was not thrown, and that the
|
|
||||||
// SubmissionConfirmationV1Handler.handleSubmissionConfirmationMessage() was called
|
|
||||||
verify(submissionConfirmationV1Handler, times(1)).handleSubmissionConfirmationMessage(any());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void givenConfirmationMessageV2_whenHandleSubmissionConfirmationMessage_thenCorrectHandlerChosen() {
|
|
||||||
// Arrange: Create a VersionedSubmissionConfirmationMessage, with a header specifying V2
|
|
||||||
AbstractSubmissionConfirmationPayload payload = new SubmissionConfirmationPayloadV2(List.of());
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> queueMessage =
|
|
||||||
new VersionedSubmissionConfirmationMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(
|
|
||||||
MessageHeaderAttribute.VERSION,
|
|
||||||
SubmissionConfirmationMessageVersion.V2.getVersion()));
|
|
||||||
|
|
||||||
// Act: Call handleSubmissionConfirmationMessage()
|
|
||||||
assertDoesNotThrow(() -> {
|
|
||||||
submissionConfirmationMessageRouter.handleSubmissionConfirmationMessage(queueMessage);
|
|
||||||
|
|
||||||
// Assert: Expect that an exception was not thrown, and that the
|
|
||||||
// SubmissionConfirmationV2Handler.handleSubmissionConfirmationMessage() was called
|
|
||||||
verify(submissionConfirmationV2Handler, times(1)).handleSubmissionConfirmationMessage(any());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void itHandlesUnsupportedVersions() {
|
|
||||||
// Arrange: Create a VersionedSubmissionMessage, with a header specifying an unsupported version
|
|
||||||
AbstractSubmissionConfirmationPayload payload = new SubmissionConfirmationPayloadV2(List.of());
|
|
||||||
String unsupportedVersion = "9.0.EGG";
|
|
||||||
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> messageWithUnsupportedVersion =
|
|
||||||
new VersionedSubmissionConfirmationMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders().addHeader(MessageHeaderAttribute.VERSION, unsupportedVersion));
|
|
||||||
|
|
||||||
// Act: call handleSubmissionConfirmationMessage()
|
|
||||||
assertThrows(UnsupportedVersionException.class, () -> {
|
|
||||||
submissionConfirmationMessageRouter.handleSubmissionConfirmationMessage(messageWithUnsupportedVersion);
|
|
||||||
|
|
||||||
// Assert: Check that we called the UnsupportedVersionHandler
|
|
||||||
verify(unsupportedMessageVersionHandler, times(1)).handleSubmissionConfirmationMessage(any());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.confirmation;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.TaxReturnSubmissionReceipt;
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.SubmissionConfirmationMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.SubmissionConfirmationPayloadV1;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.PendingAcknowledgementRepository;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.TaxReturnSubmissionRepository;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@EnableConfigurationProperties(StatusProperties.class)
|
|
||||||
@DataJpaTest
|
|
||||||
class SubmissionConfirmationV1HandlerTest {
|
|
||||||
@Autowired
|
|
||||||
PendingAcknowledgementRepository pendingRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private StatusProperties statusProperties;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void handleSubmissionConfirmationMessage() {
|
|
||||||
SubmissionConfirmationV1Handler handler =
|
|
||||||
new SubmissionConfirmationV1Handler(pendingRepo, taxReturnSubmissionRepo, statusProperties);
|
|
||||||
|
|
||||||
TaxReturnSubmissionReceipt taxReturnSubmissionReceipt1 =
|
|
||||||
new TaxReturnSubmissionReceipt(UUID.randomUUID(), "submissionId1", "receiptId1", new Date());
|
|
||||||
TaxReturnSubmissionReceipt taxReturnSubmissionReceipt2 =
|
|
||||||
new TaxReturnSubmissionReceipt(UUID.randomUUID(), "submissionId2", "receiptId2", new Date());
|
|
||||||
List<TaxReturnSubmissionReceipt> taxReturnSubmissionReceipts =
|
|
||||||
List.of(taxReturnSubmissionReceipt1, taxReturnSubmissionReceipt2);
|
|
||||||
|
|
||||||
AbstractSubmissionConfirmationPayload payload =
|
|
||||||
new SubmissionConfirmationPayloadV1(taxReturnSubmissionReceipts);
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> queueMessage =
|
|
||||||
new VersionedSubmissionConfirmationMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(
|
|
||||||
MessageHeaderAttribute.VERSION,
|
|
||||||
SubmissionConfirmationMessageVersion.V1.getVersion()));
|
|
||||||
|
|
||||||
handler.handleSubmissionConfirmationMessage(queueMessage);
|
|
||||||
|
|
||||||
assertEquals(2, pendingRepo.count());
|
|
||||||
Optional<Pending> pending1 = pendingRepo.GetPendingSubmission(taxReturnSubmissionReceipt1.getSubmissionId());
|
|
||||||
assertTrue(pending1.isPresent()
|
|
||||||
&& pending1.get().getSubmissionId().equals(taxReturnSubmissionReceipt1.getSubmissionId()));
|
|
||||||
Optional<Pending> pending2 = pendingRepo.GetPendingSubmission(taxReturnSubmissionReceipt2.getSubmissionId());
|
|
||||||
assertTrue(pending2.isPresent()
|
|
||||||
&& pending2.get().getSubmissionId().equals(taxReturnSubmissionReceipt2.getSubmissionId()));
|
|
||||||
|
|
||||||
assertEquals(2, taxReturnSubmissionRepo.count());
|
|
||||||
Optional<String> submissionId1 = taxReturnSubmissionRepo.getLatestSubmissionIdByTaxReturnId(
|
|
||||||
taxReturnSubmissionReceipt1.getTaxReturnId());
|
|
||||||
assertTrue(
|
|
||||||
submissionId1.isPresent() && submissionId1.get().equals(taxReturnSubmissionReceipt1.getSubmissionId()));
|
|
||||||
Optional<String> submissionId2 = taxReturnSubmissionRepo.getLatestSubmissionIdByTaxReturnId(
|
|
||||||
taxReturnSubmissionReceipt2.getTaxReturnId());
|
|
||||||
assertTrue(
|
|
||||||
submissionId2.isPresent() && submissionId2.get().equals(taxReturnSubmissionReceipt2.getSubmissionId()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.confirmation;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.TaxReturnSubmissionReceipt;
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.SubmissionConfirmationMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.VersionedSubmissionConfirmationMessage;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.AbstractSubmissionConfirmationPayload;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.SubmissionConfirmationPayloadV2;
|
|
||||||
import gov.irs.directfile.models.message.confirmation.payload.SubmissionConfirmationPayloadV2Entry;
|
|
||||||
import gov.irs.directfile.models.message.event.SubmissionEventTypeEnum;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.PendingAcknowledgementRepository;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.TaxReturnSubmissionRepository;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@EnableConfigurationProperties(StatusProperties.class)
|
|
||||||
@DataJpaTest
|
|
||||||
class SubmissionConfirmationV2HandlerTest {
|
|
||||||
@Autowired
|
|
||||||
PendingAcknowledgementRepository pendingRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
StatusProperties statusProperties;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void handleSubmissionConfirmationMessage() {
|
|
||||||
SubmissionConfirmationV2Handler handler =
|
|
||||||
new SubmissionConfirmationV2Handler(pendingRepo, taxReturnSubmissionRepo, statusProperties);
|
|
||||||
|
|
||||||
TaxReturnSubmissionReceipt taxReturnSubmissionReceipt1 =
|
|
||||||
new TaxReturnSubmissionReceipt(UUID.randomUUID(), "submissionId1", "receiptId1", new Date());
|
|
||||||
SubmissionConfirmationPayloadV2Entry entry1 = new SubmissionConfirmationPayloadV2Entry(
|
|
||||||
taxReturnSubmissionReceipt1, SubmissionEventTypeEnum.SUBMITTED, Map.of());
|
|
||||||
TaxReturnSubmissionReceipt taxReturnSubmissionReceipt2 =
|
|
||||||
new TaxReturnSubmissionReceipt(UUID.randomUUID(), "submissionId2", "receiptId2", new Date());
|
|
||||||
SubmissionConfirmationPayloadV2Entry entry2 = new SubmissionConfirmationPayloadV2Entry(
|
|
||||||
taxReturnSubmissionReceipt2, SubmissionEventTypeEnum.FAILED, Map.of());
|
|
||||||
TaxReturnSubmissionReceipt taxReturnSubmissionReceipt3 =
|
|
||||||
new TaxReturnSubmissionReceipt(UUID.randomUUID(), "submissionId3", "receiptId3", new Date());
|
|
||||||
SubmissionConfirmationPayloadV2Entry entry3 = new SubmissionConfirmationPayloadV2Entry(
|
|
||||||
taxReturnSubmissionReceipt3, SubmissionEventTypeEnum.SUBMITTED, Map.of());
|
|
||||||
|
|
||||||
List<SubmissionConfirmationPayloadV2Entry> entries = List.of(entry1, entry2, entry3);
|
|
||||||
|
|
||||||
AbstractSubmissionConfirmationPayload payload = new SubmissionConfirmationPayloadV2(entries);
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> queueMessage =
|
|
||||||
new VersionedSubmissionConfirmationMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(
|
|
||||||
MessageHeaderAttribute.VERSION,
|
|
||||||
SubmissionConfirmationMessageVersion.V2.getVersion()));
|
|
||||||
|
|
||||||
handler.handleSubmissionConfirmationMessage(queueMessage);
|
|
||||||
|
|
||||||
assertEquals(2, pendingRepo.count());
|
|
||||||
Optional<Pending> pending1 = pendingRepo.GetPendingSubmission(taxReturnSubmissionReceipt1.getSubmissionId());
|
|
||||||
assertTrue(pending1.isPresent()
|
|
||||||
&& pending1.get().getSubmissionId().equals(taxReturnSubmissionReceipt1.getSubmissionId()));
|
|
||||||
Optional<Pending> pending2 = pendingRepo.GetPendingSubmission(taxReturnSubmissionReceipt3.getSubmissionId());
|
|
||||||
assertTrue(pending2.isPresent()
|
|
||||||
&& pending2.get().getSubmissionId().equals(taxReturnSubmissionReceipt3.getSubmissionId()));
|
|
||||||
|
|
||||||
assertEquals(2, taxReturnSubmissionRepo.count());
|
|
||||||
Optional<String> submissionId1 = taxReturnSubmissionRepo.getLatestSubmissionIdByTaxReturnId(
|
|
||||||
taxReturnSubmissionReceipt1.getTaxReturnId());
|
|
||||||
assertTrue(
|
|
||||||
submissionId1.isPresent() && submissionId1.get().equals(taxReturnSubmissionReceipt1.getSubmissionId()));
|
|
||||||
Optional<String> submissionId2 = taxReturnSubmissionRepo.getLatestSubmissionIdByTaxReturnId(
|
|
||||||
taxReturnSubmissionReceipt3.getTaxReturnId());
|
|
||||||
assertTrue(
|
|
||||||
submissionId2.isPresent() && submissionId2.get().equals(taxReturnSubmissionReceipt3.getSubmissionId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void handleSubmissionConfirmationMessage_noSubmittedReturns() {
|
|
||||||
SubmissionConfirmationV2Handler handler =
|
|
||||||
new SubmissionConfirmationV2Handler(pendingRepo, taxReturnSubmissionRepo, statusProperties);
|
|
||||||
|
|
||||||
TaxReturnSubmissionReceipt taxReturnSubmissionReceipt1 =
|
|
||||||
new TaxReturnSubmissionReceipt(UUID.randomUUID(), "submissionId1", "receiptId1", new Date());
|
|
||||||
SubmissionConfirmationPayloadV2Entry entry1 = new SubmissionConfirmationPayloadV2Entry(
|
|
||||||
taxReturnSubmissionReceipt1, SubmissionEventTypeEnum.FAILED, Map.of());
|
|
||||||
|
|
||||||
List<SubmissionConfirmationPayloadV2Entry> entries = List.of(entry1);
|
|
||||||
|
|
||||||
AbstractSubmissionConfirmationPayload payload = new SubmissionConfirmationPayloadV2(entries);
|
|
||||||
VersionedSubmissionConfirmationMessage<AbstractSubmissionConfirmationPayload> queueMessage =
|
|
||||||
new VersionedSubmissionConfirmationMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(
|
|
||||||
MessageHeaderAttribute.VERSION,
|
|
||||||
SubmissionConfirmationMessageVersion.V2.getVersion()));
|
|
||||||
|
|
||||||
handler.handleSubmissionConfirmationMessage(queueMessage);
|
|
||||||
|
|
||||||
assertEquals(0, pendingRepo.count());
|
|
||||||
assertEquals(0, taxReturnSubmissionRepo.count());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
package gov.irs.directfile.status.services.handlers.pending;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
|
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
|
||||||
|
|
||||||
import gov.irs.directfile.models.TaxReturnIdAndSubmissionId;
|
|
||||||
import gov.irs.directfile.models.message.MessageHeaderAttribute;
|
|
||||||
import gov.irs.directfile.models.message.QueueMessageHeaders;
|
|
||||||
import gov.irs.directfile.models.message.pending.PendingSubmissionMessageVersion;
|
|
||||||
import gov.irs.directfile.models.message.pending.VersionedPendingSubmissionMessage;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.AbstractPendingSubmissionPayload;
|
|
||||||
import gov.irs.directfile.models.message.pending.payload.PendingSubmissionPayloadV1;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.PendingAcknowledgementRepository;
|
|
||||||
import gov.irs.directfile.status.acknowledgement.TaxReturnSubmissionRepository;
|
|
||||||
import gov.irs.directfile.status.config.StatusProperties;
|
|
||||||
import gov.irs.directfile.status.domain.Pending;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
|
|
||||||
@EnableConfigurationProperties(StatusProperties.class)
|
|
||||||
@DataJpaTest
|
|
||||||
class PendingSubmissionV1HandlerTest {
|
|
||||||
@Autowired
|
|
||||||
PendingAcknowledgementRepository pendingRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
TaxReturnSubmissionRepository taxReturnSubmissionRepo;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
StatusProperties statusProperties;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void handlePendingSubmissionMessage() {
|
|
||||||
PendingSubmissionV1Handler handler =
|
|
||||||
new PendingSubmissionV1Handler(pendingRepo, taxReturnSubmissionRepo, statusProperties);
|
|
||||||
|
|
||||||
TaxReturnIdAndSubmissionId taxReturnIdAndSubmissionId1 =
|
|
||||||
new TaxReturnIdAndSubmissionId(UUID.randomUUID(), "submissionId1");
|
|
||||||
TaxReturnIdAndSubmissionId taxReturnIdAndSubmissionId2 =
|
|
||||||
new TaxReturnIdAndSubmissionId(UUID.randomUUID(), "submissionId2");
|
|
||||||
List<TaxReturnIdAndSubmissionId> taxReturnIdAndSubmissionIds =
|
|
||||||
List.of(taxReturnIdAndSubmissionId1, taxReturnIdAndSubmissionId2);
|
|
||||||
|
|
||||||
AbstractPendingSubmissionPayload payload = new PendingSubmissionPayloadV1(taxReturnIdAndSubmissionIds);
|
|
||||||
VersionedPendingSubmissionMessage<AbstractPendingSubmissionPayload> queueMessage =
|
|
||||||
new VersionedPendingSubmissionMessage<>(
|
|
||||||
payload,
|
|
||||||
new QueueMessageHeaders()
|
|
||||||
.addHeader(
|
|
||||||
MessageHeaderAttribute.VERSION,
|
|
||||||
PendingSubmissionMessageVersion.V1.getVersion()));
|
|
||||||
|
|
||||||
handler.handlePendingSubmissionMessage(queueMessage);
|
|
||||||
|
|
||||||
assertEquals(2, pendingRepo.count());
|
|
||||||
Optional<Pending> pending1 = pendingRepo.GetPendingSubmission(taxReturnIdAndSubmissionId1.getSubmissionId());
|
|
||||||
assertTrue(pending1.isPresent()
|
|
||||||
&& pending1.get().getSubmissionId().equals(taxReturnIdAndSubmissionId1.getSubmissionId()));
|
|
||||||
Optional<Pending> pending2 = pendingRepo.GetPendingSubmission(taxReturnIdAndSubmissionId2.getSubmissionId());
|
|
||||||
assertTrue(pending2.isPresent()
|
|
||||||
&& pending2.get().getSubmissionId().equals(taxReturnIdAndSubmissionId2.getSubmissionId()));
|
|
||||||
|
|
||||||
assertEquals(2, taxReturnSubmissionRepo.count());
|
|
||||||
Optional<String> submissionId1 = taxReturnSubmissionRepo.getLatestSubmissionIdByTaxReturnId(
|
|
||||||
taxReturnIdAndSubmissionId1.getTaxReturnId());
|
|
||||||
assertTrue(
|
|
||||||
submissionId1.isPresent() && submissionId1.get().equals(taxReturnIdAndSubmissionId1.getSubmissionId()));
|
|
||||||
Optional<String> submissionId2 = taxReturnSubmissionRepo.getLatestSubmissionIdByTaxReturnId(
|
|
||||||
taxReturnIdAndSubmissionId2.getTaxReturnId());
|
|
||||||
assertTrue(
|
|
||||||
submissionId2.isPresent() && submissionId2.get().equals(taxReturnIdAndSubmissionId2.getSubmissionId()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
spring:
|
|
||||||
datasource:
|
|
||||||
driver-class-name: org.h2.Driver
|
|
||||||
url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true
|
|
||||||
jpa:
|
|
||||||
properties:
|
|
||||||
hibernate:
|
|
||||||
dialect: org.hibernate.dialect.H2Dialect #Override PostgreSQLDialect defined in src/main/resources/application.yaml, SpringBoot v3.3.0 enforced using dialect
|
|
||||||
status:
|
|
||||||
private-key: src/test/resources/private.p12
|
|
||||||
private-key-password: 000
|
|
||||||
unit-testing: true
|
|
||||||
etin: ${STATUS_ETIN:99999}
|
|
||||||
asid: 000
|
|
||||||
efin: 00
|
|
||||||
prod: false
|
|
||||||
toolkit: 000
|
|
||||||
root-translation-key: status
|
|
||||||
translation-key-splitter: .
|
|
||||||
ack-poll-in-milliseconds: 1200000
|
|
||||||
messageQueue:
|
|
||||||
url: http://localhost:4577/000000000000/pending-submission-queue
|
|
||||||
region: us-west-2
|
|
||||||
accessKey: accessKey
|
|
||||||
secretKey: secretKey
|
|
||||||
sqs-message-handling-enabled: false
|
|
||||||
|
|
||||||
direct-file:
|
|
||||||
local-encryption:
|
|
||||||
local-wrapping-key: lYIIKutUatfMwdEGB8qtUpQc3wMNtT5pfM+zW57qrv4=
|
|
||||||
|
|
||||||
aws:
|
|
||||||
enabled: false
|
|
||||||
default-credentials-provider-chain-enabled: false
|
|
||||||
access-key: test
|
|
||||||
secret-key: test
|
|
||||||
region: us-west-2
|
|
||||||
kmsEndpoint: http://directfile.test
|
|
|
@ -1,2 +0,0 @@
|
||||||
# This is an empty logging properties file because the MeF SDK requires one
|
|
||||||
# Because we use some MeF Java classes in our code, it requires us to have this.
|
|
|
@ -1,5 +0,0 @@
|
||||||
**/application-local.*
|
|
||||||
/src/main/java/gov/irs/directfile/submit/xml
|
|
||||||
.env*
|
|
||||||
.git/
|
|
||||||
Dockerfile*
|
|
45
direct-file/submit/.gitignore
vendored
45
direct-file/submit/.gitignore
vendored
|
@ -1,45 +0,0 @@
|
||||||
HELP.md
|
|
||||||
target/
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
|
|
||||||
### STS ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
.sts4-cache
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
/nbproject/private/
|
|
||||||
/nbbuild/
|
|
||||||
/dist/
|
|
||||||
/nbdist/
|
|
||||||
/.nb-gradle/
|
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
sample_runner.sh
|
|
||||||
/test/
|
|
||||||
/src/main/java/resources/test
|
|
||||||
*.jar
|
|
||||||
/target
|
|
||||||
/.secret/
|
|
||||||
/src/main/resources/application-local.*
|
|
||||||
/src/main/resources/test/run
|
|
||||||
audit_log.txt
|
|
||||||
|
|
||||||
### Spot Bugs ###
|
|
||||||
/src/main/resources/spotbugs/output/spotbugs.xml
|
|
|
@ -1,5 +0,0 @@
|
||||||
changeLogFile=db/changelog.yaml
|
|
||||||
url=jdbc:postgresql://localhost:32768/directfile-submit
|
|
||||||
username=postgres
|
|
||||||
password=postgres
|
|
||||||
changesetAuthor=directfile
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue