diff --git a/.clang-tidy b/.clang-tidy index 474b68ecc..c5809dfc2 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -126,8 +126,8 @@ CheckOptions: readability-braces-around-statements.ShortStatementLines: 2 bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc;::std::expected - misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*" + misc-include-cleaner.IgnoreHeaders: '.*/(detail|impl)/.*' -HeaderFilterRegex: '^.*/(src|unitests)/.*\.(h|hpp)$' +HeaderFilterRegex: '^.*/(src|unittests)/.*\.(h|hpp)$' WarningsAsErrors: '*' diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 000000000..3fc7bfb18 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,11 @@ +coverage: + status: + project: + default: + target: 50% + threshold: 2% + + patch: + default: + target: 20% # Need to bump this number https://docs.codecov.com/docs/commit-status#patch-status + threshold: 2% diff --git a/.github/actions/build_clio/action.yml b/.github/actions/build_clio/action.yml index 4cba98966..3316d2ed6 100644 --- a/.github/actions/build_clio/action.yml +++ b/.github/actions/build_clio/action.yml @@ -1,37 +1,18 @@ name: Build clio description: Build clio in build directory inputs: - conan_profile: - description: Conan profile name - required: true - default: default - conan_cache_hit: - description: Whether conan cache has been downloaded - required: true + target: + description: Build target name + default: all runs: using: composite steps: - - name: Get number of threads on mac - id: mac_threads - if: ${{ runner.os == 'macOS' }} - shell: bash - run: echo "num=$(($(sysctl -n hw.logicalcpu) - 2))" >> $GITHUB_OUTPUT - - - name: Get number of threads on Linux - id: linux_threads - if: ${{ runner.os == 'Linux' }} - shell: bash - run: echo "num=$(($(nproc) - 2))" >> $GITHUB_OUTPUT + - name: Get number of threads + uses: ./.github/actions/get_number_of_threads + id: number_of_threads - name: Build Clio shell: bash - env: - BUILD_OPTION: "${{ inputs.conan_cache_hit == 'true' && 'missing' || '' }}" - LINT: "${{ runner.os == 'Linux' && 'True' || 'False' }}" run: | - mkdir -p build cd build - threads_num=${{ steps.mac_threads.outputs.num || steps.linux_threads.outputs.num }} - conan install .. -of . -b $BUILD_OPTION -s build_type=Release -o clio:tests=True -o clio:lint=$LINT --profile ${{ inputs.conan_profile }} - cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release .. -G Ninja - cmake --build . --parallel $threads_num + cmake --build . --parallel ${{ steps.number_of_threads.outputs.threads_number }} --target ${{ inputs.target }} diff --git a/.github/actions/clang_format/action.yml b/.github/actions/clang_format/action.yml index 7763115a8..f49774bfc 100644 --- a/.github/actions/clang_format/action.yml +++ b/.github/actions/clang_format/action.yml @@ -18,6 +18,8 @@ runs: shell: bash - name: Run formatter + continue-on-error: true + id: run_formatter run: | ./.githooks/pre-commit shell: bash @@ -27,3 +29,8 @@ runs: shell: bash run: | git diff --color --exit-code | tee "clang-format.patch" + + - name: Fail job + if: ${{ steps.run_formatter.outcome != 'success' }} + shell: bash + run: exit 1 diff --git a/.github/actions/code_coverage/action.yml b/.github/actions/code_coverage/action.yml new file mode 100644 index 000000000..eb3a72c78 --- /dev/null +++ b/.github/actions/code_coverage/action.yml @@ -0,0 +1,29 @@ +name: Generate code coverage report +description: Run tests, generate code coverage report and upload it to codecov.io +runs: + using: composite + steps: + - name: Run tests + shell: bash + run: | + build/clio_tests --gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*:BackendCassandraFactoryTestWithDB*" + + - name: Run gcovr + shell: bash + run: | + gcovr -e unittests --xml build/coverage_report.xml -j8 --exclude-throw-branches + + - name: Archive coverage report + uses: actions/upload-artifact@v3 + with: + name: coverage-report.xml + path: build/coverage_report.xml + retention-days: 30 + + - name: Upload coverage report + uses: codecov/codecov-action@v3 + with: + files: build/coverage_report.xml + fail_ci_if_error: true + verbose: true + token: ${{ env.CODECOV_TOKEN }} diff --git a/.github/actions/generate/action.yml b/.github/actions/generate/action.yml new file mode 100644 index 000000000..6d2f50887 --- /dev/null +++ b/.github/actions/generate/action.yml @@ -0,0 +1,41 @@ +name: Run conan and cmake +description: Run conan and cmake +inputs: + conan_profile: + description: Conan profile name + required: true + conan_cache_hit: + description: Whether conan cache has been downloaded + required: true + default: 'false' + build_type: + description: Build type for third-party libraries and clio. Could be 'Release', 'Debug' + required: true + default: 'Release' + code_coverage: + description: Whether conan's coverage option should be on or not + required: true + default: 'false' +runs: + using: composite + steps: + - name: Create build directory + shell: bash + run: mkdir -p build + + - name: Run conan + shell: bash + env: + BUILD_OPTION: "${{ inputs.conan_cache_hit == 'true' && 'missing' || '' }}" + CODE_COVERAGE: "${{ inputs.code_coverage == 'true' && 'True' || 'False' }}" + run: | + cd build + conan install .. -of . -b $BUILD_OPTION -s build_type=${{ inputs.build_type }} -o clio:tests=True -o clio:lint=False -o clio:coverage="${CODE_COVERAGE}" --profile ${{ inputs.conan_profile }} + + - name: Run cmake + shell: bash + env: + BUILD_TYPE: "${{ inputs.build_type }}" + run: | + cd build + cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} ${{ inputs.extra_cmake_args }} .. -G Ninja diff --git a/.github/actions/get_number_of_threads/action.yml b/.github/actions/get_number_of_threads/action.yml new file mode 100644 index 000000000..3af2e9f2b --- /dev/null +++ b/.github/actions/get_number_of_threads/action.yml @@ -0,0 +1,26 @@ +name: Get number of threads +description: Determines number of threads to use on macOS and Linux +outputs: + threads_number: + description: Number of threads to use + value: ${{ steps.number_of_threads_export.outputs.num }} +runs: + using: composite + steps: + - name: Get number of threads on mac + id: mac_threads + if: ${{ runner.os == 'macOS' }} + shell: bash + run: echo "num=$(($(sysctl -n hw.logicalcpu) - 2))" >> $GITHUB_OUTPUT + + - name: Get number of threads on Linux + id: linux_threads + if: ${{ runner.os == 'Linux' }} + shell: bash + run: echo "num=$(($(nproc) - 2))" >> $GITHUB_OUTPUT + + - name: Export output variable + shell: bash + id: number_of_threads_export + run: | + echo "num=${{ steps.mac_threads.outputs.num || steps.linux_threads.outputs.num }}" >> $GITHUB_OUTPUT diff --git a/.github/actions/prepare_runner/action.yml b/.github/actions/prepare_runner/action.yml new file mode 100644 index 000000000..fe593ef7e --- /dev/null +++ b/.github/actions/prepare_runner/action.yml @@ -0,0 +1,47 @@ +name: Prepare runner +description: Install packages, set environment variables, create directories +inputs: + disable_ccache: + description: Whether ccache should be disabled + required: true +runs: + using: composite + steps: + - name: Install packages on mac + if: ${{ runner.os == 'macOS' }} + shell: bash + run: | + brew install llvm@14 pkg-config ninja bison cmake ccache jq gh + + - name: Fix git permissions on Linux + if: ${{ runner.os == 'Linux' }} + shell: bash + run: git config --global --add safe.directory $PWD + + - name: Set env variables for macOS + if: ${{ runner.os == 'macOS' }} + shell: bash + run: | + echo "CCACHE_DIR=${{ github.workspace }}/.ccache" >> $GITHUB_ENV + echo "CONAN_USER_HOME=${{ github.workspace }}" >> $GITHUB_ENV + + - name: Set env variables for Linux + if: ${{ runner.os == 'Linux' }} + shell: bash + run: | + echo "CCACHE_DIR=/root/.ccache" >> $GITHUB_ENV + echo "CONAN_USER_HOME=/root/" >> $GITHUB_ENV + + - name: Set CCACHE_DISABLE=1 + if: ${{ inputs.disable_ccache == 'true' }} + shell: bash + run: | + echo "CCACHE_DISABLE=1" >> $GITHUB_ENV + + - name: Create directories + shell: bash + run: | + mkdir -p $CCACHE_DIR + mkdir -p $CONAN_USER_HOME/.conan + + diff --git a/.github/actions/restore_cache/action.yml b/.github/actions/restore_cache/action.yml index d3aa24a28..8771ee798 100644 --- a/.github/actions/restore_cache/action.yml +++ b/.github/actions/restore_cache/action.yml @@ -7,6 +7,14 @@ inputs: ccache_dir: description: Path to .ccache directory required: true + build_type: + description: Current build type (e.g. Release, Debug) + required: true + default: Release + code_coverage: + description: Whether code coverage is on + required: true + default: 'false' outputs: conan_hash: description: Hash to use as a part of conan cache key @@ -40,11 +48,12 @@ runs: id: conan_cache with: path: ${{ inputs.conan_dir }}/data - key: clio-conan_data-${{ runner.os }}-develop-${{ steps.conan_hash.outputs.hash }} + key: clio-conan_data-${{ runner.os }}-${{ inputs.build_type }}-develop-${{ steps.conan_hash.outputs.hash }} - name: Restore ccache cache uses: actions/cache/restore@v3 id: ccache_cache + if: ${{ env.CCACHE_DISABLE != '1' }} with: path: ${{ inputs.ccache_dir }} - key: clio-ccache-${{ runner.os }}-develop-${{ steps.git_common_ancestor.outputs.commit }} + key: clio-ccache-${{ runner.os }}-${{ inputs.build_type }}${{ inputs.code_coverage == 'true' && '-code_coverage' || '' }}-develop-${{ steps.git_common_ancestor.outputs.commit }} diff --git a/.github/actions/save_cache/action.yml b/.github/actions/save_cache/action.yml index ef3407a5e..a130f44fc 100644 --- a/.github/actions/save_cache/action.yml +++ b/.github/actions/save_cache/action.yml @@ -16,6 +16,16 @@ inputs: ccache_cache_hit: description: Whether conan cache has been downloaded required: true + ccache_cache_miss_rate: + description: How many cache misses happened + build_type: + description: Current build type (e.g. Release, Debug) + required: true + default: Release + code_coverage: + description: Whether code coverage is on + required: true + default: 'false' runs: using: composite steps: @@ -34,13 +44,13 @@ runs: uses: actions/cache/save@v3 with: path: ${{ inputs.conan_dir }}/data - key: clio-conan_data-${{ runner.os }}-develop-${{ inputs.conan_hash }} + key: clio-conan_data-${{ runner.os }}-${{ inputs.build_type }}-develop-${{ inputs.conan_hash }} - name: Save ccache cache - if: ${{ inputs.ccache_cache_hit != 'true' }} + if: ${{ inputs.ccache_cache_hit != 'true' || inputs.ccache_cache_miss_rate == '100.0' }} uses: actions/cache/save@v3 with: path: ${{ inputs.ccache_dir }} - key: clio-ccache-${{ runner.os }}-develop-${{ steps.git_common_ancestor.outputs.commit }} + key: clio-ccache-${{ runner.os }}-${{ inputs.build_type }}${{ inputs.code_coverage == 'true' && '-code_coverage' || '' }}-develop-${{ steps.git_common_ancestor.outputs.commit }} diff --git a/.github/actions/setup_conan/action.yml b/.github/actions/setup_conan/action.yml index 470fe9afb..af2e95e1a 100644 --- a/.github/actions/setup_conan/action.yml +++ b/.github/actions/setup_conan/action.yml @@ -31,9 +31,6 @@ runs: shell: bash id: conan_setup_linux run: | - conan profile new default --detect - conan profile update settings.compiler.cppstd=20 default - conan profile update settings.compiler.libcxx=libstdc++11 default echo "created_conan_profile=default" >> $GITHUB_OUTPUT - name: Export output variable diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 338d8b66d..ab630d2d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: Build Clio +name: Build on: push: branches: [master, release/*, develop] @@ -6,30 +6,48 @@ on: branches: [master, release/*, develop] workflow_dispatch: + jobs: lint: - name: Lint + name: Check format runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run clang-format uses: ./.github/actions/clang_format - build_mac: - name: Build macOS + build: + name: Build needs: lint - runs-on: [self-hosted, macOS] - env: - CCACHE_DIR: ${{ github.workspace }}/.ccache - CONAN_USER_HOME: ${{ github.workspace }} + strategy: + fail-fast: false + matrix: + include: + - os: heavy + container: + image: rippleci/clio_ci:latest + build_type: Release + code_coverage: false + - os: heavy + container: + image: rippleci/clio_ci:latest + build_type: Debug + code_coverage: true + - os: macOS + build_type: Release + code_coverage: false + runs-on: [self-hosted, "${{ matrix.os }}"] + container: ${{ matrix.container }} + steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Install packages - run: | - brew install llvm@14 pkg-config ninja bison cmake ccache jq + - name: Prepare runner + uses: ./.github/actions/prepare_runner + with: + disable_ccache: false - name: Setup conan uses: ./.github/actions/setup_conan @@ -41,88 +59,44 @@ jobs: with: conan_dir: ${{ env.CONAN_USER_HOME }}/.conan ccache_dir: ${{ env.CCACHE_DIR }} + build_type: ${{ matrix.build_type }} + code_coverage: ${{ matrix.code_coverage }} - - name: Build Clio - uses: ./.github/actions/build_clio + - name: Run conan and cmake + uses: ./.github/actions/generate with: conan_profile: ${{ steps.conan.outputs.conan_profile }} conan_cache_hit: ${{ steps.restore_cache.outputs.conan_cache_hit }} - - - name: Strip tests - run: strip build/clio_tests - - - name: Upload clio_tests - uses: actions/upload-artifact@v3 - with: - name: clio_tests_mac - path: build/clio_tests - - - name: Save cache - uses: ./.github/actions/save_cache - with: - conan_dir: ${{ env.CONAN_USER_HOME }}/.conan - conan_hash: ${{ steps.restore_cache.outputs.conan_hash }} - conan_cache_hit: ${{ steps.restore_cache.outputs.conan_cache_hit }} - ccache_dir: ${{ env.CCACHE_DIR }} - ccache_cache_hit: ${{ steps.restore_cache.outputs.ccache_cache_hit }} - - build_linux: - name: Build linux - needs: lint - runs-on: [self-hosted, Linux] - container: - image: conanio/gcc11:1.61.0 - options: --user root - env: - CCACHE_DIR: /root/.ccache - CONAN_USER_HOME: /root/ - steps: - - name: Get Clio - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Add llvm repo - run: | - echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-17 main' >> /etc/apt/sources.list - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - - - - name: Install packages - run: | - apt update -qq - apt install -y jq clang-tidy-17 - - - name: Install ccache - run: | - wget https://github.com/ccache/ccache/releases/download/v4.8.3/ccache-4.8.3-linux-x86_64.tar.xz - tar xf ./ccache-4.8.3-linux-x86_64.tar.xz - mv ./ccache-4.8.3-linux-x86_64/ccache /usr/bin/ccache - - - name: Fix git permissions - run: git config --global --add safe.directory $PWD - - - name: Setup conan - uses: ./.github/actions/setup_conan - - - name: Restore cache - uses: ./.github/actions/restore_cache - id: restore_cache - with: - conan_dir: ${{ env.CONAN_USER_HOME }}/.conan - ccache_dir: ${{ env.CCACHE_DIR }} + build_type: ${{ matrix.build_type }} + code_coverage: ${{ matrix.code_coverage }} - name: Build Clio uses: ./.github/actions/build_clio - with: - conan_cache_hit: ${{ steps.restore_cache.outputs.conan_cache_hit }} + + - name: Show ccache's statistics + shell: bash + id: ccache_stats + run: | + ccache -s > /tmp/ccache.stats + miss_rate=$(cat /tmp/ccache.stats | grep 'Misses' | head -n1 | sed 's/.*(\(.*\)%).*/\1/') + echo "miss_rate=${miss_rate}" >> $GITHUB_OUTPUT + cat /tmp/ccache.stats - name: Strip tests + if: ${{ !matrix.code_coverage }} run: strip build/clio_tests + - name: Upload clio_server + uses: actions/upload-artifact@v3 + with: + name: clio_server_${{ runner.os }}_${{ matrix.build_type }} + path: build/clio_server + - name: Upload clio_tests + if: ${{ !matrix.code_coverage }} uses: actions/upload-artifact@v3 with: - name: clio_tests_linux + name: clio_tests_${{ runner.os }} path: build/clio_tests - name: Save cache @@ -133,26 +107,37 @@ jobs: conan_cache_hit: ${{ steps.restore_cache.outputs.conan_cache_hit }} ccache_dir: ${{ env.CCACHE_DIR }} ccache_cache_hit: ${{ steps.restore_cache.outputs.ccache_cache_hit }} + ccache_cache_miss_rate: ${{ steps.ccache_stats.outputs.miss_rate }} + build_type: ${{ matrix.build_type }} + code_coverage: ${{ matrix.code_coverage }} + + # TODO: This is not a part of build process but it is the easiest way to do it here. + # It will be refactored in https://github.com/XRPLF/clio/issues/1075 + - name: Run code coverage + if: ${{ matrix.code_coverage }} + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + uses: ./.github/actions/code_coverage + + + test: + name: Run Tests + needs: build + strategy: + fail-fast: false + matrix: + include: + - os: heavy + container: + image: rippleci/clio_ci:latest + - os: macOS + runs-on: [self-hosted, "${{ matrix.os }}"] + container: ${{ matrix.container }} - test_mac: - needs: build_mac - runs-on: [self-hosted, macOS] - steps: - - uses: actions/download-artifact@v3 - with: - name: clio_tests_mac - - name: Run clio_tests - run: | - chmod +x ./clio_tests - ./clio_tests --gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*:BackendCassandraFactoryTestWithDB*" - - test_linux: - needs: build_linux - runs-on: [self-hosted, x-heavy] steps: - uses: actions/download-artifact@v3 with: - name: clio_tests_linux + name: clio_tests_${{ runner.os }} - name: Run clio_tests run: | chmod +x ./clio_tests diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml new file mode 100644 index 000000000..129352e42 --- /dev/null +++ b/.github/workflows/clang-tidy.yml @@ -0,0 +1,109 @@ +name: Clang-tidy check +on: + schedule: + - cron: '0 6 * * 1-5' + workflow_dispatch: + pull_request: + branches: [develop] + paths: + - .clang_tidy + - .github/workflows/clang-tidy.yml + +jobs: + clang_tidy: + runs-on: [self-hosted, Linux] + container: + image: rippleci/clio_ci:latest + permissions: + contents: write + issues: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Prepare runner + uses: ./.github/actions/prepare_runner + with: + disable_ccache: true + + - name: Setup conan + uses: ./.github/actions/setup_conan + id: conan + + - name: Restore cache + uses: ./.github/actions/restore_cache + id: restore_cache + with: + conan_dir: ${{ env.CONAN_USER_HOME }}/.conan + ccache_dir: ${{ env.CCACHE_DIR }} + + - name: Run conan and cmake + uses: ./.github/actions/generate + with: + conan_profile: ${{ steps.conan.outputs.conan_profile }} + conan_cache_hit: ${{ steps.restore_cache.outputs.conan_cache_hit }} + build_type: Release + + - name: Get number of threads + uses: ./.github/actions/get_number_of_threads + id: number_of_threads + + - name: Run clang-tidy + continue-on-error: true + shell: bash + id: run_clang_tidy + run: | + run-clang-tidy-17 -p build -j ${{ steps.number_of_threads.outputs.threads_number }} -fix -quiet 1>output.txt + + - name: Print issues found + if: ${{ steps.run_clang_tidy.outcome != 'success' }} + shell: bash + run: | + sed -i '/error\||/!d' ./output.txt + cat output.txt + rm output.txt + + - name: Create an issue + if: ${{ steps.run_clang_tidy.outcome != 'success' }} + id: create_issue + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + echo -e 'Clang-tidy found issues in the code:\n' > issue.md + echo -e "List of the issues found: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/" >> issue.md + gh issue create --assignee 'cindyyan317,godexsoft,kuznetsss' --label bug --title 'Clang-tidy found bugs in code🐛' --body-file ./issue.md > create_issue.log + created_issue=$(cat create_issue.log | sed 's|.*/||') + echo "created_issue=$created_issue" >> $GITHUB_OUTPUT + rm create_issue.log issue.md + + - uses: crazy-max/ghaction-import-gpg@v5 + with: + gpg_private_key: ${{ secrets.ACTIONS_GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.ACTIONS_GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true + + - name: Create PR with fixes + if: ${{ steps.run_clang_tidy.outcome != 'success' }} + uses: peter-evans/create-pull-request@v5 + env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ github.token }} + with: + commit-message: '[CI] clang-tidy auto fixes' + committer: Clio CI + branch: 'clang_tidy/autofix' + branch-suffix: timestamp + delete-branch: true + title: '[CI] clang-tidy auto fixes' + body: 'Fixes #${{ steps.create_issue.outputs.created_issue }}. Please review and commit clang-tidy fixes.' + reviewers: 'cindyyan317,godexsoft,kuznetsss' + + - name: Fail the job + if: ${{ steps.run_clang_tidy.outcome != 'success' }} + shell: bash + run: exit 1 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 000000000..6c370d542 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,138 @@ +name: Nightly release +on: + schedule: + - cron: '0 5 * * 1-5' + workflow_dispatch: + +jobs: + build: + name: Build clio + strategy: + fail-fast: false + matrix: + include: + - os: macOS + build_type: Release + - os: heavy + build_type: Release + container: + image: rippleci/clio_ci:latest + - os: heavy + build_type: Debug + container: + image: rippleci/clio_ci:latest + runs-on: [self-hosted, "${{ matrix.os }}"] + container: ${{ matrix.container }} + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Prepare runner + uses: ./.github/actions/prepare_runner + with: + disable_ccache: true + + - name: Setup conan + uses: ./.github/actions/setup_conan + id: conan + + - name: Run conan and cmake + uses: ./.github/actions/generate + with: + conan_profile: ${{ steps.conan.outputs.conan_profile }} + conan_cache_hit: ${{ steps.restore_cache.outputs.conan_cache_hit }} + build_type: ${{ matrix.build_type }} + + - name: Build Clio + uses: ./.github/actions/build_clio + + - name: Strip tests + run: strip build/clio_tests + + - name: Upload clio_tests + uses: actions/upload-artifact@v3 + with: + name: clio_tests_${{ runner.os }}_${{ matrix.build_type }} + path: build/clio_tests + + - name: Compress clio_server + shell: bash + run: | + cd build + tar czf ./clio_server_${{ runner.os }}_${{ matrix.build_type }}.tar.gz ./clio_server + + - name: Upload clio_server + uses: actions/upload-artifact@v3 + with: + name: clio_server_${{ runner.os }}_${{ matrix.build_type }} + path: build/clio_server_${{ runner.os }}_${{ matrix.build_type }}.tar.gz + + + run_tests: + needs: build + strategy: + fail-fast: false + matrix: + include: + - os: macOS + build_type: Release + - os: heavy + build_type: Release + - os: heavy + build_type: Debug + runs-on: [self-hosted, "${{ matrix.os }}"] + + steps: + - uses: actions/download-artifact@v3 + with: + name: clio_tests_${{ runner.os }}_${{ matrix.build_type }} + + - name: Run clio_tests + run: | + chmod +x ./clio_tests + ./clio_tests --gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*:BackendCassandraFactoryTestWithDB*" + + nightly_release: + needs: run_tests + runs-on: ubuntu-20.04 + env: + GH_REPO: ${{ github.repository }} + GH_TOKEN: ${{ github.token }} + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v3 + with: + path: nightly_release + + - name: Prepare files + shell: bash + run: | + cp ${{ github.workspace }}/.github/workflows/nightly_notes.md "${RUNNER_TEMP}/nightly_notes.md" + cd nightly_release + rm -r clio_tests* + for d in $(ls); do + archive_name=$(ls $d) + mv ${d}/${archive_name} ./ + rm -r $d + sha256sum ./$archive_name > ./${archive_name}.sha256sum + cat ./$archive_name.sha256sum >> "${RUNNER_TEMP}/nightly_notes.md" + done + echo '```' >> "${RUNNER_TEMP}/nightly_notes.md" + + - name: Remove current nightly release and nightly tag + shell: bash + run: | + gh release delete nightly --yes || true + git push origin :nightly || true + + - name: Publish nightly release + shell: bash + run: | + gh release create nightly --prerelease --title "Clio development (nightly) build" \ + --target $GITHUB_SHA --notes-file "${RUNNER_TEMP}/nightly_notes.md" \ + ./nightly_release/clio_server* diff --git a/.github/workflows/nightly_notes.md b/.github/workflows/nightly_notes.md new file mode 100644 index 000000000..38deb4302 --- /dev/null +++ b/.github/workflows/nightly_notes.md @@ -0,0 +1,6 @@ +> **Note:** Please remember that this is a development release and it is not recommended for production use. + +Changelog (including previous releases): https://github.com/XRPLF/clio/commits/nightly + +## SHA256 checksums +``` diff --git a/.github/workflows/update_docker_ci.yml b/.github/workflows/update_docker_ci.yml new file mode 100644 index 000000000..be0b273d9 --- /dev/null +++ b/.github/workflows/update_docker_ci.yml @@ -0,0 +1,40 @@ +name: Update CI docker image +on: + push: + branches: [develop] + paths: + - 'docker/ci/**' + - .github/workflows/update_docker_ci.yml + workflow_dispatch: + +jobs: + build_and_push: + name: Build and push docker image + runs-on: ubuntu-20.04 + steps: + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_PW }} + + - uses: actions/checkout@v4 + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - uses: docker/metadata-action@v5 + id: meta + with: + images: rippleci/clio_ci + tags: | + type=raw,value=latest + type=raw,value=gcc_11 + type=raw,value=${{ env.GITHUB_SHA }} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: ${{ github.workspace }}/docker/ci + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + diff --git a/CMake/CodeCoverage.cmake b/CMake/CodeCoverage.cmake new file mode 100644 index 000000000..52f95faa4 --- /dev/null +++ b/CMake/CodeCoverage.cmake @@ -0,0 +1,440 @@ +# Copyright (c) 2012 - 2017, Lars Bilke +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# CHANGES: +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# 2016-02-03, Lars Bilke +# - Refactored functions to use named parameters +# +# 2017-06-02, Lars Bilke +# - Merged with modified version from github.com/ufz/ogs +# +# 2019-05-06, Anatolii Kurotych +# - Remove unnecessary --coverage flag +# +# 2019-12-13, FeRD (Frank Dana) +# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor +# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments. +# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY +# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list +# - Set lcov basedir with -b argument +# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be +# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().) +# - Delete output dir, .info file on 'make clean' +# - Remove Python detection, since version mismatches will break gcovr +# - Minor cleanup (lowercase function names, update examples...) +# +# 2019-12-19, FeRD (Frank Dana) +# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets +# +# 2020-01-19, Bob Apthorpe +# - Added gfortran support +# +# 2020-02-17, FeRD (Frank Dana) +# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters +# in EXCLUDEs, and remove manual escaping from gcovr targets +# +# 2021-01-19, Robin Mueller +# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run +# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional +# flags to the gcovr command +# +# 2020-05-04, Mihchael Davis +# - Add -fprofile-abs-path to make gcno files contain absolute paths +# - Fix BASE_DIRECTORY not working when defined +# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines +# +# 2021-05-10, Martin Stump +# - Check if the generator is multi-config before warning about non-Debug builds +# +# 2022-02-22, Marko Wehle +# - Change gcovr output from -o for --xml and --html output respectively. +# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt". +# +# 2022-09-28, Sebastian Mueller +# - fix append_coverage_compiler_flags_to_target to correctly add flags +# - replace "-fprofile-arcs -ftest-coverage" with "--coverage" (equivalent) +# +# 2023-12-15, Bronek Kozicki +# - remove setup_target_for_coverage_lcov (slow) and setup_target_for_coverage_fastcov (no support for Clang) +# - fix Clang support by adding find_program( ... llvm-cov ) +# - add Apple Clang support by adding execute_process( COMMAND xcrun -f llvm-cov ... ) +# - add CODE_COVERAGE_GCOV_TOOL to explicitly select gcov tool and disable find_program +# - replace both functions setup_target_for_coverage_gcovr_* with single setup_target_for_coverage_gcovr +# - add support for all gcovr output formats +# +# USAGE: +# +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt (best inside an if-condition +# using a CMake option() to enable it just optionally): +# include(CodeCoverage) +# +# 3. Append necessary compiler flags for all supported source files: +# append_coverage_compiler_flags() +# Or for specific target: +# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME) +# +# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og +# +# 4. If you need to exclude additional directories from the report, specify them +# using full paths in the COVERAGE_EXCLUDES variable before calling +# setup_target_for_coverage_*(). +# Example: +# set(COVERAGE_EXCLUDES +# '${PROJECT_SOURCE_DIR}/src/dir1/*' +# '/path/to/my/src/dir2/*') +# Or, use the EXCLUDE argument to setup_target_for_coverage_*(). +# Example: +# setup_target_for_coverage_gcovr( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") +# +# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set +# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) +# Example: +# set(COVERAGE_EXCLUDES "dir1/*") +# setup_target_for_coverage_gcovr( +# NAME coverage +# EXECUTABLE testrunner +# FORMAT html-details +# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" +# EXCLUDE "dir2/*") +# +# 4.b If you need to pass specific options to gcovr, specify them in +# GCOVR_ADDITIONAL_ARGS variable. +# Example: +# set (GCOVR_ADDITIONAL_ARGS --exclude-throw-branches --exclude-noncode-lines -s) +# setup_target_for_coverage_gcovr( +# NAME coverage +# EXECUTABLE testrunner +# EXCLUDE "src/dir1" "src/dir2") +# +# 5. Use the functions described below to create a custom make target which +# runs your test executable and produces a code coverage report. +# +# 6. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target + +include(CMakeParseArguments) + +option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) + +# Check prereqs +find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) + +if (DEFINED CODE_COVERAGE_GCOV_TOOL) + set(GCOV_TOOL "${CODE_COVERAGE_GCOV_TOOL}") +elseif (DEFINED ENV{CODE_COVERAGE_GCOV_TOOL}) + set(GCOV_TOOL "$ENV{CODE_COVERAGE_GCOV_TOOL}") +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if (APPLE) + execute_process( COMMAND xcrun -f llvm-cov + OUTPUT_VARIABLE LLVMCOV_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + else() + find_program( LLVMCOV_PATH llvm-cov ) + endif() + if(LLVMCOV_PATH) + set(GCOV_TOOL "${LLVMCOV_PATH} gcov") + endif() +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + find_program( GCOV_PATH gcov ) + set(GCOV_TOOL "${GCOV_PATH}") +endif() + +# Check supported compiler (Clang, GNU and Flang) +get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(LANG ${LANGUAGES}) + if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) + message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") + endif() + elseif(NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU" + AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(LLVM)?[Ff]lang") + message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...") + endif() +endforeach() + +set(COVERAGE_COMPILER_FLAGS "-g --coverage" + CACHE INTERNAL "") +if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path) + if(HAVE_cxx_fprofile_abs_path) + set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() + include(CheckCCompilerFlag) + check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path) + if(HAVE_c_fprofile_abs_path) + set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") + endif() +endif() + +set(CMAKE_Fortran_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the Fortran compiler during coverage builds." + FORCE ) +set(CMAKE_CXX_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C++ compiler during coverage builds." + FORCE ) +set(CMAKE_C_FLAGS_COVERAGE + ${COVERAGE_COMPILER_FLAGS} + CACHE STRING "Flags used by the C compiler during coverage builds." + FORCE ) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used for linking binaries during coverage builds." + FORCE ) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE + "" + CACHE STRING "Flags used by the shared libraries linker during coverage builds." + FORCE ) +mark_as_advanced( + CMAKE_Fortran_FLAGS_COVERAGE + CMAKE_CXX_FLAGS_COVERAGE + CMAKE_C_FLAGS_COVERAGE + CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) + +get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) + message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") +endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + link_libraries(gcov) +endif() + +# Defines a target for running and collection code coverage information +# Builds dependencies, runs the given executable and outputs reports. +# NOTE! The executable should always have a ZERO as exit code otherwise +# the coverage generation will not complete. +# +# setup_target_for_coverage_gcovr( +# NAME ctest_coverage # New target name +# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR +# DEPENDENCIES executable_target # Dependencies to build first +# BASE_DIRECTORY "../" # Base directory for report +# # (defaults to PROJECT_SOURCE_DIR) +# FORMAT "cobertura" # Output format, one of: +# # xml cobertura sonarqube json-summary +# # json-details coveralls csv txt +# # html-single html-nested html-details +# # (xml is an alias to cobertura; +# # if no format is set, defaults to xml) +# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative +# # to BASE_DIRECTORY, with CMake 3.4+) +# ) +# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the +# GCVOR command. +function(setup_target_for_coverage_gcovr) + set(options NONE) + set(oneValueArgs BASE_DIRECTORY NAME FORMAT) + set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) + cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT GCOV_TOOL) + message(FATAL_ERROR "Could not find gcov or llvm-cov tool! Aborting...") + endif() + + if(NOT GCOVR_PATH) + message(FATAL_ERROR "Could not find gcovr tool! Aborting...") + endif() + + # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR + if(DEFINED Coverage_BASE_DIRECTORY) + get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) + else() + set(BASEDIR ${PROJECT_SOURCE_DIR}) + endif() + + if(NOT DEFINED Coverage_FORMAT) + set(Coverage_FORMAT xml) + endif() + + if("--output" IN_LIST GCOVR_ADDITIONAL_ARGS) + message(FATAL_ERROR "Unsupported --output option detected in GCOVR_ADDITIONAL_ARGS! Aborting...") + else() + if((Coverage_FORMAT STREQUAL "html-details") + OR (Coverage_FORMAT STREQUAL "html-nested")) + set(GCOVR_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html) + set(GCOVR_CREATE_FOLDER ${PROJECT_BINARY_DIR}/${Coverage_NAME}) + elseif(Coverage_FORMAT STREQUAL "html-single") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.html) + elseif((Coverage_FORMAT STREQUAL "json-summary") + OR (Coverage_FORMAT STREQUAL "json-details") + OR (Coverage_FORMAT STREQUAL "coveralls")) + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.json) + elseif(Coverage_FORMAT STREQUAL "txt") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.txt) + elseif(Coverage_FORMAT STREQUAL "csv") + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.csv) + else() + set(GCOVR_OUTPUT_FILE ${Coverage_NAME}.xml) + endif() + endif() + + if ((Coverage_FORMAT STREQUAL "cobertura") + OR (Coverage_FORMAT STREQUAL "xml")) + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --cobertura-pretty ) + set(Coverage_FORMAT cobertura) # overwrite xml + elseif(Coverage_FORMAT STREQUAL "sonarqube") + list(APPEND GCOVR_ADDITIONAL_ARGS --sonarqube "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "json-summary") + list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --json-summary-pretty) + elseif(Coverage_FORMAT STREQUAL "json-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --json "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --json-pretty) + elseif(Coverage_FORMAT STREQUAL "coveralls") + list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --coveralls-pretty) + elseif(Coverage_FORMAT STREQUAL "csv") + list(APPEND GCOVR_ADDITIONAL_ARGS --csv "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "txt") + list(APPEND GCOVR_ADDITIONAL_ARGS --txt "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "html-single") + list(APPEND GCOVR_ADDITIONAL_ARGS --html "${GCOVR_OUTPUT_FILE}" ) + list(APPEND GCOVR_ADDITIONAL_ARGS --html-self-contained) + elseif(Coverage_FORMAT STREQUAL "html-nested") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-nested "${GCOVR_OUTPUT_FILE}" ) + elseif(Coverage_FORMAT STREQUAL "html-details") + list(APPEND GCOVR_ADDITIONAL_ARGS --html-details "${GCOVR_OUTPUT_FILE}" ) + else() + message(FATAL_ERROR "Unsupported output style ${Coverage_FORMAT}! Aborting...") + endif() + + # Collect excludes (CMake 3.4+: Also compute absolute paths) + set(GCOVR_EXCLUDES "") + foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) + if(CMAKE_VERSION VERSION_GREATER 3.4) + get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) + endif() + list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") + endforeach() + list(REMOVE_DUPLICATES GCOVR_EXCLUDES) + + # Combine excludes to several -e arguments + set(GCOVR_EXCLUDE_ARGS "") + foreach(EXCLUDE ${GCOVR_EXCLUDES}) + list(APPEND GCOVR_EXCLUDE_ARGS "-e") + list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") + endforeach() + + # Set up commands which will be run to generate coverage data + # Run tests + set(GCOVR_EXEC_TESTS_CMD + ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} + ) + + # Create folder + if(DEFINED GCOVR_CREATE_FOLDER) + set(GCOVR_FOLDER_CMD + ${CMAKE_COMMAND} -E make_directory ${GCOVR_CREATE_FOLDER}) + else() + set(GCOVR_FOLDER_CMD echo) # dummy + endif() + + # Running gcovr + set(GCOVR_CMD + ${GCOVR_PATH} + --gcov-executable ${GCOV_TOOL} + --gcov-ignore-parse-errors=negative_hits.warn_once_per_file + -r ${BASEDIR} + ${GCOVR_ADDITIONAL_ARGS} + ${GCOVR_EXCLUDE_ARGS} + --object-directory=${PROJECT_BINARY_DIR} + ) + + if(CODE_COVERAGE_VERBOSE) + message(STATUS "Executed command report") + + message(STATUS "Command to run tests: ") + string(REPLACE ";" " " GCOVR_EXEC_TESTS_CMD_SPACED "${GCOVR_EXEC_TESTS_CMD}") + message(STATUS "${GCOVR_EXEC_TESTS_CMD_SPACED}") + + if(NOT GCOVR_FOLDER_CMD STREQUAL "echo") + message(STATUS "Command to create a folder: ") + string(REPLACE ";" " " GCOVR_FOLDER_CMD_SPACED "${GCOVR_FOLDER_CMD}") + message(STATUS "${GCOVR_FOLDER_CMD_SPACED}") + endif() + + message(STATUS "Command to generate gcovr coverage data: ") + string(REPLACE ";" " " GCOVR_CMD_SPACED "${GCOVR_CMD}") + message(STATUS "${GCOVR_CMD_SPACED}") + endif() + + add_custom_target(${Coverage_NAME} + COMMAND ${GCOVR_EXEC_TESTS_CMD} + COMMAND ${GCOVR_FOLDER_CMD} + COMMAND ${GCOVR_CMD} + + BYPRODUCTS ${GCOVR_OUTPUT_FILE} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + DEPENDS ${Coverage_DEPENDENCIES} + VERBATIM # Protect arguments to commands + COMMENT "Running gcovr to produce code coverage report." + ) + + # Show info where to find the report + add_custom_command(TARGET ${Coverage_NAME} POST_BUILD + COMMAND ; + COMMENT "Code coverage report saved in ${GCOVR_OUTPUT_FILE} formatted as ${Coverage_FORMAT}" + ) +endfunction() # setup_target_for_coverage_gcovr + +function(append_coverage_compiler_flags) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) + message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") +endfunction() # append_coverage_compiler_flags + +# Setup coverage for specific library +function(append_coverage_compiler_flags_to_target name) + separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}") + target_compile_options(${name} PRIVATE ${_flag_list}) + if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + target_link_libraries(${name} PRIVATE gcov) + endif() +endfunction() diff --git a/CMake/Coverage.cmake b/CMake/Coverage.cmake deleted file mode 100644 index da6931ffb..000000000 --- a/CMake/Coverage.cmake +++ /dev/null @@ -1,125 +0,0 @@ -# call add_coverage(module_name) to add coverage targets for the given module -function (add_coverage module) - if ("${CMAKE_C_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang" - OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") - message ("[Coverage] Building with llvm Code Coverage Tools") - # Using llvm gcov ; llvm install by xcode - set (LLVM_COV_PATH /Library/Developer/CommandLineTools/usr/bin) - if (NOT EXISTS ${LLVM_COV_PATH}/llvm-cov) - message (FATAL_ERROR "llvm-cov not found! Aborting.") - endif () - - # set Flags - target_compile_options (${module} PRIVATE - -fprofile-instr-generate - -fcoverage-mapping) - - target_link_options (${module} PUBLIC - -fprofile-instr-generate - -fcoverage-mapping) - - target_compile_options (clio PRIVATE - -fprofile-instr-generate - -fcoverage-mapping) - - target_link_options (clio PUBLIC - -fprofile-instr-generate - -fcoverage-mapping) - - # llvm-cov - add_custom_target (${module}-ccov-preprocessing - COMMAND LLVM_PROFILE_FILE=${module}.profraw $ - COMMAND ${LLVM_COV_PATH}/llvm-profdata merge -sparse ${module}.profraw -o - ${module}.profdata - DEPENDS ${module}) - - add_custom_target (${module}-ccov-show - COMMAND ${LLVM_COV_PATH}/llvm-cov show $ - -instr-profile=${module}.profdata -show-line-counts-or-regions - DEPENDS ${module}-ccov-preprocessing) - - # add summary for CI parse - add_custom_target (${module}-ccov-report - COMMAND - ${LLVM_COV_PATH}/llvm-cov report $ - -instr-profile=${module}.profdata - -ignore-filename-regex=".*_makefiles|.*unittests|.*_deps" - -show-region-summary=false - DEPENDS ${module}-ccov-preprocessing) - - # exclude libs and unittests self - add_custom_target (${module}-ccov - COMMAND - ${LLVM_COV_PATH}/llvm-cov show $ - -instr-profile=${module}.profdata -show-line-counts-or-regions - -output-dir=${module}-llvm-cov -format="html" - -ignore-filename-regex=".*_makefiles|.*unittests|.*_deps" > /dev/null 2>&1 - DEPENDS ${module}-ccov-preprocessing) - - add_custom_command ( - TARGET ${module}-ccov - POST_BUILD - COMMENT - "Open ${module}-llvm-cov/index.html in your browser to view the coverage report." - ) - elseif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") - message ("[Coverage] Building with Gcc Code Coverage Tools") - - find_program (GCOV_PATH gcov) - if (NOT GCOV_PATH) - message (FATAL_ERROR "gcov not found! Aborting...") - endif () # NOT GCOV_PATH - find_program (GCOVR_PATH gcovr) - if (NOT GCOVR_PATH) - message (FATAL_ERROR "gcovr not found! Aborting...") - endif () # NOT GCOVR_PATH - - set (COV_OUTPUT_PATH ${module}-gcc-cov) - target_compile_options (${module} PRIVATE -fprofile-arcs -ftest-coverage - -fPIC) - target_link_libraries (${module} PRIVATE gcov) - - target_compile_options (clio PRIVATE -fprofile-arcs -ftest-coverage - -fPIC) - target_link_libraries (clio PRIVATE gcov) - # this target is used for CI as well generate the summary out.xml will send - # to github action to generate markdown, we can paste it to comments or - # readme - add_custom_target (${module}-ccov - COMMAND ${module} ${TEST_PARAMETER} - COMMAND rm -rf ${COV_OUTPUT_PATH} - COMMAND mkdir ${COV_OUTPUT_PATH} - COMMAND - gcovr -r ${CMAKE_SOURCE_DIR} --object-directory=${PROJECT_BINARY_DIR} -x - ${COV_OUTPUT_PATH}/out.xml --exclude='${CMAKE_SOURCE_DIR}/unittests/' - --exclude='${PROJECT_BINARY_DIR}/' - COMMAND - gcovr -r ${CMAKE_SOURCE_DIR} --object-directory=${PROJECT_BINARY_DIR} - --html ${COV_OUTPUT_PATH}/report.html - --exclude='${CMAKE_SOURCE_DIR}/unittests/' - --exclude='${PROJECT_BINARY_DIR}/' - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - COMMENT "Running gcovr to produce Cobertura code coverage report.") - - # generate the detail report - add_custom_target (${module}-ccov-report - COMMAND ${module} ${TEST_PARAMETER} - COMMAND rm -rf ${COV_OUTPUT_PATH} - COMMAND mkdir ${COV_OUTPUT_PATH} - COMMAND - gcovr -r ${CMAKE_SOURCE_DIR} --object-directory=${PROJECT_BINARY_DIR} - --html-details ${COV_OUTPUT_PATH}/index.html - --exclude='${CMAKE_SOURCE_DIR}/unittests/' - --exclude='${PROJECT_BINARY_DIR}/' - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - COMMENT "Running gcovr to produce Cobertura code coverage report.") - add_custom_command ( - TARGET ${module}-ccov-report - POST_BUILD - COMMENT - "Open ${COV_OUTPUT_PATH}/index.html in your browser to view the coverage report." - ) - else () - message (FATAL_ERROR "Complier not support yet") - endif () -endfunction () diff --git a/CMakeLists.txt b/CMakeLists.txt index 71bf78335..a62836cf0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,12 @@ include (CMake/Ccache.cmake) include (CheckCXXCompilerFlag) include (CMake/ClangTidy.cmake) +# Set coverage build options +if (tests AND coverage) + include (CMake/CodeCoverage.cmake) + append_coverage_compiler_flags() +endif() + if (verbose) set (CMAKE_VERBOSE_MAKEFILE TRUE) endif () @@ -99,6 +105,10 @@ target_sources (clio PRIVATE src/etl/impl/ForwardCache.cpp ## Feed src/feed/SubscriptionManager.cpp + src/feed/impl/TransactionFeed.cpp + src/feed/impl/LedgerFeed.cpp + src/feed/impl/ProposedTransactionFeed.cpp + src/feed/impl/SingleFeedBase.cpp ## Web src/web/impl/AdminVerificationStrategy.cpp src/web/IntervalSweepHandler.cpp @@ -175,9 +185,8 @@ if (tests) unittests/ProfilerTests.cpp unittests/JsonUtilTests.cpp unittests/DOSGuardTests.cpp - unittests/SubscriptionTests.cpp - unittests/SubscriptionManagerTests.cpp unittests/util/AssertTests.cpp + unittests/util/BatchingTests.cpp unittests/util/TestObject.cpp unittests/util/StringUtils.cpp unittests/util/prometheus/CounterTests.cpp @@ -253,7 +262,16 @@ if (tests) unittests/web/ServerTests.cpp unittests/web/RPCServerHandlerTests.cpp unittests/web/WhitelistHandlerTests.cpp - unittests/web/SweepHandlerTests.cpp) + unittests/web/SweepHandlerTests.cpp + # Feed + unittests/feed/SubscriptionManagerTests.cpp + unittests/feed/SingleFeedBaseTests.cpp + unittests/feed/ProposedTransactionFeedTests.cpp + unittests/feed/BookChangesFeedTests.cpp + unittests/feed/LedgerFeedTests.cpp + unittests/feed/TransactionFeedTests.cpp + unittests/feed/ForwardFeedTests.cpp + unittests/feed/TrackableSignalTests.cpp) include (CMake/deps/gtest.cmake) @@ -267,12 +285,31 @@ if (tests) target_include_directories (${TEST_TARGET} PRIVATE unittests) target_link_libraries (${TEST_TARGET} PUBLIC clio gtest::gtest) - # Generate `clio_tests-ccov` if coverage is enabled - # Note: use `make clio_tests-ccov` to generate report + # Generate `coverage_report` target if coverage is enabled if (coverage) - target_compile_definitions(${TEST_TARGET} PRIVATE COVERAGE_ENABLED) - include (CMake/Coverage.cmake) - add_coverage (${TEST_TARGET}) + if (DEFINED CODE_COVERAGE_REPORT_FORMAT) + set(CODE_COVERAGE_FORMAT ${CODE_COVERAGE_REPORT_FORMAT}) + else() + set(CODE_COVERAGE_FORMAT html-details) + endif() + + if (DEFINED CODE_COVERAGE_TESTS_ARGS) + set(TESTS_ADDITIONAL_ARGS ${CODE_COVERAGE_TESTS_ARGS}) + separate_arguments(TESTS_ADDITIONAL_ARGS) + else() + set(TESTS_ADDITIONAL_ARGS "") + endif() + + set (GCOVR_ADDITIONAL_ARGS --exclude-throw-branches -s) + + setup_target_for_coverage_gcovr( + NAME coverage_report + FORMAT ${CODE_COVERAGE_FORMAT} + EXECUTABLE clio_tests + EXECUTABLE_ARGS --gtest_brief=1 ${TESTS_ADDITIONAL_ARGS} + EXCLUDE "unittests" + DEPENDENCIES clio_tests + ) endif () endif () diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8bdc3798..2413a4874 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,6 +62,11 @@ git commit --amend -S git push --force ``` +## Use ccache (optional) +Clio uses ccache to speed up compilation. If you want to use it, please make sure it is installed on your machine. +CMake will automatically detect it and use it if it's available. + + ## Fixing issues found during code review While your code is in review, it's possible that some changes will be requested by reviewer(s). This section describes the process of adding your fixes. @@ -126,6 +131,7 @@ Existing maintainers can resign, or be subject to a vote for removal at the behe * [cindyyan317](https://github.com/cindyyan317) (Ripple) * [godexsoft](https://github.com/godexsoft) (Ripple) +* [kuznetsss](https://github.com/kuznetsss) (Ripple) * [legleux](https://github.com/legleux) (Ripple) ## Honorable ex-Maintainers diff --git a/README.md b/README.md index ff2b2266f..8f30c4a5e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ # Clio +[![Build status](https://github.com/XRPLF/clio/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/XRPLF/clio/actions/workflows/build.yml?query=branch%3Adevelop) +[![Nightly release status](https://github.com/XRPLF/clio/actions/workflows/nightly.yml/badge.svg?branch=develop)](https://github.com/XRPLF/clio/actions/workflows/nightly.yml?query=branch%3Adevelop) +[![Clang-tidy checks status](https://github.com/XRPLF/clio/actions/workflows/clang-tidy.yml/badge.svg?branch=develop)](https://github.com/XRPLF/clio/actions/workflows/clang-tidy.yml?query=branch%3Adevelop) +[![Code coverage develop branch](https://codecov.io/gh/XRPLF/clio/branch/develop/graph/badge.svg?)](https://app.codecov.io/gh/XRPLF/clio) Clio is an XRP Ledger API server. Clio is optimized for RPC calls, over WebSocket or JSON-RPC. Validated historical ledger and transaction data are stored in a more space-efficient format, @@ -36,6 +40,7 @@ It is written in C++20 and therefore requires a modern compiler. - [Conan 1.55](https://conan.io/downloads.html) - [CMake 3.16](https://cmake.org/download/) - [**Optional**] [GCovr](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html) (needed for code coverage generation) +- [**Optional**] [CCache](https://ccache.dev/) (speeds up compilation if you are going to compile Clio often) | Compiler | Version | |-------------|---------| @@ -91,7 +96,7 @@ conan remove -f xrpl Navigate to Clio's root directory and perform ```sh mkdir build && cd build -conan install .. --output-folder . --build missing --settings build_type=Release -o tests=True +conan install .. --output-folder . --build missing --settings build_type=Release -o tests=True -o lint=False cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release .. cmake --build . --parallel 8 # or without the number if you feel extra adventurous ``` @@ -101,6 +106,18 @@ If all goes well, `conan install` will find required packages and `cmake` will d > **Tip:** To generate a Code Coverage report, include `-o coverage=True` in the `conan install` command above, along with `-o tests=True` to enable tests. After running the `cmake` commands, execute `make clio_tests-ccov`. The coverage report will be found at `clio_tests-llvm-cov/index.html`. +## Building Clio with Docker + +It is possible to build Clio using docker if you don't want to install all the dependencies on your machine. +```sh +docker run -it rippleci/clio_ci:latest +git clone https://github.com/XRPLF/clio +mkdir build && cd build +conan install .. --output-folder . --build missing --settings build_type=Release -o tests=True -o lint=False +cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release .. +cmake --build . --parallel 8 # or without the number if you feel extra adventurous +``` + ## Running ```sh ./clio_server config.json @@ -276,6 +293,55 @@ E.g.: export CLIO_CLANG_TIDY_BIN=/opt/homebrew/opt/llvm@17/bin/clang-tidy ``` +## Coverage report + +Coverage report is intended for the developers using compilers GCC +or Clang (including Apple Clang). It is generated by the build target `coverage_report`, +which is only enabled when both `tests` and `coverage` options are set, e.g. with +`-o coverage=True -o tests=True` in `conan` + +Prerequisites for the coverage report: + +- [gcovr tool](https://gcovr.com/en/stable/getting-started.html) (can be installed e.g. with `pip install gcovr`) +- `gcov` for GCC (installed with the compiler by default) or +- `llvm-cov` for Clang (installed with the compiler by default, also on Apple) +- `Debug` build type + +Coverage report is created when the following steps are completed, in order: + +1. `clio_tests` binary built with the instrumentation data, enabled by the `coverage` + option mentioned above +2. completed run of unit tests, which populates coverage capture data +3. completed run of `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) + to assemble both instrumentation data and coverage capture data into a coverage report + +Above steps are automated into a single target `coverage_report`. The instrumented +`clio_tests` binary can be also used for running regular unit tests. In case of a +spurious failure of unit tests, it is possile to re-run `coverage_report` target without +rebuilding the `clio_tests` binary (since it is simply a dependency of the coverage report target). + +The default coverage report format is `html-details`, but the developers +can override it to any of the formats listed in `CMake/CodeCoverage.cmake` +by setting `CODE_COVERAGE_REPORT_FORMAT` variable in `cmake`. For example, CI +is setting this parameter to `xml` for the [codecov](codecov.io) integration. + +In case if some unit tests predictably fail e.g. due to absence of a Cassandra database, it is possible +to set unit tests options in `CODE_COVERAGE_TESTS_ARGS` cmake variable, as demonstrated below: + +``` +cd .build +conan install .. --output-folder . --build missing --settings build_type=Debug -o tests=True -o coverage=True +cmake -DCODE_COVERAGE_REPORT_FORMAT=json-details -DCMAKE_BUILD_TYPE=Debug -DCODE_COVERAGE_TESTS_ARGS="--gtest_filter=-BackendCassandra*" -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake .. +cmake --build . --target coverage_report +``` + +After `coverage_report` target is completed, the generated coverage report will be +stored inside the build directory, as either of: + +- file named `coverage_report.*`, with a suitable extension for the report format, or +- directory named `coverage_report`, with `index.html` and other files inside, for `html-details` or `html-nested` report formats. + + ## Developing against `rippled` in standalone mode If you wish you develop against a `rippled` instance running in standalone diff --git a/conanfile.py b/conanfile.py index abf3a188a..0f5a90bef 100644 --- a/conanfile.py +++ b/conanfile.py @@ -26,7 +26,7 @@ class Clio(ConanFile): 'protobuf/3.21.12', 'grpc/1.50.1', 'openssl/1.1.1u', - 'xrpl/2.0.0-rc1', + 'xrpl/2.0.0-rc6', 'libbacktrace/cci.20210118' ] diff --git a/docker/ci/dockerfile b/docker/ci/dockerfile new file mode 100644 index 000000000..ce2d67815 --- /dev/null +++ b/docker/ci/dockerfile @@ -0,0 +1,67 @@ +FROM ubuntu:focal +ARG DEBIAN_FRONTEND=noninteractive +ARG TARGETARCH + +USER root +WORKDIR /root/ + +ENV GCC_VERSION=11 \ + CCACHE_VERSION=4.8.3 \ + LLVM_TOOLS_VERSION=17 \ + GH_VERSION=2.40.0 + +# Add repositories +RUN apt-get -qq update \ + && apt-get -qq install -y --no-install-recommends --no-install-suggests gnupg wget curl software-properties-common \ + && add-apt-repository -y ppa:ubuntu-toolchain-r/test \ + && wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | apt-key add - \ + && apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main' \ + && echo "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${LLVM_TOOLS_VERSION} main" >> /etc/apt/sources.list \ + && wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - + +# Install packages +RUN apt update -qq \ + && apt install -y --no-install-recommends --no-install-suggests cmake python3 python3-pip sudo git \ + ninja-build make pkg-config libzstd-dev libzstd1 g++-${GCC_VERSION} jq \ + clang-format-${LLVM_TOOLS_VERSION} clang-tidy-${LLVM_TOOLS_VERSION} clang-tools-${LLVM_TOOLS_VERSION} \ + && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-${GCC_VERSION} 100 \ + && update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${GCC_VERSION} 100 \ + && update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_VERSION} 100 \ + && update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${GCC_VERSION} 100 \ + && update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-${GCC_VERSION} 100 \ + && update-alternatives --install /usr/bin/gcov-dump gcov-dump /usr/bin/gcov-dump-${GCC_VERSION} 100 \ + && update-alternatives --install /usr/bin/gcov-tool gcov-tool /usr/bin/gcov-tool-${GCC_VERSION} 100 \ + && apt-get clean && apt remove -y software-properties-common \ + && pip3 install -q --upgrade --no-cache-dir pip \ + && pip3 install -q --no-cache-dir conan==1.62 gcovr + +# Install ccache from source +WORKDIR /tmp +RUN wget "https://github.com/ccache/ccache/releases/download/v${CCACHE_VERSION}/ccache-${CCACHE_VERSION}.tar.gz" \ + && tar xf "ccache-${CCACHE_VERSION}.tar.gz" \ + && cd "ccache-${CCACHE_VERSION}" \ + && mkdir build && cd build \ + && cmake -GNinja -DCMAKE_BUILD_TYPE=Release .. \ + && ninja && cp ./ccache /usr/bin/ccache + +# Install gh +RUN wget https://github.com/cli/cli/releases/download/v${GH_VERSION}/gh_${GH_VERSION}_linux_${TARGETARCH}.tar.gz \ + && tar xf gh_${GH_VERSION}_linux_${TARGETARCH}.tar.gz \ + && mv gh_${GH_VERSION}_linux_${TARGETARCH}/bin/gh /usr/bin/gh + +# Clean up +RUN rm -rf /tmp/* /var/tmp/* + +WORKDIR /root/ +# Using root by default is not very secure but github checkout action doesn't work with any other user +# https://github.com/actions/checkout/issues/956 +# And Github Actions doc recommends using root +# https://docs.github.com/en/actions/creating-actions/dockerfile-support-for-github-actions#user + +# Setup conan +RUN conan profile new default --detect \ + && conan profile update settings.compiler.cppstd=20 default \ + && conan profile update settings.compiler.libcxx=libstdc++11 default \ + && conan remote add --insert 0 conan-non-prod http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod + + diff --git a/example-config.json b/example-config.json index 030c25fcf..46772280e 100644 --- a/example-config.json +++ b/example-config.json @@ -16,7 +16,8 @@ // // Advanced options. USE AT OWN RISK: // --- - "core_connections_per_host": 1 // Defaults to 1 + "core_connections_per_host": 1, // Defaults to 1 + "write_batch_size": 20 // Defaults to 20 // // Below options will use defaults from cassandra driver if left unspecified. // See https://docs.datastax.com/en/developer/cpp-driver/2.17/api/struct.CassCluster/ for details. @@ -103,7 +104,7 @@ ], "prometheus": { "enabled": true, - "compress_reply": true, + "compress_reply": true }, "log_level": "info", // Log format (this is the default format) diff --git a/src/data/BackendFactory.h b/src/data/BackendFactory.h index 174df9f2a..15e3ddb24 100644 --- a/src/data/BackendFactory.h +++ b/src/data/BackendFactory.h @@ -55,10 +55,8 @@ make_Backend(util::Config const& config) throw std::runtime_error("Invalid database type"); auto const rng = backend->hardFetchLedgerRangeNoThrow(); - if (rng) { - backend->updateRange(rng->minSequence); - backend->updateRange(rng->maxSequence); - } + if (rng) + backend->setRange(rng->minSequence, rng->maxSequence); LOG(log.info()) << "Constructed BackendInterface Successfully"; return backend; diff --git a/src/data/BackendInterface.cpp b/src/data/BackendInterface.cpp index 35216fc5d..37189edd2 100644 --- a/src/data/BackendInterface.cpp +++ b/src/data/BackendInterface.cpp @@ -270,6 +270,19 @@ BackendInterface::updateRange(uint32_t newMax) } } +void +BackendInterface::setRange(uint32_t min, uint32_t max, bool force) +{ + std::scoped_lock const lck(rngMtx_); + + if (!force) { + ASSERT(min <= max, "Range min must be less than or equal to max"); + ASSERT(not range.has_value(), "Range was already set"); + } + + range = {min, max}; +} + LedgerPage BackendInterface::fetchLedgerPage( std::optional const& cursor, diff --git a/src/data/BackendInterface.h b/src/data/BackendInterface.h index ce0dc542c..9b0496669 100644 --- a/src/data/BackendInterface.h +++ b/src/data/BackendInterface.h @@ -191,6 +191,16 @@ class BackendInterface { void updateRange(uint32_t newMax); + /** + * @brief Sets the range of sequences that are stored in the DB. + * + * @param min The new minimum sequence available + * @param max The new maximum sequence available + * @param force If set to true, the range will be set even if it's already set + */ + void + setRange(uint32_t min, uint32_t max, bool force = false); + /** * @brief Fetch the fees from a specific ledger sequence. * diff --git a/src/data/cassandra/SettingsProvider.cpp b/src/data/cassandra/SettingsProvider.cpp index fce95c9d9..aa36b3861 100644 --- a/src/data/cassandra/SettingsProvider.cpp +++ b/src/data/cassandra/SettingsProvider.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -122,8 +123,8 @@ SettingsProvider::parseSettings() const config_.valueOr("max_read_requests_outstanding", settings.maxReadRequestsOutstanding); settings.coreConnectionsPerHost = config_.valueOr("core_connections_per_host", settings.coreConnectionsPerHost); - settings.queueSizeIO = config_.maybeValue("queue_size_io"); + settings.writeBatchSize = config_.valueOr("write_batch_size", settings.writeBatchSize); auto const connectTimeoutSecond = config_.maybeValue("connect_timeout"); if (connectTimeoutSecond) diff --git a/src/data/cassandra/impl/Cluster.cpp b/src/data/cassandra/impl/Cluster.cpp index e93f02b35..a9d2a2ecf 100644 --- a/src/data/cassandra/impl/Cluster.cpp +++ b/src/data/cassandra/impl/Cluster.cpp @@ -83,6 +83,7 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), c LOG(log_.info()) << "Threads: " << settings.threads; LOG(log_.info()) << "Core connections per host: " << settings.coreConnectionsPerHost; LOG(log_.info()) << "IO queue size: " << queueSize; + LOG(log_.info()) << "Batched writes auto-chunk size: " << settings.writeBatchSize; } void diff --git a/src/data/cassandra/impl/Cluster.h b/src/data/cassandra/impl/Cluster.h index 3fbc3e16d..aa1b914bc 100644 --- a/src/data/cassandra/impl/Cluster.h +++ b/src/data/cassandra/impl/Cluster.h @@ -42,6 +42,8 @@ struct Settings { static constexpr std::size_t DEFAULT_CONNECTION_TIMEOUT = 10000; static constexpr uint32_t DEFAULT_MAX_WRITE_REQUESTS_OUTSTANDING = 10'000; static constexpr uint32_t DEFAULT_MAX_READ_REQUESTS_OUTSTANDING = 100'000; + static constexpr std::size_t DEFAULT_BATCH_SIZE = 20; + /** * @brief Represents the configuration of contact points for cassandra. */ @@ -81,6 +83,9 @@ struct Settings { /** @brief The number of connection per host to always have active */ uint32_t coreConnectionsPerHost = 1u; + /** @brief Size of batches when writing */ + std::size_t writeBatchSize = DEFAULT_BATCH_SIZE; + /** @brief Size of the IO queue */ std::optional queueSizeIO{}; diff --git a/src/data/cassandra/impl/ExecutionStrategy.h b/src/data/cassandra/impl/ExecutionStrategy.h index 18b4d7c5c..75cb5ac3c 100644 --- a/src/data/cassandra/impl/ExecutionStrategy.h +++ b/src/data/cassandra/impl/ExecutionStrategy.h @@ -25,6 +25,7 @@ #include "data/cassandra/Types.h" #include "data/cassandra/impl/AsyncExecutor.h" #include "util/Assert.h" +#include "util/Batching.h" #include "util/Expected.h" #include "util/log/Logger.h" @@ -59,6 +60,8 @@ class DefaultExecutionStrategy { std::uint32_t maxReadRequestsOutstanding_; std::atomic_uint32_t numReadRequestsOutstanding_ = 0; + std::size_t writeBatchSize_; + std::mutex throttleMutex_; std::condition_variable throttleCv_; @@ -93,6 +96,7 @@ class DefaultExecutionStrategy { ) : maxWriteRequestsOutstanding_{settings.maxWriteRequestsOutstanding} , maxReadRequestsOutstanding_{settings.maxReadRequestsOutstanding} + , writeBatchSize_{settings.writeBatchSize} , work_{ioc_} , handle_{std::cref(handle)} , thread_{[this]() { ioc_.run(); }} @@ -214,22 +218,28 @@ class DefaultExecutionStrategy { if (statements.empty()) return; - auto const startTime = std::chrono::steady_clock::now(); - - incrementOutstandingRequestCount(); - - counters_->registerWriteStarted(); - // Note: lifetime is controlled by std::shared_from_this internally - AsyncExecutor, HandleType>::run( - ioc_, - handle_, - std::move(statements), - [this, startTime](auto const&) { - decrementOutstandingRequestCount(); - counters_->registerWriteFinished(startTime); - }, - [this]() { counters_->registerWriteRetry(); } - ); + util::forEachBatch(std::move(statements), writeBatchSize_, [this](auto begin, auto end) { + auto const startTime = std::chrono::steady_clock::now(); + auto chunk = std::vector{}; + + chunk.reserve(std::distance(begin, end)); + std::move(begin, end, std::back_inserter(chunk)); + + incrementOutstandingRequestCount(); + counters_->registerWriteStarted(); + + // Note: lifetime is controlled by std::shared_from_this internally + AsyncExecutor, HandleType>::run( + ioc_, + handle_, + std::move(chunk), + [this, startTime](auto const&) { + decrementOutstandingRequestCount(); + counters_->registerWriteFinished(startTime); + }, + [this]() { counters_->registerWriteRetry(); } + ); + }); } /** diff --git a/src/feed/SubscriptionManager.cpp b/src/feed/SubscriptionManager.cpp index 7e73a29e9..bafad533a 100644 --- a/src/feed/SubscriptionManager.cpp +++ b/src/feed/SubscriptionManager.cpp @@ -19,166 +19,82 @@ #include "feed/SubscriptionManager.h" -#include "data/BackendInterface.h" #include "data/Types.h" -#include "rpc/BookChangesHelper.h" -#include "rpc/RPCHelpers.h" -#include "util/Assert.h" +#include "feed/Types.h" -#include #include #include -#include -#include -#include #include #include #include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include #include -#include -#include #include namespace feed { - void -Subscription::subscribe(SessionPtrType const& session) +SubscriptionManager::subBookChanges(SubscriberSharedPtr const& subscriber) { - boost::asio::post(strand_, [this, session]() { addSession(session, subscribers_, subCount_); }); + bookChangesFeed_.sub(subscriber); } void -Subscription::unsubscribe(SessionPtrType const& session) +SubscriptionManager::unsubBookChanges(SubscriberSharedPtr const& subscriber) { - boost::asio::post(strand_, [this, session]() { removeSession(session, subscribers_, subCount_); }); -} - -bool -Subscription::hasSession(SessionPtrType const& session) -{ - return subscribers_.contains(session); + bookChangesFeed_.unsub(subscriber); } void -Subscription::publish(std::shared_ptr const& message) -{ - boost::asio::post(strand_, [this, message]() { sendToSubscribers(message, subscribers_, subCount_); }); -} - -boost::json::object -getLedgerPubMessage( +SubscriptionManager::pubBookChanges( ripple::LedgerHeader const& lgrInfo, - ripple::Fees const& fees, - std::string const& ledgerRange, - std::uint32_t txnCount -) -{ - boost::json::object pubMsg; - - pubMsg["type"] = "ledgerClosed"; - pubMsg["ledger_index"] = lgrInfo.seq; - pubMsg["ledger_hash"] = to_string(lgrInfo.hash); - pubMsg["ledger_time"] = lgrInfo.closeTime.time_since_epoch().count(); - - pubMsg["fee_base"] = rpc::toBoostJson(fees.base.jsonClipped()); - pubMsg["reserve_base"] = rpc::toBoostJson(fees.reserve.jsonClipped()); - pubMsg["reserve_inc"] = rpc::toBoostJson(fees.increment.jsonClipped()); - - pubMsg["validated_ledgers"] = ledgerRange; - pubMsg["txn_count"] = txnCount; - return pubMsg; -} - -boost::json::object -SubscriptionManager::subLedger(boost::asio::yield_context yield, SessionPtrType session) -{ - subscribeHelper(session, ledgerSubscribers_, [this](SessionPtrType session) { unsubLedger(session); }); - - auto ledgerRange = backend_->fetchLedgerRange(); - ASSERT(ledgerRange.has_value(), "Ledger range must be valid"); - auto lgrInfo = backend_->fetchLedgerBySequence(ledgerRange->maxSequence, yield); - ASSERT(lgrInfo.has_value(), "Ledger must be valid"); - - std::optional fees; - fees = backend_->fetchFees(lgrInfo->seq, yield); - ASSERT(fees.has_value(), "Fees must be valid"); - - std::string const range = std::to_string(ledgerRange->minSequence) + "-" + std::to_string(ledgerRange->maxSequence); - - auto pubMsg = getLedgerPubMessage(*lgrInfo, *fees, range, 0); - pubMsg.erase("txn_count"); - pubMsg.erase("type"); - return pubMsg; -} - -void -SubscriptionManager::unsubLedger(SessionPtrType session) -{ - ledgerSubscribers_.unsubscribe(session); -} - -void -SubscriptionManager::subTransactions(SessionPtrType session) + std::vector const& transactions +) const { - subscribeHelper(session, txSubscribers_, [this](SessionPtrType session) { unsubTransactions(session); }); + bookChangesFeed_.pub(lgrInfo, transactions); } void -SubscriptionManager::unsubTransactions(SessionPtrType session) +SubscriptionManager::subProposedTransactions(SubscriberSharedPtr const& subscriber) { - txSubscribers_.unsubscribe(session); + proposedTransactionFeed_.sub(subscriber); } void -SubscriptionManager::subAccount(ripple::AccountID const& account, SessionPtrType const& session) +SubscriptionManager::unsubProposedTransactions(SubscriberSharedPtr const& subscriber) { - subscribeHelper(session, account, accountSubscribers_, [this, account](SessionPtrType session) { - unsubAccount(account, session); - }); + proposedTransactionFeed_.unsub(subscriber); } void -SubscriptionManager::unsubAccount(ripple::AccountID const& account, SessionPtrType const& session) +SubscriptionManager::subProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) { - accountSubscribers_.unsubscribe(session, account); + proposedTransactionFeed_.sub(account, subscriber); } void -SubscriptionManager::subBook(ripple::Book const& book, SessionPtrType session) +SubscriptionManager::unsubProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) { - subscribeHelper(session, book, bookSubscribers_, [this, book](SessionPtrType session) { - unsubBook(book, session); - }); + proposedTransactionFeed_.unsub(account, subscriber); } void -SubscriptionManager::unsubBook(ripple::Book const& book, SessionPtrType session) +SubscriptionManager::forwardProposedTransaction(boost::json::object const& receivedTxJson) { - bookSubscribers_.unsubscribe(session, book); + proposedTransactionFeed_.pub(receivedTxJson); } -void -SubscriptionManager::subBookChanges(SessionPtrType session) +boost::json::object +SubscriptionManager::subLedger(boost::asio::yield_context yield, SubscriberSharedPtr const& subscriber) { - subscribeHelper(session, bookChangesSubscribers_, [this](SessionPtrType session) { unsubBookChanges(session); }); + return ledgerFeed_.sub(yield, backend_, subscriber); } void -SubscriptionManager::unsubBookChanges(SessionPtrType session) +SubscriptionManager::unsubLedger(SubscriberSharedPtr const& subscriber) { - bookChangesSubscribers_.unsubscribe(session); + ledgerFeed_.unsub(subscriber); } void @@ -186,230 +102,96 @@ SubscriptionManager::pubLedger( ripple::LedgerHeader const& lgrInfo, ripple::Fees const& fees, std::string const& ledgerRange, - std::uint32_t txnCount -) + std::uint32_t const txnCount +) const { - auto message = - std::make_shared(boost::json::serialize(getLedgerPubMessage(lgrInfo, fees, ledgerRange, txnCount)) - ); - - ledgerSubscribers_.publish(message); + ledgerFeed_.pub(lgrInfo, fees, ledgerRange, txnCount); } void -SubscriptionManager::pubTransaction(data::TransactionAndMetadata const& blobs, ripple::LedgerHeader const& lgrInfo) +SubscriptionManager::subManifest(SubscriberSharedPtr const& subscriber) { - auto [tx, meta] = rpc::deserializeTxPlusMeta(blobs, lgrInfo.seq); - boost::json::object pubObj; - pubObj[JS(transaction)] = rpc::toJson(*tx); - pubObj[JS(meta)] = rpc::toJson(*meta); - rpc::insertDeliveredAmount(pubObj[JS(meta)].as_object(), tx, meta, blobs.date); - // hardcode api_version to 1 for now, until https://github.com/XRPLF/clio/issues/978 fixed - rpc::insertDeliverMaxAlias(pubObj[JS(transaction)].as_object(), 1); - pubObj[JS(type)] = "transaction"; - pubObj[JS(validated)] = true; - pubObj[JS(status)] = "closed"; - pubObj[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo.closeTime); - - pubObj[JS(ledger_index)] = lgrInfo.seq; - pubObj[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash); - pubObj[JS(transaction)].as_object()[JS(date)] = lgrInfo.closeTime.time_since_epoch().count(); - - pubObj[JS(engine_result_code)] = meta->getResult(); - std::string token; - std::string human; - ripple::transResultInfo(meta->getResultTER(), token, human); - pubObj[JS(engine_result)] = token; - pubObj[JS(engine_result_message)] = human; - if (tx->getTxnType() == ripple::ttOFFER_CREATE) { - auto account = tx->getAccountID(ripple::sfAccount); - auto amount = tx->getFieldAmount(ripple::sfTakerGets); - if (account != amount.issue().account) { - ripple::STAmount ownerFunds; - auto fetchFundsSynchronous = [&]() { - data::synchronous([&](boost::asio::yield_context yield) { - ownerFunds = rpc::accountFunds(*backend_, lgrInfo.seq, amount, account, yield); - }); - }; - - data::retryOnTimeout(fetchFundsSynchronous); - - pubObj[JS(transaction)].as_object()[JS(owner_funds)] = ownerFunds.getText(); - } - } - - auto pubMsg = std::make_shared(boost::json::serialize(pubObj)); - txSubscribers_.publish(pubMsg); - - auto accounts = meta->getAffectedAccounts(); - - for (auto const& account : accounts) - accountSubscribers_.publish(pubMsg, account); - - std::unordered_set alreadySent; - - for (auto const& node : meta->getNodes()) { - if (node.getFieldU16(ripple::sfLedgerEntryType) == ripple::ltOFFER) { - ripple::SField const* field = nullptr; - - // We need a field that contains the TakerGets and TakerPays - // parameters. - if (node.getFName() == ripple::sfModifiedNode) { - field = &ripple::sfPreviousFields; - } else if (node.getFName() == ripple::sfCreatedNode) { - field = &ripple::sfNewFields; - } else if (node.getFName() == ripple::sfDeletedNode) { - field = &ripple::sfFinalFields; - } - - if (field != nullptr) { - auto data = dynamic_cast(node.peekAtPField(*field)); - - if ((data != nullptr) && data->isFieldPresent(ripple::sfTakerPays) && - data->isFieldPresent(ripple::sfTakerGets)) { - // determine the OrderBook - ripple::Book const book{ - data->getFieldAmount(ripple::sfTakerGets).issue(), - data->getFieldAmount(ripple::sfTakerPays).issue() - }; - if (alreadySent.find(book) == alreadySent.end()) { - bookSubscribers_.publish(pubMsg, book); - alreadySent.insert(book); - } - } - } - } - } + manifestFeed_.sub(subscriber); } void -SubscriptionManager::pubBookChanges( - ripple::LedgerHeader const& lgrInfo, - std::vector const& transactions -) +SubscriptionManager::unsubManifest(SubscriberSharedPtr const& subscriber) { - auto const json = rpc::computeBookChanges(lgrInfo, transactions); - auto const bookChangesMsg = std::make_shared(boost::json::serialize(json)); - bookChangesSubscribers_.publish(bookChangesMsg); + manifestFeed_.unsub(subscriber); } void -SubscriptionManager::forwardProposedTransaction(boost::json::object const& response) +SubscriptionManager::forwardManifest(boost::json::object const& manifestJson) const { - auto pubMsg = std::make_shared(boost::json::serialize(response)); - txProposedSubscribers_.publish(pubMsg); - - auto transaction = response.at("transaction").as_object(); - auto accounts = rpc::getAccountsFromTransaction(transaction); - - for (ripple::AccountID const& account : accounts) - accountProposedSubscribers_.publish(pubMsg, account); + manifestFeed_.pub(manifestJson); } void -SubscriptionManager::forwardManifest(boost::json::object const& response) +SubscriptionManager::subValidation(SubscriberSharedPtr const& subscriber) { - auto pubMsg = std::make_shared(boost::json::serialize(response)); - manifestSubscribers_.publish(pubMsg); + validationsFeed_.sub(subscriber); } void -SubscriptionManager::forwardValidation(boost::json::object const& response) +SubscriptionManager::unsubValidation(SubscriberSharedPtr const& subscriber) { - auto pubMsg = std::make_shared(boost::json::serialize(response)); - validationsSubscribers_.publish(pubMsg); + validationsFeed_.unsub(subscriber); } void -SubscriptionManager::subProposedAccount(ripple::AccountID const& account, SessionPtrType session) +SubscriptionManager::forwardValidation(boost::json::object const& validationJson) const { - subscribeHelper(session, account, accountProposedSubscribers_, [this, account](SessionPtrType session) { - unsubProposedAccount(account, session); - }); + validationsFeed_.pub(validationJson); } void -SubscriptionManager::subManifest(SessionPtrType session) +SubscriptionManager::subTransactions(SubscriberSharedPtr const& subscriber, std::uint32_t const apiVersion) { - subscribeHelper(session, manifestSubscribers_, [this](SessionPtrType session) { unsubManifest(session); }); + transactionFeed_.sub(subscriber, apiVersion); } void -SubscriptionManager::unsubManifest(SessionPtrType session) +SubscriptionManager::unsubTransactions(SubscriberSharedPtr const& subscriber) { - manifestSubscribers_.unsubscribe(session); + transactionFeed_.unsub(subscriber); } void -SubscriptionManager::subValidation(SessionPtrType session) -{ - subscribeHelper(session, validationsSubscribers_, [this](SessionPtrType session) { unsubValidation(session); }); -} - -void -SubscriptionManager::unsubValidation(SessionPtrType session) -{ - validationsSubscribers_.unsubscribe(session); -} - -void -SubscriptionManager::unsubProposedAccount(ripple::AccountID const& account, SessionPtrType session) -{ - accountProposedSubscribers_.unsubscribe(session, account); -} - -void -SubscriptionManager::subProposedTransactions(SessionPtrType session) +SubscriptionManager::subAccount( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber, + std::uint32_t const apiVersion +) { - subscribeHelper(session, txProposedSubscribers_, [this](SessionPtrType session) { - unsubProposedTransactions(session); - }); + transactionFeed_.sub(account, subscriber, apiVersion); } void -SubscriptionManager::unsubProposedTransactions(SessionPtrType session) +SubscriptionManager::unsubAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) { - txProposedSubscribers_.unsubscribe(session); + transactionFeed_.unsub(account, subscriber); } void -SubscriptionManager::subscribeHelper(SessionPtrType const& session, Subscription& subs, CleanupFunction&& func) +SubscriptionManager::subBook( + ripple::Book const& book, + SubscriberSharedPtr const& subscriber, + std::uint32_t const apiVersion +) { - if (subs.hasSession(session)) - return; - subs.subscribe(session); - std::scoped_lock const lk(cleanupMtx_); - cleanupFuncs_[session].push_back(std::move(func)); + transactionFeed_.sub(book, subscriber, apiVersion); } -template void -SubscriptionManager::subscribeHelper( - SessionPtrType const& session, - Key const& k, - SubscriptionMap& subs, - CleanupFunction&& func -) +SubscriptionManager::unsubBook(ripple::Book const& book, SubscriberSharedPtr const& subscriber) { - if (subs.hasSession(session, k)) - return; - subs.subscribe(session, k); - std::scoped_lock const lk(cleanupMtx_); - cleanupFuncs_[session].push_back(std::move(func)); + transactionFeed_.unsub(book, subscriber); } void -SubscriptionManager::cleanup(SessionPtrType session) +SubscriptionManager::pubTransaction(data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo) { - std::scoped_lock const lk(cleanupMtx_); - if (!cleanupFuncs_.contains(session)) - return; - - for (auto const& f : cleanupFuncs_[session]) { - f(session); - } - - cleanupFuncs_.erase(session); + transactionFeed_.pub(txMeta, lgrInfo, backend_); } } // namespace feed diff --git a/src/feed/SubscriptionManager.h b/src/feed/SubscriptionManager.h index 75ec2109e..140c9ca2b 100644 --- a/src/feed/SubscriptionManager.h +++ b/src/feed/SubscriptionManager.h @@ -20,369 +20,140 @@ #pragma once #include "data/BackendInterface.h" -#include "util/config/Config.h" +#include "data/Types.h" +#include "feed/Types.h" +#include "feed/impl/BookChangesFeed.h" +#include "feed/impl/ForwardFeed.h" +#include "feed/impl/LedgerFeed.h" +#include "feed/impl/ProposedTransactionFeed.h" +#include "feed/impl/TransactionFeed.h" #include "util/log/Logger.h" -#include "util/prometheus/Prometheus.h" -#include "web/interface/ConnectionBase.h" -#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include +#include +#include +#include -/** - * @brief This namespace deals with subscriptions. - */ namespace feed { -using SessionPtrType = std::shared_ptr; - -/** - * @brief Sends a message to subscribers. - * - * @param message The message to send - * @param subscribers The subscription stream to send the message to - * @param counter The subscription counter to decrement if session is detected as dead - */ -template -inline void -sendToSubscribers(std::shared_ptr const& message, T& subscribers, util::prometheus::GaugeInt& counter) -{ - for (auto it = subscribers.begin(); it != subscribers.end();) { - auto& session = *it; - if (session->dead()) { - it = subscribers.erase(it); - --counter; - } else { - session->send(message); - ++it; - } - } -} - -/** - * @brief Adds a session to the subscription stream. - * - * @param session The session to add - * @param subscribers The stream to subscribe to - * @param counter The counter representing the current total subscribers - */ -template -inline void -addSession(SessionPtrType session, T& subscribers, util::prometheus::GaugeInt& counter) -{ - if (!subscribers.contains(session)) { - subscribers.insert(session); - ++counter; - } -} - -/** - * @brief Removes a session from the subscription stream. - * - * @param session The session to remove - * @param subscribers The stream to unsubscribe from - * @param counter The counter representing the current total subscribers - */ -template -inline void -removeSession(SessionPtrType session, T& subscribers, util::prometheus::GaugeInt& counter) -{ - if (subscribers.contains(session)) { - subscribers.erase(session); - --counter; - } -} +class SubscriptionManager { + std::reference_wrapper ioContext_; + std::shared_ptr backend_; -/** - * @brief Represents a subscription stream. - */ -class Subscription { - boost::asio::strand strand_; - std::unordered_set subscribers_ = {}; - util::prometheus::GaugeInt& subCount_; + impl::ForwardFeed manifestFeed_; + impl::ForwardFeed validationsFeed_; + impl::LedgerFeed ledgerFeed_; + impl::BookChangesFeed bookChangesFeed_; + impl::TransactionFeed transactionFeed_; + impl::ProposedTransactionFeed proposedTransactionFeed_; public: - Subscription() = delete; - Subscription(Subscription&) = delete; - Subscription(Subscription&&) = delete; - - /** - * @brief Create a new subscription stream. - * - * @param ioc The io_context to run on - */ - explicit Subscription(boost::asio::io_context& ioc, std::string const& name) - : strand_(boost::asio::make_strand(ioc)) - , subCount_(PrometheusService::gaugeInt( - "subscriptions_current_number", - util::prometheus::Labels({util::prometheus::Label{"stream", name}}), - fmt::format("Current subscribers number on the {} stream", name) - )) + SubscriptionManager( + boost::asio::io_context& ioContext, + std::shared_ptr const& backend + ) + : ioContext_(ioContext) + , backend_(backend) + , manifestFeed_(ioContext, "manifest") + , validationsFeed_(ioContext, "validations") + , ledgerFeed_(ioContext) + , bookChangesFeed_(ioContext) + , transactionFeed_(ioContext) + , proposedTransactionFeed_(ioContext) { } - ~Subscription() = default; - /** - * @brief Adds the given session to the subscribers set. - * - * @param session The session to add + * @brief Subscribe to the book changes feed. + * @param subscriber */ void - subscribe(SessionPtrType const& session); + subBookChanges(SubscriberSharedPtr const& subscriber); /** - * @brief Removes the given session from the subscribers set. - * - * @param session The session to remove + * @brief Unsubscribe to the book changes feed. + * @param subscriber */ void - unsubscribe(SessionPtrType const& session); - - /** - * @brief Check if a session has been in subscribers list. - * - * @param session The session to check - * @return true if the session is in the subscribers list; false otherwise - */ - bool - hasSession(SessionPtrType const& session); + unsubBookChanges(SubscriberSharedPtr const& subscriber); /** - * @brief Sends the given message to all subscribers. - * - * @param message The message to send + * @brief Publish the book changes feed. + * @param lgrInfo The current ledger header. + * @param transactions The transactions in the current ledger. */ void - publish(std::shared_ptr const& message); - - /** - * @return Total subscriber count on this stream. - */ - std::uint64_t - count() const - { - return subCount_.value(); - } - - /** - * @return true if the stream currently has no subscribers; false otherwise - */ - bool - empty() const - { - return count() == 0; - } -}; - -/** - * @brief Represents a collection of subscriptions where each stream is mapped to a key. - */ -template -class SubscriptionMap { - using SubscribersType = std::set; - - boost::asio::strand strand_; - std::unordered_map subscribers_ = {}; - util::prometheus::GaugeInt& subCount_; - -public: - SubscriptionMap() = delete; - SubscriptionMap(SubscriptionMap&) = delete; - SubscriptionMap(SubscriptionMap&&) = delete; - - /** - * @brief Create a new subscription map. - * - * @param ioc The io_context to run on - */ - explicit SubscriptionMap(boost::asio::io_context& ioc, std::string const& name) - : strand_(boost::asio::make_strand(ioc)) - , subCount_(PrometheusService::gaugeInt( - "subscriptions_current_number", - util::prometheus::Labels({util::prometheus::Label{"collection", name}}), - fmt::format("Current subscribers number on the {} collection", name) - )) - { - } - - ~SubscriptionMap() = default; + pubBookChanges(ripple::LedgerHeader const& lgrInfo, std::vector const& transactions) + const; /** - * @brief Subscribe to a specific stream by its key. - * - * @param session The session to add - * @param key The key for the subscription to subscribe to + * @brief Subscribe to the proposed transactions feed. + * @param subscriber */ void - subscribe(SessionPtrType const& session, Key const& key) - { - boost::asio::post(strand_, [this, session, key]() { addSession(session, subscribers_[key], subCount_); }); - } + subProposedTransactions(SubscriberSharedPtr const& subscriber); /** - * @brief Unsubscribe from a specific stream by its key. - * - * @param session The session to remove - * @param key The key for the subscription to unsubscribe from + * @brief Unsubscribe to the proposed transactions feed. + * @param subscriber */ void - unsubscribe(SessionPtrType const& session, Key const& key) - { - boost::asio::post(strand_, [this, key, session]() { - if (!subscribers_.contains(key)) - return; - - if (!subscribers_[key].contains(session)) - return; - - --subCount_; - subscribers_[key].erase(session); - - if (subscribers_[key].size() == 0) { - subscribers_.erase(key); - } - }); - } - - /** - * @brief Check if a session has been in subscribers list. - * - * @param session The session to check - * @param key The key for the subscription to check - * @return true if the session is in the subscribers list; false otherwise - */ - bool - hasSession(SessionPtrType const& session, Key const& key) - { - if (!subscribers_.contains(key)) - return false; - - return subscribers_[key].contains(session); - } + unsubProposedTransactions(SubscriberSharedPtr const& subscriber); /** - * @brief Sends the given message to all subscribers. - * - * @param message The message to send - * @param key The key for the subscription to send the message to + * @brief Subscribe to the proposed transactions feed, only receive the feed when particular account is affected. + * @param account The account to watch. + * @param subscriber */ void - publish(std::shared_ptr const& message, Key const& key) - { - boost::asio::post(strand_, [this, key, message]() { - if (!subscribers_.contains(key)) - return; - - sendToSubscribers(message, subscribers_[key], subCount_); - }); - } + subProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber); /** - * @return Total subscriber count on all streams in the collection. + * @brief Unsubscribe to the proposed transactions feed for particular account. + * @param account The account to stop watching. + * @param subscriber */ - std::uint64_t - count() const - { - return subCount_.value(); - } -}; - -/** - * @brief Manages subscriptions. - */ -class SubscriptionManager { - util::Logger log_{"Subscriptions"}; - - std::vector workers_; - boost::asio::io_context ioc_; - std::optional work_; - - Subscription ledgerSubscribers_; - Subscription txSubscribers_; - Subscription txProposedSubscribers_; - Subscription manifestSubscribers_; - Subscription validationsSubscribers_; - Subscription bookChangesSubscribers_; - - SubscriptionMap accountSubscribers_; - SubscriptionMap accountProposedSubscribers_; - SubscriptionMap bookSubscribers_; - - std::shared_ptr backend_; + void + unsubProposedAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber); -public: /** - * @brief A factory function that creates a new subscription manager configured from the config provided. - * - * @param config The configuration to use - * @param backend The backend to use + * @brief Forward the proposed transactions feed. + * @param receivedTxJson The proposed transaction json. */ - static std::shared_ptr - make_SubscriptionManager(util::Config const& config, std::shared_ptr const& backend) - { - auto numThreads = config.valueOr("subscription_workers", 1); - return std::make_shared(numThreads, backend); - } + void + forwardProposedTransaction(boost::json::object const& receivedTxJson); /** - * @brief Creates a new instance of the subscription manager. - * - * @param numThreads The number of worker threads to manage subscriptions - * @param backend The backend to use + * @brief Subscribe to the ledger feed. + * @param subscriber */ - SubscriptionManager(std::uint64_t numThreads, std::shared_ptr const& backend) - : ledgerSubscribers_(ioc_, "ledger") - , txSubscribers_(ioc_, "tx") - , txProposedSubscribers_(ioc_, "tx_proposed") - , manifestSubscribers_(ioc_, "manifest") - , validationsSubscribers_(ioc_, "validations") - , bookChangesSubscribers_(ioc_, "book_changes") - , accountSubscribers_(ioc_, "account") - , accountProposedSubscribers_(ioc_, "account_proposed") - , bookSubscribers_(ioc_, "book") - , backend_(backend) - { - work_.emplace(ioc_); - - // We will eventually want to clamp this to be the number of strands, - // since adding more threads than we have strands won't see any - // performance benefits - LOG(log_.info()) << "Starting subscription manager with " << numThreads << " workers"; - - workers_.reserve(numThreads); - for (auto i = numThreads; i > 0; --i) - workers_.emplace_back([this] { ioc_.run(); }); - } - - /** @brief Stops the worker threads of the subscription manager. */ - ~SubscriptionManager() - { - work_.reset(); - - ioc_.stop(); - for (auto& worker : workers_) - worker.join(); - } + boost::json::object + subLedger(boost::asio::yield_context yield, SubscriberSharedPtr const& subscriber); /** - * @brief Subscribe to the ledger stream. - * - * @param yield The coroutine context - * @param session The session to subscribe to the stream - * @return JSON object representing the first message to be sent to the new subscriber + * @brief Unsubscribe to the ledger feed. + * @param subscriber */ - boost::json::object - subLedger(boost::asio::yield_context yield, SessionPtrType session); + void + unsubLedger(SubscriberSharedPtr const& subscriber); /** - * @brief Publish to the ledger stream. - * - * @param lgrInfo The ledger header to serialize - * @param fees The fees to serialize - * @param ledgerRange The ledger range this message applies to - * @param txnCount The total number of transactions to serialize + * @brief Publish the ledger feed. + * @param lgrInfo The ledger header. + * @param fees The fees. + * @param ledgerRange The ledger range. + * @param txnCount The transaction count. */ void pubLedger( @@ -390,232 +161,160 @@ class SubscriptionManager { ripple::Fees const& fees, std::string const& ledgerRange, std::uint32_t txnCount - ); - - /** - * @brief Publish to the book changes stream. - * - * @param lgrInfo The ledger header to serialize - * @param transactions The transactions to serialize - */ - void - pubBookChanges(ripple::LedgerHeader const& lgrInfo, std::vector const& transactions); - - /** - * @brief Unsubscribe from the ledger stream. - * - * @param session The session to unsubscribe from the stream - */ - void - unsubLedger(SessionPtrType session); - - /** - * @brief Subscribe to the transactions stream. - * - * @param session The session to subscribe to the stream - */ - void - subTransactions(SessionPtrType session); - - /** - * @brief Unsubscribe from the transactions stream. - * - * @param session The session to unsubscribe from the stream - */ - void - unsubTransactions(SessionPtrType session); + ) const; /** - * @brief Publish to the book changes stream. - * - * @param blobs The transactions to serialize - * @param lgrInfo The ledger header to serialize + * @brief Subscribe to the manifest feed. + * @param subscriber */ void - pubTransaction(data::TransactionAndMetadata const& blobs, ripple::LedgerHeader const& lgrInfo); + subManifest(SubscriberSharedPtr const& subscriber); /** - * @brief Subscribe to the account changes stream. - * - * @param account The account to monitor changes for - * @param session The session to subscribe to the stream + * @brief Unsubscribe to the manifest feed. + * @param subscriber */ void - subAccount(ripple::AccountID const& account, SessionPtrType const& session); + unsubManifest(SubscriberSharedPtr const& subscriber); /** - * @brief Unsubscribe from the account changes stream. - * - * @param account The account the stream is for - * @param session The session to unsubscribe from the stream + * @brief Forward the manifest feed. + * @param manifestJson The manifest json to forward. */ void - unsubAccount(ripple::AccountID const& account, SessionPtrType const& session); + forwardManifest(boost::json::object const& manifestJson) const; /** - * @brief Subscribe to a specific book changes stream. - * - * @param book The book to monitor changes for - * @param session The session to subscribe to the stream + * @brief Subscribe to the validation feed. + * @param subscriber */ void - subBook(ripple::Book const& book, SessionPtrType session); + subValidation(SubscriberSharedPtr const& subscriber); /** - * @brief Unsubscribe from the specific book changes stream. - * - * @param book The book to stop monitoring changes for - * @param session The session to unsubscribe from the stream + * @brief Unsubscribe to the validation feed. + * @param subscriber */ void - unsubBook(ripple::Book const& book, SessionPtrType session); + unsubValidation(SubscriberSharedPtr const& subscriber); /** - * @brief Subscribe to the book changes stream. - * - * @param session The session to subscribe to the stream + * @brief Forward the validation feed. + * @param validationJson The validation feed json to forward. */ void - subBookChanges(SessionPtrType session); + forwardValidation(boost::json::object const& validationJson) const; /** - * @brief Unsubscribe from the book changes stream. - * - * @param session The session to unsubscribe from the stream + * @brief Subscribe to the transactions feed. + * @param subscriber + * @param apiVersion The api version of feed to subscribe. */ void - unsubBookChanges(SessionPtrType session); + subTransactions(SubscriberSharedPtr const& subscriber, std::uint32_t apiVersion); /** - * @brief Subscribe to the manifest stream. - * - * @param session The session to subscribe to the stream + * @brief Unsubscribe to the transactions feed. + * @param subscriber */ void - subManifest(SessionPtrType session); + unsubTransactions(SubscriberSharedPtr const& subscriber); /** - * @brief Unsubscribe from the manifest stream. - * - * @param session The session to unsubscribe from the stream + * @brief Subscribe to the transactions feed, only receive the feed when particular account is affected. + * @param account The account to watch. + * @param subscriber + * @param apiVersion The api version of feed to subscribe. */ void - unsubManifest(SessionPtrType session); + subAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber, std::uint32_t apiVersion); /** - * @brief Subscribe to the validation stream. - * - * @param session The session to subscribe to the stream + * @brief Unsubscribe to the transactions feed for particular account. + * @param subscriber */ void - subValidation(SessionPtrType session); + unsubAccount(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber); /** - * @brief Unsubscribe from the validation stream. - * - * @param session The session to unsubscribe from the stream + * @brief Subscribe to the transactions feed, only receive feed when particular order book is affected. + * @param book The book to watch. + * @param subscriber + * @param apiVersion The api version of feed to subscribe. */ void - unsubValidation(SessionPtrType session); + subBook(ripple::Book const& book, SubscriberSharedPtr const& subscriber, std::uint32_t apiVersion); /** - * @brief Publish proposed transactions and proposed accounts from a JSON response. - * - * @param response The JSON response to use + * @brief Unsubscribe to the transactions feed for particular order book. + * @param book The book to watch. + * @param subscriber */ void - forwardProposedTransaction(boost::json::object const& response); + unsubBook(ripple::Book const& book, SubscriberSharedPtr const& subscriber); /** - * @brief Publish manifest updates from a JSON response. - * - * @param response The JSON response to use + * @brief Forward the transactions feed. + * @param txMeta The transaction and metadata. + * @param lgrInfo The ledger header. */ void - forwardManifest(boost::json::object const& response); + pubTransaction(data::TransactionAndMetadata const& txMeta, ripple::LedgerHeader const& lgrInfo); /** - * @brief Publish validation updates from a JSON response. - * - * @param response The JSON response to use - */ - void - forwardValidation(boost::json::object const& response); - - /** - * @brief Subscribe to the proposed account stream. - * - * @param account The account to monitor - * @param session The session to subscribe to the stream - */ - void - subProposedAccount(ripple::AccountID const& account, SessionPtrType session); - - /** - * @brief Unsubscribe from the proposed account stream. - * - * @param account The account the stream is for - * @param session The session to unsubscribe from the stream - */ - void - unsubProposedAccount(ripple::AccountID const& account, SessionPtrType session); - - /** - * @brief Subscribe to the processed transactions stream. - * - * @param session The session to subscribe to the stream - */ - void - subProposedTransactions(SessionPtrType session); - - /** - * @brief Unsubscribe from the proposed transactions stream. - * - * @param session The session to unsubscribe from the stream - */ - void - unsubProposedTransactions(SessionPtrType session); - - /** @brief Clenup the session on removal. */ - void - cleanup(SessionPtrType session); - - /** - * @brief Generate a JSON report on the current state of the subscriptions. - * - * @return The report as a JSON object + * @brief Get the number of subscribers. */ boost::json::object report() const { return { - {"ledger", ledgerSubscribers_.count()}, - {"transactions", txSubscribers_.count()}, - {"transactions_proposed", txProposedSubscribers_.count()}, - {"manifests", manifestSubscribers_.count()}, - {"validations", validationsSubscribers_.count()}, - {"account", accountSubscribers_.count()}, - {"accounts_proposed", accountProposedSubscribers_.count()}, - {"books", bookSubscribers_.count()}, - {"book_changes", bookChangesSubscribers_.count()}, + {"ledger", ledgerFeed_.count()}, + {"transactions", transactionFeed_.transactionSubCount()}, + {"transactions_proposed", proposedTransactionFeed_.transactionSubcount()}, + {"manifests", manifestFeed_.count()}, + {"validations", validationsFeed_.count()}, + {"account", transactionFeed_.accountSubCount()}, + {"accounts_proposed", proposedTransactionFeed_.accountSubCount()}, + {"books", transactionFeed_.bookSubCount()}, + {"book_changes", bookChangesFeed_.count()}, }; } +}; -private: - using CleanupFunction = std::function; +/** + * @brief The help class to run the subscription manager. The container of io_context which is used to publish the + * feeds. + */ +class SubscriptionManagerRunner { + boost::asio::io_context ioContext_; + std::shared_ptr subscriptionManager_; + util::Logger logger_{"Subscriptions"}; + boost::asio::executor_work_guard work_ = + boost::asio::make_work_guard(ioContext_); + std::vector workers_; - void - subscribeHelper(SessionPtrType const& session, Subscription& subs, CleanupFunction&& func); +public: + SubscriptionManagerRunner(util::Config const& config, std::shared_ptr const& backend) + : subscriptionManager_(std::make_shared(ioContext_, backend)) + { + auto numThreads = config.valueOr("subscription_workers", 1); + LOG(logger_.info()) << "Starting subscription manager with " << numThreads << " workers"; + workers_.reserve(numThreads); + for (auto i = numThreads; i > 0; --i) + workers_.emplace_back([&] { ioContext_.run(); }); + } - template - void - subscribeHelper(SessionPtrType const& session, Key const& k, SubscriptionMap& subs, CleanupFunction&& func); + std::shared_ptr + getManager() + { + return subscriptionManager_; + } - // This is how we chose to cleanup subscriptions that have been closed. - // Each time we add a subscriber, we add the opposite lambda that unsubscribes that subscriber when cleanup is - // called with the session that closed. - std::mutex cleanupMtx_; - std::unordered_map> cleanupFuncs_ = {}; + ~SubscriptionManagerRunner() + { + work_.reset(); + for (auto& worker : workers_) + worker.join(); + } }; - } // namespace feed diff --git a/src/feed/Types.h b/src/feed/Types.h new file mode 100644 index 000000000..9b0811480 --- /dev/null +++ b/src/feed/Types.h @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "web/interface/ConnectionBase.h" + +#include + +namespace feed { +using Subscriber = web::ConnectionBase; +using SubscriberPtr = Subscriber*; +using SubscriberSharedPtr = std::shared_ptr; + +} // namespace feed diff --git a/src/feed/impl/BookChangesFeed.h b/src/feed/impl/BookChangesFeed.h new file mode 100644 index 000000000..0a01b9e71 --- /dev/null +++ b/src/feed/impl/BookChangesFeed.h @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "data/Types.h" +#include "feed/impl/SingleFeedBase.h" +#include "rpc/BookChangesHelper.h" + +#include +#include +#include + +#include + +namespace feed::impl { + +/** + * @brief Feed that publishes book changes. This feed will be published every ledger, even if there are no changes. + * Example : {'type': 'bookChanges', 'ledger_index': 2647936, 'ledger_hash': + * '0A5010342D8AAFABDCA58A68F6F588E1C6E58C21B63ED6CA8DB2478F58F3ECD5', 'ledger_time': 756395682, 'changes': []} + */ +struct BookChangesFeed : public SingleFeedBase { + BookChangesFeed(boost::asio::io_context& ioContext) : SingleFeedBase(ioContext, "book_changes") + { + } + + /** + * @brief Publishes the book changes. + * @param lgrInfo The ledger header. + * @param transactions The transactions that were included in the ledger. + */ + void + pub(ripple::LedgerHeader const& lgrInfo, std::vector const& transactions) const + { + SingleFeedBase::pub(boost::json::serialize(rpc::computeBookChanges(lgrInfo, transactions))); + } +}; +} // namespace feed::impl diff --git a/src/feed/impl/ForwardFeed.h b/src/feed/impl/ForwardFeed.h new file mode 100644 index 000000000..50c603ddf --- /dev/null +++ b/src/feed/impl/ForwardFeed.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "feed/impl/SingleFeedBase.h" + +#include +#include + +namespace feed::impl { + +/** + * @brief Feed that publishes the json object as it is. + */ +struct ForwardFeed : public SingleFeedBase { + using SingleFeedBase::SingleFeedBase; + + /** + * @brief Publishes the json object. + */ + void + pub(boost::json::object const& json) const + { + SingleFeedBase::pub(boost::json::serialize(json)); + } +}; +} // namespace feed::impl diff --git a/src/feed/impl/LedgerFeed.cpp b/src/feed/impl/LedgerFeed.cpp new file mode 100644 index 000000000..fee2d75f0 --- /dev/null +++ b/src/feed/impl/LedgerFeed.cpp @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/impl/LedgerFeed.h" + +#include "data/BackendInterface.h" +#include "feed/Types.h" +#include "feed/impl/SingleFeedBase.h" +#include "rpc/RPCHelpers.h" +#include "util/Assert.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace feed::impl { + +boost::json::object +LedgerFeed::makeLedgerPubMessage( + ripple::LedgerHeader const& lgrInfo, + ripple::Fees const& fees, + std::string const& ledgerRange, + std::uint32_t const txnCount +) +{ + boost::json::object pubMsg; + pubMsg["type"] = "ledgerClosed"; + pubMsg["ledger_index"] = lgrInfo.seq; + pubMsg["ledger_hash"] = to_string(lgrInfo.hash); + pubMsg["ledger_time"] = lgrInfo.closeTime.time_since_epoch().count(); + pubMsg["fee_base"] = rpc::toBoostJson(fees.base.jsonClipped()); + pubMsg["reserve_base"] = rpc::toBoostJson(fees.reserve.jsonClipped()); + pubMsg["reserve_inc"] = rpc::toBoostJson(fees.increment.jsonClipped()); + pubMsg["validated_ledgers"] = ledgerRange; + pubMsg["txn_count"] = txnCount; + return pubMsg; +} + +boost::json::object +LedgerFeed::sub( + boost::asio::yield_context yield, + std::shared_ptr const& backend, + SubscriberSharedPtr const& subscriber +) +{ + SingleFeedBase::sub(subscriber); + + // For ledger stream, we need to send the last closed ledger info as response + auto const ledgerRange = backend->fetchLedgerRange(); + ASSERT(ledgerRange.has_value(), "Ledger range must be valid"); + + auto const lgrInfo = backend->fetchLedgerBySequence(ledgerRange->maxSequence, yield); + ASSERT(lgrInfo.has_value(), "Ledger must be valid"); + + auto const fees = backend->fetchFees(lgrInfo->seq, yield); + ASSERT(fees.has_value(), "Fees must be valid"); + + auto const range = std::to_string(ledgerRange->minSequence) + "-" + std::to_string(ledgerRange->maxSequence); + + auto pubMsg = makeLedgerPubMessage(*lgrInfo, *fees, range, 0); + pubMsg.erase("txn_count"); + pubMsg.erase("type"); + + return pubMsg; +} + +void +LedgerFeed::pub( + ripple::LedgerHeader const& lgrInfo, + ripple::Fees const& fees, + std::string const& ledgerRange, + std::uint32_t const txnCount +) const +{ + SingleFeedBase::pub(boost::json::serialize(makeLedgerPubMessage(lgrInfo, fees, ledgerRange, txnCount))); +} +} // namespace feed::impl diff --git a/src/feed/impl/LedgerFeed.h b/src/feed/impl/LedgerFeed.h new file mode 100644 index 000000000..685284b26 --- /dev/null +++ b/src/feed/impl/LedgerFeed.h @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "data/BackendInterface.h" +#include "feed/Types.h" +#include "feed/impl/SingleFeedBase.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace feed::impl { + +/** + * @brief Feed that publishes the ledger info. + * Example : {'type': 'ledgerClosed', 'ledger_index': 2647935, 'ledger_hash': + * '5D022718CD782A82EE10D2147FD90B5F42F26A7E937C870B4FE3CF1086C916AE', 'ledger_time': 756395681, 'fee_base': 10, + * 'reserve_base': 10000000, 'reserve_inc': 2000000, 'validated_ledgers': '2619127-2647935', 'txn_count': 0} + */ +class LedgerFeed : public SingleFeedBase { +public: + /** + * @brief Construct a new Ledger Feed object + * @param ioContext The actual publish will be called in the strand of this. + */ + LedgerFeed(boost::asio::io_context& ioContext) : SingleFeedBase(ioContext, "ledger") + { + } + + /** + * @brief Subscribe the ledger feed. + * @param yield The coroutine yield. + * @param backend The backend. + * @param subscriber + * @return The information of the latest ledger. + */ + boost::json::object + sub(boost::asio::yield_context yield, + std::shared_ptr const& backend, + SubscriberSharedPtr const& subscriber); + + /** + * @brief Publishes the ledger feed. + * @param lgrInfo The ledger header. + * @param fees The fees. + * @param ledgerRange The ledger range. + * @param txnCount The transaction count. + */ + void + pub(ripple::LedgerHeader const& lgrInfo, + ripple::Fees const& fees, + std::string const& ledgerRange, + std::uint32_t txnCount) const; + +private: + static boost::json::object + makeLedgerPubMessage( + ripple::LedgerHeader const& lgrInfo, + ripple::Fees const& fees, + std::string const& ledgerRange, + std::uint32_t txnCount + ); +}; +} // namespace feed::impl diff --git a/src/feed/impl/ProposedTransactionFeed.cpp b/src/feed/impl/ProposedTransactionFeed.cpp new file mode 100644 index 000000000..e57f3112b --- /dev/null +++ b/src/feed/impl/ProposedTransactionFeed.cpp @@ -0,0 +1,146 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/impl/ProposedTransactionFeed.h" + +#include "feed/Types.h" +#include "rpc/RPCHelpers.h" +#include "util/log/Logger.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace feed::impl { + +void +ProposedTransactionFeed::sub(SubscriberSharedPtr const& subscriber) +{ + auto const weakPtr = std::weak_ptr(subscriber); + auto const added = signal_.connectTrackableSlot(subscriber, [weakPtr](std::shared_ptr const& msg) { + if (auto connectionPtr = weakPtr.lock()) { + connectionPtr->send(msg); + } + }); + + if (added) { + LOG(logger_.debug()) << subscriber->tag() << "Subscribed tx_proposed"; + ++subAllCount_.get(); + subscriber->onDisconnect.connect([this](SubscriberPtr connection) { unsubInternal(connection); }); + } +} + +void +ProposedTransactionFeed::sub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +{ + auto const weakPtr = std::weak_ptr(subscriber); + auto const added = accountSignal_.connectTrackableSlot( + subscriber, + account, + [this, weakPtr](std::shared_ptr const& msg) { + if (auto connectionPtr = weakPtr.lock()) { + // Check if this connection already sent + if (notified_.contains(connectionPtr.get())) + return; + + notified_.insert(connectionPtr.get()); + connectionPtr->send(msg); + } + } + ); + if (added) { + LOG(logger_.debug()) << subscriber->tag() << "Subscribed accounts_proposed " << account; + ++subAccountCount_.get(); + subscriber->onDisconnect.connect([this, account](SubscriberPtr connection) { + unsubInternal(account, connection); + }); + } +} + +void +ProposedTransactionFeed::unsub(SubscriberSharedPtr const& subscriber) +{ + unsubInternal(subscriber.get()); +} + +void +ProposedTransactionFeed::unsub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +{ + unsubInternal(account, subscriber.get()); +} + +void +ProposedTransactionFeed::pub(boost::json::object const& receivedTxJson) +{ + auto pubMsg = std::make_shared(boost::json::serialize(receivedTxJson)); + + auto const transaction = receivedTxJson.at("transaction").as_object(); + auto const accounts = rpc::getAccountsFromTransaction(transaction); + auto affectedAccounts = std::unordered_set(accounts.cbegin(), accounts.cend()); + + boost::asio::post(strand_, [this, pubMsg = std::move(pubMsg), affectedAccounts = std::move(affectedAccounts)]() { + signal_.emit(pubMsg); + // Prevent the same connection from receiving the same message twice if it is subscribed to multiple accounts + // However, if the same connection subscribe both stream and account, it will still receive the message twice. + // notified_ can be cleared before signal_ emit to improve this, but let's keep it as is for now, since rippled + // acts like this. + notified_.clear(); + for (auto const& account : affectedAccounts) + accountSignal_.emit(account, pubMsg); + }); +} + +std::uint64_t +ProposedTransactionFeed::transactionSubcount() const +{ + return subAllCount_.get().value(); +} + +std::uint64_t +ProposedTransactionFeed::accountSubCount() const +{ + return subAccountCount_.get().value(); +} + +void +ProposedTransactionFeed::unsubInternal(SubscriberPtr subscriber) +{ + if (signal_.disconnect(subscriber)) { + LOG(logger_.debug()) << subscriber->tag() << "Unsubscribed tx_proposed"; + --subAllCount_.get(); + } +} + +void +ProposedTransactionFeed::unsubInternal(ripple::AccountID const& account, SubscriberPtr subscriber) +{ + if (accountSignal_.disconnect(subscriber, account)) { + LOG(logger_.debug()) << subscriber->tag() << "Unsubscribed accounts_proposed " << account; + --subAccountCount_.get(); + } +} + +} // namespace feed::impl diff --git a/src/feed/impl/ProposedTransactionFeed.h b/src/feed/impl/ProposedTransactionFeed.h new file mode 100644 index 000000000..47eea1975 --- /dev/null +++ b/src/feed/impl/ProposedTransactionFeed.h @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "feed/Types.h" +#include "feed/impl/TrackableSignal.h" +#include "feed/impl/TrackableSignalMap.h" +#include "feed/impl/Util.h" +#include "util/log/Logger.h" +#include "util/prometheus/Gauge.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace feed::impl { + +/** + * @brief Feed that publishes the Proposed Transactions. + * @note Be aware that the Clio only forwards this stream, not respect api_version. + */ +class ProposedTransactionFeed { + util::Logger logger_{"Subscriptions"}; + + std::unordered_set + notified_; // Used by slots to prevent double notifications if tx contains multiple subscribed accounts + boost::asio::strand strand_; + std::reference_wrapper subAllCount_; + std::reference_wrapper subAccountCount_; + + TrackableSignalMap> accountSignal_; + TrackableSignal> signal_; + +public: + /** + * @brief Construct a Proposed Transaction Feed object. + * @param ioContext The actual publish will be called in the strand of this. + */ + ProposedTransactionFeed(boost::asio::io_context& ioContext) + : strand_(boost::asio::make_strand(ioContext)) + , subAllCount_(getSubscriptionsGaugeInt("tx_proposed")) + , subAccountCount_(getSubscriptionsGaugeInt("account_proposed")) + + { + } + + /** + * @brief Subscribe to the proposed transaction feed. + * @param subscriber + */ + void + sub(SubscriberSharedPtr const& subscriber); + + /** + * @brief Subscribe to the proposed transaction feed, only receive the feed when particular account is affected. + * @param subscriber + * @param account The account to watch. + */ + void + sub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber); + + /** + * @brief Unsubscribe to the proposed transaction feed. + * @param subscriber + */ + void + unsub(SubscriberSharedPtr const& subscriber); + + /** + * @brief Unsubscribe to the proposed transaction feed for particular account. + * @param subscriber + * @param account The account to unsubscribe. + */ + void + unsub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber); + + /** + * @brief Publishes the proposed transaction feed. + * @param receivedTxJson The proposed transaction json. + */ + void + pub(boost::json::object const& receivedTxJson); + + /** + * @brief Get the number of subscribers of the proposed transaction feed. + */ + std::uint64_t + transactionSubcount() const; + + /** + * @brief Get the number of accounts subscribers. + */ + std::uint64_t + accountSubCount() const; + +private: + void + unsubInternal(SubscriberPtr subscriber); + + void + unsubInternal(ripple::AccountID const& account, SubscriberPtr subscriber); +}; +} // namespace feed::impl diff --git a/src/feed/impl/SingleFeedBase.cpp b/src/feed/impl/SingleFeedBase.cpp new file mode 100644 index 000000000..c4a36cd03 --- /dev/null +++ b/src/feed/impl/SingleFeedBase.cpp @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/impl/SingleFeedBase.h" + +#include "feed/Types.h" +#include "feed/impl/TrackableSignal.h" +#include "feed/impl/Util.h" +#include "util/log/Logger.h" + +#include +#include +#include + +#include +#include +#include +#include + +namespace feed::impl { + +SingleFeedBase::SingleFeedBase(boost::asio::io_context& ioContext, std::string const& name) + : strand_(boost::asio::make_strand(ioContext)), subCount_(getSubscriptionsGaugeInt(name)), name_(name) +{ +} + +void +SingleFeedBase::sub(SubscriberSharedPtr const& subscriber) +{ + auto const weakPtr = std::weak_ptr(subscriber); + auto const added = signal_.connectTrackableSlot(subscriber, [weakPtr](std::shared_ptr const& msg) { + if (auto connectionPtr = weakPtr.lock()) + connectionPtr->send(msg); + }); + + if (added) { + LOG(logger_.debug()) << subscriber->tag() << "Subscribed " << name_; + ++subCount_.get(); + subscriber->onDisconnect.connect([this](SubscriberPtr connectionDisconnecting) { + unsubInternal(connectionDisconnecting); + }); + }; +} + +void +SingleFeedBase::unsub(SubscriberSharedPtr const& subscriber) +{ + unsubInternal(subscriber.get()); +} + +void +SingleFeedBase::pub(std::string msg) const +{ + boost::asio::post(strand_, [this, msg = std::move(msg)]() mutable { + auto const msgPtr = std::make_shared(std::move(msg)); + signal_.emit(msgPtr); + }); +} + +std::uint64_t +SingleFeedBase::count() const +{ + return subCount_.get().value(); +} + +void +SingleFeedBase::unsubInternal(SubscriberPtr subscriber) +{ + if (signal_.disconnect(subscriber)) { + LOG(logger_.debug()) << subscriber->tag() << "Unsubscribed " << name_; + --subCount_.get(); + } +} +} // namespace feed::impl diff --git a/src/feed/impl/SingleFeedBase.h b/src/feed/impl/SingleFeedBase.h new file mode 100644 index 000000000..6f5b0cbca --- /dev/null +++ b/src/feed/impl/SingleFeedBase.h @@ -0,0 +1,86 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "feed/Types.h" +#include "feed/impl/TrackableSignal.h" +#include "util/log/Logger.h" +#include "util/prometheus/Gauge.h" + +#include +#include + +#include +#include +#include +#include + +namespace feed::impl { + +/** + * @brief Base class for single feed. + */ +class SingleFeedBase { + boost::asio::strand strand_; + std::reference_wrapper subCount_; + TrackableSignal const&> signal_; + util::Logger logger_{"Subscriptions"}; + std::string name_; + +public: + /** + * @brief Construct a new Single Feed Base object + * @param ioContext The actual publish will be called in the strand of this. + * @param name The promethues counter name of the feed. + */ + SingleFeedBase(boost::asio::io_context& ioContext, std::string const& name); + + /** + * @brief Subscribe the feed. + * @param subscriber + */ + void + sub(SubscriberSharedPtr const& subscriber); + + /** + * @brief Unsubscribe the feed. + * @param subscriber + */ + void + unsub(SubscriberSharedPtr const& subscriber); + + /** + * @brief Publishes the feed in strand. + * @param msg The message. + */ + void + pub(std::string msg) const; + + /** + * @brief Get the count of subscribers. + */ + std::uint64_t + count() const; + +private: + void + unsubInternal(SubscriberPtr subscriber); +}; +} // namespace feed::impl diff --git a/src/feed/impl/TrackableSignal.h b/src/feed/impl/TrackableSignal.h new file mode 100644 index 000000000..0384d7dec --- /dev/null +++ b/src/feed/impl/TrackableSignal.h @@ -0,0 +1,122 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace feed::impl { + +/** + * @brief A thread-safe class to manage a signal and its tracking connections. + * + * @param Session The type of the object that will be tracked, when the object is destroyed, the connection will be + * removed lazily. The pointer of the session object will also be the key to disconnect. + * @param Args The types of the arguments that will be passed to the slot. + */ +template +class TrackableSignal { + using ConnectionPtr = Session*; + using ConnectionSharedPtr = std::shared_ptr; + + // map of connection and signal connection, key is the pointer of the connection object + // allow disconnect to be called in the destructor of the connection + std::unordered_map connections_; + mutable std::mutex mutex_; + + using SignalType = boost::signals2::signal; + SignalType signal_; + +public: + /** + * @brief Connect a slot to the signal, the slot will be called when the signal is emitted and trackable is still + * alive. + * + * @param trackable Track this object's lifttime, if the object is destroyed, the connection will be removed lazily. + * When the slot is being called, the object is guaranteed to be alive. + * @param slot The slot connecting to the signal, the slot will be called when the signal is emitted. + * @return true if the connection is successfully added, false if the connection already exists. + */ + bool + connectTrackableSlot(ConnectionSharedPtr const& trackable, std::function slot) + { + std::scoped_lock const lk(mutex_); + if (connections_.contains(trackable.get())) { + return false; + } + + // This class can't hold the trackable's shared_ptr, because disconnect should be able to be called in the + // the trackable's destructor. However, the trackable can not be destroied when the slot is being called + // either. track_foreign will hold a weak_ptr to the connection, which makes sure the connection is valid when + // the slot is called. + connections_.emplace( + trackable.get(), signal_.connect(typename SignalType::slot_type(slot).track_foreign(trackable)) + ); + return true; + } + + /** + * @brief Disconnect a slot to the signal. + * + * @param trackablePtr Disconnect the slot whose trackable is this pointer. Be aware that the pointer is a raw + * pointer, allowing disconnect to be called in the destructor of the trackable. + * @return true if the connection is successfully disconnected, false if the connection does not exist. + */ + bool + disconnect(ConnectionPtr trackablePtr) + { + std::scoped_lock const lk(mutex_); + if (connections_.contains(trackablePtr)) { + connections_[trackablePtr].disconnect(); + connections_.erase(trackablePtr); + return true; + } + return false; + } + + /** + * @brief Calling all slots. + * + * @param args The arguments to pass to the slots. + */ + void + emit(Args const&... args) const + { + signal_(args...); + } + + /** + * @brief Get the number of connections. + */ + std::size_t + count() const + { + std::scoped_lock const lk(mutex_); + return connections_.size(); + } +}; +} // namespace feed::impl diff --git a/src/feed/impl/TrackableSignalMap.h b/src/feed/impl/TrackableSignalMap.h new file mode 100644 index 000000000..3146669b2 --- /dev/null +++ b/src/feed/impl/TrackableSignalMap.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "feed/impl/TrackableSignal.h" + +#include + +#include +#include +#include +#include +#include + +namespace feed::impl { + +template +concept Hashable = requires(T a) { + { + std::hash{}(a) + } -> std::convertible_to; +}; + +/** + * @brief Class to manage a map of key and its associative signal. + * @param Key The type of the key. + * @param Session The type of the object that will be tracked, when the object is destroyed, the connection will be + * removed lazily. + * @param Args The types of the arguments that will be passed to the slot + */ +template +class TrackableSignalMap { + using ConnectionPtr = Session*; + using ConnectionSharedPtr = std::shared_ptr; + + mutable std::mutex mutex_; + std::unordered_map> signalsMap_; + +public: + /** + * @brief Connect a slot to the signal, the slot will be called when the signal is emitted and trackable is still + * alive. + * + * @param trackable Track this object's lifttime, if the object is destroyed, the connection will be removed lazily. + * When the slot is being called, the object is guaranteed to be alive. + * @param key The key to the signal. + * @param slot The slot connecting to the signal, the slot will be called when the assocaiative signal is emitted. + * @return true if the connection is successfully added, false if the connection already exists for the key. + */ + bool + connectTrackableSlot(ConnectionSharedPtr const& trackable, Key const& key, std::function slot) + { + std::scoped_lock const lk(mutex_); + return signalsMap_[key].connectTrackableSlot(trackable, slot); + } + + /** + * @brief Disconnect a slot from the key's associative signal. + * + * @param trackablePtr The pointer to the object that is being tracked. + * @param key The key to the signal. + * @return true if the connection is successfully removed, false if the connection does not exist. + */ + bool + disconnect(ConnectionPtr trackablePtr, Key const& key) + { + std::scoped_lock const lk(mutex_); + if (!signalsMap_.contains(key)) + return false; + + auto const disconnected = signalsMap_[key].disconnect(trackablePtr); + // clean the map if there is no connection left. + if (disconnected && signalsMap_[key].count() == 0) + signalsMap_.erase(key); + + return disconnected; + } + + /** + * @brief Emit the signal with the given key and arguments. + * + * @param key The key to the signal. + * @param args The arguments to be passed to the slot. + */ + void + emit(Key const& key, Args const&... args) + { + std::scoped_lock const lk(mutex_); + if (signalsMap_.contains(key)) + signalsMap_[key].emit(args...); + } +}; +} // namespace feed::impl diff --git a/src/feed/impl/TransactionFeed.cpp b/src/feed/impl/TransactionFeed.cpp new file mode 100644 index 000000000..c37566058 --- /dev/null +++ b/src/feed/impl/TransactionFeed.cpp @@ -0,0 +1,303 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/impl/TransactionFeed.h" + +#include "data/BackendInterface.h" +#include "data/Types.h" +#include "feed/Types.h" +#include "rpc/JS.h" +#include "rpc/RPCHelpers.h" +#include "util/log/Logger.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace feed::impl { + +void +TransactionFeed::TransactionSlot::operator()(AllVersionTransactionsType const& allVersionMsgs) const +{ + if (auto connection = connectionWeakPtr.lock(); connection) { + // Check if this connection already sent + if (feed.get().notified_.contains(connection.get())) + return; + + feed.get().notified_.insert(connection.get()); + + if (connection->apiSubVersion < 2u) { + connection->send(allVersionMsgs[0]); + return; + } + connection->send(allVersionMsgs[1]); + } +} + +void +TransactionFeed::sub(SubscriberSharedPtr const& subscriber, std::uint32_t const apiVersion) +{ + auto const added = signal_.connectTrackableSlot(subscriber, TransactionSlot(*this, subscriber)); + if (added) { + LOG(logger_.debug()) << subscriber->tag() << "Subscribed transactions"; + ++subAllCount_.get(); + subscriber->apiSubVersion = apiVersion; + subscriber->onDisconnect.connect([this](SubscriberPtr connection) { unsubInternal(connection); }); + } +} + +void +TransactionFeed::sub( + ripple::AccountID const& account, + SubscriberSharedPtr const& subscriber, + std::uint32_t const apiVersion +) +{ + auto const added = accountSignal_.connectTrackableSlot(subscriber, account, TransactionSlot(*this, subscriber)); + if (added) { + LOG(logger_.debug()) << subscriber->tag() << "Subscribed account " << account; + ++subAccountCount_.get(); + subscriber->apiSubVersion = apiVersion; + subscriber->onDisconnect.connect([this, account](SubscriberPtr connection) { + unsubInternal(account, connection); + }); + } +} + +void +TransactionFeed::sub(ripple::Book const& book, SubscriberSharedPtr const& subscriber, std::uint32_t const apiVersion) +{ + auto const added = bookSignal_.connectTrackableSlot(subscriber, book, TransactionSlot(*this, subscriber)); + if (added) { + LOG(logger_.debug()) << subscriber->tag() << "Subscribed book " << book; + ++subBookCount_.get(); + subscriber->apiSubVersion = apiVersion; + subscriber->onDisconnect.connect([this, book](SubscriberPtr connection) { unsubInternal(book, connection); }); + } +} + +void +TransactionFeed::unsub(SubscriberSharedPtr const& subscriber) +{ + unsubInternal(subscriber.get()); +} + +void +TransactionFeed::unsub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber) +{ + unsubInternal(account, subscriber.get()); +} + +void +TransactionFeed::unsub(ripple::Book const& book, SubscriberSharedPtr const& subscriber) +{ + unsubInternal(book, subscriber.get()); +} + +std::uint64_t +TransactionFeed::transactionSubCount() const +{ + return subAllCount_.get().value(); +} + +std::uint64_t +TransactionFeed::accountSubCount() const +{ + return subAccountCount_.get().value(); +} + +std::uint64_t +TransactionFeed::bookSubCount() const +{ + return subBookCount_.get().value(); +} + +void +TransactionFeed::pub( + data::TransactionAndMetadata const& txMeta, + ripple::LedgerHeader const& lgrInfo, + std::shared_ptr const& backend +) +{ + auto [tx, meta] = rpc::deserializeTxPlusMeta(txMeta, lgrInfo.seq); + + std::optional ownerFunds; + + if (tx->getTxnType() == ripple::ttOFFER_CREATE) { + auto const account = tx->getAccountID(ripple::sfAccount); + auto const amount = tx->getFieldAmount(ripple::sfTakerGets); + if (account != amount.issue().account) { + auto fetchFundsSynchronous = [&]() { + data::synchronous([&](boost::asio::yield_context yield) { + ownerFunds = rpc::accountFunds(*backend, lgrInfo.seq, amount, account, yield); + }); + }; + data::retryOnTimeout(fetchFundsSynchronous); + } + } + + auto const genJsonByVersion = [&, tx = tx, meta = meta](std::uint32_t version) { + boost::json::object pubObj; + auto const txKey = version < 2u ? JS(transaction) : JS(tx_json); + pubObj[txKey] = rpc::toJson(*tx); + pubObj[JS(meta)] = rpc::toJson(*meta); + rpc::insertDeliveredAmount(pubObj[JS(meta)].as_object(), tx, meta, txMeta.date); + rpc::insertDeliverMaxAlias(pubObj[txKey].as_object(), version); + + pubObj[JS(type)] = "transaction"; + pubObj[JS(validated)] = true; + pubObj[JS(status)] = "closed"; + pubObj[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo.closeTime); + + pubObj[JS(ledger_index)] = lgrInfo.seq; + pubObj[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash); + if (version >= 2u) { + if (pubObj[txKey].as_object().contains(JS(hash))) { + pubObj[JS(hash)] = pubObj[txKey].as_object()[JS(hash)]; + pubObj[txKey].as_object().erase(JS(hash)); + } + } + pubObj[txKey].as_object()[JS(date)] = lgrInfo.closeTime.time_since_epoch().count(); + + pubObj[JS(engine_result_code)] = meta->getResult(); + std::string token; + std::string human; + ripple::transResultInfo(meta->getResultTER(), token, human); + pubObj[JS(engine_result)] = token; + pubObj[JS(engine_result_message)] = human; + + if (ownerFunds) + pubObj[txKey].as_object()[JS(owner_funds)] = ownerFunds->getText(); + + return pubObj; + }; + + AllVersionTransactionsType allVersionsMsgs{ + std::make_shared(boost::json::serialize(genJsonByVersion(1u))), + std::make_shared(boost::json::serialize(genJsonByVersion(2u))) + }; + + auto const affectedAccountsFlat = meta->getAffectedAccounts(); + auto affectedAccounts = + std::unordered_set(affectedAccountsFlat.cbegin(), affectedAccountsFlat.cend()); + + std::unordered_set affectedBooks; + + for (auto const& node : meta->getNodes()) { + if (node.getFieldU16(ripple::sfLedgerEntryType) == ripple::ltOFFER) { + ripple::SField const* field = nullptr; + + // We need a field that contains the TakerGets and TakerPays + // parameters. + if (node.getFName() == ripple::sfModifiedNode) { + field = &ripple::sfPreviousFields; + } else if (node.getFName() == ripple::sfCreatedNode) { + field = &ripple::sfNewFields; + } else if (node.getFName() == ripple::sfDeletedNode) { + field = &ripple::sfFinalFields; + } + + if (field != nullptr) { + auto const data = dynamic_cast(node.peekAtPField(*field)); + + if ((data != nullptr) && data->isFieldPresent(ripple::sfTakerPays) && + data->isFieldPresent(ripple::sfTakerGets)) { + // determine the OrderBook + ripple::Book const book{ + data->getFieldAmount(ripple::sfTakerGets).issue(), + data->getFieldAmount(ripple::sfTakerPays).issue() + }; + if (affectedBooks.find(book) == affectedBooks.end()) { + affectedBooks.insert(book); + } + } + } + } + } + + boost::asio::post( + strand_, + [this, + allVersionsMsgs = std::move(allVersionsMsgs), + affectedAccounts = std::move(affectedAccounts), + affectedBooks = std::move(affectedBooks)]() { + notified_.clear(); + signal_.emit(allVersionsMsgs); + notified_.clear(); + // check duplicate for accounts, this prevents sending the same message multiple times if it touches + // multiple accounts watched by the same connection + for (auto const& account : affectedAccounts) { + accountSignal_.emit(account, allVersionsMsgs); + } + notified_.clear(); + // check duplicate for books, this prevents sending the same message multiple times if it touches multiple + // books watched by the same connection + for (auto const& book : affectedBooks) { + bookSignal_.emit(book, allVersionsMsgs); + } + } + ); +} + +void +TransactionFeed::unsubInternal(SubscriberPtr subscriber) +{ + if (signal_.disconnect(subscriber)) { + LOG(logger_.debug()) << subscriber->tag() << "Unsubscribed transactions"; + --subAllCount_.get(); + } +} + +void +TransactionFeed::unsubInternal(ripple::AccountID const& account, SubscriberPtr subscriber) +{ + if (accountSignal_.disconnect(subscriber, account)) { + LOG(logger_.debug()) << subscriber->tag() << "Unsubscribed account " << account; + --subAccountCount_.get(); + } +} + +void +TransactionFeed::unsubInternal(ripple::Book const& book, SubscriberPtr subscriber) +{ + if (bookSignal_.disconnect(subscriber, book)) { + LOG(logger_.debug()) << subscriber->tag() << "Unsubscribed book " << book; + --subBookCount_.get(); + } +} +} // namespace feed::impl diff --git a/src/feed/impl/TransactionFeed.h b/src/feed/impl/TransactionFeed.h new file mode 100644 index 000000000..20685c1e6 --- /dev/null +++ b/src/feed/impl/TransactionFeed.h @@ -0,0 +1,179 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "data/BackendInterface.h" +#include "data/Types.h" +#include "feed/Types.h" +#include "feed/impl/TrackableSignal.h" +#include "feed/impl/TrackableSignalMap.h" +#include "feed/impl/Util.h" +#include "util/log/Logger.h" +#include "util/prometheus/Gauge.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace feed::impl { + +class TransactionFeed { + // Hold two versions of transaction messages + using AllVersionTransactionsType = std::array, 2>; + + struct TransactionSlot { + std::reference_wrapper feed; + std::weak_ptr connectionWeakPtr; + + TransactionSlot(TransactionFeed& feed, SubscriberSharedPtr const& connection) + : feed(feed), connectionWeakPtr(connection) + { + } + + void + operator()(AllVersionTransactionsType const& allVersionMsgs) const; + }; + + util::Logger logger_{"Subscriptions"}; + + boost::asio::strand strand_; + std::reference_wrapper subAllCount_; + std::reference_wrapper subAccountCount_; + std::reference_wrapper subBookCount_; + + TrackableSignalMap accountSignal_; + TrackableSignalMap bookSignal_; + TrackableSignal signal_; + + std::unordered_set + notified_; // Used by slots to prevent double notifications if tx contains multiple subscribed accounts + +public: + /** + * @brief Construct a new Transaction Feed object. + * @param ioContext The actual publish will be called in the strand of this. + */ + TransactionFeed(boost::asio::io_context& ioContext) + : strand_(boost::asio::make_strand(ioContext)) + , subAllCount_(getSubscriptionsGaugeInt("tx")) + , subAccountCount_(getSubscriptionsGaugeInt("account")) + , subBookCount_(getSubscriptionsGaugeInt("book")) + { + } + + /** + * @brief Subscribe to the transaction feed. + * @param subscriber + * @param apiVersion The api version of feed. + */ + void + sub(SubscriberSharedPtr const& subscriber, std::uint32_t apiVersion); + + /** + * @brief Subscribe to the transaction feed, only receive the feed when particular account is affected. + * @param subscriber + * @param account The account to watch. + * @param apiVersion The api version of feed. + */ + void + sub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber, std::uint32_t apiVersion); + + /** + * @brief Subscribe to the transaction feed, only receive the feed when particular order book is affected. + * @param subscriber + * @param book The order book to watch. + * @param apiVersion The api version of feed. + */ + void + sub(ripple::Book const& book, SubscriberSharedPtr const& subscriber, std::uint32_t apiVersion); + + /** + * @brief Unsubscribe to the transaction feed. + * @param subscriber + */ + void + unsub(SubscriberSharedPtr const& subscriber); + + /** + * @brief Unsubscribe to the transaction for particular account. + * @param subscriber + * @param account The account to unsubscribe. + */ + void + unsub(ripple::AccountID const& account, SubscriberSharedPtr const& subscriber); + + /** + * @brief Unsubscribe to the transaction feed for particular order book. + * @param subscriber + * @param book The book to unsubscribe. + */ + void + unsub(ripple::Book const& book, SubscriberSharedPtr const& subscriber); + + /** + * @brief Publishes the transaction feed. + * @param txMeta The transaction and metadata. + * @param lgrInfo The ledger header. + * @param backend The backend. + */ + void + pub(data::TransactionAndMetadata const& txMeta, + ripple::LedgerHeader const& lgrInfo, + std::shared_ptr const& backend); + + /** + * @brief Get the number of subscribers of the transaction feed. + */ + std::uint64_t + transactionSubCount() const; + + /** + * @brief Get the number of accounts subscribers. + */ + std::uint64_t + accountSubCount() const; + + /** + * @brief Get the number of books subscribers. + */ + std::uint64_t + bookSubCount() const; + +private: + void + unsubInternal(SubscriberPtr subscriber); + + void + unsubInternal(ripple::AccountID const& account, SubscriberPtr subscriber); + + void + unsubInternal(ripple::Book const& book, SubscriberPtr subscriber); +}; +} // namespace feed::impl diff --git a/src/feed/impl/Util.h b/src/feed/impl/Util.h new file mode 100644 index 000000000..8b77ae60f --- /dev/null +++ b/src/feed/impl/Util.h @@ -0,0 +1,41 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "util/prometheus/Gauge.h" +#include "util/prometheus/Label.h" +#include "util/prometheus/Prometheus.h" + +#include + +#include + +namespace feed::impl { + +inline util::prometheus::GaugeInt& +getSubscriptionsGaugeInt(std::string const& counterName) +{ + return PrometheusService::gaugeInt( + "subscriptions_current_number", + util::prometheus::Labels({util::prometheus::Label{"stream", counterName}}), + fmt::format("Current subscribers number on the {} stream", counterName) + ); +} +} // namespace feed::impl diff --git a/src/main/Main.cpp b/src/main/Main.cpp index 022bdc58f..4efc6f33b 100644 --- a/src/main/Main.cpp +++ b/src/main/Main.cpp @@ -20,6 +20,7 @@ #include "data/BackendFactory.h" #include "etl/ETLHelpers.h" #include "etl/ETLService.h" +#include "feed/SubscriptionManager.h" #include "main/Build.h" #include "rpc/Counters.h" #include "rpc/RPCEngine.h" @@ -197,7 +198,9 @@ try { auto backend = data::make_Backend(config); // Manages clients subscribed to streams - auto subscriptions = feed::SubscriptionManager::make_SubscriptionManager(config, backend); + auto subscriptionsRunner = feed::SubscriptionManagerRunner(config, backend); + + auto const subscriptions = subscriptionsRunner.getManager(); // Tracks which ledgers have been validated by the network auto ledgers = etl::NetworkValidatedLedgers::make_ValidatedLedgers(); @@ -216,14 +219,12 @@ try { auto const handlerProvider = std::make_shared( config, backend, subscriptions, balancer, etl, counters ); - auto const rpcEngine = rpc::RPCEngine::make_RPCEngine( - backend, subscriptions, balancer, dosGuard, workQueue, counters, handlerProvider - ); + auto const rpcEngine = + rpc::RPCEngine::make_RPCEngine(backend, balancer, dosGuard, workQueue, counters, handlerProvider); // Init the web server - auto handler = std::make_shared>( - config, backend, rpcEngine, etl, subscriptions - ); + auto handler = + std::make_shared>(config, backend, rpcEngine, etl); auto ctx = parseCerts(config); auto const ctxRef = ctx ? std::optional>{ctx.value()} : std::nullopt; auto const httpServer = web::make_HttpServer(config, ioc, ctxRef, dosGuard, handler); diff --git a/src/rpc/RPCEngine.h b/src/rpc/RPCEngine.h index e33f9cef2..6b8f7eea1 100644 --- a/src/rpc/RPCEngine.h +++ b/src/rpc/RPCEngine.h @@ -64,7 +64,6 @@ class RPCEngine { util::Logger log_{"RPC"}; std::shared_ptr backend_; - std::shared_ptr subscriptions_; std::shared_ptr balancer_; std::reference_wrapper dosGuard_; std::reference_wrapper workQueue_; @@ -77,7 +76,6 @@ class RPCEngine { public: RPCEngine( std::shared_ptr const& backend, - std::shared_ptr const& subscriptions, std::shared_ptr const& balancer, web::DOSGuard const& dosGuard, WorkQueue& workQueue, @@ -85,7 +83,6 @@ class RPCEngine { std::shared_ptr const& handlerProvider ) : backend_{backend} - , subscriptions_{subscriptions} , balancer_{balancer} , dosGuard_{std::cref(dosGuard)} , workQueue_{std::ref(workQueue)} @@ -98,7 +95,6 @@ class RPCEngine { static std::shared_ptr make_RPCEngine( std::shared_ptr const& backend, - std::shared_ptr const& subscriptions, std::shared_ptr const& balancer, web::DOSGuard const& dosGuard, WorkQueue& workQueue, @@ -106,9 +102,7 @@ class RPCEngine { std::shared_ptr const& handlerProvider ) { - return std::make_shared( - backend, subscriptions, balancer, dosGuard, workQueue, counters, handlerProvider - ); + return std::make_shared(backend, balancer, dosGuard, workQueue, counters, handlerProvider); } /** diff --git a/src/rpc/RPCHelpers.cpp b/src/rpc/RPCHelpers.cpp index 63a71b334..5794a57aa 100644 --- a/src/rpc/RPCHelpers.cpp +++ b/src/rpc/RPCHelpers.cpp @@ -359,7 +359,7 @@ toJson(ripple::SLE const& sle) } boost::json::object -toJson(ripple::LedgerHeader const& lgrInfo, bool const binary) +toJson(ripple::LedgerHeader const& lgrInfo, bool const binary, std::uint32_t const apiVersion) { boost::json::object header; if (binary) { @@ -372,11 +372,16 @@ toJson(ripple::LedgerHeader const& lgrInfo, bool const binary) header[JS(close_time_resolution)] = lgrInfo.closeTimeResolution.count(); header[JS(close_time_iso)] = ripple::to_string_iso(lgrInfo.closeTime); header[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash); - header[JS(ledger_index)] = std::to_string(lgrInfo.seq); header[JS(parent_close_time)] = lgrInfo.parentCloseTime.time_since_epoch().count(); header[JS(parent_hash)] = ripple::strHex(lgrInfo.parentHash); header[JS(total_coins)] = ripple::to_string(lgrInfo.drops); header[JS(transaction_hash)] = ripple::strHex(lgrInfo.txHash); + + if (apiVersion < 2u) { + header[JS(ledger_index)] = std::to_string(lgrInfo.seq); + } else { + header[JS(ledger_index)] = lgrInfo.seq; + } } header[JS(closed)] = true; return header; diff --git a/src/rpc/RPCHelpers.h b/src/rpc/RPCHelpers.h index 46afd0b00..a3754625f 100644 --- a/src/rpc/RPCHelpers.h +++ b/src/rpc/RPCHelpers.h @@ -115,10 +115,11 @@ toJson(ripple::SLE const& sle); * * @param entry The LedgerHeader to convert. * @param binary Whether to convert in hex format. + * @param apiVersion The api version * @return The JSON object. */ boost::json::object -toJson(ripple::LedgerHeader const& info, bool binary); +toJson(ripple::LedgerHeader const& info, bool binary, std::uint32_t apiVersion); boost::json::object toJson(ripple::TxMeta const& meta); diff --git a/src/rpc/handlers/Ledger.cpp b/src/rpc/handlers/Ledger.cpp index b26c6a091..1296fecba 100644 --- a/src/rpc/handlers/Ledger.cpp +++ b/src/rpc/handlers/Ledger.cpp @@ -61,7 +61,7 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const auto const lgrInfo = std::get(lgrInfoOrStatus); Output output; - output.header = toJson(lgrInfo, input.binary); + output.header = toJson(lgrInfo, input.binary, ctx.apiVersion); if (input.transactions) { output.header[JS(transactions)] = boost::json::value(boost::json::array_kind); @@ -86,8 +86,13 @@ LedgerHandler::process(LedgerHandler::Input input, Context const& ctx) const if (!input.binary) { boost::json::object entry; entry[JS(validated)] = true; - // same with rippled, ledger_index is a string here - entry[JS(ledger_index)] = std::to_string(lgrInfo.seq); + + if (ctx.apiVersion < 2u) { + entry[JS(ledger_index)] = std::to_string(lgrInfo.seq); + } else { + entry[JS(ledger_index)] = lgrInfo.seq; + } + entry[JS(close_time_iso)] = isoTimeStr; entry[JS(ledger_hash)] = ripple::strHex(lgrInfo.hash); if (txn.contains(JS(hash))) { diff --git a/src/rpc/handlers/LedgerData.cpp b/src/rpc/handlers/LedgerData.cpp index e889a92d9..643bbcf00 100644 --- a/src/rpc/handlers/LedgerData.cpp +++ b/src/rpc/handlers/LedgerData.cpp @@ -105,7 +105,7 @@ LedgerDataHandler::process(Input input, Context const& ctx) const // no marker -> first call, return header information if ((!input.marker) && (!input.diffMarker)) { - output.header = toJson(lgrInfo, input.binary); + output.header = toJson(lgrInfo, input.binary, ctx.apiVersion); } else { if (input.marker && !sharedPtrBackend_->fetchLedgerObject(*(input.marker), lgrInfo.seq, ctx.yield)) return Error{Status{RippledError::rpcINVALID_PARAMS, "markerDoesNotExist"}}; diff --git a/src/rpc/handlers/Subscribe.h b/src/rpc/handlers/Subscribe.h index 796e57820..5ac1a6ff2 100644 --- a/src/rpc/handlers/Subscribe.h +++ b/src/rpc/handlers/Subscribe.h @@ -20,11 +20,32 @@ #pragma once #include "data/BackendInterface.h" +#include "data/Types.h" +#include "rpc/Errors.h" +#include "rpc/JS.h" #include "rpc/RPCHelpers.h" #include "rpc/common/MetaProcessors.h" #include "rpc/common/Types.h" #include "rpc/common/Validators.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + namespace feed { class SubscriptionManager; } // namespace feed @@ -125,20 +146,19 @@ class BaseSubscribeHandler { auto output = Output{}; if (input.streams) { - auto const ledger = subscribeToStreams(ctx.yield, *(input.streams), ctx.session); + auto const ledger = subscribeToStreams(ctx.yield, *(input.streams), ctx.session, ctx.apiVersion); if (!ledger.empty()) output.ledger = ledger; } if (input.accounts) - subscribeToAccounts(*(input.accounts), ctx.session); + subscribeToAccounts(*(input.accounts), ctx.session, ctx.apiVersion); if (input.accountsProposed) subscribeToAccountsProposed(*(input.accountsProposed), ctx.session); - if (input.books) { - subscribeToBooks(*(input.books), ctx.session, ctx.yield, output); - }; + if (input.books) + subscribeToBooks(*(input.books), ctx.session, ctx.yield, ctx.apiVersion, output); return output; } @@ -148,7 +168,8 @@ class BaseSubscribeHandler { subscribeToStreams( boost::asio::yield_context yield, std::vector const& streams, - std::shared_ptr const& session + std::shared_ptr const& session, + std::uint32_t apiVersion ) const { auto response = boost::json::object{}; @@ -157,7 +178,7 @@ class BaseSubscribeHandler { if (stream == "ledger") { response = subscriptions_->subLedger(yield, session); } else if (stream == "transactions") { - subscriptions_->subTransactions(session); + subscriptions_->subTransactions(session, apiVersion); } else if (stream == "transactions_proposed") { subscriptions_->subProposedTransactions(session); } else if (stream == "validations") { @@ -173,12 +194,15 @@ class BaseSubscribeHandler { } void - subscribeToAccounts(std::vector const& accounts, std::shared_ptr const& session) - const + subscribeToAccounts( + std::vector const& accounts, + std::shared_ptr const& session, + std::uint32_t apiVersion + ) const { for (auto const& account : accounts) { auto const accountID = accountFromStringStrict(account); - subscriptions_->subAccount(*accountID, session); + subscriptions_->subAccount(*accountID, session, apiVersion); } } @@ -199,6 +223,7 @@ class BaseSubscribeHandler { std::vector const& books, std::shared_ptr const& session, boost::asio::yield_context yield, + uint32_t apiVersion, Output& output ) const { @@ -240,10 +265,10 @@ class BaseSubscribeHandler { } } - subscriptions_->subBook(internalBook.book, session); + subscriptions_->subBook(internalBook.book, session, apiVersion); if (internalBook.both) - subscriptions_->subBook(ripple::reversed(internalBook.book), session); + subscriptions_->subBook(ripple::reversed(internalBook.book), session, apiVersion); } } diff --git a/src/util/Batching.h b/src/util/Batching.h new file mode 100644 index 000000000..f0931246a --- /dev/null +++ b/src/util/Batching.h @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "util/Assert.h" + +#include +#include +#include +#include + +namespace util { + +void +forEachBatch(std::ranges::forward_range auto&& container, std::size_t batchSize, auto&& fn) +{ + ASSERT(batchSize > 0, "Batch size must be greater than 0"); + + auto to = std::begin(container); + auto end = std::end(container); + + while (to != end) { + auto from = to; + + auto cnt = batchSize; + while (to != end and cnt > 0) { + ++to; + --cnt; + } + + std::invoke(fn, from, to); + } +} + +} // namespace util diff --git a/src/util/prometheus/impl/CounterImpl.h b/src/util/prometheus/impl/CounterImpl.h index c5982acaf..c3b58c2c5 100644 --- a/src/util/prometheus/impl/CounterImpl.h +++ b/src/util/prometheus/impl/CounterImpl.h @@ -30,7 +30,7 @@ namespace util::prometheus::detail { template concept SomeCounterImpl = requires(T a) { typename std::remove_cvref_t::ValueType; - SomeNumberType::ValueType>; + requires SomeNumberType::ValueType>; { a.add(typename std::remove_cvref_t::ValueType{1}) } -> std::same_as; diff --git a/src/util/prometheus/impl/HistogramImpl.h b/src/util/prometheus/impl/HistogramImpl.h index c1d914730..1254423c2 100644 --- a/src/util/prometheus/impl/HistogramImpl.h +++ b/src/util/prometheus/impl/HistogramImpl.h @@ -30,7 +30,7 @@ namespace util::prometheus::detail { template concept SomeHistogramImpl = requires(T t) { typename std::remove_cvref_t::ValueType; - SomeNumberType::ValueType>; + requires SomeNumberType::ValueType>; { t.observe(typename std::remove_cvref_t::ValueType{1}) } -> std::same_as; diff --git a/src/web/RPCServerHandler.h b/src/web/RPCServerHandler.h index 0c679be38..0dbc80003 100644 --- a/src/web/RPCServerHandler.h +++ b/src/web/RPCServerHandler.h @@ -19,16 +19,38 @@ #pragma once +#include "data/BackendInterface.h" #include "feed/SubscriptionManager.h" #include "rpc/Errors.h" #include "rpc/Factories.h" +#include "rpc/JS.h" #include "rpc/RPCHelpers.h" #include "rpc/common/impl/APIVersionParser.h" #include "util/JsonUtils.h" #include "util/Profiler.h" +#include "util/Taggable.h" +#include "util/config/Config.h" +#include "util/log/Logger.h" #include "web/impl/ErrorHandling.h" +#include "web/interface/ConnectionBase.h" +#include +#include +#include +#include #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include namespace web { @@ -42,8 +64,6 @@ class RPCServerHandler { std::shared_ptr const backend_; std::shared_ptr const rpcEngine_; std::shared_ptr const etl_; - // subscription manager holds the shared_ptr of this class - std::weak_ptr const subscriptions_; util::TagDecoratorFactory const tagFactory_; rpc::detail::ProductionAPIVersionParser apiVersionParser_; // can be injected if needed @@ -64,13 +84,11 @@ class RPCServerHandler { util::Config const& config, std::shared_ptr const& backend, std::shared_ptr const& rpcEngine, - std::shared_ptr const& etl, - std::shared_ptr const& subscriptions + std::shared_ptr const& etl ) : backend_(backend) , rpcEngine_(rpcEngine) , etl_(etl) - , subscriptions_(subscriptions) , tagFactory_(config) , apiVersionParser_(config.sectionOr("api_version", {})) { @@ -104,11 +122,13 @@ class RPCServerHandler { } catch (boost::system::system_error const& ex) { // system_error thrown when json parsing failed rpcEngine_->notifyBadSyntax(); - web::detail::ErrorHelper(connection).sendJsonParsingError(ex.what()); + web::detail::ErrorHelper(connection).sendJsonParsingError(); + LOG(log_.warn()) << "Error parsing JSON: " << ex.what() << ". For request: " << request; } catch (std::invalid_argument const& ex) { // thrown when json parses something that is not an object at top level rpcEngine_->notifyBadSyntax(); - web::detail::ErrorHelper(connection).sendJsonParsingError(ex.what()); + LOG(log_.warn()) << "Invalid argument error: " << ex.what() << ". For request: " << request; + web::detail::ErrorHelper(connection).sendJsonParsingError(); } catch (std::exception const& ex) { LOG(perfLog_.error()) << connection->tag() << "Caught exception: " << ex.what(); rpcEngine_->notifyInternalError(); @@ -116,21 +136,6 @@ class RPCServerHandler { } } - /** - * @brief The callback when there is an error. - * - * Remove the session shared ptr from subscription manager. - * - * @param ec The error code - * @param connection The connection - */ - void - operator()([[maybe_unused]] boost::beast::error_code ec, std::shared_ptr const& connection) - { - if (auto manager = subscriptions_.lock(); manager) - manager->cleanup(connection); - } - private: void handleRequest( @@ -209,28 +214,31 @@ class RPCServerHandler { // if the result is forwarded - just use it as is // if forwarded request has error, for http, error should be in "result"; for ws, error should // be at top - if (isForwarded && (json.contains("result") || connection->upgraded)) { + if (isForwarded && (json.contains(JS(result)) || connection->upgraded)) { for (auto const& [k, v] : json) response.insert_or_assign(k, v); } else { - response["result"] = json; + response[JS(result)] = json; } // for ws there is an additional field "status" in the response, // otherwise the "status" is in the "result" field if (connection->upgraded) { - auto const id = request.contains("id") ? request.at("id") : nullptr; + auto const appendFieldIfExist = [&](auto const& field) { + if (request.contains(field) and not request.at(field).is_null()) + response[field] = request.at(field); + }; - if (not id.is_null()) - response["id"] = id; + appendFieldIfExist(JS(id)); + appendFieldIfExist(JS(api_version)); - if (!response.contains("error")) - response["status"] = "success"; + if (!response.contains(JS(error))) + response[JS(status)] = JS(success); - response["type"] = "response"; + response[JS(type)] = JS(response); } else { - if (response.contains("result") && !response["result"].as_object().contains("error")) - response["result"].as_object()["status"] = "success"; + if (response.contains(JS(result)) && !response[JS(result)].as_object().contains(JS(error))) + response[JS(result)].as_object()[JS(status)] = JS(success); } } diff --git a/src/web/impl/ErrorHandling.h b/src/web/impl/ErrorHandling.h index 048f18d73..b58915ad4 100644 --- a/src/web/impl/ErrorHandling.h +++ b/src/web/impl/ErrorHandling.h @@ -23,12 +23,18 @@ #include "util/Assert.h" #include "web/interface/ConnectionBase.h" -#include -#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include namespace web::detail { @@ -127,15 +133,13 @@ class ErrorHelper { } void - sendJsonParsingError(std::string_view reason) const + sendJsonParsingError() const { if (connection_->upgraded) { - connection_->send( - boost::json::serialize(rpc::makeError(rpc::RippledError::rpcBAD_SYNTAX)), boost::beast::http::status::ok - ); + connection_->send(boost::json::serialize(rpc::makeError(rpc::RippledError::rpcBAD_SYNTAX))); } else { connection_->send( - fmt::format("Unable to parse request: {}", reason), boost::beast::http::status::bad_request + fmt::format("Unable to parse JSON from the request"), boost::beast::http::status::bad_request ); } } @@ -146,18 +150,23 @@ class ErrorHelper { auto e = rpc::makeError(error); if (request_) { - auto const& req = request_.value(); - auto const id = req.contains("id") ? req.at("id") : nullptr; - if (not id.is_null()) - e["id"] = id; + auto const appendFieldIfExist = [&](auto const& field) { + if (request_->contains(field) and not request_->at(field).is_null()) + e[field] = request_->at(field); + }; + + appendFieldIfExist(JS(id)); + + if (connection_->upgraded) + appendFieldIfExist(JS(api_version)); - e["request"] = req; + e[JS(request)] = request_.value(); } if (connection_->upgraded) { return e; } - return {{"result", e}}; + return {{JS(result), e}}; } }; diff --git a/src/web/impl/HttpBase.h b/src/web/impl/HttpBase.h index a7924ac91..330181165 100644 --- a/src/web/impl/HttpBase.h +++ b/src/web/impl/HttpBase.h @@ -21,6 +21,7 @@ #include "main/Build.h" #include "rpc/Errors.h" +#include "util/Taggable.h" #include "util/log/Logger.h" #include "util/prometheus/Http.h" #include "web/DOSGuard.h" @@ -28,13 +29,33 @@ #include "web/interface/Concepts.h" #include "web/interface/ConnectionBase.h" +#include +#include +#include #include +#include +#include #include +#include +#include +#include +#include +#include +#include #include +#include #include - +#include +#include +#include +#include + +#include +#include +#include #include #include +#include namespace web::detail { diff --git a/src/web/impl/WsBase.h b/src/web/impl/WsBase.h index 4dbde82e9..454128b22 100644 --- a/src/web/impl/WsBase.h +++ b/src/web/impl/WsBase.h @@ -19,17 +19,40 @@ #pragma once +#include "rpc/Errors.h" #include "rpc/common/Types.h" +#include "util/Taggable.h" #include "util/log/Logger.h" #include "web/DOSGuard.h" #include "web/interface/Concepts.h" #include "web/interface/ConnectionBase.h" +#include +#include #include -#include - -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include +#include +#include +#include namespace web::detail { @@ -63,7 +86,6 @@ class WsBase : public ConnectionBase, public std::enable_shared_from_this +#include #include @@ -42,6 +43,8 @@ struct ConnectionBase : public util::Taggable { std::string const clientIp; bool upgraded = false; bool isAdmin_ = false; + boost::signals2::signal onDisconnect; + std::uint32_t apiSubVersion = 0; /** * @brief Create a new connection base. @@ -54,7 +57,10 @@ struct ConnectionBase : public util::Taggable { { } - ~ConnectionBase() override = default; + ~ConnectionBase() override + { + onDisconnect(this); + }; /** * @brief Send the response to the client. diff --git a/unittests/SubscriptionManagerTests.cpp b/unittests/SubscriptionManagerTests.cpp deleted file mode 100644 index c8e0fb6cf..000000000 --- a/unittests/SubscriptionManagerTests.cpp +++ /dev/null @@ -1,877 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of clio: https://github.com/XRPLF/clio - Copyright (c) 2023, the clio developers. - - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include "data/Types.h" -#include "feed/SubscriptionManager.h" -#include "util/Fixtures.h" -#include "util/MockBackend.h" -#include "util/MockWsBase.h" -#include "util/Taggable.h" -#include "util/TestObject.h" -#include "util/config/Config.h" -#include "web/interface/ConnectionBase.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -using std::chrono::milliseconds; -namespace json = boost::json; -using namespace data; -using ::testing::Return; - -// common const -constexpr static auto CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000"; -constexpr static auto ISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD"; -constexpr static auto ACCOUNT1 = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"; -constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; -constexpr static auto LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652"; -constexpr static auto LEDGERHASH2 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC"; -constexpr static auto TXNID = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321"; - -/* - * test subscription factory method and report function - */ -TEST(SubscriptionManagerTest, InitAndReport) -{ - constexpr static auto ReportReturn = R"({ - "ledger":0, - "transactions":0, - "transactions_proposed":0, - "manifests":0, - "validations":0, - "account":0, - "accounts_proposed":0, - "books":0, - "book_changes":0 - })"; - util::Config const cfg; - auto backend = std::make_shared(cfg); - auto subManager = feed::SubscriptionManager::make_SubscriptionManager(cfg, backend); - EXPECT_EQ(subManager->report(), json::parse(ReportReturn)); -} - -void -CheckSubscriberMessage(std::string out, std::shared_ptr session, int retry = 10) -{ - auto sessionPtr = dynamic_cast(session.get()); - ASSERT_NE(sessionPtr, nullptr); - while (retry-- != 0) { - std::this_thread::sleep_for(milliseconds(20)); - if ((!sessionPtr->message.empty()) && json::parse(sessionPtr->message) == json::parse(out)) { - return; - } - } - EXPECT_TRUE(false) << "Could not wait the subscriber message, expect:" << out << " Get:" << sessionPtr->message; -} - -// Fixture contains test target and mock backend -class SubscriptionManagerSimpleBackendTest : public MockBackendTest { -protected: - util::Config cfg; - std::shared_ptr subManagerPtr; - util::TagDecoratorFactory tagDecoratorFactory{cfg}; - std::shared_ptr session; - void - SetUp() override - { - MockBackendTest::SetUp(); - subManagerPtr = feed::SubscriptionManager::make_SubscriptionManager(cfg, mockBackendPtr); - session = std::make_shared(tagDecoratorFactory); - } - void - TearDown() override - { - MockBackendTest::TearDown(); - subManagerPtr.reset(); - } -}; - -/* - * test report function and unsub functions - */ -TEST_F(SubscriptionManagerSimpleBackendTest, ReportCurrentSubscriber) -{ - constexpr static auto ReportReturn = R"({ - "ledger":0, - "transactions":2, - "transactions_proposed":2, - "manifests":2, - "validations":2, - "account":2, - "accounts_proposed":2, - "books":2, - "book_changes":2 - })"; - std::shared_ptr const session1 = std::make_shared(tagDecoratorFactory); - std::shared_ptr const session2 = std::make_shared(tagDecoratorFactory); - subManagerPtr->subBookChanges(session1); - subManagerPtr->subBookChanges(session2); - subManagerPtr->subManifest(session1); - subManagerPtr->subManifest(session2); - subManagerPtr->subProposedTransactions(session1); - subManagerPtr->subProposedTransactions(session2); - subManagerPtr->subTransactions(session1); - subManagerPtr->subTransactions(session2); - subManagerPtr->subValidation(session1); - subManagerPtr->subValidation(session2); - auto account = GetAccountIDWithString(ACCOUNT1); - subManagerPtr->subAccount(account, session1); - subManagerPtr->subAccount(account, session2); - subManagerPtr->subProposedAccount(account, session1); - subManagerPtr->subProposedAccount(account, session2); - auto issue1 = GetIssue(CURRENCY, ISSUER); - ripple::Book const book{ripple::xrpIssue(), issue1}; - subManagerPtr->subBook(book, session1); - subManagerPtr->subBook(book, session2); - std::this_thread::sleep_for(milliseconds(20)); - EXPECT_EQ(subManagerPtr->report(), json::parse(ReportReturn)); - subManagerPtr->unsubBookChanges(session1); - subManagerPtr->unsubManifest(session1); - subManagerPtr->unsubProposedTransactions(session1); - subManagerPtr->unsubTransactions(session1); - subManagerPtr->unsubValidation(session1); - subManagerPtr->unsubAccount(account, session1); - subManagerPtr->unsubProposedAccount(account, session1); - subManagerPtr->unsubBook(book, session1); - std::this_thread::sleep_for(milliseconds(20)); - auto checkResult = [](json::object reportReturn, int result) { - EXPECT_EQ(reportReturn["book_changes"], result); - EXPECT_EQ(reportReturn["validations"], result); - EXPECT_EQ(reportReturn["transactions_proposed"], result); - EXPECT_EQ(reportReturn["transactions"], result); - EXPECT_EQ(reportReturn["manifests"], result); - EXPECT_EQ(reportReturn["accounts_proposed"], result); - EXPECT_EQ(reportReturn["account"], result); - EXPECT_EQ(reportReturn["books"], result); - }; - checkResult(subManagerPtr->report(), 1); - subManagerPtr->cleanup(session2); // clean a removed session - std::this_thread::sleep_for(milliseconds(20)); - checkResult(subManagerPtr->report(), 0); -} - -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerLedgerUnSub) -{ - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - boost::asio::io_context ctx; - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - // mock fetchLedgerBySequence return this ledger - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - // mock doFetchLedgerObject return fee setting ledger object - auto feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(feeBlob)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - boost::asio::spawn(ctx, [this](boost::asio::yield_context yield) { subManagerPtr->subLedger(yield, session); }); - ctx.run(); - std::this_thread::sleep_for(milliseconds(20)); - auto report = subManagerPtr->report(); - EXPECT_EQ(report["ledger"], 1); - subManagerPtr->cleanup(session); - subManagerPtr->unsubLedger(session); - std::this_thread::sleep_for(milliseconds(20)); - report = subManagerPtr->report(); - EXPECT_EQ(report["ledger"], 0); -} - -/* - * test Manifest - * Subscription Manager forward the manifest message to subscribers - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerManifestTest) -{ - subManagerPtr->subManifest(session); - constexpr static auto dummyManifest = R"({"manifest":"test"})"; - subManagerPtr->forwardManifest(json::parse(dummyManifest).get_object()); - CheckSubscriberMessage(dummyManifest, session); -} - -/* - * test Validation - * Subscription Manager forward the validation message to subscribers - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerValidation) -{ - subManagerPtr->subValidation(session); - constexpr static auto dummyValidation = R"({"validation":"test"})"; - subManagerPtr->forwardValidation(json::parse(dummyValidation).get_object()); - CheckSubscriberMessage(dummyValidation, session); -} - -/* - * test ProposedTransaction - * We don't need the valid transaction in this test, subscription manager just - * forward the message to subscriber - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerProposedTransaction) -{ - subManagerPtr->subProposedTransactions(session); - // transaction contains account and its public key - // make sure it is not parsed to two identical accounts - constexpr static auto dummyTransaction = R"({ - "transaction": - { - "Account":"rh1HPuRVsYYvThxG2Bs1MfjmrVC73S16Fb", - "Amount":"40000000", - "Destination":"rDgGprMjMWkJRnJ8M5RXq3SXYD8zuQncPc", - "Fee":"20", - "Flags":2147483648, - "Sequence":13767283, - "SigningPubKey":"036F3CFFE1EA77C1EEC5DCCA38C83E62E3AC068F8A16369620AF1D609BA5A620B2", - "TransactionType":"Payment", - "TxnSignature":"30450221009BD0D563B24E50B26A42F30455AD21C3D5CD4D80174C41F7B54969FFC08DE94C02201FC35320B56D56D1E34D1D281D48AC68CBEDDD6EE9DFA639CCB08BB251453A87", - "hash":"F44393295DB860C6860769C16F5B23887762F09F87A8D1174E0FCFF9E7247F07" - } - })"; - subManagerPtr->forwardProposedTransaction(json::parse(dummyTransaction).get_object()); - CheckSubscriberMessage(dummyTransaction, session); -} - -/* - * test ProposedTransaction for one account - * we need to construct a valid account in the transaction - * this test subscribe the proposed transaction for two accounts - * but only forward a transaction with one of them - * check the correct session is called - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerAccountProposedTransaction) -{ - auto account = GetAccountIDWithString(ACCOUNT1); - subManagerPtr->subProposedAccount(account, session); - - std::shared_ptr const sessionIdle = std::make_shared(tagDecoratorFactory); - auto accountIdle = GetAccountIDWithString(ACCOUNT2); - subManagerPtr->subProposedAccount(accountIdle, sessionIdle); - - constexpr static auto dummyTransaction = R"({ - "transaction": - { - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" - } - })"; - subManagerPtr->forwardProposedTransaction(json::parse(dummyTransaction).get_object()); - CheckSubscriberMessage(dummyTransaction, session); - auto rawIdle = dynamic_cast(sessionIdle.get()); - ASSERT_NE(rawIdle, nullptr); - EXPECT_EQ("", rawIdle->message); -} - -/* - * test ledger stream - * check 1 subscribe response, 2 publish message - * mock backend to return fee ledger object - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerLedger) -{ - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - boost::asio::io_context ctx; - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - // mock fetchLedgerBySequence return this ledger - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - // mock doFetchLedgerObject return fee setting ledger object - auto feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(feeBlob)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - // check the function response - // Information about the ledgers on hand and current fee schedule. This - // includes the same fields as a ledger stream message, except that it omits - // the type and txn_count fields - constexpr static auto LedgerResponse = R"({ - "validated_ledgers":"10-30", - "ledger_index":30, - "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", - "ledger_time":0, - "fee_base":1, - "reserve_base":3, - "reserve_inc":2 - })"; - boost::asio::spawn(ctx, [this](boost::asio::yield_context yield) { - auto res = subManagerPtr->subLedger(yield, session); - // check the response - EXPECT_EQ(res, json::parse(LedgerResponse)); - }); - ctx.run(); - // test publish - auto ledgerinfo2 = CreateLedgerInfo(LEDGERHASH, 31); - auto fee2 = ripple::Fees(); - fee2.reserve = 10; - subManagerPtr->pubLedger(ledgerinfo2, fee2, "10-31", 8); - constexpr static auto LedgerPub = R"({ - "type":"ledgerClosed", - "ledger_index":31, - "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", - "ledger_time":0, - "fee_base":0, - "reserve_base":10, - "reserve_inc":0, - "validated_ledgers":"10-31", - "txn_count":8 - })"; - CheckSubscriberMessage(LedgerPub, session); -} - -/* - * test book change - * create a book change meta data for - * XRP vs A token - * the transaction is just placeholder - * Book change computing only needs meta data - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerBookChange) -{ - subManagerPtr->subBookChanges(session); - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 32); - auto transactions = std::vector{}; - auto trans1 = TransactionAndMetadata(); - ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); - trans1.transaction = obj.getSerializer().peekData(); - trans1.ledgerSequence = 32; - ripple::STObject const metaObj = CreateMetaDataForBookChange(CURRENCY, ISSUER, 22, 1, 3, 3, 1); - trans1.metadata = metaObj.getSerializer().peekData(); - transactions.push_back(trans1); - subManagerPtr->pubBookChanges(ledgerinfo, transactions); - constexpr static auto BookChangePublish = R"({ - "type":"bookChanges", - "ledger_index":32, - "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", - "ledger_time":0, - "changes":[ - { - "currency_a":"XRP_drops", - "currency_b":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD/0158415500000000C1F76FF6ECB0BAC600000000", - "volume_a":"2", - "volume_b":"2", - "high":"-1", - "low":"-1", - "open":"-1", - "close":"-1" - } - ] - })"; - CheckSubscriberMessage(BookChangePublish, session, 20); -} - -/* - * test transaction stream - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerTransaction) -{ - subManagerPtr->subTransactions(session); - - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH2, 33); - - auto trans1 = TransactionAndMetadata(); - ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); - trans1.transaction = obj.getSerializer().peekData(); - trans1.ledgerSequence = 32; - // create an empty meta object - ripple::STArray const metaArray{0}; - ripple::STObject metaObj(ripple::sfTransactionMetaData); - metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); - metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); - metaObj.setFieldU32(ripple::sfTransactionIndex, 22); - trans1.metadata = metaObj.getSerializer().peekData(); - subManagerPtr->pubTransaction(trans1, ledgerinfo); - constexpr static auto TransactionPublish = R"({ - "transaction":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Amount":"1", - "DeliverMax":"1", - "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", - "Fee":"1", - "Sequence":32, - "SigningPubKey":"74657374", - "TransactionType":"Payment", - "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", - "date":0 - }, - "meta":{ - "AffectedNodes":[], - "TransactionIndex":22, - "TransactionResult":"tesSUCCESS", - "delivered_amount":"unavailable" - }, - "type":"transaction", - "validated":true, - "status":"closed", - "ledger_index":33, - "close_time_iso": "2000-01-01T00:00:00Z", - "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "engine_result_code":0, - "engine_result":"tesSUCCESS", - "engine_result_message":"The transaction was applied. Only final in a validated ledger." - })"; - CheckSubscriberMessage(TransactionPublish, session); -} - -/* - * test transaction for offer creation - * check owner_funds - * mock backend return a trustline - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerTransactionOfferCreation) -{ - subManagerPtr->subTransactions(session); - - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH2, 33); - auto trans1 = TransactionAndMetadata(); - ripple::STObject const obj = CreateCreateOfferTransactionObject(ACCOUNT1, 1, 32, CURRENCY, ISSUER, 1, 3); - trans1.transaction = obj.getSerializer().peekData(); - trans1.ledgerSequence = 32; - ripple::STArray const metaArray{0}; - ripple::STObject metaObj(ripple::sfTransactionMetaData); - metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); - metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); - metaObj.setFieldU32(ripple::sfTransactionIndex, 22); - trans1.metadata = metaObj.getSerializer().peekData(); - - ripple::STObject line(ripple::sfIndexes); - line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); - line.setFieldAmount(ripple::sfLowLimit, ripple::STAmount(10, false)); - line.setFieldAmount(ripple::sfHighLimit, ripple::STAmount(100, false)); - line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{TXNID}); - line.setFieldU32(ripple::sfPreviousTxnLgrSeq, 3); - line.setFieldU32(ripple::sfFlags, 0); - auto issue2 = GetIssue(CURRENCY, ISSUER); - line.setFieldAmount(ripple::sfBalance, ripple::STAmount(issue2, 100)); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(line.getSerializer().peekData())); - subManagerPtr->pubTransaction(trans1, ledgerinfo); - constexpr static auto TransactionForOwnerFund = R"({ - "transaction":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Fee":"1", - "Sequence":32, - "SigningPubKey":"74657374", - "TakerGets":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", - "value":"1" - }, - "TakerPays":"3", - "TransactionType":"OfferCreate", - "hash":"EE8775B43A67F4803DECEC5E918E0EA9C56D8ED93E512EBE9F2891846509AAAB", - "date":0, - "owner_funds":"100" - }, - "meta":{ - "AffectedNodes":[], - "TransactionIndex":22, - "TransactionResult":"tesSUCCESS" - }, - "type":"transaction", - "validated":true, - "status":"closed", - "ledger_index":33, - "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "engine_result_code":0, - "close_time_iso": "2000-01-01T00:00:00Z", - "engine_result":"tesSUCCESS", - "engine_result_message":"The transaction was applied. Only final in a validated ledger." - })"; - CheckSubscriberMessage(TransactionForOwnerFund, session); -} - -constexpr static auto TransactionForOwnerFundFrozen = R"({ - "transaction":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Fee":"1", - "Sequence":32, - "SigningPubKey":"74657374", - "TakerGets":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", - "value":"1" - }, - "TakerPays":"3", - "TransactionType":"OfferCreate", - "hash":"EE8775B43A67F4803DECEC5E918E0EA9C56D8ED93E512EBE9F2891846509AAAB", - "date":0, - "owner_funds":"0" - }, - "meta":{ - "AffectedNodes":[], - "TransactionIndex":22, - "TransactionResult":"tesSUCCESS" - }, - "type":"transaction", - "validated":true, - "status":"closed", - "ledger_index":33, - "close_time_iso": "2000-01-01T00:00:00Z", - "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "engine_result_code":0, - "engine_result":"tesSUCCESS", - "engine_result_message":"The transaction was applied. Only final in a validated ledger." -})"; - -/* - * test transaction for offer creation - * check owner_funds when line is frozen - * mock backend return a trustline - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerTransactionOfferCreationFrozenLine) -{ - subManagerPtr->subTransactions(session); - - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH2, 33); - auto trans1 = TransactionAndMetadata(); - ripple::STObject const obj = CreateCreateOfferTransactionObject(ACCOUNT1, 1, 32, CURRENCY, ISSUER, 1, 3); - trans1.transaction = obj.getSerializer().peekData(); - trans1.ledgerSequence = 32; - ripple::STArray const metaArray{0}; - ripple::STObject metaObj(ripple::sfTransactionMetaData); - metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); - metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); - metaObj.setFieldU32(ripple::sfTransactionIndex, 22); - trans1.metadata = metaObj.getSerializer().peekData(); - - ripple::STObject line(ripple::sfIndexes); - line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); - line.setFieldAmount(ripple::sfLowLimit, ripple::STAmount(10, false)); - line.setFieldAmount(ripple::sfHighLimit, ripple::STAmount(100, false)); - line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{TXNID}); - line.setFieldU32(ripple::sfPreviousTxnLgrSeq, 3); - line.setFieldU32(ripple::sfFlags, ripple::lsfHighFreeze); - line.setFieldAmount(ripple::sfBalance, ripple::STAmount(GetIssue(CURRENCY, ISSUER), 100)); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(line.getSerializer().peekData())); - subManagerPtr->pubTransaction(trans1, ledgerinfo); - CheckSubscriberMessage(TransactionForOwnerFundFrozen, session); -} - -/* - * test transaction for offer creation - * check owner_funds when issue global frozen - * mock backend return a frozen account setting - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerTransactionOfferCreationGlobalFrozen) -{ - subManagerPtr->subTransactions(session); - - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH2, 33); - auto trans1 = TransactionAndMetadata(); - ripple::STObject const obj = CreateCreateOfferTransactionObject(ACCOUNT1, 1, 32, CURRENCY, ISSUER, 1, 3); - trans1.transaction = obj.getSerializer().peekData(); - trans1.ledgerSequence = 32; - ripple::STArray const metaArray{0}; - ripple::STObject metaObj(ripple::sfTransactionMetaData); - metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); - metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); - metaObj.setFieldU32(ripple::sfTransactionIndex, 22); - trans1.metadata = metaObj.getSerializer().peekData(); - - ripple::STObject line(ripple::sfIndexes); - line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); - line.setFieldAmount(ripple::sfLowLimit, ripple::STAmount(10, false)); - line.setFieldAmount(ripple::sfHighLimit, ripple::STAmount(100, false)); - line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{TXNID}); - line.setFieldU32(ripple::sfPreviousTxnLgrSeq, 3); - line.setFieldU32(ripple::sfFlags, ripple::lsfHighFreeze); - auto issueAccount = GetAccountIDWithString(ISSUER); - line.setFieldAmount(ripple::sfBalance, ripple::STAmount(GetIssue(CURRENCY, ISSUER), 100)); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); - auto kk = ripple::keylet::account(issueAccount).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(testing::_, testing::_, testing::_)) - .WillByDefault(Return(line.getSerializer().peekData())); - ripple::STObject const accountRoot = CreateAccountRootObject(ISSUER, ripple::lsfGlobalFreeze, 1, 10, 2, TXNID, 3); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(kk, testing::_, testing::_)) - .WillByDefault(Return(accountRoot.getSerializer().peekData())); - subManagerPtr->pubTransaction(trans1, ledgerinfo); - CheckSubscriberMessage(TransactionForOwnerFundFrozen, session); -} - -/* - * test subscribe account - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerAccount) -{ - auto account = GetAccountIDWithString(ACCOUNT1); - subManagerPtr->subAccount(account, session); - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH2, 33); - - ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); - auto trans1 = TransactionAndMetadata(); - trans1.transaction = obj.getSerializer().peekData(); - trans1.ledgerSequence = 32; - ripple::STArray metaArray{1}; - ripple::STObject node(ripple::sfModifiedNode); - // emplace account into meta, trigger publish - ripple::STObject finalFields(ripple::sfFinalFields); - finalFields.setAccountID(ripple::sfAccount, account); - node.emplace_back(finalFields); - node.setFieldU16(ripple::sfLedgerEntryType, ripple::ltACCOUNT_ROOT); - metaArray.push_back(node); - ripple::STObject metaObj(ripple::sfTransactionMetaData); - metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); - metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); - metaObj.setFieldU32(ripple::sfTransactionIndex, 22); - trans1.metadata = metaObj.getSerializer().peekData(); - - subManagerPtr->pubTransaction(trans1, ledgerinfo); - constexpr static auto AccountPublish = R"({ - "transaction":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Amount":"1", - "DeliverMax":"1", - "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", - "Fee":"1", - "Sequence":32, - "SigningPubKey":"74657374", - "TransactionType":"Payment", - "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", - "date":0 - }, - "meta":{ - "AffectedNodes":[ - { - "ModifiedNode":{ - "FinalFields":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" - }, - "LedgerEntryType":"AccountRoot" - } - } - ], - "TransactionIndex":22, - "TransactionResult":"tesSUCCESS", - "delivered_amount":"unavailable" - }, - "type":"transaction", - "validated":true, - "status":"closed", - "ledger_index":33, - "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "engine_result_code":0, - "close_time_iso": "2000-01-01T00:00:00Z", - "engine_result":"tesSUCCESS", - "engine_result_message":"The transaction was applied. Only final in a validated ledger." - })"; - CheckSubscriberMessage(AccountPublish, session); -} - -/* - * test subscribe order book - * Create/Delete/Update offer node will trigger publish - */ -TEST_F(SubscriptionManagerSimpleBackendTest, SubscriptionManagerOrderBook) -{ - auto issue1 = GetIssue(CURRENCY, ISSUER); - ripple::Book const book{ripple::xrpIssue(), issue1}; - subManagerPtr->subBook(book, session); - auto ledgerinfo = CreateLedgerInfo(LEDGERHASH2, 33); - - auto trans1 = TransactionAndMetadata(); - auto obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); - trans1.transaction = obj.getSerializer().peekData(); - trans1.ledgerSequence = 32; - - auto metaObj = CreateMetaDataForBookChange(CURRENCY, ISSUER, 22, 3, 1, 1, 3); - trans1.metadata = metaObj.getSerializer().peekData(); - subManagerPtr->pubTransaction(trans1, ledgerinfo); - - constexpr static auto OrderbookPublish = R"({ - "transaction":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Amount":"1", - "DeliverMax":"1", - "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", - "Fee":"1", - "Sequence":32, - "SigningPubKey":"74657374", - "TransactionType":"Payment", - "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", - "date":0 - }, - "meta":{ - "AffectedNodes":[ - { - "ModifiedNode":{ - "FinalFields":{ - "TakerGets":"3", - "TakerPays":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", - "value":"1" - } - }, - "LedgerEntryType":"Offer", - "PreviousFields":{ - "TakerGets":"1", - "TakerPays":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", - "value":"3" - } - } - } - } - ], - "TransactionIndex":22, - "TransactionResult":"tesSUCCESS", - "delivered_amount":"unavailable" - }, - "type":"transaction", - "validated":true, - "status":"closed", - "ledger_index":33, - "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "engine_result_code":0, - "engine_result":"tesSUCCESS", - "close_time_iso": "2000-01-01T00:00:00Z", - "engine_result_message":"The transaction was applied. Only final in a validated ledger." - })"; - CheckSubscriberMessage(OrderbookPublish, session); - - // trigger by offer cancel meta data - std::shared_ptr const session1 = std::make_shared(tagDecoratorFactory); - subManagerPtr->subBook(book, session1); - metaObj = CreateMetaDataForCancelOffer(CURRENCY, ISSUER, 22, 3, 1); - trans1.metadata = metaObj.getSerializer().peekData(); - subManagerPtr->pubTransaction(trans1, ledgerinfo); - constexpr static auto OrderbookCancelPublish = R"({ - "transaction":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Amount":"1", - "DeliverMax":"1", - "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", - "Fee":"1", - "Sequence":32, - "SigningPubKey":"74657374", - "TransactionType":"Payment", - "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", - "date":0 - }, - "meta":{ - "AffectedNodes":[ - { - "DeletedNode":{ - "FinalFields":{ - "TakerGets":"3", - "TakerPays":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", - "value":"1" - } - }, - "LedgerEntryType":"Offer" - } - } - ], - "TransactionIndex":22, - "TransactionResult":"tesSUCCESS", - "delivered_amount":"unavailable" - }, - "type":"transaction", - "validated":true, - "status":"closed", - "ledger_index":33, - "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "engine_result_code":0, - "engine_result":"tesSUCCESS", - "close_time_iso": "2000-01-01T00:00:00Z", - "engine_result_message":"The transaction was applied. Only final in a validated ledger." - })"; - CheckSubscriberMessage(OrderbookCancelPublish, session1); - // trigger by offer create meta data - constexpr static auto OrderbookCreatePublish = R"({ - "transaction":{ - "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", - "Amount":"1", - "DeliverMax":"1", - "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", - "Fee":"1", - "Sequence":32, - "SigningPubKey":"74657374", - "TransactionType":"Payment", - "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", - "date":0 - }, - "meta":{ - "AffectedNodes":[ - { - "CreatedNode":{ - "NewFields":{ - "TakerGets":"3", - "TakerPays":{ - "currency":"0158415500000000C1F76FF6ECB0BAC600000000", - "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", - "value":"1" - } - }, - "LedgerEntryType":"Offer" - } - } - ], - "TransactionIndex":22, - "TransactionResult":"tesSUCCESS", - "delivered_amount":"unavailable" - }, - "type":"transaction", - "validated":true, - "status":"closed", - "ledger_index":33, - "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", - "engine_result_code":0, - "engine_result":"tesSUCCESS", - "close_time_iso": "2000-01-01T00:00:00Z", - "engine_result_message":"The transaction was applied. Only final in a validated ledger." - })"; - std::shared_ptr const session2 = std::make_shared(tagDecoratorFactory); - subManagerPtr->subBook(book, session2); - metaObj = CreateMetaDataForCreateOffer(CURRENCY, ISSUER, 22, 3, 1); - trans1.metadata = metaObj.getSerializer().peekData(); - subManagerPtr->pubTransaction(trans1, ledgerinfo); - CheckSubscriberMessage(OrderbookCreatePublish, session2); -} diff --git a/unittests/SubscriptionTests.cpp b/unittests/SubscriptionTests.cpp deleted file mode 100644 index 52fc5d7ac..000000000 --- a/unittests/SubscriptionTests.cpp +++ /dev/null @@ -1,314 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of clio: https://github.com/XRPLF/clio - Copyright (c) 2023, the clio developers. - - Permission to use, copy, modify, and distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include "feed/SubscriptionManager.h" -#include "util/Fixtures.h" -#include "util/MockPrometheus.h" -#include "util/MockWsBase.h" -#include "util/Taggable.h" -#include "util/config/Config.h" -#include "util/prometheus/Gauge.h" -#include "web/interface/ConnectionBase.h" - -#include -#include - -#include -#include - -using namespace feed; -using namespace util::prometheus; - -// io_context -struct SubscriptionTestBase { - util::Config cfg; - util::TagDecoratorFactory tagDecoratorFactory{cfg}; -}; - -struct SubscriptionTest : WithPrometheus, SyncAsioContextTest, SubscriptionTestBase { - Subscription sub{ctx, "test"}; -}; - -// subscribe/unsubscribe the same session would not change the count -TEST_F(SubscriptionTest, SubscriptionCount) -{ - std::shared_ptr const session1 = std::make_shared(tagDecoratorFactory); - std::shared_ptr const session2 = std::make_shared(tagDecoratorFactory); - sub.subscribe(session1); - sub.subscribe(session2); - ctx.run(); - EXPECT_EQ(sub.count(), 2); - sub.subscribe(session1); - ctx.restart(); - ctx.run(); - EXPECT_EQ(sub.count(), 2); - EXPECT_TRUE(sub.hasSession(session1)); - EXPECT_TRUE(sub.hasSession(session2)); - EXPECT_FALSE(sub.empty()); - sub.unsubscribe(session1); - ctx.restart(); - ctx.run(); - EXPECT_EQ(sub.count(), 1); - sub.unsubscribe(session1); - ctx.restart(); - ctx.run(); - EXPECT_EQ(sub.count(), 1); - sub.unsubscribe(session2); - ctx.restart(); - ctx.run(); - EXPECT_EQ(sub.count(), 0); - EXPECT_TRUE(sub.empty()); - EXPECT_FALSE(sub.hasSession(session1)); - EXPECT_FALSE(sub.hasSession(session2)); -} - -// send interface will be called when publish called -TEST_F(SubscriptionTest, SubscriptionPublish) -{ - std::shared_ptr const session1 = std::make_shared(tagDecoratorFactory); - std::shared_ptr const session2 = std::make_shared(tagDecoratorFactory); - sub.subscribe(session1); - sub.subscribe(session2); - ctx.run(); - EXPECT_EQ(sub.count(), 2); - sub.publish(std::make_shared("message")); - ctx.restart(); - ctx.run(); - MockSession* p1 = dynamic_cast(session1.get()); - ASSERT_NE(p1, nullptr); - EXPECT_EQ(p1->message, "message"); - MockSession* p2 = dynamic_cast(session2.get()); - ASSERT_NE(p2, nullptr); - EXPECT_EQ(p2->message, "message"); - sub.unsubscribe(session1); - ctx.restart(); - ctx.run(); - sub.publish(std::make_shared("message2")); - ctx.restart(); - ctx.run(); - EXPECT_EQ(p1->message, "message"); - EXPECT_EQ(p2->message, "messagemessage2"); -} - -// when error happen during send(), the subsciber will be removed after -TEST_F(SubscriptionTest, SubscriptionDeadRemoveSubscriber) -{ - std::shared_ptr const session1(new MockDeadSession(tagDecoratorFactory)); - sub.subscribe(session1); - ctx.run(); - EXPECT_EQ(sub.count(), 1); - // trigger dead - sub.publish(std::make_shared("message")); - ctx.restart(); - ctx.run(); - EXPECT_EQ(session1->dead(), true); - sub.publish(std::make_shared("message")); - ctx.restart(); - ctx.run(); - EXPECT_EQ(sub.count(), 0); -} - -struct SubscriptionMockPrometheusTest : WithMockPrometheus, SubscriptionTestBase, SyncAsioContextTest { - Subscription sub{ctx, "test"}; - std::shared_ptr const session = std::make_shared(tagDecoratorFactory); -}; - -TEST_F(SubscriptionMockPrometheusTest, subscribe) -{ - auto& counter = makeMock("subscriptions_current_number", "{stream=\"test\"}"); - EXPECT_CALL(counter, add(1)); - sub.subscribe(session); - ctx.run(); -} - -TEST_F(SubscriptionMockPrometheusTest, unsubscribe) -{ - auto& counter = makeMock("subscriptions_current_number", "{stream=\"test\"}"); - EXPECT_CALL(counter, add(1)); - sub.subscribe(session); - ctx.run(); - EXPECT_CALL(counter, add(-1)); - sub.unsubscribe(session); - ctx.restart(); - ctx.run(); -} - -TEST_F(SubscriptionMockPrometheusTest, publish) -{ - auto deadSession = std::make_shared(tagDecoratorFactory); - auto& counter = makeMock("subscriptions_current_number", "{stream=\"test\"}"); - EXPECT_CALL(counter, add(1)); - sub.subscribe(deadSession); - ctx.run(); - EXPECT_CALL(counter, add(-1)); - sub.publish(std::make_shared("message")); - sub.publish(std::make_shared("message")); // Dead session is detected only after failed send - ctx.restart(); - ctx.run(); -} - -TEST_F(SubscriptionMockPrometheusTest, count) -{ - auto& counter = makeMock("subscriptions_current_number", "{stream=\"test\"}"); - EXPECT_CALL(counter, value()); - sub.count(); -} - -struct SubscriptionMapTest : SubscriptionTest { - SubscriptionMap subMap{ctx, "test"}; -}; - -TEST_F(SubscriptionMapTest, SubscriptionMapCount) -{ - std::shared_ptr const session1 = std::make_shared(tagDecoratorFactory); - std::shared_ptr const session2 = std::make_shared(tagDecoratorFactory); - std::shared_ptr const session3 = std::make_shared(tagDecoratorFactory); - subMap.subscribe(session1, "topic1"); - subMap.subscribe(session2, "topic1"); - subMap.subscribe(session3, "topic2"); - ctx.run(); - EXPECT_EQ(subMap.count(), 3); - subMap.subscribe(session1, "topic1"); - subMap.subscribe(session2, "topic1"); - ctx.restart(); - ctx.run(); - EXPECT_EQ(subMap.count(), 3); - EXPECT_TRUE(subMap.hasSession(session1, "topic1")); - EXPECT_TRUE(subMap.hasSession(session2, "topic1")); - EXPECT_TRUE(subMap.hasSession(session3, "topic2")); - subMap.unsubscribe(session1, "topic1"); - ctx.restart(); - ctx.run(); - subMap.unsubscribe(session1, "topic1"); - subMap.unsubscribe(session2, "topic1"); - subMap.unsubscribe(session3, "topic2"); - ctx.restart(); - ctx.run(); - EXPECT_FALSE(subMap.hasSession(session1, "topic1")); - EXPECT_FALSE(subMap.hasSession(session2, "topic1")); - EXPECT_FALSE(subMap.hasSession(session3, "topic2")); - EXPECT_EQ(subMap.count(), 0); - subMap.unsubscribe(session3, "topic2"); - subMap.unsubscribe(session3, "no exist"); - ctx.restart(); - ctx.run(); - EXPECT_EQ(subMap.count(), 0); -} - -TEST_F(SubscriptionMapTest, SubscriptionMapPublish) -{ - std::shared_ptr const session1 = std::make_shared(tagDecoratorFactory); - std::shared_ptr const session2 = std::make_shared(tagDecoratorFactory); - std::string const topic1 = "topic1"; - std::string const topic2 = "topic2"; - std::string const topic1Message = "topic1Message"; - std::string const topic2Message = "topic2Message"; - subMap.subscribe(session1, topic1); - subMap.subscribe(session2, topic2); - ctx.run(); - EXPECT_EQ(subMap.count(), 2); - auto message1 = std::make_shared(topic1Message.data()); - subMap.publish(message1, topic1); // lvalue - subMap.publish(std::make_shared(topic2Message.data()), topic2); // rvalue - ctx.restart(); - ctx.run(); - MockSession* p1 = dynamic_cast(session1.get()); - ASSERT_NE(p1, nullptr); - EXPECT_EQ(p1->message, topic1Message); - MockSession* p2 = dynamic_cast(session2.get()); - ASSERT_NE(p2, nullptr); - EXPECT_EQ(p2->message, topic2Message); -} - -TEST_F(SubscriptionMapTest, SubscriptionMapDeadRemoveSubscriber) -{ - std::shared_ptr const session1(new MockDeadSession(tagDecoratorFactory)); - std::shared_ptr const session2 = std::make_shared(tagDecoratorFactory); - std::string const topic1 = "topic1"; - std::string const topic2 = "topic2"; - std::string const topic1Message = "topic1Message"; - std::string const topic2Message = "topic2Message"; - subMap.subscribe(session1, topic1); - subMap.subscribe(session2, topic2); - ctx.run(); - EXPECT_EQ(subMap.count(), 2); - auto message1 = std::make_shared(topic1Message); - subMap.publish(message1, topic1); // lvalue - subMap.publish(std::make_shared(topic2Message), topic2); // rvalue - ctx.restart(); - ctx.run(); - MockDeadSession* p1 = dynamic_cast(session1.get()); - ASSERT_NE(p1, nullptr); - EXPECT_EQ(p1->dead(), true); - MockSession* p2 = dynamic_cast(session2.get()); - ASSERT_NE(p2, nullptr); - EXPECT_EQ(p2->message, topic2Message); - subMap.publish(message1, topic1); - ctx.restart(); - ctx.run(); - EXPECT_EQ(subMap.count(), 1); -} - -struct SubscriptionMapMockPrometheusTest : SubscriptionMockPrometheusTest { - SubscriptionMap subMap{ctx, "test"}; - std::shared_ptr const session = std::make_shared(tagDecoratorFactory); -}; - -TEST_F(SubscriptionMapMockPrometheusTest, subscribe) -{ - auto& counter = makeMock("subscriptions_current_number", "{collection=\"test\"}"); - EXPECT_CALL(counter, add(1)); - subMap.subscribe(session, "topic"); - ctx.run(); -} - -TEST_F(SubscriptionMapMockPrometheusTest, unsubscribe) -{ - auto& counter = makeMock("subscriptions_current_number", "{collection=\"test\"}"); - EXPECT_CALL(counter, add(1)); - subMap.subscribe(session, "topic"); - ctx.run(); - EXPECT_CALL(counter, add(-1)); - subMap.unsubscribe(session, "topic"); - ctx.restart(); - ctx.run(); -} - -TEST_F(SubscriptionMapMockPrometheusTest, publish) -{ - auto deadSession = std::make_shared(tagDecoratorFactory); - auto& counter = makeMock("subscriptions_current_number", "{collection=\"test\"}"); - EXPECT_CALL(counter, add(1)); - subMap.subscribe(deadSession, "topic"); - ctx.run(); - EXPECT_CALL(counter, add(-1)); - subMap.publish(std::make_shared("message"), "topic"); - subMap.publish( - std::make_shared("message"), "topic" - ); // Dead session is detected only after failed send - ctx.restart(); - ctx.run(); -} - -TEST_F(SubscriptionMapMockPrometheusTest, count) -{ - auto& counter = makeMock("subscriptions_current_number", "{collection=\"test\"}"); - EXPECT_CALL(counter, value()); - subMap.count(); -} diff --git a/unittests/data/cassandra/impl/FakesAndMocks.h b/unittests/data/cassandra/impl/FakesAndMocks.h index cb22cb5ab..31df196c8 100644 --- a/unittests/data/cassandra/impl/FakesAndMocks.h +++ b/unittests/data/cassandra/impl/FakesAndMocks.h @@ -43,8 +43,8 @@ struct FakeResultOrError { return err; } - FakeResult - value() const + static FakeResult + value() { return FakeResult{}; } @@ -65,8 +65,8 @@ struct FakeFuture { return data; } - FakeMaybeError - await() const + static FakeMaybeError + await() { return {}; } @@ -103,14 +103,14 @@ struct MockHandle { struct FakeRetryPolicy { FakeRetryPolicy(boost::asio::io_context&){}; // required by concept - std::chrono::milliseconds + static std::chrono::milliseconds calculateDelay(uint32_t /* attempt */) { return std::chrono::milliseconds{1}; } - bool - shouldRetry(CassandraError) const + static bool + shouldRetry(CassandraError) { return false; } diff --git a/unittests/etl/CacheLoaderTests.cpp b/unittests/etl/CacheLoaderTests.cpp index 2544b8a5d..6d2596692 100644 --- a/unittests/etl/CacheLoaderTests.cpp +++ b/unittests/etl/CacheLoaderTests.cpp @@ -20,7 +20,6 @@ #include "data/Types.h" #include "etl/impl/CacheLoader.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/MockCache.h" #include "util/config/Config.h" @@ -103,39 +102,37 @@ getLatestDiff() TEST_F(CacheLoaderTest, FromCache) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - CacheLoader loader{cfg, ctx, mockBackendPtr, cache}; + CacheLoader loader{cfg, ctx, backend, cache}; auto const diffs = getLatestDiff(); - ON_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).WillByDefault(Return(diffs)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(32); + ON_CALL(*backend, fetchLedgerDiff(_, _)).WillByDefault(Return(diffs)); + EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(32); auto const loops = diffs.size() + 1; auto const keysSize = 14; std::mutex keysMutex; std::map threadKeysMap; - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, SEQ, _)) - .WillByDefault(Invoke([&]() -> std::optional { - // mock the result from doFetchSuccessorKey, be aware this function will be called from multiple threads - // for each thread, the last 2 items must be end flag and nullopt, otherwise it will loop forever - std::lock_guard const guard(keysMutex); - threadKeysMap[std::this_thread::get_id()]++; - - if (threadKeysMap[std::this_thread::get_id()] == keysSize - 1) { - return lastKey; - } - if (threadKeysMap[std::this_thread::get_id()] == keysSize) { - threadKeysMap[std::this_thread::get_id()] = 0; - return std::nullopt; - } - return ripple::uint256{INDEX1}; - })); - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(keysSize * loops); - - ON_CALL(*rawBackendPtr, doFetchLedgerObjects(_, SEQ, _)) + ON_CALL(*backend, doFetchSuccessorKey(_, SEQ, _)).WillByDefault(Invoke([&]() -> std::optional { + // mock the result from doFetchSuccessorKey, be aware this function will be called from multiple threads + // for each thread, the last 2 items must be end flag and nullopt, otherwise it will loop forever + std::lock_guard const guard(keysMutex); + threadKeysMap[std::this_thread::get_id()]++; + + if (threadKeysMap[std::this_thread::get_id()] == keysSize - 1) { + return lastKey; + } + if (threadKeysMap[std::this_thread::get_id()] == keysSize) { + threadKeysMap[std::this_thread::get_id()] = 0; + return std::nullopt; + } + return ripple::uint256{INDEX1}; + })); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(keysSize * loops); + + ON_CALL(*backend, doFetchLedgerObjects(_, SEQ, _)) .WillByDefault(Return(std::vector{keysSize - 1, Blob{'s'}})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(loops); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(loops); EXPECT_CALL(cache, updateImp).Times(loops); EXPECT_CALL(cache, isFull).Times(1); diff --git a/unittests/etl/LedgerPublisherTests.cpp b/unittests/etl/LedgerPublisherTests.cpp index ab37fd193..57136e5af 100644 --- a/unittests/etl/LedgerPublisherTests.cpp +++ b/unittests/etl/LedgerPublisherTests.cpp @@ -22,7 +22,6 @@ #include "etl/SystemState.h" #include "etl/impl/LedgerPublisher.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/MockCache.h" #include "util/MockSubscriptionManager.h" #include "util/TestObject.h" @@ -77,14 +76,11 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingFalse) SystemState dummyState; dummyState.isWriting = false; auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, AGE); - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); publisher.publish(dummyLedgerInfo); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - - ON_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).Times(1); + ON_CALL(*backend, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector{})); + EXPECT_CALL(*backend, fetchLedgerDiff(SEQ, _)).Times(1); // setLastPublishedSequence not in strand, should verify before run EXPECT_TRUE(publisher.getLastPublishedSequence()); @@ -93,9 +89,9 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingFalse) EXPECT_CALL(mockCache, updateImp).Times(1); ctx.run(); - EXPECT_TRUE(rawBackendPtr->fetchLedgerRange()); - EXPECT_EQ(rawBackendPtr->fetchLedgerRange().value().minSequence, SEQ); - EXPECT_EQ(rawBackendPtr->fetchLedgerRange().value().maxSequence, SEQ); + EXPECT_TRUE(backend->fetchLedgerRange()); + EXPECT_EQ(backend->fetchLedgerRange().value().minSequence, SEQ); + EXPECT_EQ(backend->fetchLedgerRange().value().maxSequence, SEQ); } TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingTrue) @@ -103,18 +99,17 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoIsWritingTrue) SystemState dummyState; dummyState.isWriting = true; auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, AGE); - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); publisher.publish(dummyLedgerInfo); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0); + EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0); // setLastPublishedSequence not in strand, should verify before run EXPECT_TRUE(publisher.getLastPublishedSequence()); EXPECT_EQ(publisher.getLastPublishedSequence().value(), SEQ); ctx.run(); - EXPECT_FALSE(rawBackendPtr->fetchLedgerRange()); + EXPECT_FALSE(backend->fetchLedgerRange()); } TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoInRange) @@ -123,27 +118,25 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoInRange) dummyState.isWriting = true; auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, 0); // age is 0 - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); - mockBackendPtr->updateRange(SEQ - 1); - mockBackendPtr->updateRange(SEQ); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); + backend->setRange(SEQ - 1, SEQ); publisher.publish(dummyLedgerInfo); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0); + EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0); // mock fetch fee - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _)) + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); // mock fetch transactions - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = SEQ; - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ, _)) + ON_CALL(*backend, fetchAllTransactionsInLedger(SEQ, _)) .WillByDefault(Return(std::vector{t1})); // setLastPublishedSequence not in strand, should verify before run @@ -173,27 +166,25 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerInfoCloseTimeGreaterThanNow) auto const closeTime = duration_cast(nowPlus10.time_since_epoch()).count() - rippleEpochStart; dummyLedgerInfo.closeTime = ripple::NetClock::time_point{seconds{closeTime}}; - mockBackendPtr->updateRange(SEQ - 1); - mockBackendPtr->updateRange(SEQ); + backend->setRange(SEQ - 1, SEQ); - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); publisher.publish(dummyLedgerInfo); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0); + EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0); // mock fetch fee - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _)) + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); // mock fetch transactions - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = SEQ; - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ, _)) + ON_CALL(*backend, fetchAllTransactionsInLedger(SEQ, _)) .WillByDefault(Return(std::vector{t1})); // setLastPublishedSequence not in strand, should verify before run @@ -217,7 +208,7 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqStopIsTrue) { SystemState dummyState; dummyState.isStopping = true; - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); EXPECT_FALSE(publisher.publish(SEQ, {})); } @@ -225,14 +216,14 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqMaxAttampt) { SystemState dummyState; dummyState.isStopping = false; - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); static auto constexpr MAX_ATTEMPT = 2; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - EXPECT_CALL(*rawBackendPtr, hardFetchLedgerRange).Times(MAX_ATTEMPT); + + EXPECT_CALL(*backend, hardFetchLedgerRange).Times(MAX_ATTEMPT); LedgerRange const range{.minSequence = SEQ - 1, .maxSequence = SEQ - 1}; - ON_CALL(*rawBackendPtr, hardFetchLedgerRange(_)).WillByDefault(Return(range)); + ON_CALL(*backend, hardFetchLedgerRange(_)).WillByDefault(Return(range)); EXPECT_FALSE(publisher.publish(SEQ, MAX_ATTEMPT)); } @@ -240,19 +231,18 @@ TEST_F(ETLLedgerPublisherTest, PublishLedgerSeqStopIsFalse) { SystemState dummyState; dummyState.isStopping = false; - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); LedgerRange const range{.minSequence = SEQ, .maxSequence = SEQ}; - ON_CALL(*rawBackendPtr, hardFetchLedgerRange(_)).WillByDefault(Return(range)); - EXPECT_CALL(*rawBackendPtr, hardFetchLedgerRange).Times(1); + ON_CALL(*backend, hardFetchLedgerRange(_)).WillByDefault(Return(range)); + EXPECT_CALL(*backend, hardFetchLedgerRange).Times(1); auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, AGE); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(SEQ, _)).WillByDefault(Return(dummyLedgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(SEQ, _)).WillByDefault(Return(dummyLedgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(SEQ, _)).Times(1); + ON_CALL(*backend, fetchLedgerDiff(SEQ, _)).WillByDefault(Return(std::vector{})); + EXPECT_CALL(*backend, fetchLedgerDiff(SEQ, _)).Times(1); EXPECT_CALL(mockCache, updateImp).Times(1); EXPECT_TRUE(publisher.publish(SEQ, {})); @@ -265,22 +255,20 @@ TEST_F(ETLLedgerPublisherTest, PublishMultipleTxInOrder) dummyState.isWriting = true; auto const dummyLedgerInfo = CreateLedgerInfo(LEDGERHASH, SEQ, 0); // age is 0 - detail::LedgerPublisher publisher(ctx, mockBackendPtr, mockCache, mockSubscriptionManagerPtr, dummyState); - mockBackendPtr->updateRange(SEQ - 1); - mockBackendPtr->updateRange(SEQ); + detail::LedgerPublisher publisher(ctx, backend, mockCache, mockSubscriptionManagerPtr, dummyState); + backend->setRange(SEQ - 1, SEQ); publisher.publish(dummyLedgerInfo); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff(_, _)).Times(0); + EXPECT_CALL(*backend, fetchLedgerDiff(_, _)).Times(0); // mock fetch fee - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _)) + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, SEQ, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); // mock fetch transactions - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); // t1 index > t2 index TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, SEQ).getSerializer().peekData(); @@ -292,7 +280,7 @@ TEST_F(ETLLedgerPublisherTest, PublishMultipleTxInOrder) t2.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30, 1).getSerializer().peekData(); t2.ledgerSequence = SEQ; t2.date = 2; - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ, _)) + ON_CALL(*backend, fetchAllTransactionsInLedger(SEQ, _)) .WillByDefault(Return(std::vector{t1, t2})); // setLastPublishedSequence not in strand, should verify before run diff --git a/unittests/etl/TransformerTests.cpp b/unittests/etl/TransformerTests.cpp index a4a13c8f8..94b3830b5 100644 --- a/unittests/etl/TransformerTests.cpp +++ b/unittests/etl/TransformerTests.cpp @@ -22,7 +22,6 @@ #include "util/FakeFetchResponse.h" #include "util/Fixtures.h" #include "util/MockAmendmentBlockHandler.h" -#include "util/MockBackend.h" #include "util/MockExtractionDataPipe.h" #include "util/MockLedgerLoader.h" #include "util/MockLedgerPublisher.h" @@ -92,7 +91,7 @@ TEST_F(ETLTransformerTest, StopsOnWriteConflict) EXPECT_CALL(ledgerPublisher_, publish(_)).Times(0); transformer_ = std::make_unique( - dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_ + dataPipe_, backend, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_ ); transformer_->waitTillFinished(); // explicitly joins the thread @@ -100,9 +99,7 @@ TEST_F(ETLTransformerTest, StopsOnWriteConflict) TEST_F(ETLTransformerTest, StopsOnEmptyFetchResponse) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->cache().setFull(); // to avoid throwing exception in updateCache + backend->cache().setFull(); // to avoid throwing exception in updateCache auto const blob = hexStringToBinaryString(RAW_HEADER); auto const response = std::make_optional(blob); @@ -112,21 +109,21 @@ TEST_F(ETLTransformerTest, StopsOnEmptyFetchResponse) return std::nullopt; return response; // NOLINT (performance-no-automatic-move) }); - ON_CALL(*rawBackendPtr, doFinishWrites).WillByDefault(Return(true)); + ON_CALL(*backend, doFinishWrites).WillByDefault(Return(true)); // TODO: most of this should be hidden in a smaller entity that is injected into the transformer thread EXPECT_CALL(dataPipe_, popNext).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, startWrites).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeLedger(_, _)).Times(AtLeast(1)); + EXPECT_CALL(*backend, startWrites).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeLedger(_, _)).Times(AtLeast(1)); EXPECT_CALL(ledgerLoader_, insertTransactions).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeAccountTransactions).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeNFTs).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeNFTTransactions).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, doFinishWrites).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeAccountTransactions).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeNFTs).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeNFTTransactions).Times(AtLeast(1)); + EXPECT_CALL(*backend, doFinishWrites).Times(AtLeast(1)); EXPECT_CALL(ledgerPublisher_, publish(_)).Times(AtLeast(1)); transformer_ = std::make_unique( - dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_ + dataPipe_, backend, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_ ); // after 10ms we start spitting out empty responses which means the extractor is finishing up @@ -137,31 +134,29 @@ TEST_F(ETLTransformerTest, StopsOnEmptyFetchResponse) TEST_F(ETLTransformerTest, DoesNotPublishIfCanNotBuildNextLedger) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->cache().setFull(); // to avoid throwing exception in updateCache + backend->cache().setFull(); // to avoid throwing exception in updateCache auto const blob = hexStringToBinaryString(RAW_HEADER); auto const response = std::make_optional(blob); ON_CALL(dataPipe_, popNext).WillByDefault(Return(response)); - ON_CALL(*rawBackendPtr, doFinishWrites).WillByDefault(Return(false)); // emulate write failure + ON_CALL(*backend, doFinishWrites).WillByDefault(Return(false)); // emulate write failure // TODO: most of this should be hidden in a smaller entity that is injected into the transformer thread EXPECT_CALL(dataPipe_, popNext).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, startWrites).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeLedger(_, _)).Times(AtLeast(1)); + EXPECT_CALL(*backend, startWrites).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeLedger(_, _)).Times(AtLeast(1)); EXPECT_CALL(ledgerLoader_, insertTransactions).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeAccountTransactions).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeNFTs).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, writeNFTTransactions).Times(AtLeast(1)); - EXPECT_CALL(*rawBackendPtr, doFinishWrites).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeAccountTransactions).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeNFTs).Times(AtLeast(1)); + EXPECT_CALL(*backend, writeNFTTransactions).Times(AtLeast(1)); + EXPECT_CALL(*backend, doFinishWrites).Times(AtLeast(1)); // should not call publish EXPECT_CALL(ledgerPublisher_, publish(_)).Times(0); transformer_ = std::make_unique( - dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_ + dataPipe_, backend, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_ ); } diff --git a/unittests/feed/BookChangesFeedTests.cpp b/unittests/feed/BookChangesFeedTests.cpp new file mode 100644 index 000000000..0f3e00a0a --- /dev/null +++ b/unittests/feed/BookChangesFeedTests.cpp @@ -0,0 +1,91 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "data/Types.h" +#include "feed/FeedBaseTest.h" +#include "feed/impl/BookChangesFeed.h" +#include "feed/impl/ForwardFeed.h" +#include "util/TestObject.h" + +#include +#include +#include +#include + +#include + +using namespace feed::impl; +namespace json = boost::json; + +constexpr static auto LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652"; +constexpr static auto ACCOUNT1 = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"; +constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; +constexpr static auto CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000"; +constexpr static auto ISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD"; + +using FeedBookChangeTest = FeedBaseTest; + +TEST_F(FeedBookChangeTest, Pub) +{ + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 32); + auto transactions = std::vector{}; + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + ripple::STObject const metaObj = CreateMetaDataForBookChange(CURRENCY, ISSUER, 22, 1, 3, 3, 1); + trans1.metadata = metaObj.getSerializer().peekData(); + transactions.push_back(trans1); + + testFeedPtr->pub(ledgerinfo, transactions); + constexpr static auto bookChangePublish = + R"({ + "type":"bookChanges", + "ledger_index":32, + "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_time":0, + "changes": + [ + { + "currency_a":"XRP_drops", + "currency_b":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD/0158415500000000C1F76FF6ECB0BAC600000000", + "volume_a":"2", + "volume_b":"2", + "high":"-1", + "low":"-1", + "open":"-1", + "close":"-1" + } + ] + })"; + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(bookChangePublish)); + + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 0); + cleanReceivedFeed(); + testFeedPtr->pub(ledgerinfo, transactions); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} diff --git a/unittests/feed/FeedBaseTest.h b/unittests/feed/FeedBaseTest.h new file mode 100644 index 000000000..fb427ca68 --- /dev/null +++ b/unittests/feed/FeedBaseTest.h @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#pragma once + +#include "util/Fixtures.h" +#include "util/MockWsBase.h" +#include "util/Taggable.h" +#include "util/config/Config.h" +#include "web/interface/ConnectionBase.h" + +#include + +#include +#include + +// Base class for feed tests, providing easy way to access the received feed +template +class FeedBaseTest : public SyncAsioContextTest, public MockBackendTest { +protected: + util::TagDecoratorFactory tagDecoratorFactory{util::Config{}}; + std::shared_ptr sessionPtr; + std::shared_ptr testFeedPtr; + + void + SetUp() override + { + SyncAsioContextTest::SetUp(); + MockBackendTest::SetUp(); + testFeedPtr = std::make_shared(ctx); + sessionPtr = std::make_shared(tagDecoratorFactory); + } + + void + TearDown() override + { + sessionPtr.reset(); + testFeedPtr.reset(); + MockBackendTest::TearDown(); + SyncAsioContextTest::TearDown(); + } + + std::string const& + receivedFeedMessage() const + { + auto const mockSession = dynamic_cast(sessionPtr.get()); + [&] { ASSERT_NE(mockSession, nullptr); }(); + return mockSession->message; + } + + void + cleanReceivedFeed() + { + auto mockSession = dynamic_cast(sessionPtr.get()); + [&] { ASSERT_NE(mockSession, nullptr); }(); + mockSession->message.clear(); + } +}; diff --git a/unittests/feed/ForwardFeedTests.cpp b/unittests/feed/ForwardFeedTests.cpp new file mode 100644 index 000000000..954beef7e --- /dev/null +++ b/unittests/feed/ForwardFeedTests.cpp @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/FeedBaseTest.h" +#include "feed/impl/ForwardFeed.h" + +#include +#include +#include + +#include + +using namespace feed::impl; +namespace json = boost::json; +using namespace util::prometheus; + +constexpr static auto FEED = R"({"test":"test"})"; + +class NamedForwardFeedTest : public ForwardFeed { +public: + NamedForwardFeedTest(boost::asio::io_context& ioContext) : ForwardFeed(ioContext, "test") + { + } +}; + +using FeedForwardTest = FeedBaseTest; + +TEST_F(FeedForwardTest, Pub) +{ + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 1); + auto const json = json::parse(FEED).as_object(); + testFeedPtr->pub(json); + ctx.run(); + + EXPECT_EQ(receivedFeedMessage(), FEED); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 0); + cleanReceivedFeed(); + testFeedPtr->pub(json); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedForwardTest, AutoDisconnect) +{ + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 1); + auto const json = json::parse(FEED).as_object(); + testFeedPtr->pub(json); + ctx.run(); + EXPECT_EQ(receivedFeedMessage(), FEED); + sessionPtr.reset(); + EXPECT_EQ(testFeedPtr->count(), 0); + testFeedPtr->pub(json); +} diff --git a/unittests/feed/LedgerFeedTests.cpp b/unittests/feed/LedgerFeedTests.cpp new file mode 100644 index 000000000..38dc015f6 --- /dev/null +++ b/unittests/feed/LedgerFeedTests.cpp @@ -0,0 +1,141 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/FeedBaseTest.h" +#include "feed/impl/LedgerFeed.h" +#include "util/Fixtures.h" +#include "util/TestObject.h" + +#include +#include +#include +#include +#include +#include + +#include + +constexpr static auto LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652"; + +using namespace feed::impl; +namespace json = boost::json; + +using FeedLedgerTest = FeedBaseTest; + +TEST_F(FeedLedgerTest, SubPub) +{ + backend->setRange(10, 30); + auto const ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(testing::Return(ledgerInfo)); + + auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(testing::Return(feeBlob)); + // check the function response + // Information about the ledgers on hand and current fee schedule. This + // includes the same fields as a ledger stream message, except that it omits + // the type and txn_count fields + constexpr static auto LedgerResponse = + R"({ + "validated_ledgers":"10-30", + "ledger_index":30, + "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_time":0, + "fee_base":1, + "reserve_base":3, + "reserve_inc":2 + })"; + boost::asio::spawn(ctx, [this](boost::asio::yield_context yield) { + auto res = testFeedPtr->sub(yield, backend, sessionPtr); + // check the response + EXPECT_EQ(res, json::parse(LedgerResponse)); + }); + ctx.run(); + EXPECT_EQ(testFeedPtr->count(), 1); + + // test publish + auto const ledgerinfo2 = CreateLedgerInfo(LEDGERHASH, 31); + auto fee2 = ripple::Fees(); + fee2.reserve = 10; + testFeedPtr->pub(ledgerinfo2, fee2, "10-31", 8); + constexpr static auto ledgerPub = + R"({ + "type":"ledgerClosed", + "ledger_index":31, + "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_time":0, + "fee_base":0, + "reserve_base":10, + "reserve_inc":0, + "validated_ledgers":"10-31", + "txn_count":8 + })"; + ctx.restart(); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(ledgerPub)); + + // test unsub + cleanReceivedFeed(); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 0); + + testFeedPtr->pub(ledgerinfo2, fee2, "10-31", 8); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedLedgerTest, AutoDisconnect) +{ + backend->setRange(10, 30); + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(testing::Return(ledgerinfo)); + + auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(testing::Return(feeBlob)); + constexpr static auto LedgerResponse = + R"({ + "validated_ledgers":"10-30", + "ledger_index":30, + "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_time":0, + "fee_base":1, + "reserve_base":3, + "reserve_inc":2 + })"; + boost::asio::spawn(ctx, [this](boost::asio::yield_context yield) { + auto res = testFeedPtr->sub(yield, backend, sessionPtr); + // check the response + EXPECT_EQ(res, json::parse(LedgerResponse)); + }); + ctx.run(); + EXPECT_EQ(testFeedPtr->count(), 1); + + // destroy the session + sessionPtr.reset(); + EXPECT_EQ(testFeedPtr->count(), 0); + + auto const ledgerinfo2 = CreateLedgerInfo(LEDGERHASH, 31); + auto fee2 = ripple::Fees(); + fee2.reserve = 10; + // no error + testFeedPtr->pub(ledgerinfo2, fee2, "10-31", 8); + ctx.restart(); + ctx.run(); +} diff --git a/unittests/feed/ProposedTransactionFeedTests.cpp b/unittests/feed/ProposedTransactionFeedTests.cpp new file mode 100644 index 000000000..b92b4b625 --- /dev/null +++ b/unittests/feed/ProposedTransactionFeedTests.cpp @@ -0,0 +1,325 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/FeedBaseTest.h" +#include "feed/impl/ProposedTransactionFeed.h" +#include "util/Fixtures.h" +#include "util/MockPrometheus.h" +#include "util/MockWsBase.h" +#include "util/Taggable.h" +#include "util/TestObject.h" +#include "util/config/Config.h" +#include "util/prometheus/Gauge.h" +#include "web/interface/ConnectionBase.h" + +#include +#include +#include +#include +#include + +#include + +constexpr static auto ACCOUNT1 = "rh1HPuRVsYYvThxG2Bs1MfjmrVC73S16Fb"; +constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; +constexpr static auto DUMMY_TRANSACTION = + R"({ + "transaction": + { + "Account":"rh1HPuRVsYYvThxG2Bs1MfjmrVC73S16Fb", + "Amount":"40000000", + "Destination":"rDgGprMjMWkJRnJ8M5RXq3SXYD8zuQncPc", + "Fee":"20", + "Flags":2147483648, + "Sequence":13767283, + "SigningPubKey":"036F3CFFE1EA77C1EEC5DCCA38C83E62E3AC068F8A16369620AF1D609BA5A620B2", + "TransactionType":"Payment", + "TxnSignature":"30450221009BD0D563B24E50B26A42F30455AD21C3D5CD4D80174C41F7B54969FFC08DE94C02201FC35320B56D56D1E34D1D281D48AC68CBEDDD6EE9DFA639CCB08BB251453A87", + "hash":"F44393295DB860C6860769C16F5B23887762F09F87A8D1174E0FCFF9E7247F07" + } + })"; + +using namespace feed::impl; +namespace json = boost::json; +using namespace util::prometheus; + +using FeedProposedTransactionTest = FeedBaseTest; + +TEST_F(FeedProposedTransactionTest, ProposedTransaction) +{ + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 1); + + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(DUMMY_TRANSACTION)); + + cleanReceivedFeed(); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 0); + + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedProposedTransactionTest, AccountProposedTransaction) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + std::shared_ptr const sessionIdle = std::make_shared(tagDecoratorFactory); + auto const accountIdle = GetAccountIDWithString(ACCOUNT2); + testFeedPtr->sub(accountIdle, sessionIdle); + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(DUMMY_TRANSACTION)); + + auto const rawIdle = dynamic_cast(sessionIdle.get()); + ASSERT_NE(rawIdle, nullptr); + EXPECT_TRUE(rawIdle->message.empty()); + + // unsub + cleanReceivedFeed(); + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedProposedTransactionTest, SubStreamAndAccount) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr); + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 1); + + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.run(); + + EXPECT_EQ(receivedFeedMessage().size(), json::serialize(json::parse(DUMMY_TRANSACTION)).size() * 2); + + cleanReceivedFeed(); + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_EQ(receivedFeedMessage().size(), json::serialize(json::parse(DUMMY_TRANSACTION)).size() * 2); + + // unsub + cleanReceivedFeed(); + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_EQ(receivedFeedMessage().size(), json::serialize(json::parse(DUMMY_TRANSACTION)).size()); + + // unsub transaction + cleanReceivedFeed(); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 0); + + testFeedPtr->pub(json::parse(DUMMY_TRANSACTION).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedProposedTransactionTest, AccountProposedTransactionDuplicate) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + auto const account2 = GetAccountIDWithString(ACCOUNT2); + + testFeedPtr->sub(account, sessionPtr); + testFeedPtr->sub(account2, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + + constexpr static auto dummyTransaction = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun" + } + })"; + + testFeedPtr->pub(json::parse(dummyTransaction).get_object()); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(dummyTransaction)); + + // unsub account1 + cleanReceivedFeed(); + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + testFeedPtr->pub(json::parse(dummyTransaction).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(dummyTransaction)); + + // unsub account2 + cleanReceivedFeed(); + testFeedPtr->unsub(account2, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + + testFeedPtr->pub(json::parse(dummyTransaction).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedProposedTransactionTest, Count) +{ + testFeedPtr->sub(sessionPtr); + // repeat + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 1); + + auto const account1 = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account1, sessionPtr); + // repeat + testFeedPtr->sub(account1, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + auto const sessionPtr2 = std::make_shared(tagDecoratorFactory); + testFeedPtr->sub(sessionPtr2); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 2); + + auto const account2 = GetAccountIDWithString(ACCOUNT2); + testFeedPtr->sub(account2, sessionPtr2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + testFeedPtr->sub(account1, sessionPtr2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 3); + + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 1); + + // unsub unsubscribed account + testFeedPtr->unsub(account2, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 3); + + testFeedPtr->unsub(account1, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + testFeedPtr->unsub(account1, sessionPtr2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + testFeedPtr->unsub(account2, sessionPtr2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); +} + +TEST_F(FeedProposedTransactionTest, AutoDisconnect) +{ + testFeedPtr->sub(sessionPtr); + // repeat + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 1); + + auto const account1 = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account1, sessionPtr); + // repeat + testFeedPtr->sub(account1, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + auto sessionPtr2 = std::make_shared(tagDecoratorFactory); + testFeedPtr->sub(sessionPtr2); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 2); + + auto const account2 = GetAccountIDWithString(ACCOUNT2); + testFeedPtr->sub(account2, sessionPtr2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + testFeedPtr->sub(account1, sessionPtr2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 3); + + sessionPtr2.reset(); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 1); + + sessionPtr.reset(); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + EXPECT_EQ(testFeedPtr->transactionSubcount(), 0); +} + +struct ProposedTransactionFeedMockPrometheusTest : WithMockPrometheus, SyncAsioContextTest { +protected: + util::TagDecoratorFactory tagDecoratorFactory{util::Config{}}; + std::shared_ptr sessionPtr; + std::shared_ptr testFeedPtr; + + void + SetUp() override + { + SyncAsioContextTest::SetUp(); + testFeedPtr = std::make_shared(ctx); + sessionPtr = std::make_shared(tagDecoratorFactory); + } + void + TearDown() override + { + sessionPtr.reset(); + testFeedPtr.reset(); + SyncAsioContextTest::TearDown(); + } +}; + +TEST_F(ProposedTransactionFeedMockPrometheusTest, subUnsub) +{ + auto& counterTx = makeMock("subscriptions_current_number", "{stream=\"tx_proposed\"}"); + auto& counterAccount = makeMock("subscriptions_current_number", "{stream=\"account_proposed\"}"); + + EXPECT_CALL(counterTx, add(1)); + EXPECT_CALL(counterTx, add(-1)); + EXPECT_CALL(counterAccount, add(1)); + EXPECT_CALL(counterAccount, add(-1)); + + testFeedPtr->sub(sessionPtr); + testFeedPtr->unsub(sessionPtr); + + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr); + testFeedPtr->unsub(account, sessionPtr); +} + +TEST_F(ProposedTransactionFeedMockPrometheusTest, AutoDisconnect) +{ + auto& counterTx = makeMock("subscriptions_current_number", "{stream=\"tx_proposed\"}"); + auto& counterAccount = makeMock("subscriptions_current_number", "{stream=\"account_proposed\"}"); + + EXPECT_CALL(counterTx, add(1)); + EXPECT_CALL(counterTx, add(-1)); + EXPECT_CALL(counterAccount, add(1)); + EXPECT_CALL(counterAccount, add(-1)); + + testFeedPtr->sub(sessionPtr); + + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr); + + sessionPtr.reset(); +} diff --git a/unittests/feed/SingleFeedBaseTests.cpp b/unittests/feed/SingleFeedBaseTests.cpp new file mode 100644 index 000000000..db06b5220 --- /dev/null +++ b/unittests/feed/SingleFeedBaseTests.cpp @@ -0,0 +1,131 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/FeedBaseTest.h" +#include "feed/impl/SingleFeedBase.h" +#include "util/Fixtures.h" +#include "util/MockPrometheus.h" +#include "util/MockWsBase.h" +#include "util/Taggable.h" +#include "util/config/Config.h" +#include "util/prometheus/Gauge.h" +#include "web/interface/ConnectionBase.h" + +#include +#include +#include + +#include + +constexpr static auto FEED = R"({"test":"test"})"; + +using namespace feed::impl; +using namespace util::prometheus; + +struct FeedBaseMockPrometheusTest : WithMockPrometheus, SyncAsioContextTest { +protected: + util::TagDecoratorFactory tagDecoratorFactory{util::Config{}}; + std::shared_ptr sessionPtr; + std::shared_ptr testFeedPtr; + + void + SetUp() override + { + SyncAsioContextTest::SetUp(); + testFeedPtr = std::make_shared(ctx, "testFeed"); + sessionPtr = std::make_shared(tagDecoratorFactory); + } + void + TearDown() override + { + sessionPtr.reset(); + testFeedPtr.reset(); + SyncAsioContextTest::TearDown(); + } +}; + +TEST_F(FeedBaseMockPrometheusTest, subUnsub) +{ + auto& counter = makeMock("subscriptions_current_number", "{stream=\"testFeed\"}"); + EXPECT_CALL(counter, add(1)); + EXPECT_CALL(counter, add(-1)); + + testFeedPtr->sub(sessionPtr); + testFeedPtr->unsub(sessionPtr); +} + +TEST_F(FeedBaseMockPrometheusTest, AutoUnsub) +{ + auto& counter = makeMock("subscriptions_current_number", "{stream=\"testFeed\"}"); + EXPECT_CALL(counter, add(1)); + EXPECT_CALL(counter, add(-1)); + + testFeedPtr->sub(sessionPtr); + sessionPtr.reset(); +} + +class NamedSingleFeedTest : public SingleFeedBase { +public: + NamedSingleFeedTest(boost::asio::io_context& ioContext) : SingleFeedBase(ioContext, "forTest") + { + } +}; + +using SingleFeedBaseTest = FeedBaseTest; + +TEST_F(SingleFeedBaseTest, Test) +{ + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 1); + testFeedPtr->pub(FEED); + ctx.run(); + + EXPECT_EQ(receivedFeedMessage(), FEED); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 0); + cleanReceivedFeed(); + testFeedPtr->pub(FEED); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(SingleFeedBaseTest, TestAutoDisconnect) +{ + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 1); + testFeedPtr->pub(FEED); + ctx.run(); + + EXPECT_EQ(receivedFeedMessage(), FEED); + sessionPtr.reset(); + EXPECT_EQ(testFeedPtr->count(), 0); +} + +TEST_F(SingleFeedBaseTest, RepeatSub) +{ + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 1); + testFeedPtr->sub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 1); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 0); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->count(), 0); +} diff --git a/unittests/feed/SubscriptionManagerTests.cpp b/unittests/feed/SubscriptionManagerTests.cpp new file mode 100644 index 000000000..41b67e084 --- /dev/null +++ b/unittests/feed/SubscriptionManagerTests.cpp @@ -0,0 +1,478 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "data/Types.h" +#include "feed/SubscriptionManager.h" +#include "util/Fixtures.h" +#include "util/MockWsBase.h" +#include "util/Taggable.h" +#include "util/TestObject.h" +#include "util/config/Config.h" +#include "web/interface/ConnectionBase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +constexpr static auto ACCOUNT1 = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"; +constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; +constexpr static auto CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000"; +constexpr static auto ISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD"; +constexpr static auto LEDGERHASH = "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652"; + +namespace json = boost::json; +using namespace feed; +using namespace feed::impl; + +class SubscriptionManagerTest : public MockBackendTest, public SyncAsioContextTest { +protected: + util::Config cfg; + std::shared_ptr SubscriptionManagerPtr; + util::TagDecoratorFactory tagDecoratorFactory{cfg}; + std::shared_ptr session; + + void + SetUp() override + { + MockBackendTest::SetUp(); + SyncAsioContextTest::SetUp(); + SubscriptionManagerPtr = std::make_shared(ctx, backend); + session = std::make_shared(tagDecoratorFactory); + } + + void + TearDown() override + { + session.reset(); + SubscriptionManagerPtr.reset(); + SyncAsioContextTest::TearDown(); + MockBackendTest::TearDown(); + } + + std::string const& + receivedFeedMessage() const + { + auto const mockSession = dynamic_cast(session.get()); + [&] { ASSERT_NE(mockSession, nullptr); }(); + return mockSession->message; + } + + void + cleanReceivedFeed() + { + auto mockSession = dynamic_cast(session.get()); + [&] { ASSERT_NE(mockSession, nullptr); }(); + mockSession->message.clear(); + } +}; + +TEST_F(SubscriptionManagerTest, MultipleThreadCtx) +{ + std::vector workers; + workers.reserve(2); + + SubscriptionManagerPtr->subManifest(session); + SubscriptionManagerPtr->subValidation(session); + + SubscriptionManagerPtr->forwardManifest(json::parse(R"({"manifest":"test"})").get_object()); + SubscriptionManagerPtr->forwardValidation(json::parse(R"({"validation":"test"})").get_object()); + + for (int i = 0; i < 2; ++i) + workers.emplace_back([this]() { ctx.run(); }); + + // wait for all jobs in ctx to finish + for (auto& worker : workers) + worker.join(); + + EXPECT_TRUE( + receivedFeedMessage() == R"({"manifest":"test"}{"validation":"test"})" || + receivedFeedMessage() == R"({"validation":"test"}{"manifest":"test"})" + ) << "receivedFeedMessage() = " + << receivedFeedMessage(); + + session.reset(); + SubscriptionManagerPtr.reset(); +} + +TEST_F(SubscriptionManagerTest, MultipleThreadCtxSessionDieEarly) +{ + boost::asio::executor_work_guard work_ = boost::asio::make_work_guard(ctx); + + std::vector workers; + workers.reserve(2); + for (int i = 0; i < 2; ++i) + workers.emplace_back([this]() { ctx.run(); }); + + SubscriptionManagerPtr->subManifest(session); + SubscriptionManagerPtr->subValidation(session); + + SubscriptionManagerPtr->forwardManifest(json::parse(R"({"manifest":"test"})").get_object()); + SubscriptionManagerPtr->forwardValidation(json::parse(R"({"validation":"test"})").get_object()); + + session.reset(); + + work_.reset(); + for (auto& worker : workers) + worker.join(); + // SubscriptionManager's pub job is running in thread pool, so we let thread pool run out of work, otherwise + // SubscriptionManager will die before the job is called + SubscriptionManagerPtr.reset(); +} + +TEST_F(SubscriptionManagerTest, ReportCurrentSubscriber) +{ + constexpr static auto ReportReturn = + R"({ + "ledger":0, + "transactions":2, + "transactions_proposed":2, + "manifests":2, + "validations":2, + "account":2, + "accounts_proposed":2, + "books":2, + "book_changes":2 + })"; + std::shared_ptr const session1 = std::make_shared(tagDecoratorFactory); + std::shared_ptr session2 = std::make_shared(tagDecoratorFactory); + SubscriptionManagerPtr->subBookChanges(session1); + SubscriptionManagerPtr->subBookChanges(session2); + SubscriptionManagerPtr->subManifest(session1); + SubscriptionManagerPtr->subManifest(session2); + SubscriptionManagerPtr->subProposedTransactions(session1); + SubscriptionManagerPtr->subProposedTransactions(session2); + SubscriptionManagerPtr->subTransactions(session1, 1); + SubscriptionManagerPtr->subTransactions(session2, 2); + SubscriptionManagerPtr->subValidation(session1); + SubscriptionManagerPtr->subValidation(session2); + auto const account = GetAccountIDWithString(ACCOUNT1); + SubscriptionManagerPtr->subAccount(account, session1, 1); + SubscriptionManagerPtr->subAccount(account, session2, 2); + SubscriptionManagerPtr->subProposedAccount(account, session1); + SubscriptionManagerPtr->subProposedAccount(account, session2); + auto const issue1 = GetIssue(CURRENCY, ISSUER); + ripple::Book const book{ripple::xrpIssue(), issue1}; + SubscriptionManagerPtr->subBook(book, session1, 1); + SubscriptionManagerPtr->subBook(book, session2, 2); + EXPECT_EQ(SubscriptionManagerPtr->report(), json::parse(ReportReturn)); + + // count down when unsub manually + SubscriptionManagerPtr->unsubBookChanges(session1); + SubscriptionManagerPtr->unsubManifest(session1); + SubscriptionManagerPtr->unsubProposedTransactions(session1); + SubscriptionManagerPtr->unsubTransactions(session1); + SubscriptionManagerPtr->unsubValidation(session1); + SubscriptionManagerPtr->unsubAccount(account, session1); + SubscriptionManagerPtr->unsubProposedAccount(account, session1); + SubscriptionManagerPtr->unsubBook(book, session1); + + // try to unsub an account which is not subscribed + auto const account2 = GetAccountIDWithString(ACCOUNT2); + SubscriptionManagerPtr->unsubAccount(account2, session1); + SubscriptionManagerPtr->unsubProposedAccount(account2, session1); + auto checkResult = [](json::object reportReturn, int result) { + EXPECT_EQ(reportReturn["book_changes"], result); + EXPECT_EQ(reportReturn["validations"], result); + EXPECT_EQ(reportReturn["transactions_proposed"], result); + EXPECT_EQ(reportReturn["transactions"], result); + EXPECT_EQ(reportReturn["manifests"], result); + EXPECT_EQ(reportReturn["accounts_proposed"], result); + EXPECT_EQ(reportReturn["account"], result); + EXPECT_EQ(reportReturn["books"], result); + }; + checkResult(SubscriptionManagerPtr->report(), 1); + + // count down when session disconnect + session2.reset(); + checkResult(SubscriptionManagerPtr->report(), 0); +} + +TEST_F(SubscriptionManagerTest, ManifestTest) +{ + SubscriptionManagerPtr->subManifest(session); + constexpr static auto dummyManifest = R"({"manifest":"test"})"; + SubscriptionManagerPtr->forwardManifest(json::parse(dummyManifest).get_object()); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(dummyManifest)); + + cleanReceivedFeed(); + SubscriptionManagerPtr->unsubManifest(session); + SubscriptionManagerPtr->forwardManifest(json::parse(dummyManifest).get_object()); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(SubscriptionManagerTest, ValidationTest) +{ + SubscriptionManagerPtr->subValidation(session); + constexpr static auto dummyManifest = R"({"validation":"test"})"; + SubscriptionManagerPtr->forwardValidation(json::parse(dummyManifest).get_object()); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(dummyManifest)); + cleanReceivedFeed(); + SubscriptionManagerPtr->unsubValidation(session); + SubscriptionManagerPtr->forwardValidation(json::parse(dummyManifest).get_object()); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(SubscriptionManagerTest, BookChangesTest) +{ + SubscriptionManagerPtr->subBookChanges(session); + EXPECT_EQ(SubscriptionManagerPtr->report()["book_changes"], 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 32); + auto transactions = std::vector{}; + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + ripple::STObject const metaObj = CreateMetaDataForBookChange(CURRENCY, ISSUER, 22, 1, 3, 3, 1); + trans1.metadata = metaObj.getSerializer().peekData(); + transactions.push_back(trans1); + + SubscriptionManagerPtr->pubBookChanges(ledgerinfo, transactions); + constexpr static auto bookChangePublish = + R"({ + "type":"bookChanges", + "ledger_index":32, + "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_time":0, + "changes": + [ + { + "currency_a":"XRP_drops", + "currency_b":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD/0158415500000000C1F76FF6ECB0BAC600000000", + "volume_a":"2", + "volume_b":"2", + "high":"-1", + "low":"-1", + "open":"-1", + "close":"-1" + } + ] + })"; + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(bookChangePublish)); + + SubscriptionManagerPtr->unsubBookChanges(session); + EXPECT_EQ(SubscriptionManagerPtr->report()["book_changes"], 0); +} + +TEST_F(SubscriptionManagerTest, LedgerTest) +{ + backend->setRange(10, 30); + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(testing::Return(ledgerinfo)); + + auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(testing::Return(feeBlob)); + // check the function response + // Information about the ledgers on hand and current fee schedule. This + // includes the same fields as a ledger stream message, except that it omits + // the type and txn_count fields + constexpr static auto LedgerResponse = + R"({ + "validated_ledgers":"10-30", + "ledger_index":30, + "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_time":0, + "fee_base":1, + "reserve_base":3, + "reserve_inc":2 + })"; + boost::asio::spawn(ctx, [this](boost::asio::yield_context yield) { + auto const res = SubscriptionManagerPtr->subLedger(yield, session); + // check the response + EXPECT_EQ(res, json::parse(LedgerResponse)); + }); + ctx.run(); + EXPECT_EQ(SubscriptionManagerPtr->report()["ledger"], 1); + + // test publish + auto const ledgerinfo2 = CreateLedgerInfo(LEDGERHASH, 31); + auto fee2 = ripple::Fees(); + fee2.reserve = 10; + SubscriptionManagerPtr->pubLedger(ledgerinfo2, fee2, "10-31", 8); + constexpr static auto ledgerPub = + R"({ + "type":"ledgerClosed", + "ledger_index":31, + "ledger_hash":"4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_time":0, + "fee_base":0, + "reserve_base":10, + "reserve_inc":0, + "validated_ledgers":"10-31", + "txn_count":8 + })"; + ctx.restart(); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(ledgerPub)); + + // test unsub + SubscriptionManagerPtr->unsubLedger(session); + EXPECT_EQ(SubscriptionManagerPtr->report()["ledger"], 0); +} + +TEST_F(SubscriptionManagerTest, TransactionTest) +{ + auto const issue1 = GetIssue(CURRENCY, ISSUER); + auto const account = GetAccountIDWithString(ISSUER); + ripple::Book const book{ripple::xrpIssue(), issue1}; + SubscriptionManagerPtr->subBook(book, session, 1); + SubscriptionManagerPtr->subTransactions(session, 1); + SubscriptionManagerPtr->subAccount(account, session, 1); + EXPECT_EQ(SubscriptionManagerPtr->report()["account"], 1); + EXPECT_EQ(SubscriptionManagerPtr->report()["transactions"], 1); + EXPECT_EQ(SubscriptionManagerPtr->report()["books"], 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + auto obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + + auto const metaObj = CreateMetaDataForBookChange(CURRENCY, ISSUER, 22, 3, 1, 1, 3); + trans1.metadata = metaObj.getSerializer().peekData(); + SubscriptionManagerPtr->pubTransaction(trans1, ledgerinfo); + + constexpr static auto OrderbookPublish = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount":"1", + "DeliverMax":"1", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TransactionType":"Payment", + "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "date":0 + }, + "meta": + { + "AffectedNodes": + [ + { + "ModifiedNode": + { + "FinalFields": + { + "TakerGets":"3", + "TakerPays": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"1" + } + }, + "LedgerEntryType":"Offer", + "PreviousFields": + { + "TakerGets":"1", + "TakerPays": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"3" + } + } + } + } + ], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS", + "delivered_amount":"unavailable" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "close_time_iso": "2000-01-01T00:00:00Z", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + + ctx.run(); + + EXPECT_EQ(receivedFeedMessage().size(), json::serialize(json::parse(OrderbookPublish)).size() * 3); + + SubscriptionManagerPtr->unsubBook(book, session); + SubscriptionManagerPtr->unsubTransactions(session); + SubscriptionManagerPtr->unsubAccount(account, session); + EXPECT_EQ(SubscriptionManagerPtr->report()["account"], 0); + EXPECT_EQ(SubscriptionManagerPtr->report()["transactions"], 0); + EXPECT_EQ(SubscriptionManagerPtr->report()["books"], 0); +} + +TEST_F(SubscriptionManagerTest, ProposedTransactionTest) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + SubscriptionManagerPtr->subProposedAccount(account, session); + SubscriptionManagerPtr->subProposedTransactions(session); + EXPECT_EQ(SubscriptionManagerPtr->report()["accounts_proposed"], 1); + EXPECT_EQ(SubscriptionManagerPtr->report()["transactions_proposed"], 1); + + constexpr static auto dummyTransaction = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun" + } + })"; + + SubscriptionManagerPtr->forwardProposedTransaction(json::parse(dummyTransaction).get_object()); + ctx.run(); + + EXPECT_EQ(receivedFeedMessage().size(), json::serialize(json::parse(dummyTransaction)).size() * 2); + + // unsub account1 + cleanReceivedFeed(); + SubscriptionManagerPtr->unsubProposedAccount(account, session); + EXPECT_EQ(SubscriptionManagerPtr->report()["accounts_proposed"], 0); + SubscriptionManagerPtr->unsubProposedTransactions(session); + EXPECT_EQ(SubscriptionManagerPtr->report()["transactions_proposed"], 0); +} diff --git a/unittests/feed/TrackableSignalTests.cpp b/unittests/feed/TrackableSignalTests.cpp new file mode 100644 index 000000000..8a8e5ebf9 --- /dev/null +++ b/unittests/feed/TrackableSignalTests.cpp @@ -0,0 +1,142 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "feed/impl/TrackableSignal.h" +#include "feed/impl/TrackableSignalMap.h" +#include "util/MockWsBase.h" +#include "util/Taggable.h" +#include "util/config/Config.h" +#include "web/interface/ConnectionBase.h" + +#include + +#include +#include + +using namespace testing; + +struct FeedTrackableSignalTests : Test { +protected: + util::TagDecoratorFactory tagDecoratorFactory{util::Config{}}; + std::shared_ptr sessionPtr; + + void + SetUp() override + { + sessionPtr = std::make_shared(tagDecoratorFactory); + } + + void + TearDown() override + { + sessionPtr.reset(); + } +}; + +TEST_F(FeedTrackableSignalTests, Connect) +{ + feed::impl::TrackableSignal signal; + std::string testString; + auto const slot = [&](std::string const& s) { testString += s; }; + EXPECT_TRUE(signal.connectTrackableSlot(sessionPtr, slot)); + EXPECT_FALSE(signal.connectTrackableSlot(sessionPtr, slot)); + + EXPECT_EQ(signal.count(), 1); + + signal.emit("test"); + EXPECT_EQ(testString, "test"); + + EXPECT_TRUE(signal.disconnect(sessionPtr.get())); + EXPECT_EQ(signal.count(), 0); + EXPECT_FALSE(signal.disconnect(sessionPtr.get())); + + testString.clear(); + signal.emit("test2"); + EXPECT_TRUE(testString.empty()); +} + +TEST_F(FeedTrackableSignalTests, AutoDisconnect) +{ + feed::impl::TrackableSignal signal; + std::string testString; + auto const slot = [&](std::string const& s) { testString += s; }; + EXPECT_TRUE(signal.connectTrackableSlot(sessionPtr, slot)); + EXPECT_FALSE(signal.connectTrackableSlot(sessionPtr, slot)); + + EXPECT_EQ(signal.count(), 1); + + signal.emit("test"); + EXPECT_EQ(testString, "test"); + + sessionPtr.reset(); + // track object is destroyed, but the connection is still there + EXPECT_EQ(signal.count(), 1); + + testString.clear(); + signal.emit("test2"); + EXPECT_TRUE(testString.empty()); +} + +TEST_F(FeedTrackableSignalTests, MapConnect) +{ + feed::impl::TrackableSignalMap signalMap; + std::string testString; + auto const slot = [&](std::string const& s) { testString += s; }; + EXPECT_TRUE(signalMap.connectTrackableSlot(sessionPtr, "test", slot)); + EXPECT_TRUE(signalMap.connectTrackableSlot(sessionPtr, "test1", slot)); + EXPECT_FALSE(signalMap.connectTrackableSlot(sessionPtr, "test", slot)); + + signalMap.emit("test", "test"); + signalMap.emit("test2", "test2"); + EXPECT_EQ(testString, "test"); + + EXPECT_TRUE(signalMap.disconnect(sessionPtr.get(), "test")); + EXPECT_FALSE(signalMap.disconnect(sessionPtr.get(), "test")); + + testString.clear(); + signalMap.emit("test", "test2"); + EXPECT_TRUE(testString.empty()); + + signalMap.emit("test1", "test1"); + EXPECT_EQ(testString, "test1"); +} + +TEST_F(FeedTrackableSignalTests, MapAutoDisconnect) +{ + feed::impl::TrackableSignalMap signalMap; + std::string testString; + auto const slot = [&](std::string const& s) { testString += s; }; + EXPECT_TRUE(signalMap.connectTrackableSlot(sessionPtr, "test", slot)); + EXPECT_TRUE(signalMap.connectTrackableSlot(sessionPtr, "test1", slot)); + EXPECT_FALSE(signalMap.connectTrackableSlot(sessionPtr, "test", slot)); + + signalMap.emit("test", "test"); + signalMap.emit("test2", "test2"); + EXPECT_EQ(testString, "test"); + + // kill trackable + sessionPtr.reset(); + + testString.clear(); + signalMap.emit("test", "test"); + EXPECT_TRUE(testString.empty()); + + signalMap.emit("test1", "test1"); + EXPECT_TRUE(testString.empty()); +} diff --git a/unittests/feed/TransactionFeedTests.cpp b/unittests/feed/TransactionFeedTests.cpp new file mode 100644 index 000000000..569999fa6 --- /dev/null +++ b/unittests/feed/TransactionFeedTests.cpp @@ -0,0 +1,1044 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "data/Types.h" +#include "feed/FeedBaseTest.h" +#include "feed/impl/TransactionFeed.h" +#include "util/Fixtures.h" +#include "util/MockPrometheus.h" +#include "util/MockWsBase.h" +#include "util/Taggable.h" +#include "util/TestObject.h" +#include "util/config/Config.h" +#include "util/prometheus/Gauge.h" +#include "web/interface/ConnectionBase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +constexpr static auto ACCOUNT1 = "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn"; +constexpr static auto ACCOUNT2 = "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun"; +constexpr static auto LEDGERHASH = "1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC"; +constexpr static auto CURRENCY = "0158415500000000C1F76FF6ECB0BAC600000000"; +constexpr static auto ISSUER = "rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD"; +constexpr static auto TXNID = "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC321"; + +constexpr static auto TRAN_V1 = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount":"1", + "DeliverMax":"1", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TransactionType":"Payment", + "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "date":0 + }, + "meta": + { + "AffectedNodes": + [ + { + "ModifiedNode": + { + "FinalFields": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Balance":"110" + }, + "LedgerEntryType":"AccountRoot" + } + }, + { + "ModifiedNode": + { + "FinalFields": + { + "Account":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Balance":"30" + }, + "LedgerEntryType":"AccountRoot" + } + } + ], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS", + "delivered_amount":"unavailable" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "close_time_iso": "2000-01-01T00:00:00Z", + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + +constexpr static auto TRAN_V2 = + R"({ + "tx_json": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "DeliverMax":"1", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TransactionType":"Payment", + "date":0 + }, + "meta": + { + "AffectedNodes": + [ + { + "ModifiedNode":{ + "FinalFields":{ + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Balance":"110" + }, + "LedgerEntryType":"AccountRoot" + } + }, + { + "ModifiedNode":{ + "FinalFields":{ + "Account":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Balance":"30" + }, + "LedgerEntryType":"AccountRoot" + } + } + ], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS", + "delivered_amount":"unavailable" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "close_time_iso": "2000-01-01T00:00:00Z", + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + +using namespace feed::impl; +using namespace util::prometheus; +namespace json = boost::json; + +using FeedTransactionTest = FeedBaseTest; + +TEST_F(FeedTransactionTest, SubTransactionV1) +{ + testFeedPtr->sub(sessionPtr, 1); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V1)); + + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubTransactionV2) +{ + testFeedPtr->sub(sessionPtr, 2); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V2)); + + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubAccountV1) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr, 1); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V1)); + + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubAccountV2) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr, 2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V2)); + + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubBothTransactionAndAccount) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr, 2); + testFeedPtr->sub(sessionPtr, 2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.run(); + + EXPECT_EQ(receivedFeedMessage().size(), json::serialize(json::parse(TRAN_V2)).size() * 2); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_EQ(receivedFeedMessage().size(), json::serialize(json::parse(TRAN_V2)).size() * 2); + + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubBookV1) +{ + auto const issue1 = GetIssue(CURRENCY, ISSUER); + ripple::Book const book{ripple::xrpIssue(), issue1}; + testFeedPtr->sub(book, sessionPtr, 1); + EXPECT_EQ(testFeedPtr->bookSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + auto obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + + auto metaObj = CreateMetaDataForBookChange(CURRENCY, ISSUER, 22, 3, 1, 1, 3); + trans1.metadata = metaObj.getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + constexpr static auto OrderbookPublish = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount":"1", + "DeliverMax":"1", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TransactionType":"Payment", + "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "date":0 + }, + "meta": + { + "AffectedNodes": + [ + { + "ModifiedNode": + { + "FinalFields": + { + "TakerGets":"3", + "TakerPays": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"1" + } + }, + "LedgerEntryType":"Offer", + "PreviousFields":{ + "TakerGets":"1", + "TakerPays": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"3" + } + } + } + } + ], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS", + "delivered_amount":"unavailable" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "close_time_iso": "2000-01-01T00:00:00Z", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(OrderbookPublish)); + + cleanReceivedFeed(); + + // trigger by offer cancel meta data + metaObj = CreateMetaDataForCancelOffer(CURRENCY, ISSUER, 22, 3, 1); + trans1.metadata = metaObj.getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + constexpr static auto OrderbookCancelPublish = + R"({ + "transaction":{ + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount":"1", + "DeliverMax":"1", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TransactionType":"Payment", + "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "date":0 + }, + "meta":{ + "AffectedNodes": + [ + { + "DeletedNode": + { + "FinalFields": + { + "TakerGets":"3", + "TakerPays":{ + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"1" + } + }, + "LedgerEntryType":"Offer" + } + } + ], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS", + "delivered_amount":"unavailable" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "close_time_iso": "2000-01-01T00:00:00Z", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + ctx.restart(); + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(OrderbookCancelPublish)); + + // trigger by offer create meta data + constexpr static auto OrderbookCreatePublish = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Amount":"1", + "DeliverMax":"1", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TransactionType":"Payment", + "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "date":0 + }, + "meta": + { + "AffectedNodes": + [ + { + "CreatedNode": + { + "NewFields":{ + "TakerGets":"3", + "TakerPays": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"1" + } + }, + "LedgerEntryType":"Offer" + } + } + ], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS", + "delivered_amount":"unavailable" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "close_time_iso": "2000-01-01T00:00:00Z", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + metaObj = CreateMetaDataForCreateOffer(CURRENCY, ISSUER, 22, 3, 1); + trans1.metadata = metaObj.getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + cleanReceivedFeed(); + ctx.restart(); + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(OrderbookCreatePublish)); + + testFeedPtr->unsub(book, sessionPtr); + EXPECT_EQ(testFeedPtr->bookSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubBookV2) +{ + auto const issue1 = GetIssue(CURRENCY, ISSUER); + ripple::Book const book{ripple::xrpIssue(), issue1}; + testFeedPtr->sub(book, sessionPtr, 2); + EXPECT_EQ(testFeedPtr->bookSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + auto obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + + auto const metaObj = CreateMetaDataForBookChange(CURRENCY, ISSUER, 22, 3, 1, 1, 3); + trans1.metadata = metaObj.getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + constexpr static auto OrderbookPublish = + R"({ + "tx_json": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "DeliverMax":"1", + "Destination":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TransactionType":"Payment", + "date":0 + }, + "meta": + { + "AffectedNodes": + [ + { + "ModifiedNode": + { + "FinalFields": + { + "TakerGets":"3", + "TakerPays": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"1" + } + }, + "LedgerEntryType":"Offer", + "PreviousFields": + { + "TakerGets":"1", + "TakerPays": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"3" + } + } + } + } + ], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS", + "delivered_amount":"unavailable" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "close_time_iso": "2000-01-01T00:00:00Z", + "hash":"51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(OrderbookPublish)); + + testFeedPtr->unsub(book, sessionPtr); + EXPECT_EQ(testFeedPtr->bookSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, TransactionContainsBothAccountsSubed) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr, 2); + + auto const account2 = GetAccountIDWithString(ACCOUNT2); + testFeedPtr->sub(account2, sessionPtr, 2); + + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V2)); + + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V2)); + + cleanReceivedFeed(); + testFeedPtr->unsub(account2, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubAccountRepeatWithDifferentVersion) +{ + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr, 1); + + auto const account2 = GetAccountIDWithString(ACCOUNT2); + testFeedPtr->sub(account2, sessionPtr, 2); + + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V2)); + + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V2)); + + testFeedPtr->unsub(account2, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + + cleanReceivedFeed(); + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubTransactionRepeatWithDifferentVersion) +{ + // sub version 1 first + testFeedPtr->sub(sessionPtr, 1); + // sub version 2 later + testFeedPtr->sub(sessionPtr, 2); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreatePaymentTransactionObject(ACCOUNT1, ACCOUNT2, 1, 1, 32); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + trans1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT1, ACCOUNT2, 110, 30, 22).getSerializer().peekData(); + + testFeedPtr->pub(trans1, ledgerinfo, backend); + + ctx.run(); + + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_V1)); + + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); + cleanReceivedFeed(); + + testFeedPtr->pub(trans1, ledgerinfo, backend); + ctx.restart(); + ctx.run(); + EXPECT_TRUE(receivedFeedMessage().empty()); +} + +TEST_F(FeedTransactionTest, SubRepeat) +{ + auto const session2 = std::make_shared(tagDecoratorFactory); + + testFeedPtr->sub(sessionPtr, 1); + testFeedPtr->sub(session2, 1); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 2); + + testFeedPtr->sub(sessionPtr, 1); + testFeedPtr->sub(session2, 1); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 2); + + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 1); + testFeedPtr->unsub(session2); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); + testFeedPtr->unsub(sessionPtr); + EXPECT_EQ(testFeedPtr->transactionSubCount(), 0); + + auto const account = GetAccountIDWithString(ACCOUNT1); + auto const account2 = GetAccountIDWithString(ACCOUNT2); + testFeedPtr->sub(account, sessionPtr, 1); + testFeedPtr->sub(account2, session2, 1); + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + + testFeedPtr->sub(account, sessionPtr, 1); + testFeedPtr->sub(account2, session2, 1); + EXPECT_EQ(testFeedPtr->accountSubCount(), 2); + + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 1); + testFeedPtr->unsub(account2, session2); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + testFeedPtr->unsub(account, sessionPtr); + EXPECT_EQ(testFeedPtr->accountSubCount(), 0); + + auto const issue1 = GetIssue(CURRENCY, ISSUER); + ripple::Book const book{ripple::xrpIssue(), issue1}; + testFeedPtr->sub(book, sessionPtr, 1); + EXPECT_EQ(testFeedPtr->bookSubCount(), 1); + testFeedPtr->sub(book, session2, 1); + EXPECT_EQ(testFeedPtr->bookSubCount(), 2); + + testFeedPtr->unsub(book, sessionPtr); + EXPECT_EQ(testFeedPtr->bookSubCount(), 1); + testFeedPtr->unsub(book, session2); + EXPECT_EQ(testFeedPtr->bookSubCount(), 0); + testFeedPtr->unsub(book, sessionPtr); + EXPECT_EQ(testFeedPtr->bookSubCount(), 0); +} + +TEST_F(FeedTransactionTest, PubTransactionWithOwnerFund) +{ + testFeedPtr->sub(sessionPtr, 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreateCreateOfferTransactionObject(ACCOUNT1, 1, 32, CURRENCY, ISSUER, 1, 3); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + ripple::STArray const metaArray{0}; + ripple::STObject metaObj(ripple::sfTransactionMetaData); + metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); + metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); + metaObj.setFieldU32(ripple::sfTransactionIndex, 22); + trans1.metadata = metaObj.getSerializer().peekData(); + + ripple::STObject line(ripple::sfIndexes); + line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); + line.setFieldAmount(ripple::sfLowLimit, ripple::STAmount(10, false)); + line.setFieldAmount(ripple::sfHighLimit, ripple::STAmount(100, false)); + line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{TXNID}); + line.setFieldU32(ripple::sfPreviousTxnLgrSeq, 3); + line.setFieldU32(ripple::sfFlags, 0); + auto const issue2 = GetIssue(CURRENCY, ISSUER); + line.setFieldAmount(ripple::sfBalance, ripple::STAmount(issue2, 100)); + + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); + auto const issueAccount = GetAccountIDWithString(ISSUER); + auto const kk = ripple::keylet::account(issueAccount).key; + ON_CALL(*backend, doFetchLedgerObject(testing::_, testing::_, testing::_)) + .WillByDefault(testing::Return(line.getSerializer().peekData())); + ripple::STObject const accountRoot = CreateAccountRootObject(ISSUER, 0, 1, 10, 2, TXNID, 3); + ON_CALL(*backend, doFetchLedgerObject(kk, testing::_, testing::_)) + .WillByDefault(testing::Return(accountRoot.getSerializer().peekData())); + + testFeedPtr->pub(trans1, ledgerinfo, backend); + constexpr static auto TransactionForOwnerFund = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TakerGets": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"1" + }, + "TakerPays":"3", + "TransactionType":"OfferCreate", + "hash":"EE8775B43A67F4803DECEC5E918E0EA9C56D8ED93E512EBE9F2891846509AAAB", + "date":0, + "owner_funds":"100" + }, + "meta": + { + "AffectedNodes":[], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "close_time_iso": "2000-01-01T00:00:00Z", + "engine_result":"tesSUCCESS", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TransactionForOwnerFund)); +} + +constexpr static auto TRAN_FROZEN = + R"({ + "transaction": + { + "Account":"rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", + "Fee":"1", + "Sequence":32, + "SigningPubKey":"74657374", + "TakerGets": + { + "currency":"0158415500000000C1F76FF6ECB0BAC600000000", + "issuer":"rK9DrarGKnVEo2nYp5MfVRXRYf5yRX3mwD", + "value":"1" + }, + "TakerPays":"3", + "TransactionType":"OfferCreate", + "hash":"EE8775B43A67F4803DECEC5E918E0EA9C56D8ED93E512EBE9F2891846509AAAB", + "date":0, + "owner_funds":"0" + }, + "meta":{ + "AffectedNodes":[], + "TransactionIndex":22, + "TransactionResult":"tesSUCCESS" + }, + "type":"transaction", + "validated":true, + "status":"closed", + "ledger_index":33, + "close_time_iso": "2000-01-01T00:00:00Z", + "ledger_hash":"1B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC", + "engine_result_code":0, + "engine_result":"tesSUCCESS", + "engine_result_message":"The transaction was applied. Only final in a validated ledger." + })"; + +TEST_F(FeedTransactionTest, PubTransactionOfferCreationFrozenLine) +{ + testFeedPtr->sub(sessionPtr, 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreateCreateOfferTransactionObject(ACCOUNT1, 1, 32, CURRENCY, ISSUER, 1, 3); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + ripple::STArray const metaArray{0}; + ripple::STObject metaObj(ripple::sfTransactionMetaData); + metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); + metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); + metaObj.setFieldU32(ripple::sfTransactionIndex, 22); + trans1.metadata = metaObj.getSerializer().peekData(); + + ripple::STObject line(ripple::sfIndexes); + line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); + line.setFieldAmount(ripple::sfLowLimit, ripple::STAmount(10, false)); + line.setFieldAmount(ripple::sfHighLimit, ripple::STAmount(100, false)); + line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{TXNID}); + line.setFieldU32(ripple::sfPreviousTxnLgrSeq, 3); + line.setFieldU32(ripple::sfFlags, ripple::lsfHighFreeze); + line.setFieldAmount(ripple::sfBalance, ripple::STAmount(GetIssue(CURRENCY, ISSUER), 100)); + + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); + auto const issueAccount = GetAccountIDWithString(ISSUER); + auto const kk = ripple::keylet::account(issueAccount).key; + ON_CALL(*backend, doFetchLedgerObject(testing::_, testing::_, testing::_)) + .WillByDefault(testing::Return(line.getSerializer().peekData())); + ripple::STObject const accountRoot = CreateAccountRootObject(ISSUER, 0, 1, 10, 2, TXNID, 3); + ON_CALL(*backend, doFetchLedgerObject(kk, testing::_, testing::_)) + .WillByDefault(testing::Return(accountRoot.getSerializer().peekData())); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_FROZEN)); +} + +TEST_F(FeedTransactionTest, SubTransactionOfferCreationGlobalFrozen) +{ + testFeedPtr->sub(sessionPtr, 1); + + auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 33); + auto trans1 = TransactionAndMetadata(); + ripple::STObject const obj = CreateCreateOfferTransactionObject(ACCOUNT1, 1, 32, CURRENCY, ISSUER, 1, 3); + trans1.transaction = obj.getSerializer().peekData(); + trans1.ledgerSequence = 32; + ripple::STArray const metaArray{0}; + ripple::STObject metaObj(ripple::sfTransactionMetaData); + metaObj.setFieldArray(ripple::sfAffectedNodes, metaArray); + metaObj.setFieldU8(ripple::sfTransactionResult, ripple::tesSUCCESS); + metaObj.setFieldU32(ripple::sfTransactionIndex, 22); + trans1.metadata = metaObj.getSerializer().peekData(); + + ripple::STObject line(ripple::sfIndexes); + line.setFieldU16(ripple::sfLedgerEntryType, ripple::ltRIPPLE_STATE); + line.setFieldAmount(ripple::sfLowLimit, ripple::STAmount(10, false)); + line.setFieldAmount(ripple::sfHighLimit, ripple::STAmount(100, false)); + line.setFieldH256(ripple::sfPreviousTxnID, ripple::uint256{TXNID}); + line.setFieldU32(ripple::sfPreviousTxnLgrSeq, 3); + line.setFieldU32(ripple::sfFlags, ripple::lsfHighFreeze); + auto const issueAccount = GetAccountIDWithString(ISSUER); + line.setFieldAmount(ripple::sfBalance, ripple::STAmount(GetIssue(CURRENCY, ISSUER), 100)); + + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); + auto const kk = ripple::keylet::account(issueAccount).key; + ON_CALL(*backend, doFetchLedgerObject(testing::_, testing::_, testing::_)) + .WillByDefault(testing::Return(line.getSerializer().peekData())); + ripple::STObject const accountRoot = CreateAccountRootObject(ISSUER, ripple::lsfGlobalFreeze, 1, 10, 2, TXNID, 3); + ON_CALL(*backend, doFetchLedgerObject(kk, testing::_, testing::_)) + .WillByDefault(testing::Return(accountRoot.getSerializer().peekData())); + testFeedPtr->pub(trans1, ledgerinfo, backend); + + ctx.run(); + EXPECT_EQ(json::parse(receivedFeedMessage()), json::parse(TRAN_FROZEN)); +} + +struct TransactionFeedMockPrometheusTest : WithMockPrometheus, SyncAsioContextTest { +protected: + util::TagDecoratorFactory tagDecoratorFactory{util::Config{}}; + std::shared_ptr sessionPtr; + std::shared_ptr testFeedPtr; + + void + SetUp() override + { + SyncAsioContextTest::SetUp(); + testFeedPtr = std::make_shared(ctx); + sessionPtr = std::make_shared(tagDecoratorFactory); + } + void + TearDown() override + { + sessionPtr.reset(); + testFeedPtr.reset(); + SyncAsioContextTest::TearDown(); + } +}; + +TEST_F(TransactionFeedMockPrometheusTest, subUnsub) +{ + auto& counterTx = makeMock("subscriptions_current_number", "{stream=\"tx\"}"); + auto& counterAccount = makeMock("subscriptions_current_number", "{stream=\"account\"}"); + auto& counterBook = makeMock("subscriptions_current_number", "{stream=\"book\"}"); + + EXPECT_CALL(counterTx, add(1)); + EXPECT_CALL(counterTx, add(-1)); + EXPECT_CALL(counterAccount, add(1)); + EXPECT_CALL(counterAccount, add(-1)); + EXPECT_CALL(counterBook, add(1)); + EXPECT_CALL(counterBook, add(-1)); + + testFeedPtr->sub(sessionPtr, 1); + testFeedPtr->unsub(sessionPtr); + + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr, 1); + testFeedPtr->unsub(account, sessionPtr); + + auto const issue1 = GetIssue(CURRENCY, ISSUER); + ripple::Book const book{ripple::xrpIssue(), issue1}; + testFeedPtr->sub(book, sessionPtr, 1); + testFeedPtr->unsub(book, sessionPtr); +} + +TEST_F(TransactionFeedMockPrometheusTest, AutoDisconnect) +{ + auto& counterTx = makeMock("subscriptions_current_number", "{stream=\"tx\"}"); + auto& counterAccount = makeMock("subscriptions_current_number", "{stream=\"account\"}"); + auto& counterBook = makeMock("subscriptions_current_number", "{stream=\"book\"}"); + + EXPECT_CALL(counterTx, add(1)); + EXPECT_CALL(counterTx, add(-1)); + EXPECT_CALL(counterAccount, add(1)); + EXPECT_CALL(counterAccount, add(-1)); + EXPECT_CALL(counterBook, add(1)); + EXPECT_CALL(counterBook, add(-1)); + + testFeedPtr->sub(sessionPtr, 1); + + auto const account = GetAccountIDWithString(ACCOUNT1); + testFeedPtr->sub(account, sessionPtr, 1); + + auto const issue1 = GetIssue(CURRENCY, ISSUER); + ripple::Book const book{ripple::xrpIssue(), issue1}; + testFeedPtr->sub(book, sessionPtr, 1); + + sessionPtr.reset(); +} diff --git a/unittests/rpc/ForwardingProxyTests.cpp b/unittests/rpc/ForwardingProxyTests.cpp index 2144bed14..d4e4721cc 100644 --- a/unittests/rpc/ForwardingProxyTests.cpp +++ b/unittests/rpc/ForwardingProxyTests.cpp @@ -71,7 +71,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfClioOnly) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -91,7 +91,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfProxied) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -111,7 +111,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfCurrentLedgerSpecified) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -131,7 +131,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfClosedLedgerSpecified) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -151,7 +151,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfAccountInfoWithQueueSpe EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -171,7 +171,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithQueueSpecifie EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -191,7 +191,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithFullSpecified EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -211,7 +211,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithAccountsSpeci EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -231,7 +231,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAccountInfoQueueIsFals EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -251,7 +251,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerQueueIsFalse) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -271,7 +271,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerFullIsFalse) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -291,7 +291,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerAccountsIsFalse) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -311,7 +311,7 @@ TEST_F(RPCForwardingProxyTest, ShouldNotForwardReturnsTrueIfAPIVersionIsV1) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -331,7 +331,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAPIVersionIsV2) EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -347,7 +347,7 @@ TEST_F(RPCForwardingProxyTest, ShouldNeverForwardSubscribe) auto const params = json::parse("{}"); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -363,7 +363,7 @@ TEST_F(RPCForwardingProxyTest, ShouldNeverForwardUnsubscribe) auto const params = json::parse("{}"); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -392,7 +392,7 @@ TEST_F(RPCForwardingProxyTest, ForwardCallsBalancerWithCorrectParams) EXPECT_CALL(counters, rpcForwarded(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); @@ -423,7 +423,7 @@ TEST_F(RPCForwardingProxyTest, ForwardingFailYieldsErrorStatus) EXPECT_CALL(counters, rpcFailedToForward(method)).Times(1); runSpawn([&](auto yield) { - auto const range = mockBackendPtr->fetchLedgerRange(); + auto const range = backend->fetchLedgerRange(); auto const ctx = web::Context(yield, method, apiVersion, params.as_object(), nullptr, tagFactory, *range, CLIENT_IP, true); diff --git a/unittests/rpc/RPCHelpersTests.cpp b/unittests/rpc/RPCHelpersTests.cpp index 2791471d1..93e6b349b 100644 --- a/unittests/rpc/RPCHelpersTests.cpp +++ b/unittests/rpc/RPCHelpersTests.cpp @@ -23,7 +23,6 @@ #include "rpc/RPCHelpers.h" #include "rpc/common/Types.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -75,7 +74,7 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesMarkerInvalidIndexNotHex) { boost::asio::spawn(ctx, [this](boost::asio::yield_context yield) { auto account = GetAccountIDWithString(ACCOUNT); - auto ret = traverseOwnedNodes(*mockBackendPtr, account, 9, 10, "nothex,10", yield, [](auto) { + auto ret = traverseOwnedNodes(*backend, account, 9, 10, "nothex,10", yield, [](auto) { }); auto status = std::get_if(&ret); @@ -90,7 +89,7 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesMarkerInvalidPageNotInt) { boost::asio::spawn(ctx, [this](boost::asio::yield_context yield) { auto account = GetAccountIDWithString(ACCOUNT); - auto ret = traverseOwnedNodes(*mockBackendPtr, account, 9, 10, "nothex,abc", yield, [](auto) { + auto ret = traverseOwnedNodes(*backend, account, 9, 10, "nothex,abc", yield, [](auto) { }); auto status = std::get_if(&ret); @@ -104,17 +103,14 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesMarkerInvalidPageNotInt) // limit = 10, return 2 objects TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarker) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - auto account = GetAccountIDWithString(ACCOUNT); auto owneDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); // return owner index ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); // return two payment channel objects @@ -122,11 +118,11 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarker) ripple::STObject const channel1 = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); bbs.push_back(channel1.getSerializer().peekData()); bbs.push_back(channel1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); boost::asio::spawn(ctx, [this, &account](boost::asio::yield_context yield) { - auto ret = traverseOwnedNodes(*mockBackendPtr, account, 9, 10, {}, yield, [](auto) { + auto ret = traverseOwnedNodes(*backend, account, 9, 10, {}, yield, [](auto) { }); auto cursor = std::get_if(&ret); @@ -143,12 +139,9 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarker) // limit = 10, return 10 objects and marker TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnSamePageMarker) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - auto account = GetAccountIDWithString(ACCOUNT); auto owneDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); std::vector bbs; @@ -164,15 +157,15 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnSamePageMarker) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, 99); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); boost::asio::spawn(ctx, [this, &account](boost::asio::yield_context yield) { auto count = 0; - auto ret = traverseOwnedNodes(*mockBackendPtr, account, 9, 10, {}, yield, [&](auto) { count++; }); + auto ret = traverseOwnedNodes(*backend, account, 9, 10, {}, yield, [&](auto) { count++; }); auto cursor = std::get_if(&ret); EXPECT_TRUE(cursor != nullptr); EXPECT_EQ(count, 10); @@ -184,16 +177,13 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnSamePageMarker) // 10 objects per page, limit is 15, return the second page as marker TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnOtherPageMarker) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - auto account = GetAccountIDWithString(ACCOUNT); auto ownerDirKk = ripple::keylet::ownerDir(account).key; constexpr static auto nextPage = 99; constexpr static auto limit = 15; auto ownerDir2Kk = ripple::keylet::page(ripple::keylet::ownerDir(account), nextPage).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; @@ -214,20 +204,20 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnOtherPageMarker) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, nextPage); // first page 's next page is 99 - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); ripple::STObject ownerDir2 = CreateOwnerDirLedgerObject(indexes, INDEX1); // second page's next page is 0 ownerDir2.setFieldU64(ripple::sfIndexNext, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) .WillByDefault(Return(ownerDir2.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); boost::asio::spawn(ctx, [&, this](boost::asio::yield_context yield) { auto count = 0; - auto ret = traverseOwnedNodes(*mockBackendPtr, account, 9, limit, {}, yield, [&](auto) { count++; }); + auto ret = traverseOwnedNodes(*backend, account, 9, limit, {}, yield, [&](auto) { count++; }); auto cursor = std::get_if(&ret); EXPECT_TRUE(cursor != nullptr); EXPECT_EQ(count, limit); @@ -239,14 +229,11 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesNoInputMarkerReturnOtherPageMarker) // Send a valid marker TEST_F(RPCHelpersTest, TraverseOwnedNodesWithMarkerReturnSamePageMarker) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - auto account = GetAccountIDWithString(ACCOUNT); auto ownerDir2Kk = ripple::keylet::page(ripple::keylet::ownerDir(account), 99).key; constexpr static auto limit = 8; constexpr static auto pageNum = 99; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; @@ -267,16 +254,16 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesWithMarkerReturnSamePageMarker) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, 0); // return ownerdir when search by marker - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); boost::asio::spawn(ctx, [&, this](boost::asio::yield_context yield) { auto count = 0; auto ret = traverseOwnedNodes( - *mockBackendPtr, account, 9, limit, fmt::format("{},{}", INDEX1, pageNum), yield, [&](auto) { count++; } + *backend, account, 9, limit, fmt::format("{},{}", INDEX1, pageNum), yield, [&](auto) { count++; } ); auto cursor = std::get_if(&ret); EXPECT_TRUE(cursor != nullptr); @@ -290,14 +277,11 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesWithMarkerReturnSamePageMarker) // return invalid params error TEST_F(RPCHelpersTest, TraverseOwnedNodesWithUnexistingIndexMarker) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - auto account = GetAccountIDWithString(ACCOUNT); auto ownerDir2Kk = ripple::keylet::page(ripple::keylet::ownerDir(account), 99).key; constexpr static auto limit = 8; constexpr static auto pageNum = 99; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); int objectsCount = 10; ripple::STObject const channel1 = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -310,13 +294,13 @@ TEST_F(RPCHelpersTest, TraverseOwnedNodesWithUnexistingIndexMarker) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, 0); // return ownerdir when search by marker - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); boost::asio::spawn(ctx, [&, this](boost::asio::yield_context yield) { auto count = 0; auto ret = traverseOwnedNodes( - *mockBackendPtr, account, 9, limit, fmt::format("{},{}", INDEX2, pageNum), yield, [&](auto) { count++; } + *backend, account, 9, limit, fmt::format("{},{}", INDEX2, pageNum), yield, [&](auto) { count++; } ); auto status = std::get_if(&ret); EXPECT_TRUE(status != nullptr); @@ -443,7 +427,7 @@ TEST_F(RPCHelpersTest, DeliverMaxAliasV2) TEST_F(RPCHelpersTest, LedgerHeaderJson) { auto const ledgerHeader = CreateLedgerInfo(INDEX1, 30); - auto const binJson = toJson(ledgerHeader, true); + auto const binJson = toJson(ledgerHeader, true, 1u); auto constexpr EXPECTBIN = R"({ "ledger_data": "0000001E000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -469,7 +453,35 @@ TEST_F(RPCHelpersTest, LedgerHeaderJson) INDEX1, 30 ); - auto json = toJson(ledgerHeader, false); + auto json = toJson(ledgerHeader, false, 1u); + // remove platform-related close_time_human field + json.erase(JS(close_time_human)); + EXPECT_EQ(json, boost::json::parse(EXPECTJSON)); +} + +TEST_F(RPCHelpersTest, LedgerHeaderJsonV2) +{ + auto const ledgerHeader = CreateLedgerInfo(INDEX1, 30); + + auto const EXPECTJSON = fmt::format( + R"({{ + "account_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "close_flags": 0, + "close_time": 0, + "close_time_resolution": 0, + "close_time_iso": "2000-01-01T00:00:00Z", + "ledger_hash": "{}", + "ledger_index": {}, + "parent_close_time": 0, + "parent_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "total_coins": "0", + "transaction_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "closed": true + }})", + INDEX1, + 30 + ); + auto json = toJson(ledgerHeader, false, 2u); // remove platform-related close_time_human field json.erase(JS(close_time_human)); EXPECT_EQ(json, boost::json::parse(EXPECTJSON)); diff --git a/unittests/rpc/handlers/AccountChannelsTests.cpp b/unittests/rpc/handlers/AccountChannelsTests.cpp index ecbc101a6..8609aa8f4 100644 --- a/unittests/rpc/handlers/AccountChannelsTests.cpp +++ b/unittests/rpc/handlers/AccountChannelsTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountChannels.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -56,7 +55,7 @@ class RPCAccountChannelsHandlerTest : public HandlerBaseTest {}; TEST_F(RPCAccountChannelsHandlerTest, LimitNotInt) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -75,7 +74,7 @@ TEST_F(RPCAccountChannelsHandlerTest, LimitNotInt) TEST_F(RPCAccountChannelsHandlerTest, LimitNagetive) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -94,7 +93,7 @@ TEST_F(RPCAccountChannelsHandlerTest, LimitNagetive) TEST_F(RPCAccountChannelsHandlerTest, LimitZero) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -113,7 +112,7 @@ TEST_F(RPCAccountChannelsHandlerTest, LimitZero) TEST_F(RPCAccountChannelsHandlerTest, NonHexLedgerHash) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -134,7 +133,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonHexLedgerHash) TEST_F(RPCAccountChannelsHandlerTest, NonStringLedgerHash) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -155,7 +154,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonStringLedgerHash) TEST_F(RPCAccountChannelsHandlerTest, InvalidLedgerIndexString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -176,7 +175,7 @@ TEST_F(RPCAccountChannelsHandlerTest, InvalidLedgerIndexString) TEST_F(RPCAccountChannelsHandlerTest, MarkerNotString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -199,7 +198,7 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerNotString) TEST_F(RPCAccountChannelsHandlerTest, InvalidMarker) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -215,7 +214,7 @@ TEST_F(RPCAccountChannelsHandlerTest, InvalidMarker) EXPECT_EQ(err.at("error_message").as_string(), "Malformed cursor."); }); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -235,7 +234,7 @@ TEST_F(RPCAccountChannelsHandlerTest, InvalidMarker) TEST_F(RPCAccountChannelsHandlerTest, AccountInvalidFormat) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jp" })"); @@ -251,7 +250,7 @@ TEST_F(RPCAccountChannelsHandlerTest, AccountInvalidFormat) TEST_F(RPCAccountChannelsHandlerTest, AccountNotString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(R"({ "account": 12 })"); @@ -267,12 +266,10 @@ TEST_F(RPCAccountChannelsHandlerTest, AccountNotString) // error case ledger non exist via hash TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerHash) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); // mock fetchLedgerByHash return empty - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -283,7 +280,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerHash) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -296,13 +293,10 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerHash) // error case ledger non exist via index TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerStringIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -311,7 +305,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerStringIndex) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -322,13 +316,10 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerStringIndex) TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerIntIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -337,7 +328,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerIntIndex) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -350,14 +341,11 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerIntIndex) // idk why this case will happen in reality TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerHash2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerByHash return ledger but seq is 31 > 30 auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 31); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -367,7 +355,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerHash2) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -379,13 +367,10 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerHash2) // error case ledger > max seq via index TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerIndex2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // no need to check from db,call fetchLedgerBySequence 0 time // differ from previous logic - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(0); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(0); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -394,7 +379,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerIndex2) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -406,16 +391,13 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistLedgerViaLedgerIndex2) // error case account not exist TEST_F(RPCAccountChannelsHandlerTest, NonExistAccount) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return emtpy - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -425,7 +407,7 @@ TEST_F(RPCAccountChannelsHandlerTest, NonExistAccount) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -466,36 +448,34 @@ TEST_F(RPCAccountChannelsHandlerTest, DefaultParameterTest) } ] })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index containing 2 indexes ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return two payment channel objects std::vector bbs; ripple::STObject const channel1 = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); bbs.push_back(channel1.getSerializer().peekData()); bbs.push_back(channel1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -504,7 +484,7 @@ TEST_F(RPCAccountChannelsHandlerTest, DefaultParameterTest) ACCOUNT )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(correctOutput), *output); @@ -514,20 +494,17 @@ TEST_F(RPCAccountChannelsHandlerTest, DefaultParameterTest) // normal case : limit is used TEST_F(RPCAccountChannelsHandlerTest, UseLimit) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(3); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(3); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index std::vector indexes; @@ -542,15 +519,15 @@ TEST_F(RPCAccountChannelsHandlerTest, UseLimit) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); // it should not appear in return marker,marker is the current page ownerDir.setFieldU64(ripple::sfIndexNext, 99); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(7); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(7); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(3); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(3); runSpawn([this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -566,7 +543,7 @@ TEST_F(RPCAccountChannelsHandlerTest, UseLimit) }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -579,7 +556,7 @@ TEST_F(RPCAccountChannelsHandlerTest, UseLimit) }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountChannelsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountChannelsHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -595,20 +572,17 @@ TEST_F(RPCAccountChannelsHandlerTest, UseLimit) // normal case : destination is used TEST_F(RPCAccountChannelsHandlerTest, UseDestination) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index std::vector indexes; @@ -631,12 +605,12 @@ TEST_F(RPCAccountChannelsHandlerTest, UseDestination) } ripple::STObject const ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -648,7 +622,7 @@ TEST_F(RPCAccountChannelsHandlerTest, UseDestination) ACCOUNT3 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("channels").as_array().size(), 20); @@ -658,27 +632,24 @@ TEST_F(RPCAccountChannelsHandlerTest, UseDestination) // normal case : but the lines is emtpy TEST_F(RPCAccountChannelsHandlerTest, EmptyChannel) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const input = json::parse(fmt::format( R"({{ "account": "{}" @@ -686,7 +657,7 @@ TEST_F(RPCAccountChannelsHandlerTest, EmptyChannel) ACCOUNT )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("channels").as_array().size(), 0); @@ -733,28 +704,26 @@ TEST_F(RPCAccountChannelsHandlerTest, OptionalResponseField) } ] })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return two payment channel objects std::vector bbs; @@ -765,8 +734,8 @@ TEST_F(RPCAccountChannelsHandlerTest, OptionalResponseField) channel1.setFieldU32(ripple::sfDestinationTag, 400); bbs.push_back(channel1.getSerializer().peekData()); bbs.push_back(channel1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}" @@ -774,7 +743,7 @@ TEST_F(RPCAccountChannelsHandlerTest, OptionalResponseField) ACCOUNT )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(correctOutput), *output); @@ -784,10 +753,7 @@ TEST_F(RPCAccountChannelsHandlerTest, OptionalResponseField) // normal case : test marker output correct TEST_F(RPCAccountChannelsHandlerTest, MarkerOutput) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto ownerDirKk = ripple::keylet::ownerDir(account).key; @@ -795,12 +761,12 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerOutput) constexpr static auto limit = 15; auto ownerDir2Kk = ripple::keylet::page(ripple::keylet::ownerDir(account), nextPage).key; auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto fake = Blob{'f', 'a', 'k', 'e'}; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); std::vector bbs; ripple::STObject const channel1 = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -822,16 +788,16 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerOutput) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, nextPage); // first page 's next page is 99 - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); ripple::STObject ownerDir2 = CreateOwnerDirLedgerObject(indexes, INDEX1); // second page's next page is 0 ownerDir2.setFieldU64(ripple::sfIndexNext, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) .WillByDefault(Return(ownerDir2.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -842,7 +808,7 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerOutput) limit )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("marker").as_string().c_str(), fmt::format("{},{}", INDEX1, nextPage)); @@ -853,22 +819,19 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerOutput) // normal case : handler marker correctly TEST_F(RPCAccountChannelsHandlerTest, MarkerInput) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; constexpr static auto nextPage = 99; constexpr static auto limit = 15; auto ownerDirKk = ripple::keylet::page(ripple::keylet::ownerDir(account), nextPage).key; auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto fake = Blob{'f', 'a', 'k', 'e'}; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); std::vector bbs; ripple::STObject const channel1 = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -883,11 +846,11 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerInput) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -901,7 +864,7 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerInput) nextPage )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_TRUE((*output).as_object().if_contains("marker") == nullptr); @@ -913,36 +876,33 @@ TEST_F(RPCAccountChannelsHandlerTest, MarkerInput) TEST_F(RPCAccountChannelsHandlerTest, LimitLessThanMin) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index containing 2 indexes ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return two payment channel objects std::vector bbs; ripple::STObject const channel1 = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); bbs.push_back(channel1.getSerializer().peekData()); bbs.push_back(channel1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -953,7 +913,7 @@ TEST_F(RPCAccountChannelsHandlerTest, LimitLessThanMin) AccountChannelsHandler::LIMIT_MIN - 1 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("channels").as_array().size(), 2); @@ -963,36 +923,33 @@ TEST_F(RPCAccountChannelsHandlerTest, LimitLessThanMin) TEST_F(RPCAccountChannelsHandlerTest, LimitMoreThanMax) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index containing 2 indexes ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return two payment channel objects std::vector bbs; ripple::STObject const channel1 = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); bbs.push_back(channel1.getSerializer().peekData()); bbs.push_back(channel1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -1003,7 +960,7 @@ TEST_F(RPCAccountChannelsHandlerTest, LimitMoreThanMax) AccountChannelsHandler::LIMIT_MAX + 1 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountChannelsHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountChannelsHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("channels").as_array().size(), 2); diff --git a/unittests/rpc/handlers/AccountCurrenciesTests.cpp b/unittests/rpc/handlers/AccountCurrenciesTests.cpp index b42fd2b5a..6fb4e5ddf 100644 --- a/unittests/rpc/handlers/AccountCurrenciesTests.cpp +++ b/unittests/rpc/handlers/AccountCurrenciesTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountCurrencies.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -53,16 +52,13 @@ class RPCAccountCurrenciesHandlerTest : public HandlerBaseTest {}; TEST_F(RPCAccountCurrenciesHandlerTest, AccountNotExist) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -70,7 +66,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, AccountNotExist) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountCurrenciesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountCurrenciesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -82,13 +78,10 @@ TEST_F(RPCAccountCurrenciesHandlerTest, AccountNotExist) TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -96,7 +89,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaIntSequence) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountCurrenciesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountCurrenciesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -109,13 +102,11 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaIntSequence) TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaStringSequence) { auto constexpr seq = 12; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(12, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(12, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -125,7 +116,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaStringSequence) ACCOUNT, seq )); - auto const handler = AnyHandler{AccountCurrenciesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountCurrenciesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -137,13 +128,10 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaStringSequence) TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( @@ -154,7 +142,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaHash) ACCOUNT, LEDGERHASH )); - auto const handler = AnyHandler{AccountCurrenciesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountCurrenciesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -179,24 +167,22 @@ TEST_F(RPCAccountCurrenciesHandlerTest, DefaultParameter) "USD" ] })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(30, _)).WillByDefault(Return(ledgerinfo)); // return valid account auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // ACCOUNT can receive USD 10 from ACCOUNT2 and send USD 20 to ACCOUNT2, now // the balance is 100, ACCOUNT can only send USD to ACCOUNT2 @@ -212,15 +198,15 @@ TEST_F(RPCAccountCurrenciesHandlerTest, DefaultParameter) bbs.push_back(line2.getSerializer().peekData()); bbs.push_back(line3.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ "account":"{}" }})", ACCOUNT )); - auto const handler = AnyHandler{AccountCurrenciesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountCurrenciesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -230,29 +216,26 @@ TEST_F(RPCAccountCurrenciesHandlerTest, DefaultParameter) TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); // return valid account auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ "account":"{}", @@ -261,7 +244,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderHash) ACCOUNT, LEDGERHASH )); - auto const handler = AnyHandler{AccountCurrenciesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountCurrenciesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -270,31 +253,27 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderHash) TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderSeq) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto const ledgerSeq = 29; // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, ledgerSeq); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(ledgerSeq, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(ledgerSeq, _)).WillByDefault(Return(ledgerinfo)); // return valid account auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, ledgerSeq, _)) - .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, ledgerSeq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ "account":"{}", @@ -303,7 +282,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderSeq) ACCOUNT, ledgerSeq )); - auto const handler = AnyHandler{AccountCurrenciesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountCurrenciesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/AccountInfoTests.cpp b/unittests/rpc/handlers/AccountInfoTests.cpp index 98fbee62a..9a1990fc7 100644 --- a/unittests/rpc/handlers/AccountInfoTests.cpp +++ b/unittests/rpc/handlers/AccountInfoTests.cpp @@ -24,7 +24,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountInfo.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -120,7 +119,7 @@ TEST_P(AccountInfoParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2}); ASSERT_FALSE(output); @@ -136,11 +135,11 @@ TEST_F(AccountInfoParameterTest, ApiV1SignerListIsNotBool) static constexpr auto reqJson = R"( {"ident":"rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun", "signer_lists":1} )"; - auto* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence); + + EXPECT_CALL(*backend, fetchLedgerBySequence); + runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; auto const req = json::parse(reqJson); auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1}); ASSERT_FALSE(output); @@ -153,13 +152,11 @@ TEST_F(AccountInfoParameterTest, ApiV1SignerListIsNotBool) TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(10, 30); + + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -168,7 +165,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaIntSequence) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -180,13 +177,10 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaIntSequence) TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaStringSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::nullopt)); + ON_CALL(*backend, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::nullopt)); auto static const input = json::parse(fmt::format( R"({{ @@ -195,7 +189,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaStringSequence) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -207,13 +201,10 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaStringSequence) TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( @@ -224,7 +215,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaHash) ACCOUNT, LEDGERHASH )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -236,16 +227,13 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaHash) TEST_F(RPCAccountInfoHandlerTest, AccountNotExist) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -253,7 +241,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountNotExist) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -265,17 +253,14 @@ TEST_F(RPCAccountInfoHandlerTest, AccountNotExist) TEST_F(RPCAccountInfoHandlerTest, AccountInvalid) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); // return a valid ledger object but not account root - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -283,7 +268,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountInvalid) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -295,25 +280,22 @@ TEST_F(RPCAccountInfoHandlerTest, AccountInvalid) TEST_F(RPCAccountInfoHandlerTest, SignerListsInvalid) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; auto const accountRoot = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)) .WillByDefault(Return(accountRoot.getSerializer().peekData())); auto signersKey = ripple::keylet::signers(account).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(signersKey, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(signersKey, 30, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) .WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(4); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(4); auto static const input = json::parse(fmt::format( R"({{ @@ -322,7 +304,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsInvalid) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -401,25 +383,23 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV2) ACCOUNT2, LEDGERHASH ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; auto const accountRoot = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)) .WillByDefault(Return(accountRoot.getSerializer().peekData())); auto signersKey = ripple::keylet::signers(account).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(signersKey, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(signersKey, 30, _)) .WillByDefault(Return(CreateSignerLists({{ACCOUNT1, 1}, {ACCOUNT2, 1}}).getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) .WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(4); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(4); auto static const input = json::parse(fmt::format( R"({{ @@ -428,7 +408,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV2) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 2}); ASSERT_TRUE(output); @@ -505,25 +485,23 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV1) ACCOUNT2, LEDGERHASH ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; auto const accountRoot = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)) .WillByDefault(Return(accountRoot.getSerializer().peekData())); auto signersKey = ripple::keylet::signers(account).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(signersKey, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(signersKey, 30, _)) .WillByDefault(Return(CreateSignerLists({{ACCOUNT1, 1}, {ACCOUNT2, 1}}).getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) .WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(4); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(4); auto static const input = json::parse(fmt::format( R"({{ @@ -532,7 +510,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrueV1) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{.yield = yield, .apiVersion = 1}); ASSERT_TRUE(output); @@ -575,13 +553,11 @@ TEST_F(RPCAccountInfoHandlerTest, Flags) INDEX1, LEDGERHASH ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; @@ -596,11 +572,11 @@ TEST_F(RPCAccountInfoHandlerTest, Flags) INDEX1, 2 ); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)) .WillByDefault(Return(accountRoot.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) .WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto static const input = json::parse(fmt::format( R"({{ @@ -608,7 +584,7 @@ TEST_F(RPCAccountInfoHandlerTest, Flags) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -618,22 +594,19 @@ TEST_F(RPCAccountInfoHandlerTest, Flags) TEST_F(RPCAccountInfoHandlerTest, IdentAndSignerListsFalse) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; auto const accountRoot = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)) .WillByDefault(Return(accountRoot.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) .WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto static const input = json::parse(fmt::format( R"({{ @@ -641,7 +614,7 @@ TEST_F(RPCAccountInfoHandlerTest, IdentAndSignerListsFalse) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -688,13 +661,11 @@ TEST_F(RPCAccountInfoHandlerTest, DisallowIncoming) INDEX1, LEDGERHASH ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; @@ -710,11 +681,11 @@ TEST_F(RPCAccountInfoHandlerTest, DisallowIncoming) INDEX1, 2 ); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)) .WillByDefault(Return(accountRoot.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) .WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::DisallowIncoming}).getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto static const input = json::parse(fmt::format( R"({{ @@ -722,7 +693,7 @@ TEST_F(RPCAccountInfoHandlerTest, DisallowIncoming) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -766,13 +737,11 @@ TEST_F(RPCAccountInfoHandlerTest, Clawback) INDEX1, LEDGERHASH ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; @@ -787,11 +756,11 @@ TEST_F(RPCAccountInfoHandlerTest, Clawback) INDEX1, 2 ); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)) .WillByDefault(Return(accountRoot.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::amendments().key, 30, _)) .WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::Clawback}).getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto static const input = json::parse(fmt::format( R"({{ @@ -799,7 +768,7 @@ TEST_F(RPCAccountInfoHandlerTest, Clawback) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountInfoHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/AccountLinesTests.cpp b/unittests/rpc/handlers/AccountLinesTests.cpp index fdd88e687..7cbc698a1 100644 --- a/unittests/rpc/handlers/AccountLinesTests.cpp +++ b/unittests/rpc/handlers/AccountLinesTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountLines.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -62,7 +61,7 @@ class RPCAccountLinesHandlerTest : public HandlerBaseTest {}; TEST_F(RPCAccountLinesHandlerTest, NonHexLedgerHash) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -83,7 +82,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonHexLedgerHash) TEST_F(RPCAccountLinesHandlerTest, NonStringLedgerHash) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -104,7 +103,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonStringLedgerHash) TEST_F(RPCAccountLinesHandlerTest, InvalidLedgerIndexString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -125,7 +124,7 @@ TEST_F(RPCAccountLinesHandlerTest, InvalidLedgerIndexString) TEST_F(RPCAccountLinesHandlerTest, MarkerNotString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -148,7 +147,7 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerNotString) TEST_F(RPCAccountLinesHandlerTest, InvalidMarker) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -164,7 +163,7 @@ TEST_F(RPCAccountLinesHandlerTest, InvalidMarker) EXPECT_EQ(err.at("error_message").as_string(), "Malformed cursor."); }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -184,7 +183,7 @@ TEST_F(RPCAccountLinesHandlerTest, InvalidMarker) TEST_F(RPCAccountLinesHandlerTest, AccountInvalidFormat) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse( R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jp" @@ -202,7 +201,7 @@ TEST_F(RPCAccountLinesHandlerTest, AccountInvalidFormat) TEST_F(RPCAccountLinesHandlerTest, AccountNotString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse( R"({ "account": 12 @@ -220,7 +219,7 @@ TEST_F(RPCAccountLinesHandlerTest, AccountNotString) TEST_F(RPCAccountLinesHandlerTest, PeerInvalidFormat) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse( R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", @@ -238,7 +237,7 @@ TEST_F(RPCAccountLinesHandlerTest, PeerInvalidFormat) TEST_F(RPCAccountLinesHandlerTest, PeerNotString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse( R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", @@ -257,7 +256,7 @@ TEST_F(RPCAccountLinesHandlerTest, PeerNotString) TEST_F(RPCAccountLinesHandlerTest, LimitNotInt) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse( R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", @@ -275,7 +274,7 @@ TEST_F(RPCAccountLinesHandlerTest, LimitNotInt) TEST_F(RPCAccountLinesHandlerTest, LimitNagetive) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse( R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", @@ -293,7 +292,7 @@ TEST_F(RPCAccountLinesHandlerTest, LimitNagetive) TEST_F(RPCAccountLinesHandlerTest, LimitZero) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse( R"({ "account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", @@ -311,12 +310,10 @@ TEST_F(RPCAccountLinesHandlerTest, LimitZero) // error case ledger non exist via hash TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerHash) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); // mock fetchLedgerByHash return empty - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -327,7 +324,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerHash) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -340,13 +337,10 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerHash) // error case ledger non exist via index TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerStringIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -355,7 +349,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerStringIndex) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -366,13 +360,10 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerStringIndex) TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerIntIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -381,7 +372,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerIntIndex) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -394,14 +385,11 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerIntIndex) // idk why this case will happen in reality TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerHash2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerByHash return ledger but seq is 31 > 30 auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 31); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -411,7 +399,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerHash2) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -423,13 +411,10 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerHash2) // error case ledger > max seq via index TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerIndex2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // no need to check from db, call fetchLedgerBySequence 0 time // differ from previous logic - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(0); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(0); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -438,7 +423,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerIndex2) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -450,16 +435,13 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistLedgerViaLedgerIndex2) // error case account not exist TEST_F(RPCAccountLinesHandlerTest, NonExistAccount) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return emtpy - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -469,7 +451,7 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistAccount) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -481,28 +463,25 @@ TEST_F(RPCAccountLinesHandlerTest, NonExistAccount) // normal case when only provide account TEST_F(RPCAccountLinesHandlerTest, DefaultParameterTest) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index containing 2 indexes ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return two trust lines std::vector bbs; @@ -510,8 +489,8 @@ TEST_F(RPCAccountLinesHandlerTest, DefaultParameterTest) auto const line2 = CreateRippleStateLedgerObject("USD", ACCOUNT, 10, ACCOUNT2, 100, ACCOUNT, 200, TXNID, 123); bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([this](auto yield) { auto const input = json::parse(fmt::format( @@ -553,7 +532,7 @@ TEST_F(RPCAccountLinesHandlerTest, DefaultParameterTest) ] })"; - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(correctOutput), *output); @@ -563,20 +542,17 @@ TEST_F(RPCAccountLinesHandlerTest, DefaultParameterTest) // normal case : limit is used TEST_F(RPCAccountLinesHandlerTest, UseLimit) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(3); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(3); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index std::vector indexes; @@ -591,15 +567,15 @@ TEST_F(RPCAccountLinesHandlerTest, UseLimit) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); // it should not appear in return marker,marker is the current page ownerDir.setFieldU64(ripple::sfIndexNext, 99); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(7); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(7); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(3); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(3); runSpawn([this](auto yield) { - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -615,7 +591,7 @@ TEST_F(RPCAccountLinesHandlerTest, UseLimit) }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -628,7 +604,7 @@ TEST_F(RPCAccountLinesHandlerTest, UseLimit) }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{AccountLinesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountLinesHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -644,20 +620,17 @@ TEST_F(RPCAccountLinesHandlerTest, UseLimit) // normal case : destination is used TEST_F(RPCAccountLinesHandlerTest, UseDestination) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index std::vector indexes; @@ -680,12 +653,12 @@ TEST_F(RPCAccountLinesHandlerTest, UseDestination) } ripple::STObject const ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -697,7 +670,7 @@ TEST_F(RPCAccountLinesHandlerTest, UseDestination) ACCOUNT3 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("lines").as_array().size(), 20); @@ -707,27 +680,24 @@ TEST_F(RPCAccountLinesHandlerTest, UseDestination) // normal case : but the lines is emtpy TEST_F(RPCAccountLinesHandlerTest, EmptyChannel) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const input = json::parse(fmt::format( R"({{ "account": "{}" @@ -735,7 +705,7 @@ TEST_F(RPCAccountLinesHandlerTest, EmptyChannel) ACCOUNT )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("lines").as_array().size(), 0); @@ -779,13 +749,11 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField) } ] })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; @@ -793,15 +761,15 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField) auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return few trust lines std::vector bbs; @@ -817,8 +785,8 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField) line2.setFlag(ripple::lsfLowFreeze); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}" @@ -826,7 +794,7 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField) ACCOUNT )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(correctOutput), *output); @@ -836,10 +804,7 @@ TEST_F(RPCAccountLinesHandlerTest, OptionalResponseField) // normal case : test marker output correct TEST_F(RPCAccountLinesHandlerTest, MarkerOutput) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto ownerDirKk = ripple::keylet::ownerDir(account).key; @@ -847,12 +812,12 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerOutput) constexpr static auto limit = 15; auto ownerDir2Kk = ripple::keylet::page(ripple::keylet::ownerDir(account), nextPage).key; auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto fake = Blob{'f', 'a', 'k', 'e'}; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); std::vector bbs; auto line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 0); @@ -875,16 +840,16 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerOutput) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, nextPage); // first page's next page is 99 - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); ripple::STObject ownerDir2 = CreateOwnerDirLedgerObject(indexes, INDEX1); // second page's next page is 0 ownerDir2.setFieldU64(ripple::sfIndexNext, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDir2Kk, testing::_, testing::_)) .WillByDefault(Return(ownerDir2.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -895,7 +860,7 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerOutput) limit )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ((*output).as_object().at("marker").as_string().c_str(), fmt::format("{},{}", INDEX1, nextPage)); @@ -906,22 +871,19 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerOutput) // normal case : handler marker correctly TEST_F(RPCAccountLinesHandlerTest, MarkerInput) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; constexpr static auto nextPage = 99; constexpr static auto limit = 15; auto ownerDirKk = ripple::keylet::page(ripple::keylet::ownerDir(account), nextPage).key; auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto fake = Blob{'f', 'a', 'k', 'e'}; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); std::vector bbs; auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 0); @@ -936,11 +898,11 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerInput) ripple::STObject ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); ownerDir.setFieldU64(ripple::sfIndexNext, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -954,7 +916,7 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerInput) nextPage )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_TRUE((*output).as_object().if_contains("marker") == nullptr); @@ -966,28 +928,25 @@ TEST_F(RPCAccountLinesHandlerTest, MarkerInput) TEST_F(RPCAccountLinesHandlerTest, LimitLessThanMin) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index containing 2 indexes ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return two trust lines std::vector bbs; @@ -995,8 +954,8 @@ TEST_F(RPCAccountLinesHandlerTest, LimitLessThanMin) auto const line2 = CreateRippleStateLedgerObject("USD", ACCOUNT, 10, ACCOUNT2, 100, ACCOUNT, 200, TXNID, 123); bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([this](auto yield) { auto const input = json::parse(fmt::format( @@ -1042,7 +1001,7 @@ TEST_F(RPCAccountLinesHandlerTest, LimitLessThanMin) AccountLinesHandler::LIMIT_MIN ); - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(correctOutput), *output); @@ -1051,28 +1010,25 @@ TEST_F(RPCAccountLinesHandlerTest, LimitLessThanMin) TEST_F(RPCAccountLinesHandlerTest, LimitMoreThanMax) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch account object return something auto account = GetAccountIDWithString(ACCOUNT); auto accountKk = ripple::keylet::account(account).key; auto owneDirKk = ripple::keylet::ownerDir(account).key; auto fake = Blob{'f', 'a', 'k', 'e'}; // return a non empty account - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, testing::_, testing::_)).WillByDefault(Return(fake)); // return owner index containing 2 indexes ripple::STObject const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(owneDirKk, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // return two trust lines std::vector bbs; @@ -1080,8 +1036,8 @@ TEST_F(RPCAccountLinesHandlerTest, LimitMoreThanMax) auto const line2 = CreateRippleStateLedgerObject("USD", ACCOUNT, 10, ACCOUNT2, 100, ACCOUNT, 200, TXNID, 123); bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([this](auto yield) { auto const input = json::parse(fmt::format( @@ -1127,7 +1083,7 @@ TEST_F(RPCAccountLinesHandlerTest, LimitMoreThanMax) AccountLinesHandler::LIMIT_MAX ); - auto handler = AnyHandler{AccountLinesHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{AccountLinesHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(correctOutput), *output); diff --git a/unittests/rpc/handlers/AccountNFTsTests.cpp b/unittests/rpc/handlers/AccountNFTsTests.cpp index 45f08cda8..05bf4c733 100644 --- a/unittests/rpc/handlers/AccountNFTsTests.cpp +++ b/unittests/rpc/handlers/AccountNFTsTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountNFTs.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -163,7 +162,7 @@ TEST_P(AccountNFTParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -175,13 +174,10 @@ TEST_P(AccountNFTParameterTest, InvalidParams) TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(MINSEQ, MAXSEQ); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( @@ -192,7 +188,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaHash) ACCOUNT, LEDGERHASH )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -205,13 +201,11 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaHash) TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaStringIndex) { auto constexpr seq = 12; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(MINSEQ, MAXSEQ); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -221,7 +215,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaStringIndex) ACCOUNT, seq )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -234,13 +228,11 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaStringIndex) TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaIntIndex) { auto constexpr seq = 12; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(MINSEQ, MAXSEQ); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -250,7 +242,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaIntIndex) ACCOUNT, seq )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -262,16 +254,13 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaIntIndex) TEST_F(RPCAccountNFTsHandlerTest, AccountNotFound) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -279,7 +268,7 @@ TEST_F(RPCAccountNFTsHandlerTest, AccountNotFound) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -318,25 +307,23 @@ TEST_F(RPCAccountNFTsHandlerTest, NormalPath) TAXON, SERIAL ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); + + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountObject = CreateAccountRootObject(ACCOUNT, 0, 1, 10, 2, TXNID, 3); auto const accountID = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) .WillByDefault(Return(accountObject.getSerializer().peekData())); auto const firstPage = ripple::keylet::nftpage_max(accountID).key; auto const pageObject = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(firstPage, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(firstPage, 30, _)) .WillByDefault(Return(pageObject.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto static const input = json::parse(fmt::format( R"({{ @@ -344,7 +331,7 @@ TEST_F(RPCAccountNFTsHandlerTest, NormalPath) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -355,25 +342,23 @@ TEST_F(RPCAccountNFTsHandlerTest, NormalPath) TEST_F(RPCAccountNFTsHandlerTest, Limit) { static auto constexpr limit = 20; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); + + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountObject = CreateAccountRootObject(ACCOUNT, 0, 1, 10, 2, TXNID, 3); auto const accountID = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) .WillByDefault(Return(accountObject.getSerializer().peekData())); auto const firstPage = ripple::keylet::nftpage_max(accountID).key; auto const pageObject = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, firstPage); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(firstPage, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(firstPage, 30, _)) .WillByDefault(Return(pageObject.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1 + limit); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1 + limit); auto static const input = json::parse(fmt::format( R"({{ @@ -383,7 +368,7 @@ TEST_F(RPCAccountNFTsHandlerTest, Limit) ACCOUNT, limit )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -394,24 +379,21 @@ TEST_F(RPCAccountNFTsHandlerTest, Limit) TEST_F(RPCAccountNFTsHandlerTest, Marker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountObject = CreateAccountRootObject(ACCOUNT, 0, 1, 10, 2, TXNID, 3); auto const accountID = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) .WillByDefault(Return(accountObject.getSerializer().peekData())); auto const pageObject = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{PAGE}, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{PAGE}, 30, _)) .WillByDefault(Return(pageObject.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto static const input = json::parse(fmt::format( R"({{ @@ -421,7 +403,7 @@ TEST_F(RPCAccountNFTsHandlerTest, Marker) ACCOUNT, PAGE )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -459,25 +441,23 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitLessThanMin) SERIAL, AccountNFTsHandler::LIMIT_MIN ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); + + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountObject = CreateAccountRootObject(ACCOUNT, 0, 1, 10, 2, TXNID, 3); auto const accountID = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) .WillByDefault(Return(accountObject.getSerializer().peekData())); auto const firstPage = ripple::keylet::nftpage_max(accountID).key; auto const pageObject = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(firstPage, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(firstPage, 30, _)) .WillByDefault(Return(pageObject.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto static const input = json::parse(fmt::format( R"({{ @@ -487,7 +467,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitLessThanMin) ACCOUNT, AccountNFTsHandler::LIMIT_MIN - 1 )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -525,25 +505,23 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitMoreThanMax) SERIAL, AccountNFTsHandler::LIMIT_MAX ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); + + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountObject = CreateAccountRootObject(ACCOUNT, 0, 1, 10, 2, TXNID, 3); auto const accountID = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(accountID).key, 30, _)) .WillByDefault(Return(accountObject.getSerializer().peekData())); auto const firstPage = ripple::keylet::nftpage_max(accountID).key; auto const pageObject = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(firstPage, 30, _)) + ON_CALL(*backend, doFetchLedgerObject(firstPage, 30, _)) .WillByDefault(Return(pageObject.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto static const input = json::parse(fmt::format( R"({{ @@ -553,7 +531,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitMoreThanMax) ACCOUNT, AccountNFTsHandler::LIMIT_MAX + 1 )); - auto const handler = AnyHandler{AccountNFTsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountNFTsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/AccountObjectsTests.cpp b/unittests/rpc/handlers/AccountObjectsTests.cpp index 1ffec30cf..492db5612 100644 --- a/unittests/rpc/handlers/AccountObjectsTests.cpp +++ b/unittests/rpc/handlers/AccountObjectsTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountObjects.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -188,7 +187,7 @@ TEST_P(AccountObjectsParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -200,12 +199,9 @@ TEST_P(AccountObjectsParameterTest, InvalidParams) TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); // return empty ledgerinfo - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillOnce(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillOnce(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -214,7 +210,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaIntSequence) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -226,12 +222,9 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaIntSequence) TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaStringSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); // return empty ledgerinfo - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillOnce(Return(std::nullopt)); auto static const input = json::parse(fmt::format( R"({{ @@ -240,7 +233,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaStringSequence) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -252,12 +245,9 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaStringSequence) TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); // return empty ledgerinfo - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + EXPECT_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillOnce(Return(std::optional{})); auto static const input = json::parse(fmt::format( @@ -268,7 +258,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaHash) ACCOUNT, LEDGERHASH )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -280,14 +270,11 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaHash) TEST_F(RPCAccountObjectsHandlerTest, AccountNotExist) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -295,7 +282,7 @@ TEST_F(RPCAccountObjectsHandlerTest, AccountNotExist) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -339,31 +326,27 @@ TEST_F(RPCAccountObjectsHandlerTest, DefaultParameterNoNFTFound) ] })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -372,7 +355,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DefaultParameterNoNFTFound) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -382,35 +365,31 @@ TEST_F(RPCAccountObjectsHandlerTest, DefaultParameterNoNFTFound) TEST_F(RPCAccountObjectsHandlerTest, Limit) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); static auto constexpr limit = 10; auto count = limit * 2; // put 20 items in owner dir, but only return 10 auto const ownerDir = CreateOwnerDirLedgerObject(std::vector(count, ripple::uint256{INDEX1}), INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; while (count-- != 0) { auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); } - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -421,7 +400,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Limit) limit )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -432,15 +411,12 @@ TEST_F(RPCAccountObjectsHandlerTest, Limit) TEST_F(RPCAccountObjectsHandlerTest, Marker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); static auto constexpr limit = 20; static auto constexpr page = 2; @@ -448,7 +424,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Marker) auto const ownerDir = CreateOwnerDirLedgerObject(std::vector(count, ripple::uint256{INDEX1}), INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; auto const hintIndex = ripple::keylet::page(ownerDirKk, page).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(hintIndex, 30, _)) + EXPECT_CALL(*backend, doFetchLedgerObject(hintIndex, 30, _)) .Times(2) .WillRepeatedly(Return(ownerDir.getSerializer().peekData())); @@ -457,7 +433,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Marker) auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); } - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -469,7 +445,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Marker) page )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -480,16 +456,13 @@ TEST_F(RPCAccountObjectsHandlerTest, Marker) TEST_F(RPCAccountObjectsHandlerTest, MultipleDirNoNFT) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); static auto constexpr count = 10; static auto constexpr nextpage = 1; @@ -499,14 +472,12 @@ TEST_F(RPCAccountObjectsHandlerTest, MultipleDirNoNFT) ownerDir.setFieldU64(ripple::sfIndexNext, nextpage); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; auto const page1 = ripple::keylet::page(ownerDirKk, nextpage).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(page1, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(page1, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; // 10 items per page, 2 pages @@ -515,7 +486,7 @@ TEST_F(RPCAccountObjectsHandlerTest, MultipleDirNoNFT) auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); } - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -526,7 +497,7 @@ TEST_F(RPCAccountObjectsHandlerTest, MultipleDirNoNFT) 2 * count )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -537,25 +508,21 @@ TEST_F(RPCAccountObjectsHandlerTest, MultipleDirNoNFT) TEST_F(RPCAccountObjectsHandlerTest, TypeFilter) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; // put 1 state and 1 offer @@ -573,7 +540,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilter) bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -583,7 +550,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilter) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -593,25 +560,21 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilter) TEST_F(RPCAccountObjectsHandlerTest, TypeFilterAmmType) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; // put 1 state and 1 amm @@ -621,7 +584,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterAmmType) auto const ammObject = CreateAMMObject(ACCOUNT, "XRP", toBase58(ripple::xrpAccount()), "JPY", ACCOUNT2); bbs.push_back(ammObject.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -631,7 +594,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterAmmType) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -643,25 +606,21 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterAmmType) TEST_F(RPCAccountObjectsHandlerTest, TypeFilterReturnEmpty) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); @@ -678,7 +637,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterReturnEmpty) bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -688,7 +647,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterReturnEmpty) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -698,28 +657,23 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterReturnEmpty) TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilter) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); auto const line = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); auto const channel = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -739,7 +693,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilter) bbs.push_back(channel.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -749,7 +703,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilter) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -759,27 +713,22 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilter) TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithTypeFilter) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); auto const line = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); auto const channel = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -788,7 +737,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithTypeFilter) bbs.push_back(line.getSerializer().peekData()); bbs.push_back(channel.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -799,7 +748,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithTypeFilter) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -809,27 +758,22 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithTypeFilter) TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterEmptyResult) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); auto const offer1 = CreateOfferLedgerObject( ACCOUNT, @@ -856,7 +800,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterEmptyResult) bbs.push_back(offer1.getSerializer().peekData()); bbs.push_back(offer2.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -866,7 +810,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterEmptyResult) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -876,26 +820,21 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterEmptyResult) TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithIncompatibleTypeYieldsEmptyResult) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); auto const offer1 = CreateOfferLedgerObject( ACCOUNT, @@ -922,7 +861,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithIncompatibleT bbs.push_back(offer1.getSerializer().peekData()); bbs.push_back(offer2.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -933,7 +872,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithIncompatibleT ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1006,41 +945,35 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMixOtherObjects) ] })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft page 1 auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; auto const nftPage2KK = ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{INDEX1}).key; auto const nftpage1 = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, nftPage2KK); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)) - .WillOnce(Return(nftpage1.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(nftpage1.getSerializer().peekData())); // nft page 2 , end auto const nftpage2 = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftPage2KK, 30, _)) - .WillOnce(Return(nftpage2.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(nftPage2KK, 30, _)).WillOnce(Return(nftpage2.getSerializer().peekData())); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1049,7 +982,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMixOtherObjects) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1059,16 +992,13 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMixOtherObjects) TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitReturnMarker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto current = ripple::keylet::nftpage_max(account).key; std::string first{INDEX1}; @@ -1079,8 +1009,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitReturnMarker) ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{first.c_str()}).key; auto const nftpage = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, previous); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(current, 30, _)) - .WillOnce(Return(nftpage.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(current, 30, _)).WillOnce(Return(nftpage.getSerializer().peekData())); current = previous; } @@ -1093,7 +1022,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitReturnMarker) 10 )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1107,16 +1036,13 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitReturnMarker) TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitNoMarker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto current = ripple::keylet::nftpage_max(account).key; std::string first{INDEX1}; @@ -1127,14 +1053,12 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitNoMarker) ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{first.c_str()}).key; auto const nftpage = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, previous); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(current, 30, _)) - .WillOnce(Return(nftpage.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(current, 30, _)).WillOnce(Return(nftpage.getSerializer().peekData())); current = previous; } auto const nftpage11 = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(current, 30, _)) - .WillOnce(Return(nftpage11.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(current, 30, _)).WillOnce(Return(nftpage11.getSerializer().peekData())); auto static const input = json::parse(fmt::format( R"({{ @@ -1145,7 +1069,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitNoMarker) 11 )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1160,16 +1084,13 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitNoMarker) TEST_F(RPCAccountObjectsHandlerTest, NFTMarker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); std::string first{INDEX1}; auto current = ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{first.c_str()}).key; @@ -1181,20 +1102,17 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarker) ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{first.c_str()}).key; auto const nftpage = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, previous); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(current, 30, _)) - .WillOnce(Return(nftpage.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(current, 30, _)).WillOnce(Return(nftpage.getSerializer().peekData())); current = previous; } auto const nftpage11 = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(current, 30, _)) - .WillOnce(Return(nftpage11.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(current, 30, _)).WillOnce(Return(nftpage11.getSerializer().peekData())); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); auto const line = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); auto const channel = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -1214,7 +1132,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarker) bbs.push_back(channel.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1226,7 +1144,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarker) std::numeric_limits::max() )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1238,22 +1156,18 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarker) // when limit reached, happen to be the end of NFT page list TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNoMoreNFT) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); auto const line = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); auto const channel = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -1273,7 +1187,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNoMoreNFT) bbs.push_back(channel.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1285,7 +1199,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNoMoreNFT) std::numeric_limits::max() )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1296,16 +1210,13 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNoMoreNFT) TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotInRange) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto static const input = json::parse(fmt::format( R"({{ @@ -1317,7 +1228,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotInRange) std::numeric_limits::max() )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -1329,20 +1240,17 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotInRange) TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotExist) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); // return null for this marker auto const accountNftMax = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountNftMax, MAXSEQ, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(accountNftMax, MAXSEQ, _)).WillOnce(Return(std::nullopt)); auto static const input = json::parse(fmt::format( R"({{ @@ -1354,7 +1262,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotExist) std::numeric_limits::max() )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -1366,16 +1274,13 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotExist) TEST_F(RPCAccountObjectsHandlerTest, NFTLimitAdjust) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); std::string first{INDEX1}; auto current = ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{first.c_str()}).key; @@ -1387,19 +1292,16 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTLimitAdjust) ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{first.c_str()}).key; auto const nftpage = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, previous); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(current, 30, _)) - .WillOnce(Return(nftpage.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(current, 30, _)).WillOnce(Return(nftpage.getSerializer().peekData())); current = previous; } auto const nftpage11 = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(current, 30, _)) - .WillOnce(Return(nftpage11.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(current, 30, _)).WillOnce(Return(nftpage11.getSerializer().peekData())); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); auto const line = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); auto const channel = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 10, 32, TXNID, 28); @@ -1419,7 +1321,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTLimitAdjust) bbs.push_back(channel.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1432,7 +1334,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTLimitAdjust) std::numeric_limits::max() )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1485,41 +1387,35 @@ TEST_F(RPCAccountObjectsHandlerTest, FilterNFT) ] })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft page 1 auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; auto const nftPage2KK = ripple::keylet::nftpage(ripple::keylet::nftpage_min(account), ripple::uint256{INDEX1}).key; auto const nftpage1 = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, nftPage2KK); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)) - .WillOnce(Return(nftpage1.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(nftpage1.getSerializer().peekData())); // nft page 2 , end auto const nftpage2 = CreateNFTTokenPage(std::vector{std::make_pair(TOKENID, "www.ok.com")}, std::nullopt); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftPage2KK, 30, _)) - .WillOnce(Return(nftpage2.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(nftPage2KK, 30, _)).WillOnce(Return(nftpage2.getSerializer().peekData())); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1529,7 +1425,7 @@ TEST_F(RPCAccountObjectsHandlerTest, FilterNFT) ACCOUNT )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1539,31 +1435,27 @@ TEST_F(RPCAccountObjectsHandlerTest, FilterNFT) TEST_F(RPCAccountObjectsHandlerTest, NFTZeroMarkerNotAffectOtherMarker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); static auto constexpr limit = 10; auto count = limit * 2; // put 20 items in owner dir, but only return 10 auto const ownerDir = CreateOwnerDirLedgerObject(std::vector(count, ripple::uint256{INDEX1}), INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); std::vector bbs; while (count-- != 0) { auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); } - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1577,7 +1469,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTZeroMarkerNotAffectOtherMarker) std::numeric_limits::max() )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1623,31 +1515,27 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitLessThanMin) AccountObjectsHandler::LIMIT_MIN ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1658,7 +1546,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitLessThanMin) AccountObjectsHandler::LIMIT_MIN - 1 )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1703,31 +1591,27 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitMoreThanMax) AccountObjectsHandler::LIMIT_MAX ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const account = GetAccountIDWithString(ACCOUNT); auto const accountKk = ripple::keylet::account(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); + EXPECT_CALL(*backend, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillOnce(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, 30, _)) - .WillOnce(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject(ownerDirKk, 30, _)).WillOnce(Return(ownerDir.getSerializer().peekData())); // nft null auto const nftMaxKK = ripple::keylet::nftpage_max(account).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject(nftMaxKK, 30, _)).WillOnce(Return(std::nullopt)); std::vector bbs; auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); bbs.push_back(line1.getSerializer().peekData()); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).WillOnce(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); auto static const input = json::parse(fmt::format( R"({{ @@ -1738,7 +1622,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitMoreThanMax) AccountObjectsHandler::LIMIT_MAX + 1 )); - auto const handler = AnyHandler{AccountObjectsHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountObjectsHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/AccountOffersTests.cpp b/unittests/rpc/handlers/AccountOffersTests.cpp index d5dd438d9..2fef7bcde 100644 --- a/unittests/rpc/handlers/AccountOffersTests.cpp +++ b/unittests/rpc/handlers/AccountOffersTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountOffers.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -157,7 +156,7 @@ TEST_P(AccountOfferParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -169,13 +168,10 @@ TEST_P(AccountOfferParameterTest, InvalidParams) TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( @@ -186,7 +182,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaHash) ACCOUNT, LEDGERHASH )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -199,13 +195,11 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaHash) TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaStringIndex) { auto constexpr seq = 12; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -215,7 +209,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaStringIndex) ACCOUNT, seq )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -228,13 +222,11 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaStringIndex) TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaIntIndex) { auto constexpr seq = 12; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -244,7 +236,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaIntIndex) ACCOUNT, seq )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -256,16 +248,13 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaIntIndex) TEST_F(RPCAccountOffersHandlerTest, AccountNotFound) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -273,7 +262,7 @@ TEST_F(RPCAccountOffersHandlerTest, AccountNotFound) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -313,23 +302,20 @@ TEST_F(RPCAccountOffersHandlerTest, DefaultParams) ACCOUNT2 ); auto constexpr ledgerSeq = 30; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(ledgerSeq); // max + + backend->setRange(10, ledgerSeq); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, ledgerSeq); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, ledgerSeq, _)) - .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, ledgerSeq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; auto offer = CreateOfferLedgerObject( @@ -345,8 +331,8 @@ TEST_F(RPCAccountOffersHandlerTest, DefaultParams) offer.setFieldU32(ripple::sfExpiration, 123); bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -354,7 +340,7 @@ TEST_F(RPCAccountOffersHandlerTest, DefaultParams) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -365,23 +351,20 @@ TEST_F(RPCAccountOffersHandlerTest, DefaultParams) TEST_F(RPCAccountOffersHandlerTest, Limit) { auto constexpr ledgerSeq = 30; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(ledgerSeq); // max + + backend->setRange(10, ledgerSeq); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, ledgerSeq); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, ledgerSeq, _)) - .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, ledgerSeq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{20, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; for (auto i = 0; i < 20; i++) { @@ -397,8 +380,8 @@ TEST_F(RPCAccountOffersHandlerTest, Limit) ); bbs.push_back(offer.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -407,7 +390,7 @@ TEST_F(RPCAccountOffersHandlerTest, Limit) }})", ACCOUNT )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -419,26 +402,23 @@ TEST_F(RPCAccountOffersHandlerTest, Limit) TEST_F(RPCAccountOffersHandlerTest, Marker) { auto constexpr ledgerSeq = 30; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(ledgerSeq); // max + + backend->setRange(10, ledgerSeq); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, ledgerSeq); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, ledgerSeq, _)) - .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, ledgerSeq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const startPage = 2; auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{20, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; auto const hintIndex = ripple::keylet::page(ownerDirKk, startPage).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(hintIndex, ledgerSeq, _)) + ON_CALL(*backend, doFetchLedgerObject(hintIndex, ledgerSeq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); std::vector bbs; for (auto i = 0; i < 20; i++) { @@ -454,8 +434,8 @@ TEST_F(RPCAccountOffersHandlerTest, Marker) ); bbs.push_back(offer.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -466,7 +446,7 @@ TEST_F(RPCAccountOffersHandlerTest, Marker) INDEX1, startPage )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -478,24 +458,21 @@ TEST_F(RPCAccountOffersHandlerTest, Marker) TEST_F(RPCAccountOffersHandlerTest, MarkerNotExists) { auto constexpr ledgerSeq = 30; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(ledgerSeq); // max + + backend->setRange(10, ledgerSeq); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, ledgerSeq); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, ledgerSeq, _)) - .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, ledgerSeq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const startPage = 2; auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; auto const hintIndex = ripple::keylet::page(ownerDirKk, startPage).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(hintIndex, ledgerSeq, _)).WillByDefault(Return(std::nullopt)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + ON_CALL(*backend, doFetchLedgerObject(hintIndex, ledgerSeq, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto static const input = json::parse(fmt::format( R"({{ @@ -506,7 +483,7 @@ TEST_F(RPCAccountOffersHandlerTest, MarkerNotExists) INDEX1, startPage )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -519,24 +496,21 @@ TEST_F(RPCAccountOffersHandlerTest, MarkerNotExists) TEST_F(RPCAccountOffersHandlerTest, LimitLessThanMin) { auto constexpr ledgerSeq = 30; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(ledgerSeq); // max + + backend->setRange(10, ledgerSeq); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, ledgerSeq); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, ledgerSeq, _)) - .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, ledgerSeq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{AccountOffersHandler::LIMIT_MIN + 1, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; auto offer = CreateOfferLedgerObject( @@ -555,8 +529,8 @@ TEST_F(RPCAccountOffersHandlerTest, LimitLessThanMin) for (auto i = 0; i < AccountOffersHandler::LIMIT_MIN + 1; i++) bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -566,7 +540,7 @@ TEST_F(RPCAccountOffersHandlerTest, LimitLessThanMin) ACCOUNT, AccountOffersHandler::LIMIT_MIN - 1 )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -577,25 +551,22 @@ TEST_F(RPCAccountOffersHandlerTest, LimitLessThanMin) TEST_F(RPCAccountOffersHandlerTest, LimitMoreThanMax) { auto constexpr ledgerSeq = 30; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(ledgerSeq); // max + + backend->setRange(10, ledgerSeq); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, ledgerSeq); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, ledgerSeq, _)) - .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, ledgerSeq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{AccountOffersHandler::LIMIT_MAX + 1, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, ledgerSeq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; auto offer = CreateOfferLedgerObject( @@ -613,8 +584,8 @@ TEST_F(RPCAccountOffersHandlerTest, LimitMoreThanMax) for (auto i = 0; i < AccountOffersHandler::LIMIT_MAX + 1; i++) bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -624,7 +595,7 @@ TEST_F(RPCAccountOffersHandlerTest, LimitMoreThanMax) ACCOUNT, AccountOffersHandler::LIMIT_MAX + 1 )); - auto const handler = AnyHandler{AccountOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountOffersHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/AccountTxTests.cpp b/unittests/rpc/handlers/AccountTxTests.cpp index 39f5a4f6b..a81dbc0da 100644 --- a/unittests/rpc/handlers/AccountTxTests.cpp +++ b/unittests/rpc/handlers/AccountTxTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/AccountTx.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -398,17 +397,15 @@ INSTANTIATE_TEST_CASE_P( TEST_P(AccountTxParameterTest, CheckParams) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const& testBundle = GetParam(); - auto* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + auto const req = json::parse(testBundle.testJson); if (testBundle.expectedError.has_value()) { ASSERT_TRUE(testBundle.expectedErrorMessage.has_value()); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const output = handler.process(req, Context{.yield = yield, .apiVersion = testBundle.apiVersion}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -416,10 +413,10 @@ TEST_P(AccountTxParameterTest, CheckParams) EXPECT_EQ(err.at("error_message").as_string(), *testBundle.expectedErrorMessage); }); } else { - EXPECT_CALL(*rawBackendPtr, fetchAccountTransactions); + EXPECT_CALL(*backend, fetchAccountTransactions); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const output = handler.process(req, Context{.yield = yield, .apiVersion = testBundle.apiVersion}); EXPECT_TRUE(output); }); @@ -482,15 +479,13 @@ genNFTTransactions(uint32_t seq) TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardTrue) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -502,7 +497,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardTrue) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -527,15 +522,13 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardTrue) TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardFalse) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -547,7 +540,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardFalse) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -572,15 +565,13 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardFalse) TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardTrue) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -592,7 +583,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardTrue) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -617,15 +608,13 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardTrue) TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardFalse) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -637,7 +626,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardFalse) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -662,15 +651,13 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardFalse) TEST_F(RPCAccountTxHandlerTest, BinaryTrue) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -682,7 +669,7 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrue) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -721,14 +708,12 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrue) TEST_F(RPCAccountTxHandlerTest, BinaryTrueV2) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -740,7 +725,7 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrueV2) .WillOnce(Return(transCursor)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -779,15 +764,13 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrueV2) TEST_F(RPCAccountTxHandlerTest, LimitAndMarker) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, false, testing::Optional(testing::Eq(TransactionsCursor{10, 11})), testing::_ ) @@ -795,7 +778,7 @@ TEST_F(RPCAccountTxHandlerTest, LimitAndMarker) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -822,16 +805,14 @@ TEST_F(RPCAccountTxHandlerTest, LimitAndMarker) TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndex) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + // adjust the order for forward->false auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -843,11 +824,11 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndex) .Times(1); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ - 1); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -869,16 +850,13 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndex) TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerIntIndex) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -897,16 +875,13 @@ TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerIntIndex) TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerStringIndex) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -925,16 +900,14 @@ TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerStringIndex) TEST_F(RPCAccountTxHandlerTest, SpecificLedgerHash) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + // adjust the order for forward->false auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -946,11 +919,11 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerHash) .Times(1); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ - 1); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -972,16 +945,14 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerHash) TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndexValidated) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + // adjust the order for forward->false auto const transactions = genTransactions(MAXSEQ, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -993,11 +964,11 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndexValidated) .Times(1); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -1018,15 +989,13 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndexValidated) TEST_F(RPCAccountTxHandlerTest, TxLessThanMinSeq) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -1038,7 +1007,7 @@ TEST_F(RPCAccountTxHandlerTest, TxLessThanMinSeq) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -1063,15 +1032,13 @@ TEST_F(RPCAccountTxHandlerTest, TxLessThanMinSeq) TEST_F(RPCAccountTxHandlerTest, TxLargerThanMaxSeq) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, @@ -1083,7 +1050,7 @@ TEST_F(RPCAccountTxHandlerTest, TxLargerThanMaxSeq) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -1304,15 +1271,13 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v1) "seq": 34 } })"; - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genNFTTransactions(MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, false, testing::Optional(testing::Eq(TransactionsCursor{10, 11})), testing::_ ) @@ -1320,7 +1285,7 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v1) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -1545,15 +1510,13 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2) "seq": 34 } })"; - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genNFTTransactions(MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchAccountTransactions( testing::_, testing::_, false, testing::Optional(testing::Eq(TransactionsCursor{10, 11})), testing::_ ) @@ -1561,10 +1524,10 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs_API_v2) .Times(1); auto const ledgerInfo = CreateLedgerInfo(LEDGERHASH, 11); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(transactions.size()).WillRepeatedly(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(transactions.size()).WillRepeatedly(Return(ledgerInfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "account": "{}", @@ -2030,26 +1993,21 @@ INSTANTIATE_TEST_CASE_P( TEST_P(AccountTxTransactionTypeTest, SpecificTransactionType) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); auto const transactions = genTransactions(MAXSEQ, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor)); - EXPECT_CALL( - *rawBackendPtr, fetchAccountTransactions(_, _, false, Optional(Eq(TransactionsCursor{MAXSEQ, INT32_MAX})), _) - ) + ON_CALL(*backend, fetchAccountTransactions).WillByDefault(Return(transCursor)); + EXPECT_CALL(*backend, fetchAccountTransactions(_, _, false, Optional(Eq(TransactionsCursor{MAXSEQ, INT32_MAX})), _)) .Times(1); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).Times(Between(1, 2)); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).Times(Between(1, 2)); auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}}; + auto const handler = AnyHandler{AccountTxHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{.yield = yield, .apiVersion = testBundle.apiVersion}); EXPECT_TRUE(output); diff --git a/unittests/rpc/handlers/BookChangesTests.cpp b/unittests/rpc/handlers/BookChangesTests.cpp index 5744982cc..ff0353f0c 100644 --- a/unittests/rpc/handlers/BookChangesTests.cpp +++ b/unittests/rpc/handlers/BookChangesTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/BookChanges.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -100,7 +99,7 @@ TEST_P(BookChangesParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookChangesHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -112,17 +111,13 @@ TEST_P(BookChangesParameterTest, InvalidParams) TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(MINSEQ, MAXSEQ); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)) - .WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(R"({"ledger_index":30})"); - auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookChangesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -134,16 +129,13 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaIntSequence) TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaStringSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(MINSEQ, MAXSEQ); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(std::nullopt)); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(std::nullopt)); auto static const input = json::parse(R"({"ledger_index":"30"})"); - auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookChangesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -155,13 +147,10 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaStringSequence) TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(MINSEQ, MAXSEQ); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( @@ -170,7 +159,7 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaHash) }})", LEDGERHASH )); - auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookChangesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -202,13 +191,10 @@ TEST_F(RPCBookChangesHandlerTest, NormalPath) } ] })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, MAXSEQ))); + + backend->setRange(MINSEQ, MAXSEQ); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, MAXSEQ))); auto transactions = std::vector{}; auto trans1 = TransactionAndMetadata(); @@ -219,10 +205,10 @@ TEST_F(RPCBookChangesHandlerTest, NormalPath) trans1.metadata = metaObj.getSerializer().peekData(); transactions.push_back(trans1); - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(MAXSEQ, _)).WillByDefault(Return(transactions)); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(MAXSEQ, _)).WillByDefault(Return(transactions)); - auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookChangesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(json::parse("{}"), Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/BookOffersTests.cpp b/unittests/rpc/handlers/BookOffersTests.cpp index 768f6514f..2714e7796 100644 --- a/unittests/rpc/handlers/BookOffersTests.cpp +++ b/unittests/rpc/handlers/BookOffersTests.cpp @@ -24,7 +24,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/BookOffers.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -91,7 +90,7 @@ struct RPCBookOffersParameterTest : public RPCBookOffersHandlerTest, public With TEST_P(RPCBookOffersParameterTest, CheckError) { auto bundle = GetParam(); - auto const handler = AnyHandler{BookOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookOffersHandler{backend}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(json::parse(bundle.testJson), Context{yield}); ASSERT_FALSE(output); @@ -528,25 +527,23 @@ TEST_P(RPCBookOffersNormalPathTest, CheckOutput) { auto const& bundle = GetParam(); auto const seq = 300; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, seq); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); // return valid book dir - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(bundle.mockedSuccessors.size()); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(bundle.mockedSuccessors.size()); for (auto const& [key, value] : bundle.mockedSuccessors) { - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(key, seq, _)).WillByDefault(Return(value)); + ON_CALL(*backend, doFetchSuccessorKey(key, seq, _)).WillByDefault(Return(value)); } - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(bundle.ledgerObjectCalls); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(bundle.ledgerObjectCalls); for (auto const& [key, value] : bundle.mockedLedgerObjects) { - ON_CALL(*rawBackendPtr, doFetchLedgerObject(key, seq, _)).WillByDefault(Return(value)); + ON_CALL(*backend, doFetchLedgerObject(key, seq, _)).WillByDefault(Return(value)); } std::vector bbs; @@ -556,10 +553,10 @@ TEST_P(RPCBookOffersNormalPathTest, CheckOutput) std::back_inserter(bbs), [](auto const& obj) { return obj.getSerializer().peekData(); } ); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); - auto const handler = AnyHandler{BookOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookOffersHandler{backend}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(json::parse(bundle.inputJson), Context{yield}); ASSERT_TRUE(output); @@ -1181,13 +1178,10 @@ INSTANTIATE_TEST_SUITE_P( // ledger not exist TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -1204,7 +1198,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaIntSequence) }})", ACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookOffersHandler{backend}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -1216,13 +1210,10 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaIntSequence) TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( R"({{ @@ -1239,7 +1230,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaSequence) }})", ACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookOffersHandler{backend}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -1251,13 +1242,10 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaSequence) TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); auto static const input = json::parse(fmt::format( @@ -1276,7 +1264,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaHash) LEDGERHASH, ACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookOffersHandler{backend}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -1289,37 +1277,35 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaHash) TEST_F(RPCBookOffersHandlerTest, Limit) { auto const seq = 300; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, seq); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); auto const issuer = GetAccountIDWithString(ACCOUNT); // return valid book dir - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(1); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(1); auto const getsXRPPaysUSDBook = getBookBase(std::get( rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount()) )); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(getsXRPPaysUSDBook, seq, _)) + ON_CALL(*backend, doFetchSuccessorKey(getsXRPPaysUSDBook, seq, _)) .WillByDefault(Return(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(5); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(5); auto const indexes = std::vector(10, ripple::uint256{INDEX2}); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, seq, _)) .WillByDefault(Return(CreateOwnerDirLedgerObject(indexes, INDEX1).getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, seq, _)) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT2, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(issuer).key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(issuer).key, seq, _)) .WillByDefault( Return(CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2, TRANSFERRATEX2).getSerializer().peekData()) ); @@ -1336,8 +1322,8 @@ TEST_F(RPCBookOffersHandlerTest, Limit) ); std::vector const bbs(10, gets10XRPPays20USDOffer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -1354,7 +1340,7 @@ TEST_F(RPCBookOffersHandlerTest, Limit) }})", ACCOUNT )); - auto const handler = AnyHandler{BookOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookOffersHandler{backend}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -1365,37 +1351,35 @@ TEST_F(RPCBookOffersHandlerTest, Limit) TEST_F(RPCBookOffersHandlerTest, LimitMoreThanMax) { auto const seq = 300; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, seq); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); auto const issuer = GetAccountIDWithString(ACCOUNT); // return valid book dir - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(1); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(1); auto const getsXRPPaysUSDBook = getBookBase(std::get( rpc::parseBook(ripple::to_currency("USD"), issuer, ripple::xrpCurrency(), ripple::xrpAccount()) )); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(getsXRPPaysUSDBook, seq, _)) + ON_CALL(*backend, doFetchSuccessorKey(getsXRPPaysUSDBook, seq, _)) .WillByDefault(Return(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(5); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(5); auto const indexes = std::vector(BookOffersHandler::LIMIT_MAX + 1, ripple::uint256{INDEX2}); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, seq, _)) .WillByDefault(Return(CreateOwnerDirLedgerObject(indexes, INDEX1).getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, seq, _)) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT2, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(issuer).key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(issuer).key, seq, _)) .WillByDefault( Return(CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2, TRANSFERRATEX2).getSerializer().peekData()) ); @@ -1412,8 +1396,8 @@ TEST_F(RPCBookOffersHandlerTest, LimitMoreThanMax) ); std::vector const bbs(BookOffersHandler::LIMIT_MAX + 1, gets10XRPPays20USDOffer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto static const input = json::parse(fmt::format( R"({{ @@ -1431,7 +1415,7 @@ TEST_F(RPCBookOffersHandlerTest, LimitMoreThanMax) ACCOUNT, BookOffersHandler::LIMIT_MAX + 1 )); - auto const handler = AnyHandler{BookOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{BookOffersHandler{backend}}; runSpawn([&](boost::asio::yield_context yield) { auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/DepositAuthorizedTests.cpp b/unittests/rpc/handlers/DepositAuthorizedTests.cpp index b55ecc460..440eddaa2 100644 --- a/unittests/rpc/handlers/DepositAuthorizedTests.cpp +++ b/unittests/rpc/handlers/DepositAuthorizedTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/DepositAuthorized.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -180,7 +179,7 @@ TEST_P(DepositAuthorizedParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); @@ -194,15 +193,13 @@ TEST_P(DepositAuthorizedParameterTest, InvalidParams) TEST_F(RPCDepositAuthorizedTest, LedgerNotExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "source_account": "{}", @@ -225,15 +222,13 @@ TEST_F(RPCDepositAuthorizedTest, LedgerNotExistViaIntSequence) TEST_F(RPCDepositAuthorizedTest, LedgerNotExistViaStringSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "source_account": "{}", @@ -256,15 +251,13 @@ TEST_F(RPCDepositAuthorizedTest, LedgerNotExistViaStringSequence) TEST_F(RPCDepositAuthorizedTest, LedgerNotExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "source_account": "{}", @@ -287,17 +280,15 @@ TEST_F(RPCDepositAuthorizedTest, LedgerNotExistViaHash) TEST_F(RPCDepositAuthorizedTest, SourceAccountDoesNotExist) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -311,7 +302,7 @@ TEST_F(RPCDepositAuthorizedTest, SourceAccountDoesNotExist) )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -324,21 +315,19 @@ TEST_F(RPCDepositAuthorizedTest, SourceAccountDoesNotExist) TEST_F(RPCDepositAuthorizedTest, DestinationAccountDoesNotExist) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const accountRoot = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(_, _, _)).WillByDefault(Return(accountRoot.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) + ON_CALL(*backend, doFetchLedgerObject(_, _, _)).WillByDefault(Return(accountRoot.getSerializer().peekData())); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const input = json::parse(fmt::format( R"({{ @@ -352,7 +341,7 @@ TEST_F(RPCDepositAuthorizedTest, DestinationAccountDoesNotExist) )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -375,18 +364,16 @@ TEST_F(RPCDepositAuthorizedTest, AccountsAreEqual) "destination_account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn" })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const accountRoot = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(accountRoot.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(accountRoot.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const input = json::parse(fmt::format( R"({{ @@ -400,7 +387,7 @@ TEST_F(RPCDepositAuthorizedTest, AccountsAreEqual) )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -420,23 +407,21 @@ TEST_F(RPCDepositAuthorizedTest, DifferentAccountsNoDepositAuthFlag) "destination_account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun" })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const account1Root = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); auto const account2Root = CreateAccountRootObject(ACCOUNT2, 0, 2, 200, 2, INDEX2, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, _, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, _, _)) .WillByDefault(Return(account1Root.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) .WillByDefault(Return(account2Root.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const input = json::parse(fmt::format( R"({{ @@ -450,7 +435,7 @@ TEST_F(RPCDepositAuthorizedTest, DifferentAccountsNoDepositAuthFlag) )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -470,24 +455,22 @@ TEST_F(RPCDepositAuthorizedTest, DifferentAccountsWithDepositAuthFlagReturnsFals "destination_account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun" })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const account1Root = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); auto const account2Root = CreateAccountRootObject(ACCOUNT2, ripple::lsfDepositAuth, 2, 200, 2, INDEX2, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(_, _, _)).WillByDefault(Return(std::nullopt)); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, _, _)) + ON_CALL(*backend, doFetchLedgerObject(_, _, _)).WillByDefault(Return(std::nullopt)); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, _, _)) .WillByDefault(Return(account1Root.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) .WillByDefault(Return(account2Root.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto const input = json::parse(fmt::format( R"({{ @@ -501,7 +484,7 @@ TEST_F(RPCDepositAuthorizedTest, DifferentAccountsWithDepositAuthFlagReturnsFals )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -521,24 +504,22 @@ TEST_F(RPCDepositAuthorizedTest, DifferentAccountsWithDepositAuthFlagReturnsTrue "destination_account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun" })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const account1Root = CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2); auto const account2Root = CreateAccountRootObject(ACCOUNT2, ripple::lsfDepositAuth, 2, 200, 2, INDEX2, 2); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(_, _, _)).WillByDefault(Return(std::optional{{1, 2, 3}})); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, _, _)) + ON_CALL(*backend, doFetchLedgerObject(_, _, _)).WillByDefault(Return(std::optional{{1, 2, 3}})); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, _, _)) .WillByDefault(Return(account1Root.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, _, _)) .WillByDefault(Return(account2Root.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto const input = json::parse(fmt::format( R"({{ @@ -552,7 +533,7 @@ TEST_F(RPCDepositAuthorizedTest, DifferentAccountsWithDepositAuthFlagReturnsTrue )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{DepositAuthorizedHandler{mockBackendPtr}}; + auto const handler = AnyHandler{DepositAuthorizedHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/GatewayBalancesTests.cpp b/unittests/rpc/handlers/GatewayBalancesTests.cpp index a8c203174..cb81dcb19 100644 --- a/unittests/rpc/handlers/GatewayBalancesTests.cpp +++ b/unittests/rpc/handlers/GatewayBalancesTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/GatewayBalances.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -82,7 +81,7 @@ struct ParameterTest : public RPCGatewayBalancesHandlerTest, public WithParamInt TEST_P(ParameterTest, CheckError) { auto bundle = GetParam(); - auto const handler = AnyHandler{GatewayBalancesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{GatewayBalancesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(json::parse(bundle.testJson), Context{yield}); ASSERT_FALSE(output); @@ -216,15 +215,13 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(RPCGatewayBalancesHandlerTest, LedgerNotFoundViaStringIndex) { auto const seq = 123; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(300); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, 300); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); - auto const handler = AnyHandler{GatewayBalancesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{GatewayBalancesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process( json::parse(fmt::format( @@ -247,15 +244,13 @@ TEST_F(RPCGatewayBalancesHandlerTest, LedgerNotFoundViaStringIndex) TEST_F(RPCGatewayBalancesHandlerTest, LedgerNotFoundViaIntIndex) { auto const seq = 123; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(300); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, 300); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional{})); - auto const handler = AnyHandler{GatewayBalancesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{GatewayBalancesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process( json::parse(fmt::format( @@ -277,16 +272,13 @@ TEST_F(RPCGatewayBalancesHandlerTest, LedgerNotFoundViaIntIndex) TEST_F(RPCGatewayBalancesHandlerTest, LedgerNotFoundViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(300); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(10, 300); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); - auto const handler = AnyHandler{GatewayBalancesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{GatewayBalancesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process( json::parse(fmt::format( @@ -309,21 +301,19 @@ TEST_F(RPCGatewayBalancesHandlerTest, LedgerNotFoundViaHash) TEST_F(RPCGatewayBalancesHandlerTest, AccountNotFound) { auto const seq = 300; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, seq); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); // return empty account auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, seq, _)).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(accountKk, seq, _)).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); - auto const handler = AnyHandler{GatewayBalancesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{GatewayBalancesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process( json::parse(fmt::format( @@ -344,34 +334,32 @@ TEST_F(RPCGatewayBalancesHandlerTest, AccountNotFound) TEST_F(RPCGatewayBalancesHandlerTest, InvalidHotWallet) { auto const seq = 300; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, seq); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); // return valid account auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, seq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, seq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); // return valid owner dir auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); // create a valid line, balance is 0 auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 0, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123); std::vector bbs; bbs.push_back(line1.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); - auto const handler = AnyHandler{GatewayBalancesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{GatewayBalancesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process( json::parse(fmt::format( @@ -415,25 +403,23 @@ TEST_P(NormalPathTest, CheckOutput) { auto const& bundle = GetParam(); auto const seq = 300; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, seq); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(ledgerinfo)); // return valid account auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, seq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, seq, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); // return valid owner dir auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(bundle.mockedDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); std::vector bbs; std::transform( @@ -442,10 +428,10 @@ TEST_P(NormalPathTest, CheckOutput) std::back_inserter(bbs), [](auto const& obj) { return obj.getSerializer().peekData(); } ); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); - auto const handler = AnyHandler{GatewayBalancesHandler{mockBackendPtr}}; + auto const handler = AnyHandler{GatewayBalancesHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process( json::parse(fmt::format( diff --git a/unittests/rpc/handlers/LedgerDataTests.cpp b/unittests/rpc/handlers/LedgerDataTests.cpp index 5e03d6547..113586354 100644 --- a/unittests/rpc/handlers/LedgerDataTests.cpp +++ b/unittests/rpc/handlers/LedgerDataTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/LedgerData.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -117,11 +116,10 @@ INSTANTIATE_TEST_CASE_P( TEST_P(LedgerDataParameterTest, InvalidParams) { - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -133,16 +131,13 @@ TEST_P(LedgerDataParameterTest, InvalidParams) TEST_F(RPCLedgerDataHandlerTest, LedgerNotExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "ledger_index": {} @@ -159,16 +154,13 @@ TEST_F(RPCLedgerDataHandlerTest, LedgerNotExistViaIntSequence) TEST_F(RPCLedgerDataHandlerTest, LedgerNotExistViaStringSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "ledger_index": "{}" @@ -185,16 +177,13 @@ TEST_F(RPCLedgerDataHandlerTest, LedgerNotExistViaStringSequence) TEST_F(RPCLedgerDataHandlerTest, LedgerNotExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "ledger_hash": "{}" @@ -211,21 +200,16 @@ TEST_F(RPCLedgerDataHandlerTest, LedgerNotExistViaHash) TEST_F(RPCLedgerDataHandlerTest, MarkerNotExist) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)) - .WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "marker": "{}" @@ -257,22 +241,17 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker) "closed":true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); // when 'type' not specified, default to all the types auto limitLine = 5; auto limitTicket = 5; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(limitLine + limitTicket); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(limitLine + limitTicket); + ON_CALL(*backend, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); while ((limitLine--) != 0) { auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); @@ -284,16 +263,17 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker) bbs.push_back(ticket.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(R"({"limit":10})"); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().contains("ledger")); - //"close_time_human" 's format depends on platform, might be sightly different + + // Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however + // guaranteed to be consistent on the same platform. EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1); EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected)); EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2); @@ -303,6 +283,61 @@ TEST_F(RPCLedgerDataHandlerTest, NoMarker) }); } +TEST_F(RPCLedgerDataHandlerTest, Version2) +{ + static auto const ledgerExpected = R"({ + "account_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "close_flags": 0, + "close_time": 0, + "close_time_resolution": 0, + "close_time_iso": "2000-01-01T00:00:00Z", + "ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", + "ledger_index": 30, + "parent_close_time": 0, + "parent_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "total_coins": "0", + "transaction_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "closed": true + })"; + + backend->setRange(RANGEMIN, RANGEMAX); + + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + + // When 'type' not specified, default to all the types + auto limitLine = 5; + auto limitTicket = 5; + + std::vector bbs; + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(limitLine + limitTicket); + ON_CALL(*backend, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + + while ((limitLine--) != 0) { + auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); + bbs.push_back(line.getSerializer().peekData()); + } + + while ((limitTicket--) != 0) { + auto const ticket = CreateTicketLedgerObject(ACCOUNT, limitTicket); + bbs.push_back(ticket.getSerializer().peekData()); + } + + EXPECT_CALL(*backend, doFetchLedgerObjects).WillOnce(Return(bbs)); + + runSpawn([&, this](auto yield) { + auto const handler = AnyHandler{LedgerDataHandler{backend}}; + auto const req = json::parse(R"({"limit":10})"); + auto output = handler.process(req, Context{.yield = yield, .apiVersion = 2}); + ASSERT_TRUE(output); + EXPECT_TRUE(output->as_object().contains("ledger")); + + // Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however + // guaranteed to be consistent on the same platform. + EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1); + EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected)); + }); +} + TEST_F(RPCLedgerDataHandlerTest, TypeFilter) { static auto const ledgerExpected = R"({ @@ -320,21 +355,17 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilter) "closed":true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); auto limitLine = 5; auto limitTicket = 5; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(limitLine + limitTicket); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(limitLine + limitTicket); + ON_CALL(*backend, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); while ((limitLine--) != 0) { auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); @@ -346,11 +377,11 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilter) bbs.push_back(ticket.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(R"({ "limit":10, "type":"state" @@ -359,7 +390,9 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilter) auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().contains("ledger")); - //"close_time_human" 's format depends on platform, might be sightly different + + // Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however + // guaranteed to be consistent on the same platform. EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1); EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected)); EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2); @@ -386,20 +419,16 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilterAMM) "closed":true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); auto limitLine = 5; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(limitLine + 1); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(limitLine + 1); + ON_CALL(*backend, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); while ((limitLine--) != 0) { auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); @@ -409,11 +438,11 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilterAMM) auto const amm = CreateAMMObject(ACCOUNT, "XRP", ripple::toBase58(ripple::xrpAccount()), "JPY", ACCOUNT2); bbs.push_back(amm.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(R"({ "limit":6, "type":"amm" @@ -422,7 +451,9 @@ TEST_F(RPCLedgerDataHandlerTest, TypeFilterAMM) auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().contains("ledger")); - //"close_time_human" 's format depends on platform, might be sightly different + + // Note: the format of "close_time_human" depends on the platform and might differ per platform. It is however + // guaranteed to be consistent on the same platform. EXPECT_EQ(output->as_object().at("ledger").as_object().erase("close_time_human"), 1); EXPECT_EQ(output->as_object().at("ledger"), json::parse(ledgerExpected)); EXPECT_EQ(output->as_object().at("marker").as_string(), INDEX2); @@ -449,31 +480,26 @@ TEST_F(RPCLedgerDataHandlerTest, OutOfOrder) "closed":true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); // page end // marker return seq std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(2); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(firstKey, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(ripple::uint256{INDEX2}, RANGEMAX, _)) - .WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(2); + ON_CALL(*backend, doFetchSuccessorKey(firstKey, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + ON_CALL(*backend, doFetchSuccessorKey(ripple::uint256{INDEX2}, RANGEMAX, _)).WillByDefault(Return(std::nullopt)); auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); bbs.push_back(line.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(R"({"limit":10, "out_of_order":true})"); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -489,17 +515,13 @@ TEST_F(RPCLedgerDataHandlerTest, OutOfOrder) TEST_F(RPCLedgerDataHandlerTest, Marker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)) + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)) .WillByDefault( Return(CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123) .getSerializer() @@ -508,10 +530,10 @@ TEST_F(RPCLedgerDataHandlerTest, Marker) auto limit = 10; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(limit); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(ripple::uint256{INDEX1}, RANGEMAX, _)) + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(limit); + ON_CALL(*backend, doFetchSuccessorKey(ripple::uint256{INDEX1}, RANGEMAX, _)) .WillByDefault(Return(ripple::uint256{INDEX2})); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(ripple::uint256{INDEX2}, RANGEMAX, _)) + ON_CALL(*backend, doFetchSuccessorKey(ripple::uint256{INDEX2}, RANGEMAX, _)) .WillByDefault(Return(ripple::uint256{INDEX2})); while ((limit--) != 0) { @@ -519,11 +541,11 @@ TEST_F(RPCLedgerDataHandlerTest, Marker) bbs.push_back(line.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "limit":10, @@ -543,33 +565,29 @@ TEST_F(RPCLedgerDataHandlerTest, Marker) TEST_F(RPCLedgerDataHandlerTest, DiffMarker) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); auto limit = 10; std::vector los; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff).Times(1); + EXPECT_CALL(*backend, fetchLedgerDiff).Times(1); while ((limit--) != 0) { auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); bbs.push_back(line.getSerializer().peekData()); los.emplace_back(LedgerObject{ripple::uint256{INDEX2}, Blob{}}); // NOLINT(modernize-use-emplace) } - ON_CALL(*rawBackendPtr, fetchLedgerDiff(RANGEMAX, _)).WillByDefault(Return(los)); + ON_CALL(*backend, fetchLedgerDiff(RANGEMAX, _)).WillByDefault(Return(los)); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "limit":10, @@ -590,31 +608,27 @@ TEST_F(RPCLedgerDataHandlerTest, DiffMarker) TEST_F(RPCLedgerDataHandlerTest, Binary) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); auto limit = 10; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(limit); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(limit); + ON_CALL(*backend, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); while ((limit--) != 0) { auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); bbs.push_back(line.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse( R"({ "limit":10, @@ -634,31 +648,27 @@ TEST_F(RPCLedgerDataHandlerTest, Binary) TEST_F(RPCLedgerDataHandlerTest, BinaryLimitMoreThanMax) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); auto limit = LedgerDataHandler::LIMITBINARY + 1; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(LedgerDataHandler::LIMITBINARY); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(LedgerDataHandler::LIMITBINARY); + ON_CALL(*backend, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); while ((limit--) != 0u) { auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); bbs.push_back(line.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "limit":{}, @@ -679,31 +689,27 @@ TEST_F(RPCLedgerDataHandlerTest, BinaryLimitMoreThanMax) TEST_F(RPCLedgerDataHandlerTest, JsonLimitMoreThanMax) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)) - .WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(CreateLedgerInfo(LEDGERHASH, RANGEMAX))); auto limit = LedgerDataHandler::LIMITJSON + 1; std::vector bbs; - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(LedgerDataHandler::LIMITJSON); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(LedgerDataHandler::LIMITJSON); + ON_CALL(*backend, doFetchSuccessorKey(_, RANGEMAX, _)).WillByDefault(Return(ripple::uint256{INDEX2})); while ((limit--) != 0u) { auto const line = CreateRippleStateLedgerObject("USD", ACCOUNT2, 10, ACCOUNT, 100, ACCOUNT2, 200, TXNID, 123); bbs.push_back(line.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerDataHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerDataHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "limit":{}, diff --git a/unittests/rpc/handlers/LedgerEntryTests.cpp b/unittests/rpc/handlers/LedgerEntryTests.cpp index f223a7bb1..97879acf9 100644 --- a/unittests/rpc/handlers/LedgerEntryTests.cpp +++ b/unittests/rpc/handlers/LedgerEntryTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/LedgerEntry.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -884,7 +883,7 @@ TEST_P(LedgerEntryParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -919,7 +918,7 @@ TEST_P(IndexTest, InvalidIndexUint256) { auto const index = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "{}": "invalid" @@ -939,7 +938,7 @@ TEST_P(IndexTest, InvalidIndexNotString) { auto const index = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "{}": 123 @@ -957,22 +956,19 @@ TEST_P(IndexTest, InvalidIndexNotString) TEST_F(RPCLedgerEntryTest, LedgerEntryNotFound) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // return null for ledger entry auto const key = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(key, RANGEMAX, _)).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(key, RANGEMAX, _)).WillByDefault(Return(std::optional{})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "account_root": "{}" @@ -1322,21 +1318,19 @@ INSTANTIATE_TEST_CASE_P( TEST_P(RPCLedgerEntryNormalPathTest, NormalPath) { auto const testBundle = GetParam(); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + + backend->setRange(RANGEMIN, RANGEMAX); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(testBundle.expectedIndex, RANGEMAX, _)) + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(testBundle.expectedIndex, RANGEMAX, _)) .WillByDefault(Return(testBundle.mockedEntity.getSerializer().peekData())); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -1373,23 +1367,21 @@ TEST_F(RPCLedgerEntryTest, BinaryFalse) "index":"05FB0EB4B899F056FA095537C5817163801F544BAFCEA39C995D76DB4D16F9DD" } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + + backend->setRange(RANGEMIN, RANGEMAX); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // return valid ledger entry which can be deserialized auto const ledgerEntry = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 200, 300, INDEX1, 400); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)) + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)) .WillByDefault(Return(ledgerEntry.getSerializer().peekData())); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "payment_channel": "{}" @@ -1404,23 +1396,20 @@ TEST_F(RPCLedgerEntryTest, BinaryFalse) TEST_F(RPCLedgerEntryTest, UnexpectedLedgerType) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // return valid ledger entry which can be deserialized auto const ledgerEntry = CreatePaymentChannelLedgerObject(ACCOUNT, ACCOUNT2, 100, 200, 300, INDEX1, 400); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)) + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{INDEX1}, RANGEMAX, _)) .WillByDefault(Return(ledgerEntry.getSerializer().peekData())); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "check": "{}" @@ -1436,16 +1425,13 @@ TEST_F(RPCLedgerEntryTest, UnexpectedLedgerType) TEST_F(RPCLedgerEntryTest, LedgerNotExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "check": "{}", @@ -1464,16 +1450,13 @@ TEST_F(RPCLedgerEntryTest, LedgerNotExistViaIntSequence) TEST_F(RPCLedgerEntryTest, LedgerNotExistViaStringSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "check": "{}", @@ -1492,16 +1475,13 @@ TEST_F(RPCLedgerEntryTest, LedgerNotExistViaStringSequence) TEST_F(RPCLedgerEntryTest, LedgerNotExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "check": "{}", @@ -1521,7 +1501,7 @@ TEST_F(RPCLedgerEntryTest, LedgerNotExistViaHash) TEST_F(RPCLedgerEntryTest, InvalidEntryTypeVersion2) { runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(R"({})"); auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2}); ASSERT_FALSE(output); @@ -1534,7 +1514,7 @@ TEST_F(RPCLedgerEntryTest, InvalidEntryTypeVersion2) TEST_F(RPCLedgerEntryTest, InvalidEntryTypeVersion1) { runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerEntryHandler{backend}}; auto const req = json::parse(R"({})"); auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1}); ASSERT_FALSE(output); diff --git a/unittests/rpc/handlers/LedgerRangeTests.cpp b/unittests/rpc/handlers/LedgerRangeTests.cpp index d7774f267..0571606f1 100644 --- a/unittests/rpc/handlers/LedgerRangeTests.cpp +++ b/unittests/rpc/handlers/LedgerRangeTests.cpp @@ -37,8 +37,9 @@ class RPCLedgerRangeTest : public HandlerBaseTest {}; TEST_F(RPCLedgerRangeTest, LedgerRangeMinMaxSame) { runSpawn([this](auto yield) { - mockBackendPtr->updateRange(RANGEMIN); - auto const handler = AnyHandler{LedgerRangeHandler{mockBackendPtr}}; + backend->updateRange(RANGEMIN); + + auto const handler = AnyHandler{LedgerRangeHandler{backend}}; auto const req = json::parse("{}"); auto const output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -51,9 +52,9 @@ TEST_F(RPCLedgerRangeTest, LedgerRangeMinMaxSame) TEST_F(RPCLedgerRangeTest, LedgerRangeFullySet) { runSpawn([this](auto yield) { - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); - auto const handler = AnyHandler{LedgerRangeHandler{mockBackendPtr}}; + backend->setRange(RANGEMIN, RANGEMAX); + + auto const handler = AnyHandler{LedgerRangeHandler{backend}}; auto const req = json::parse("{}"); auto const output = handler.process(req, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/LedgerTests.cpp b/unittests/rpc/handlers/LedgerTests.cpp index fe015cc49..22b34329c 100644 --- a/unittests/rpc/handlers/LedgerTests.cpp +++ b/unittests/rpc/handlers/LedgerTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/Ledger.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -177,7 +176,7 @@ TEST_P(LedgerParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -189,16 +188,13 @@ TEST_P(LedgerParameterTest, InvalidParams) TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaIntSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "ledger_index": {} @@ -215,16 +211,13 @@ TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaIntSequence) TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaStringSequence) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "ledger_index": "{}" @@ -241,16 +234,13 @@ TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaStringSequence) TEST_F(RPCLedgerHandlerTest, LedgerNotExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); // min - mockBackendPtr->updateRange(RANGEMAX); // max + backend->setRange(RANGEMIN, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "ledger_hash": "{}" @@ -287,17 +277,15 @@ TEST_F(RPCLedgerHandlerTest, Default) "transaction_hash":"0000000000000000000000000000000000000000000000000000000000000000" } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse("{}"); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -310,17 +298,14 @@ TEST_F(RPCLedgerHandlerTest, Default) // not supported fields can be set to its default value TEST_F(RPCLedgerHandlerTest, NotSupportedFieldsDefaultValue) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "full": false, @@ -335,17 +320,14 @@ TEST_F(RPCLedgerHandlerTest, NotSupportedFieldsDefaultValue) TEST_F(RPCLedgerHandlerTest, QueryViaLedgerIndex) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(15, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(15, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse(R"({"ledger_index": 15})"); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -355,17 +337,14 @@ TEST_F(RPCLedgerHandlerTest, QueryViaLedgerIndex) TEST_F(RPCLedgerHandlerTest, QueryViaLedgerHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{INDEX1}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{INDEX1}, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse(fmt::format(R"({{"ledger_hash": "{}" }})", INDEX1)); auto output = handler.process(req, Context{yield}); ASSERT_TRUE(output); @@ -385,17 +364,15 @@ TEST_F(RPCLedgerHandlerTest, BinaryTrue) "closed":true } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true @@ -429,25 +406,23 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandBinary) ] } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{t1, t1})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{t1, t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true, @@ -485,23 +460,21 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandBinaryV2) ] } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo)); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1, t1})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1, t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true, @@ -575,25 +548,23 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinary) ] } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{t1})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": false, @@ -623,7 +594,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2) "close_time_resolution": 0, "closed": true, "ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", - "ledger_index": "30", + "ledger_index": 30, "parent_close_time": 0, "close_time_iso": "2000-01-01T00:00:00Z", "parent_hash": "0000000000000000000000000000000000000000000000000000000000000000", @@ -635,7 +606,7 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2) "close_time_iso": "2000-01-01T00:00:00Z", "hash": "70436A9332F7CD928FAEC1A41269A677739D8B11F108CE23AE23CBF0C9113F8C", "ledger_hash": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A652", - "ledger_index": "30", + "ledger_index": 30, "tx_json": { "Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn", @@ -679,23 +650,21 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2) ] } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo)); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": false, @@ -713,27 +682,24 @@ TEST_F(RPCLedgerHandlerTest, TransactionsExpandNotBinaryV2) TEST_F(RPCLedgerHandlerTest, TwoRequestInARowTransactionsExpandNotBinaryV2) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillOnce(Return(ledgerinfo)); auto const ledgerinfo2 = CreateLedgerInfo(LEDGERHASH, RANGEMAX - 1, 10); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX - 1, _)).WillOnce(Return(ledgerinfo2)); + EXPECT_CALL(*backend, fetchLedgerBySequence(RANGEMAX - 1, _)).WillOnce(Return(ledgerinfo2)); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1})); - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX - 1, _)).WillOnce(Return(std::vector{t1})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillOnce(Return(std::vector{t1})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX - 1, _)).WillOnce(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": false, @@ -764,21 +730,18 @@ TEST_F(RPCLedgerHandlerTest, TwoRequestInARowTransactionsExpandNotBinaryV2) TEST_F(RPCLedgerHandlerTest, TransactionsNotExpand) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionHashesInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionHashesInLedger(RANGEMAX, _)) + EXPECT_CALL(*backend, fetchAllTransactionHashesInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionHashesInLedger(RANGEMAX, _)) .WillByDefault(Return(std::vector{ripple::uint256{INDEX1}, ripple::uint256{INDEX2}})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "transactions": true @@ -817,18 +780,16 @@ TEST_F(RPCLedgerHandlerTest, DiffNotBinary) } } ])"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); std::vector los; - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff).Times(1); + EXPECT_CALL(*backend, fetchLedgerDiff).Times(1); los.push_back(LedgerObject{ripple::uint256{INDEX2}, Blob{}}); // NOLINT(modernize-use-emplace) los.push_back(LedgerObject{ @@ -836,10 +797,10 @@ TEST_F(RPCLedgerHandlerTest, DiffNotBinary) CreateAccountRootObject(ACCOUNT, ripple::lsfGlobalFreeze, 1, 10, 2, INDEX1, 3).getSerializer().peekData() }); - ON_CALL(*rawBackendPtr, fetchLedgerDiff(RANGEMAX, _)).WillByDefault(Return(los)); + ON_CALL(*backend, fetchLedgerDiff(RANGEMAX, _)).WillByDefault(Return(los)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "diff": true @@ -864,18 +825,16 @@ TEST_F(RPCLedgerHandlerTest, DiffBinary) "object":"1100612200400000240000000125000000032B000000002D00000002551B8590C01B0006EDFA9ED60296DD052DC5E90F99659B25014D08E1BC983515BC62400000000000000A81144B4E9C06F24296074F7BC48F92A97916C6DC5EA9" } ])"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); std::vector los; - EXPECT_CALL(*rawBackendPtr, fetchLedgerDiff).Times(1); + EXPECT_CALL(*backend, fetchLedgerDiff).Times(1); los.push_back(LedgerObject{ripple::uint256{INDEX2}, Blob{}}); // NOLINT(modernize-use-emplace) los.push_back(LedgerObject{ @@ -883,10 +842,10 @@ TEST_F(RPCLedgerHandlerTest, DiffBinary) CreateAccountRootObject(ACCOUNT, ripple::lsfGlobalFreeze, 1, 10, 2, INDEX1, 3).getSerializer().peekData() }); - ON_CALL(*rawBackendPtr, fetchLedgerDiff(RANGEMAX, _)).WillByDefault(Return(los)); + ON_CALL(*backend, fetchLedgerDiff(RANGEMAX, _)).WillByDefault(Return(los)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "diff": true, @@ -959,25 +918,23 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsEmtpy) ] } })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); TransactionAndMetadata t1; t1.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 100, 3, RANGEMAX).getSerializer().peekData(); t1.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); t1.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{t1})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{t1})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": false, @@ -1052,14 +1009,12 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryFalse) "ledger_index": 30, "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // account doFetchLedgerObject auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; @@ -1067,14 +1022,13 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryFalse) CreateAccountRootObject(ACCOUNT, 0, RANGEMAX, 200 /*balance*/, 2 /*owner object*/, INDEX1, RANGEMAX - 1, 0) .getSerializer() .peekData(); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, RANGEMAX, _)).WillByDefault(Return(accountObject)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, RANGEMAX, _)).WillByDefault(Return(accountObject)); // fee object 2*2+3->7 ; balance 200 - 7 -> 193 auto feeBlob = CreateFeeSettingBlob(1, 2 /*reserve inc*/, 3 /*reserve base*/, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, RANGEMAX, _)) - .WillByDefault(Return(feeBlob)); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, RANGEMAX, _)).WillByDefault(Return(feeBlob)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT2, 100, 300, 200).getSerializer().peekData(); @@ -1084,11 +1038,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryFalse) tx.date = 123456; tx.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": false, @@ -1124,14 +1078,12 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryTrue) "ledger_index": 30, "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // account doFetchLedgerObject auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; @@ -1139,14 +1091,13 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryTrue) CreateAccountRootObject(ACCOUNT, 0, RANGEMAX, 200 /*balance*/, 2 /*owner object*/, INDEX1, RANGEMAX - 1, 0) .getSerializer() .peekData(); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, RANGEMAX, _)).WillByDefault(Return(accountObject)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, RANGEMAX, _)).WillByDefault(Return(accountObject)); // fee object 2*2+3->7 ; balance 200 - 7 -> 193 auto feeBlob = CreateFeeSettingBlob(1, 2 /*reserve inc*/, 3 /*reserve base*/, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, RANGEMAX, _)) - .WillByDefault(Return(feeBlob)); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, RANGEMAX, _)).WillByDefault(Return(feeBlob)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT2, 100, 300, 200).getSerializer().peekData(); @@ -1156,11 +1107,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryTrue) tx.date = 123456; tx.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true, @@ -1177,14 +1128,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsTrueBinaryTrue) TEST_F(RPCLedgerHandlerTest, OwnerFundsIssuerIsSelf) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // issuer is self TransactionAndMetadata tx; @@ -1194,11 +1142,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsIssuerIsSelf) tx.date = 123456; tx.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true, @@ -1234,14 +1182,12 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotEnoughForReserve) "ledger_index": 30, "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // account doFetchLedgerObject auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; @@ -1249,14 +1195,13 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotEnoughForReserve) CreateAccountRootObject(ACCOUNT, 0, RANGEMAX, 6 /*balance*/, 2 /*owner object*/, INDEX1, RANGEMAX - 1, 0) .getSerializer() .peekData(); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, RANGEMAX, _)).WillByDefault(Return(accountObject)); + ON_CALL(*backend, doFetchLedgerObject(accountKk, RANGEMAX, _)).WillByDefault(Return(accountObject)); // fee object 2*2+3->7 ; balance 6 - 7 -> -1 auto feeBlob = CreateFeeSettingBlob(1, 2 /*reserve inc*/, 3 /*reserve base*/, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, RANGEMAX, _)) - .WillByDefault(Return(feeBlob)); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, RANGEMAX, _)).WillByDefault(Return(feeBlob)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT2, 100, 300, 200).getSerializer().peekData(); @@ -1266,11 +1211,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotEnoughForReserve) tx.date = 123456; tx.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true, @@ -1287,14 +1232,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotEnoughForReserve) TEST_F(RPCLedgerHandlerTest, OwnerFundsNotXRP) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // mock line auto const line = @@ -1305,10 +1247,9 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotXRP) ripple::to_currency(std::string(CURRENCY)) ) .key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(lineKey, RANGEMAX, _)) - .WillByDefault(Return(line.getSerializer().peekData())); + ON_CALL(*backend, doFetchLedgerObject(lineKey, RANGEMAX, _)).WillByDefault(Return(line.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT2, 100, 300, 200, true).getSerializer().peekData(); @@ -1317,11 +1258,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotXRP) tx.date = 123456; tx.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true, @@ -1345,14 +1286,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsNotXRP) TEST_F(RPCLedgerHandlerTest, OwnerFundsIgnoreFreezeLine) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(RANGEMIN); - mockBackendPtr->updateRange(RANGEMAX); + backend->setRange(RANGEMIN, RANGEMAX); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, RANGEMAX); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(RANGEMAX, _)).WillByDefault(Return(ledgerinfo)); // mock line freeze auto const line = CreateRippleStateLedgerObject( @@ -1373,10 +1311,9 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsIgnoreFreezeLine) ripple::to_currency(std::string(CURRENCY)) ) .key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(lineKey, RANGEMAX, _)) - .WillByDefault(Return(line.getSerializer().peekData())); + ON_CALL(*backend, doFetchLedgerObject(lineKey, RANGEMAX, _)).WillByDefault(Return(line.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT2, 100, 300, 200, true).getSerializer().peekData(); @@ -1385,11 +1322,11 @@ TEST_F(RPCLedgerHandlerTest, OwnerFundsIgnoreFreezeLine) tx.date = 123456; tx.ledgerSequence = RANGEMAX; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger).Times(1); - ON_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger).Times(1); + ON_CALL(*backend, fetchAllTransactionsInLedger(RANGEMAX, _)).WillByDefault(Return(std::vector{tx})); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{LedgerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{LedgerHandler{backend}}; auto const req = json::parse( R"({ "binary": true, diff --git a/unittests/rpc/handlers/NFTBuyOffersTests.cpp b/unittests/rpc/handlers/NFTBuyOffersTests.cpp index faf7d4803..5344ba7c5 100644 --- a/unittests/rpc/handlers/NFTBuyOffersTests.cpp +++ b/unittests/rpc/handlers/NFTBuyOffersTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/NFTBuyOffers.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -54,7 +53,7 @@ class RPCNFTBuyOffersHandlerTest : public HandlerBaseTest {}; TEST_F(RPCNFTBuyOffersHandlerTest, NonHexLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -74,7 +73,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonHexLedgerHash) TEST_F(RPCNFTBuyOffersHandlerTest, LimitNotInt) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -93,7 +92,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitNotInt) TEST_F(RPCNFTBuyOffersHandlerTest, LimitNegative) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -112,7 +111,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitNegative) TEST_F(RPCNFTBuyOffersHandlerTest, LimitZero) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -131,7 +130,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitZero) TEST_F(RPCNFTBuyOffersHandlerTest, NonStringLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -151,7 +150,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonStringLedgerHash) TEST_F(RPCNFTBuyOffersHandlerTest, InvalidLedgerIndexString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -172,7 +171,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, InvalidLedgerIndexString) TEST_F(RPCNFTBuyOffersHandlerTest, NFTIDInvalidFormat) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(R"({ "nft_id": "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE7" })"); @@ -188,7 +187,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NFTIDInvalidFormat) TEST_F(RPCNFTBuyOffersHandlerTest, NFTIDNotString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(R"({ "nft_id": 12 })"); @@ -204,12 +203,10 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NFTIDNotString) // error case ledger non exist via hash TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerHash) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); // mock fetchLedgerByHash return empty - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -220,7 +217,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerHash) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -233,13 +230,10 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerHash) // error case ledger non exist via index TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -248,7 +242,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerIndex) NFTID )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -261,14 +255,11 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerIndex) // idk why this case will happen in reality TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerHash2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerByHash return ledger but seq is 31 > 30 auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 31); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -278,7 +269,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerHash2) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -290,13 +281,10 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerHash2) // error case ledger > max seq via index TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerIndex2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // no need to check from db, call fetchLedgerBySequence 0 time // differ from previous logic - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(0); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(0); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -305,7 +293,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerIndex2) NFTID )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -317,15 +305,12 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NonExistLedgerViaLedgerIndex2) // error case when nft is not found TEST_F(RPCNFTBuyOffersHandlerTest, NoNFT) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::nullopt)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -335,7 +320,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NoNFT) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -347,7 +332,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, NoNFT) TEST_F(RPCNFTBuyOffersHandlerTest, MarkerNotString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -369,7 +354,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, MarkerNotString) TEST_F(RPCNFTBuyOffersHandlerTest, InvalidMarker) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -385,7 +370,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, InvalidMarker) EXPECT_EQ(err.at("error_message").as_string(), "markerMalformed"); }); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -422,29 +407,27 @@ TEST_F(RPCNFTBuyOffersHandlerTest, DefaultParameters) } ] })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index containing 2 indexes auto const directory = ripple::keylet::nft_buys(ripple::uint256{NFTID}); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); // return two nft buy offers std::vector bbs; auto const offer = CreateNFTBuyOffer(NFTID, ACCOUNT); bbs.push_back(offer.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -453,7 +436,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, DefaultParameters) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTBuyOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTBuyOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -464,13 +447,10 @@ TEST_F(RPCNFTBuyOffersHandlerTest, DefaultParameters) // normal case when provided with nft_id and limit TEST_F(RPCNFTBuyOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index std::vector indexes; @@ -484,11 +464,11 @@ TEST_F(RPCNFTBuyOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) } ripple::STObject const ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -498,7 +478,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTBuyOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTBuyOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -513,13 +493,10 @@ TEST_F(RPCNFTBuyOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) // normal case when provided with nft_id, limit and marker TEST_F(RPCNFTBuyOffersHandlerTest, ResultsForInputWithMarkerAndLimit) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index std::vector indexes; @@ -537,19 +514,19 @@ TEST_F(RPCNFTBuyOffersHandlerTest, ResultsForInputWithMarkerAndLimit) // first is nft offer object auto const cursor = ripple::uint256{"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC353"}; auto const first = ripple::keylet::nftoffer(cursor); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)) .WillByDefault(Return(cursorBuyOffer.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); auto const directory = ripple::keylet::nft_buys(ripple::uint256{NFTID}); auto const startHint = 0ul; // offer node is hardcoded to 0ul auto const secondKey = ripple::keylet::page(directory, startHint).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(3); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -560,7 +537,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, ResultsForInputWithMarkerAndLimit) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTBuyOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTBuyOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -577,13 +554,10 @@ TEST_F(RPCNFTBuyOffersHandlerTest, ResultsForInputWithMarkerAndLimit) // nothing left after reading remaining 50 entries TEST_F(RPCNFTBuyOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLimit) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(3); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(3); // return owner index std::vector indexes; @@ -601,22 +575,22 @@ TEST_F(RPCNFTBuyOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLimi // first is nft offer object auto const cursor = ripple::uint256{"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC353"}; auto const first = ripple::keylet::nftoffer(cursor); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)) .WillByDefault(Return(cursorBuyOffer.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); auto const directory = ripple::keylet::nft_buys(ripple::uint256{NFTID}); auto const startHint = 0ul; // offer node is hardcoded to 0ul auto const secondKey = ripple::keylet::page(directory, startHint).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(7); + EXPECT_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(7); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(3); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(3); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTBuyOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTBuyOffersHandler{this->backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -635,7 +609,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLimi }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -648,7 +622,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLimi }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTBuyOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTBuyOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -663,22 +637,19 @@ TEST_F(RPCNFTBuyOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLimi TEST_F(RPCNFTBuyOffersHandlerTest, LimitLessThanMin) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index containing 2 indexes auto const directory = ripple::keylet::nft_buys(ripple::uint256{NFTID}); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{NFTBuyOffersHandler::LIMIT_MIN + 1, ripple::uint256{INDEX1}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); // return two nft buy offers std::vector bbs; @@ -686,8 +657,8 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitLessThanMin) bbs.reserve(NFTBuyOffersHandler::LIMIT_MIN + 1); for (auto i = 0; i < NFTBuyOffersHandler::LIMIT_MIN + 1; i++) bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -698,7 +669,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitLessThanMin) NFTBuyOffersHandler::LIMIT_MIN - 1 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTBuyOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTBuyOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -709,22 +680,19 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitLessThanMin) TEST_F(RPCNFTBuyOffersHandlerTest, LimitMoreThanMax) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index containing 2 indexes auto const directory = ripple::keylet::nft_buys(ripple::uint256{NFTID}); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{NFTBuyOffersHandler::LIMIT_MAX + 1, ripple::uint256{INDEX1}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); // return two nft buy offers std::vector bbs; @@ -732,8 +700,8 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitMoreThanMax) bbs.reserve(NFTBuyOffersHandler::LIMIT_MAX + 1); for (auto i = 0; i < NFTBuyOffersHandler::LIMIT_MAX + 1; i++) bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -744,7 +712,7 @@ TEST_F(RPCNFTBuyOffersHandlerTest, LimitMoreThanMax) NFTBuyOffersHandler::LIMIT_MAX + 1 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTBuyOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTBuyOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/NFTHistoryTests.cpp b/unittests/rpc/handlers/NFTHistoryTests.cpp index 510f63b8c..9f5ff9755 100644 --- a/unittests/rpc/handlers/NFTHistoryTests.cpp +++ b/unittests/rpc/handlers/NFTHistoryTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/NFTHistory.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -238,11 +237,10 @@ INSTANTIATE_TEST_CASE_P( TEST_P(NFTHistoryParameterTest, InvalidParams) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max + backend->setRange(MINSEQ, MAXSEQ); auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -279,15 +277,13 @@ genTransactions(uint32_t seq1, uint32_t seq2) TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardTrue) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, true, testing::Optional(testing::Eq(TransactionsCursor{MINSEQ + 1, 0})), testing::_ ) @@ -295,7 +291,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardTrue) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -422,15 +418,13 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalseV1) "seq": 34 } })"; - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -442,7 +436,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalseV1) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -576,14 +570,12 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalseV2) "seq": 34 } })"; - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -595,11 +587,11 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalseV2) .WillOnce(Return(transCursor)); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(2); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(2); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -619,15 +611,13 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalseV2) TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardTrue) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, true, testing::Optional(testing::Eq(TransactionsCursor{MINSEQ, 0})), testing::_ ) @@ -635,7 +625,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardTrue) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -660,15 +650,13 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardTrue) TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardFalse) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -680,7 +668,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardFalse) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -705,15 +693,13 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardFalse) TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV1) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -725,7 +711,7 @@ TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV1) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -764,14 +750,12 @@ TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV1) TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV2) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -783,7 +767,7 @@ TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV2) .WillOnce(Return(transCursor)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -822,15 +806,13 @@ TEST_F(RPCNFTHistoryHandlerTest, BinaryTrueV2) TEST_F(RPCNFTHistoryHandlerTest, LimitAndMarker) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, false, testing::Optional(testing::Eq(TransactionsCursor{10, 11})), testing::_ ) @@ -838,7 +820,7 @@ TEST_F(RPCNFTHistoryHandlerTest, LimitAndMarker) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -865,16 +847,14 @@ TEST_F(RPCNFTHistoryHandlerTest, LimitAndMarker) TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerIndex) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + // adjust the order for forward->false auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -886,11 +866,11 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerIndex) .Times(1); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ - 1); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -912,16 +892,13 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerIndex) TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerIntIndex) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -940,16 +917,13 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerIntIndex) TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerStringIndex) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ - 1, _)).WillByDefault(Return(std::nullopt)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -968,16 +942,14 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerStringIndex) TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerHash) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + // adjust the order for forward->false auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -989,11 +961,11 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerHash) .Times(1); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ - 1); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -1015,15 +987,13 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerHash) TEST_F(RPCNFTHistoryHandlerTest, TxLessThanMinSeq) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -1035,7 +1005,7 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLessThanMinSeq) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -1060,15 +1030,13 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLessThanMinSeq) TEST_F(RPCNFTHistoryHandlerTest, TxLargerThanMaxSeq) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MAXSEQ - 1, MINSEQ + 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -1080,7 +1048,7 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLargerThanMaxSeq) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", @@ -1105,15 +1073,13 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLargerThanMaxSeq) TEST_F(RPCNFTHistoryHandlerTest, LimitMoreThanMax) { - mockBackendPtr->updateRange(MINSEQ); // min - mockBackendPtr->updateRange(MAXSEQ); // max - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const transactions = genTransactions(MINSEQ + 1, MAXSEQ - 1); auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}}; - ON_CALL(*rawBackendPtr, fetchNFTTransactions).WillByDefault(Return(transCursor)); + ON_CALL(*backend, fetchNFTTransactions).WillByDefault(Return(transCursor)); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTTransactions( testing::_, testing::_, @@ -1125,7 +1091,7 @@ TEST_F(RPCNFTHistoryHandlerTest, LimitMoreThanMax) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTHistoryHandler{backend}}; auto const static input = json::parse(fmt::format( R"({{ "nft_id":"{}", diff --git a/unittests/rpc/handlers/NFTInfoTests.cpp b/unittests/rpc/handlers/NFTInfoTests.cpp index ff814478c..0ad932ba8 100644 --- a/unittests/rpc/handlers/NFTInfoTests.cpp +++ b/unittests/rpc/handlers/NFTInfoTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/NFTInfo.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -51,7 +50,7 @@ class RPCNFTInfoHandlerTest : public HandlerBaseTest {}; TEST_F(RPCNFTInfoHandlerTest, NonHexLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -71,7 +70,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonHexLedgerHash) TEST_F(RPCNFTInfoHandlerTest, NonStringLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -91,7 +90,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonStringLedgerHash) TEST_F(RPCNFTInfoHandlerTest, InvalidLedgerIndexString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -112,7 +111,7 @@ TEST_F(RPCNFTInfoHandlerTest, InvalidLedgerIndexString) TEST_F(RPCNFTInfoHandlerTest, NFTIDInvalidFormat) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const input = json::parse(R"({ "nft_id": "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE7" })"); @@ -128,7 +127,7 @@ TEST_F(RPCNFTInfoHandlerTest, NFTIDInvalidFormat) TEST_F(RPCNFTInfoHandlerTest, NFTIDNotString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const input = json::parse(R"({ "nft_id": 12 })"); @@ -144,12 +143,10 @@ TEST_F(RPCNFTInfoHandlerTest, NFTIDNotString) // error case ledger non exist via hash TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerHash) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); // mock fetchLedgerByHash return empty - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -160,7 +157,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerHash) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -173,13 +170,10 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerHash) // error case ledger non exist via index TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerStringIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -188,7 +182,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerStringIndex) NFTID )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -199,13 +193,10 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerStringIndex) TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerIntIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -214,7 +205,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerIntIndex) NFTID )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -227,14 +218,11 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerIntIndex) // idk why this case will happen in reality TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerHash2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerByHash return ledger but seq is 31 > 30 auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 31); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -244,7 +232,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerHash2) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -256,13 +244,10 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerHash2) // error case ledger > max seq via index TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerIndex2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // no need to check from db,call fetchLedgerBySequence 0 time // differ from previous logic - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(0); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(0); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -271,7 +256,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerIndex2) NFTID )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -283,16 +268,13 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistLedgerViaLedgerIndex2) // error case nft does not exist TEST_F(RPCNFTInfoHandlerTest, NonExistNFT) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch nft return emtpy - ON_CALL(*rawBackendPtr, fetchNFT).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); + ON_CALL(*backend, fetchNFT).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -302,7 +284,7 @@ TEST_F(RPCNFTInfoHandlerTest, NonExistNFT) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTInfoHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTInfoHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -327,18 +309,16 @@ TEST_F(RPCNFTInfoHandlerTest, DefaultParameters) "uri": "757269", "validated": true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch nft return something auto const nft = std::make_optional(CreateNFT(NFTID, ACCOUNT, ledgerInfo.seq)); - ON_CALL(*rawBackendPtr, fetchNFT).WillByDefault(Return(nft)); - EXPECT_CALL(*rawBackendPtr, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); + ON_CALL(*backend, fetchNFT).WillByDefault(Return(nft)); + EXPECT_CALL(*backend, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -347,7 +327,7 @@ TEST_F(RPCNFTInfoHandlerTest, DefaultParameters) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTInfoHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTInfoHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -370,19 +350,17 @@ TEST_F(RPCNFTInfoHandlerTest, BurnedNFT) "uri": "757269", "validated": true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch nft return something auto const nft = std::make_optional(CreateNFT(NFTID, ACCOUNT, ledgerInfo.seq, ripple::Blob{'u', 'r', 'i'}, true)); - ON_CALL(*rawBackendPtr, fetchNFT).WillByDefault(Return(nft)); - EXPECT_CALL(*rawBackendPtr, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); + ON_CALL(*backend, fetchNFT).WillByDefault(Return(nft)); + EXPECT_CALL(*backend, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -391,7 +369,7 @@ TEST_F(RPCNFTInfoHandlerTest, BurnedNFT) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTInfoHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTInfoHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -414,18 +392,16 @@ TEST_F(RPCNFTInfoHandlerTest, NotBurnedNFTWithoutURI) "uri": "", "validated": true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch nft return something auto const nft = std::make_optional(CreateNFT(NFTID, ACCOUNT, ledgerInfo.seq, ripple::Blob{})); - ON_CALL(*rawBackendPtr, fetchNFT).WillByDefault(Return(nft)); - EXPECT_CALL(*rawBackendPtr, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); + ON_CALL(*backend, fetchNFT).WillByDefault(Return(nft)); + EXPECT_CALL(*backend, fetchNFT(ripple::uint256{NFTID}, 30, _)).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -434,7 +410,7 @@ TEST_F(RPCNFTInfoHandlerTest, NotBurnedNFTWithoutURI) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTInfoHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTInfoHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -457,18 +433,16 @@ TEST_F(RPCNFTInfoHandlerTest, NFTWithExtraFieldsSet) "uri": "757269", "validated": true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // fetch nft return something auto const nft = std::make_optional(CreateNFT(NFTID2, ACCOUNT, ledgerInfo.seq)); - ON_CALL(*rawBackendPtr, fetchNFT).WillByDefault(Return(nft)); - EXPECT_CALL(*rawBackendPtr, fetchNFT(ripple::uint256{NFTID2}, 30, _)).Times(1); + ON_CALL(*backend, fetchNFT).WillByDefault(Return(nft)); + EXPECT_CALL(*backend, fetchNFT(ripple::uint256{NFTID2}, 30, _)).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -477,7 +451,7 @@ TEST_F(RPCNFTInfoHandlerTest, NFTWithExtraFieldsSet) NFTID2 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTInfoHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTInfoHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); diff --git a/unittests/rpc/handlers/NFTSellOffersTests.cpp b/unittests/rpc/handlers/NFTSellOffersTests.cpp index 9ae59a79b..fa9e5045b 100644 --- a/unittests/rpc/handlers/NFTSellOffersTests.cpp +++ b/unittests/rpc/handlers/NFTSellOffersTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/NFTSellOffers.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -54,7 +53,7 @@ class RPCNFTSellOffersHandlerTest : public HandlerBaseTest {}; TEST_F(RPCNFTSellOffersHandlerTest, LimitNotInt) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -73,7 +72,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitNotInt) TEST_F(RPCNFTSellOffersHandlerTest, LimitNegative) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -92,7 +91,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitNegative) TEST_F(RPCNFTSellOffersHandlerTest, LimitZero) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -111,7 +110,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitZero) TEST_F(RPCNFTSellOffersHandlerTest, NonHexLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -131,7 +130,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonHexLedgerHash) TEST_F(RPCNFTSellOffersHandlerTest, NonStringLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -151,7 +150,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonStringLedgerHash) TEST_F(RPCNFTSellOffersHandlerTest, InvalidLedgerIndexString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -172,7 +171,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, InvalidLedgerIndexString) TEST_F(RPCNFTSellOffersHandlerTest, NFTIDInvalidFormat) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(R"({ "nft_id": "00080000B4F4AFC5FBCBD76873F18006173D2193467D3EE7" })"); @@ -188,7 +187,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NFTIDInvalidFormat) TEST_F(RPCNFTSellOffersHandlerTest, NFTIDNotString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(R"({ "nft_id": 12 })"); @@ -204,12 +203,10 @@ TEST_F(RPCNFTSellOffersHandlerTest, NFTIDNotString) // error case ledger non exist via hash TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerHash) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); // mock fetchLedgerByHash return empty - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -220,7 +217,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerHash) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -233,13 +230,10 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerHash) // error case ledger non exist via index TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -248,7 +242,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerIndex) NFTID )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -261,14 +255,11 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerIndex) // idk why this case will happen in reality TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerHash2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerByHash return ledger but seq is 31 > 30 auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 31); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -278,7 +269,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerHash2) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -290,13 +281,10 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerHash2) // error case ledger > max seq via index TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerIndex2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // no need to check from db, call fetchLedgerBySequence 0 time // differ from previous logic - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(0); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(0); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -305,7 +293,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerIndex2) NFTID )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -317,15 +305,12 @@ TEST_F(RPCNFTSellOffersHandlerTest, NonExistLedgerViaLedgerIndex2) // error case when nft is not found TEST_F(RPCNFTSellOffersHandlerTest, NoNFT) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::nullopt)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::nullopt)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -335,7 +320,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NoNFT) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -347,7 +332,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, NoNFT) TEST_F(RPCNFTSellOffersHandlerTest, MarkerNotString) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -369,7 +354,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, MarkerNotString) TEST_F(RPCNFTSellOffersHandlerTest, InvalidMarker) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -385,7 +370,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, InvalidMarker) EXPECT_EQ(err.at("error_message").as_string(), "markerMalformed"); }); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -422,29 +407,27 @@ TEST_F(RPCNFTSellOffersHandlerTest, DefaultParameters) } ] })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index containing 2 indexes auto const directory = ripple::keylet::nft_sells(ripple::uint256{NFTID}); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); // return two nft sell offers std::vector bbs; auto const offer = CreateNFTSellOffer(NFTID, ACCOUNT); bbs.push_back(offer.getSerializer().peekData()); bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -453,7 +436,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, DefaultParameters) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTSellOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTSellOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -464,13 +447,10 @@ TEST_F(RPCNFTSellOffersHandlerTest, DefaultParameters) // normal case when provided with nft_id and limit TEST_F(RPCNFTSellOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index std::vector indexes; @@ -484,11 +464,11 @@ TEST_F(RPCNFTSellOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) } ripple::STObject const ownerDir = CreateOwnerDirLedgerObject(indexes, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(ownerDir.getSerializer().peekData())); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -498,7 +478,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTSellOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTSellOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -513,13 +493,10 @@ TEST_F(RPCNFTSellOffersHandlerTest, MultipleResultsWithMarkerAndLimitOutput) // normal case when provided with nft_id, limit and marker TEST_F(RPCNFTSellOffersHandlerTest, ResultsForInputWithMarkerAndLimit) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index std::vector indexes; @@ -537,19 +514,19 @@ TEST_F(RPCNFTSellOffersHandlerTest, ResultsForInputWithMarkerAndLimit) // first is nft offer object auto const cursor = ripple::uint256{"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC353"}; auto const first = ripple::keylet::nftoffer(cursor); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)) .WillByDefault(Return(cursorSellOffer.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); auto const directory = ripple::keylet::nft_sells(ripple::uint256{NFTID}); auto const startHint = 0ul; // offer node is hardcoded to 0ul auto const secondKey = ripple::keylet::page(directory, startHint).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(3); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -560,7 +537,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, ResultsForInputWithMarkerAndLimit) NFTID )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTSellOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTSellOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -577,13 +554,10 @@ TEST_F(RPCNFTSellOffersHandlerTest, ResultsForInputWithMarkerAndLimit) // nothing left after reading remaining 50 entries TEST_F(RPCNFTSellOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLimit) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(3); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(3); // return owner index std::vector indexes; @@ -601,22 +575,22 @@ TEST_F(RPCNFTSellOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLim // first is nft offer object auto const cursor = ripple::uint256{"E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC353"}; auto const first = ripple::keylet::nftoffer(cursor); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)) .WillByDefault(Return(cursorSellOffer.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObject(first.key, testing::_, testing::_)).Times(1); auto const directory = ripple::keylet::nft_sells(ripple::uint256{NFTID}); auto const startHint = 0ul; // offer node is hardcoded to 0ul auto const secondKey = ripple::keylet::page(directory, startHint).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(7); + EXPECT_CALL(*backend, doFetchLedgerObject(secondKey, testing::_, testing::_)).Times(7); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(3); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(3); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTSellOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTSellOffersHandler{this->backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -635,7 +609,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLim }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -648,7 +622,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLim }); runSpawn([this](auto yield) { - auto const handler = AnyHandler{NFTSellOffersHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTSellOffersHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "nft_id": "{}", @@ -663,22 +637,19 @@ TEST_F(RPCNFTSellOffersHandlerTest, ResultsWithoutMarkerForInputWithMarkerAndLim TEST_F(RPCNFTSellOffersHandlerTest, LimitLessThanMin) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index containing 2 indexes auto const directory = ripple::keylet::nft_sells(ripple::uint256{NFTID}); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{NFTSellOffersHandler::LIMIT_MIN + 1, ripple::uint256{INDEX1}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); // return two nft buy offers std::vector bbs; @@ -686,8 +657,8 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitLessThanMin) bbs.reserve(NFTSellOffersHandler::LIMIT_MIN + 1); for (auto i = 0; i < NFTSellOffersHandler::LIMIT_MIN + 1; i++) bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -698,7 +669,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitLessThanMin) NFTSellOffersHandler::LIMIT_MIN - 1 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTSellOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTSellOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); @@ -709,22 +680,19 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitLessThanMin) TEST_F(RPCNFTSellOffersHandlerTest, LimitMoreThanMax) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return owner index containing 2 indexes auto const directory = ripple::keylet::nft_sells(ripple::uint256{NFTID}); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{NFTSellOffersHandler::LIMIT_MAX + 1, ripple::uint256{INDEX1}}, INDEX1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)) + ON_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject(directory.key, testing::_, testing::_)).Times(2); // return two nft buy offers std::vector bbs; @@ -732,8 +700,8 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitMoreThanMax) bbs.reserve(NFTSellOffersHandler::LIMIT_MAX + 1); for (auto i = 0; i < NFTSellOffersHandler::LIMIT_MAX + 1; i++) bbs.push_back(offer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -744,7 +712,7 @@ TEST_F(RPCNFTSellOffersHandlerTest, LimitMoreThanMax) NFTSellOffersHandler::LIMIT_MAX + 1 )); runSpawn([&, this](auto yield) { - auto handler = AnyHandler{NFTSellOffersHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTSellOffersHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); diff --git a/unittests/rpc/handlers/NFTsByIssuerTest.cpp b/unittests/rpc/handlers/NFTsByIssuerTest.cpp index a2bf39c5b..734353ebd 100644 --- a/unittests/rpc/handlers/NFTsByIssuerTest.cpp +++ b/unittests/rpc/handlers/NFTsByIssuerTest.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/NFTsByIssuer.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -95,7 +94,7 @@ class RPCNFTsByIssuerHandlerTest : public HandlerBaseTest {}; TEST_F(RPCNFTsByIssuerHandlerTest, NonHexLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "issuer": "{}", @@ -115,7 +114,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonHexLedgerHash) TEST_F(RPCNFTsByIssuerHandlerTest, NonStringLedgerHash) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "issuer": "{}", @@ -135,7 +134,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonStringLedgerHash) TEST_F(RPCNFTsByIssuerHandlerTest, InvalidLedgerIndexString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const input = json::parse(fmt::format( R"({{ "issuer": "{}", @@ -156,7 +155,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, InvalidLedgerIndexString) TEST_F(RPCNFTsByIssuerHandlerTest, NFTIssuerInvalidFormat) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const input = json::parse(R"({ "issuer": "xxx" })"); @@ -172,7 +171,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NFTIssuerInvalidFormat) TEST_F(RPCNFTsByIssuerHandlerTest, NFTIssuerMissing) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const input = json::parse(R"({})"); auto const output = handler.process(input, Context{std::ref(yield)}); ASSERT_FALSE(output); @@ -186,7 +185,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NFTIssuerMissing) TEST_F(RPCNFTsByIssuerHandlerTest, NFTIssuerNotString) { runSpawn([this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const input = json::parse(R"({ "issuer": 12 })"); @@ -202,10 +201,9 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NFTIssuerNotString) // error case ledger non exist via hash TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerHash) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); // mock fetchLedgerByHash return empty - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)) .WillByDefault(Return(std::optional{})); auto const input = json::parse(fmt::format( @@ -217,7 +215,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerHash) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const output = handler.process(input, Context{std::ref(yield)}); ASSERT_FALSE(output); @@ -230,11 +228,9 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerHash) // error case ledger non exist via index TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerStringIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(std::optional{})); auto const input = json::parse(fmt::format( R"({{ "issuer": "{}", @@ -243,7 +239,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerStringIndex) ACCOUNT )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const output = handler.process(input, Context{std::ref(yield)}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -254,12 +250,9 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerStringIndex) TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerIntIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(std::optional{})); auto const input = json::parse(fmt::format( R"({{ "issuer": "{}", @@ -268,7 +261,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerIntIndex) ACCOUNT )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const output = handler.process(input, Context{std::ref(yield)}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -281,14 +274,11 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerIntIndex) // idk why this case will happen in reality TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerHash2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerByHash return ledger but seq is 31 > 30 auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 31); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ "issuer": "{}", @@ -298,7 +288,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerHash2) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const output = handler.process(input, Context{std::ref(yield)}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -310,13 +300,10 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerHash2) // error case ledger > max seq via index TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerIndex2) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // no need to check from db,call fetchLedgerBySequence 0 time // differ from previous logic - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(0); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(0); auto const input = json::parse(fmt::format( R"({{ "issuer": "{}", @@ -325,7 +312,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerIndex2) ACCOUNT )); runSpawn([&, this](boost::asio::yield_context yield) { - auto const handler = AnyHandler{NFTsByIssuerHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NFTsByIssuerHandler{backend}}; auto const output = handler.process(input, Context{std::ref(yield)}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -337,15 +324,12 @@ TEST_F(RPCNFTsByIssuerHandlerTest, NonExistLedgerViaLedgerIndex2) // normal case when issuer does not exist or has no NFTs TEST_F(RPCNFTsByIssuerHandlerTest, AccountNotFound) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -356,7 +340,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, AccountNotFound) LEDGERHASH )); runSpawn([&, this](boost::asio::yield_context yield) { - auto handler = AnyHandler{NFTsByIssuerHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTsByIssuerHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -379,20 +363,18 @@ TEST_F(RPCNFTsByIssuerHandlerTest, DefaultParameters) ACCOUNT, NFT1OUT ); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); std::vector const nfts = {CreateNFT(NFTID1, ACCOUNT, 29)}; auto const account = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); + ON_CALL(*backend, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTsByIssuer( account, testing::Eq(std::nullopt), Const(30), testing::_, testing::Eq(std::nullopt), testing::_ ) @@ -406,7 +388,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, DefaultParameters) ACCOUNT )); runSpawn([&, this](auto& yield) { - auto handler = AnyHandler{NFTsByIssuerHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTsByIssuerHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -438,22 +420,20 @@ TEST_F(RPCNFTsByIssuerHandlerTest, SpecificLedgerIndex) ACCOUNT, specificLedger ); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, specificLedger); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(specificLedger, _)).WillByDefault(Return(ledgerInfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence(specificLedger, _)).WillByDefault(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, specificLedger, _)) + ON_CALL(*backend, doFetchLedgerObject(accountKk, specificLedger, _)) .WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); std::vector const nfts = {CreateNFT(NFTID1, ACCOUNT, specificLedger)}; auto const account = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); + ON_CALL(*backend, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTsByIssuer( account, testing::Eq(std::nullopt), Const(specificLedger), testing::_, testing::Eq(std::nullopt), testing::_ ) @@ -469,7 +449,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, SpecificLedgerIndex) specificLedger )); runSpawn([&, this](auto& yield) { - auto handler = AnyHandler{NFTsByIssuerHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTsByIssuerHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -490,20 +470,18 @@ TEST_F(RPCNFTsByIssuerHandlerTest, TaxonParameter) ACCOUNT, NFT1OUT ); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); std::vector const nfts = {CreateNFT(NFTID1, ACCOUNT, 29)}; auto const account = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); + ON_CALL(*backend, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTsByIssuer(account, testing::Optional(0), Const(30), testing::_, testing::Eq(std::nullopt), testing::_) ) .Times(1); @@ -516,7 +494,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, TaxonParameter) ACCOUNT )); runSpawn([&, this](auto& yield) { - auto handler = AnyHandler{NFTsByIssuerHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTsByIssuerHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -537,20 +515,18 @@ TEST_F(RPCNFTsByIssuerHandlerTest, MarkerParameter) ACCOUNT, NFT3OUT ); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); std::vector const nfts = {CreateNFT(NFTID3, ACCOUNT, 29)}; auto const account = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, ripple::uint256{NFTID3}})); + ON_CALL(*backend, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, ripple::uint256{NFTID3}})); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTsByIssuer(account, testing::_, Const(30), testing::_, testing::Eq(ripple::uint256{NFTID1}), testing::_) ) .Times(1); @@ -564,7 +540,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, MarkerParameter) NFTID1 )); runSpawn([&, this](auto& yield) { - auto handler = AnyHandler{NFTsByIssuerHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTsByIssuerHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -586,22 +562,20 @@ TEST_F(RPCNFTsByIssuerHandlerTest, MultipleNFTs) NFT2OUT, NFT3OUT ); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); std::vector const nfts = { CreateNFT(NFTID1, ACCOUNT, 29), CreateNFT(NFTID2, ACCOUNT, 29), CreateNFT(NFTID3, ACCOUNT, 29) }; auto const account = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); + ON_CALL(*backend, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTsByIssuer( account, testing::Eq(std::nullopt), Const(30), testing::_, testing::Eq(std::nullopt), testing::_ ) @@ -615,7 +589,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, MultipleNFTs) ACCOUNT )); runSpawn([&, this](auto& yield) { - auto handler = AnyHandler{NFTsByIssuerHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTsByIssuerHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); @@ -635,20 +609,18 @@ TEST_F(RPCNFTsByIssuerHandlerTest, LimitMoreThanMAx) ACCOUNT, NFT1OUT ); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerInfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerInfo)); auto const accountKk = ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); + ON_CALL(*backend, doFetchLedgerObject(accountKk, 30, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'})); std::vector const nfts = {CreateNFT(NFTID1, ACCOUNT, 29)}; auto const account = GetAccountIDWithString(ACCOUNT); - ON_CALL(*rawBackendPtr, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); + ON_CALL(*backend, fetchNFTsByIssuer).WillByDefault(Return(NFTsAndCursor{nfts, {}})); EXPECT_CALL( - *rawBackendPtr, + *backend, fetchNFTsByIssuer( account, testing::Eq(std::nullopt), @@ -669,7 +641,7 @@ TEST_F(RPCNFTsByIssuerHandlerTest, LimitMoreThanMAx) NFTsByIssuerHandler::LIMIT_MAX + 1 )); runSpawn([&, this](auto& yield) { - auto handler = AnyHandler{NFTsByIssuerHandler{this->mockBackendPtr}}; + auto handler = AnyHandler{NFTsByIssuerHandler{this->backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(json::parse(currentOutput), *output); diff --git a/unittests/rpc/handlers/NoRippleCheckTests.cpp b/unittests/rpc/handlers/NoRippleCheckTests.cpp index c8db5de82..6261a3eb6 100644 --- a/unittests/rpc/handlers/NoRippleCheckTests.cpp +++ b/unittests/rpc/handlers/NoRippleCheckTests.cpp @@ -22,7 +22,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/NoRippleCheck.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -174,7 +173,7 @@ TEST_P(NoRippleCheckParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 2}); ASSERT_FALSE(output); @@ -194,11 +193,10 @@ TEST_F(NoRippleCheckParameterTest, V1ApiTransactionsIsNotBool) "transactions": "gg" } )"; - auto rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence); + + EXPECT_CALL(*backend, fetchLedgerBySequence); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const req = json::parse(reqJson); auto const output = handler.process(req, Context{.yield = yield, .apiVersion = 1}); ASSERT_FALSE(output); @@ -211,13 +209,10 @@ TEST_F(NoRippleCheckParameterTest, V1ApiTransactionsIsNotBool) TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaHash) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt)); auto static const input = json::parse(fmt::format( R"({{ @@ -228,7 +223,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaHash) ACCOUNT, LEDGERHASH )); - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -241,13 +236,11 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaHash) TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaIntIndex) { auto constexpr seq = 12; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt)); auto static const input = json::parse(fmt::format( R"({{ @@ -258,7 +251,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaIntIndex) ACCOUNT, seq )); - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -271,13 +264,11 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaIntIndex) TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaStringIndex) { auto constexpr seq = 12; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return empty ledgerinfo - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt)); + ON_CALL(*backend, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt)); auto static const input = json::parse(fmt::format( R"({{ @@ -288,7 +279,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaStringIndex) ACCOUNT, seq )); - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; runSpawn([&](auto yield) { auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); @@ -300,16 +291,13 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaStringIndex) TEST_F(RPCNoRippleCheckTest, AccountNotExist) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return emtpy - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); auto const input = json::parse(fmt::format( R"({{ "account": "{}", @@ -320,7 +308,7 @@ TEST_F(RPCNoRippleCheckTest, AccountNotExist) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -342,24 +330,22 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleUserDefaultRippleSetTrustLineNoRipple ], "validated":true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max + + backend->setRange(10, seq); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault(Return( CreateAccountRootObject(ACCOUNT, ripple::lsfDefaultRipple, 2, 200, 2, INDEX1, 2).getSerializer().peekData() )); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const line1 = CreateRippleStateLedgerObject( "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, ripple::lsfLowNoRipple @@ -373,8 +359,8 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleUserDefaultRippleSetTrustLineNoRipple bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -386,7 +372,7 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleUserDefaultRippleSetTrustLineNoRipple LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(*output, json::parse(expectedOutput)); @@ -406,22 +392,20 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleUserDefaultRippleUnsetTrustLineNoRipp ], "validated":true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max + + backend->setRange(10, seq); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); @@ -431,8 +415,8 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleUserDefaultRippleUnsetTrustLineNoRipp bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -444,7 +428,7 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleUserDefaultRippleUnsetTrustLineNoRipp LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(*output, json::parse(expectedOutput)); @@ -465,24 +449,22 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleSetTrustLineNoRip ], "validated":true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max + + backend->setRange(10, seq); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault(Return( CreateAccountRootObject(ACCOUNT, ripple::lsfDefaultRipple, 2, 200, 2, INDEX1, 2).getSerializer().peekData() )); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const line1 = CreateRippleStateLedgerObject( "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, ripple::lsfLowNoRipple @@ -496,8 +478,8 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleSetTrustLineNoRip bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -509,7 +491,7 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleSetTrustLineNoRip LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(*output, json::parse(expectedOutput)); @@ -529,22 +511,20 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoR ], "validated":true })"; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max + + backend->setRange(10, seq); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, 0); @@ -554,8 +534,8 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoR bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -567,7 +547,7 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoR LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(*output, json::parse(expectedOutput)); @@ -577,24 +557,22 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoR TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoRippleUnsetHighAccount) { static auto constexpr seq = 30; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max + + backend->setRange(10, seq); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto const line1 = CreateRippleStateLedgerObject("USD", ISSUER, 100, ACCOUNT2, 10, ACCOUNT, 20, TXNID, 123, 0); @@ -604,8 +582,8 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoR bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -618,7 +596,7 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoR LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(output->as_object().at("transactions").as_array().size(), 1); @@ -629,24 +607,22 @@ TEST_F(RPCNoRippleCheckTest, NormalPathRoleGatewayDefaultRippleUnsetTrustLineNoR TEST_F(RPCNoRippleCheckTest, NormalPathLimit) { constexpr auto seq = 30; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault(Return( CreateAccountRootObject(ACCOUNT, ripple::lsfDefaultRipple, 2, 200, 2, INDEX1, 2).getSerializer().peekData() )); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const line1 = CreateRippleStateLedgerObject( "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, ripple::lsfLowNoRipple @@ -660,8 +636,8 @@ TEST_F(RPCNoRippleCheckTest, NormalPathLimit) bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -674,7 +650,7 @@ TEST_F(RPCNoRippleCheckTest, NormalPathLimit) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(output->as_object().at("problems").as_array().size(), 1); @@ -735,26 +711,24 @@ TEST_F(RPCNoRippleCheckTest, NormalPathTransactions) transactionSeq + 2, ripple::tfClearNoRipple ); - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(seq); // max + + backend->setRange(10, seq); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault( Return(CreateAccountRootObject(ACCOUNT, 0, transactionSeq, 200, 2, INDEX1, 2).getSerializer().peekData()) ); auto const ownerDir = CreateOwnerDirLedgerObject({ripple::uint256{INDEX1}, ripple::uint256{INDEX2}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, seq, _)) .WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0))); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(3); auto const line1 = CreateRippleStateLedgerObject( "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, ripple::lsfLowNoRipple @@ -768,8 +742,8 @@ TEST_F(RPCNoRippleCheckTest, NormalPathTransactions) bbs.push_back(line1.getSerializer().peekData()); bbs.push_back(line2.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -782,7 +756,7 @@ TEST_F(RPCNoRippleCheckTest, NormalPathTransactions) LEDGERHASH )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(*output, json::parse(expectedOutput)); @@ -792,25 +766,23 @@ TEST_F(RPCNoRippleCheckTest, NormalPathTransactions) TEST_F(RPCNoRippleCheckTest, LimitMoreThanMax) { constexpr auto seq = 30; - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + + backend->setRange(10, 30); auto ledgerinfo = CreateLedgerInfo(LEDGERHASH, seq); - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); // fetch account object return valid account with DefaultRippleSet flag - ON_CALL(*rawBackendPtr, doFetchLedgerObject) + ON_CALL(*backend, doFetchLedgerObject) .WillByDefault(Return( CreateAccountRootObject(ACCOUNT, ripple::lsfDefaultRipple, 2, 200, 2, INDEX1, 2).getSerializer().peekData() )); auto const ownerDir = CreateOwnerDirLedgerObject(std::vector{NoRippleCheckHandler::LIMIT_MAX + 1, ripple::uint256{INDEX1}}, INDEX1); auto const ownerDirKk = ripple::keylet::ownerDir(GetAccountIDWithString(ACCOUNT)).key; - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ownerDirKk, seq, _)) + ON_CALL(*backend, doFetchLedgerObject(ownerDirKk, seq, _)) .WillByDefault(Return(ownerDir.getSerializer().peekData())); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(2); auto const line1 = CreateRippleStateLedgerObject( "USD", ISSUER, 100, ACCOUNT, 10, ACCOUNT2, 20, TXNID, 123, ripple::lsfLowNoRipple @@ -822,8 +794,8 @@ TEST_F(RPCNoRippleCheckTest, LimitMoreThanMax) bbs.push_back(line1.getSerializer().peekData()); } - ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + ON_CALL(*backend, doFetchLedgerObjects).WillByDefault(Return(bbs)); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -837,7 +809,7 @@ TEST_F(RPCNoRippleCheckTest, LimitMoreThanMax) NoRippleCheckHandler::LIMIT_MAX + 1 )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{NoRippleCheckHandler{mockBackendPtr}}; + auto const handler = AnyHandler{NoRippleCheckHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_TRUE(output); EXPECT_EQ(output->as_object().at("problems").as_array().size(), NoRippleCheckHandler::LIMIT_MAX); diff --git a/unittests/rpc/handlers/ServerInfoTests.cpp b/unittests/rpc/handlers/ServerInfoTests.cpp index daf778676..47f8d6162 100644 --- a/unittests/rpc/handlers/ServerInfoTests.cpp +++ b/unittests/rpc/handlers/ServerInfoTests.cpp @@ -22,7 +22,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/ServerInfo.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/MockCounters.h" #include "util/MockETLService.h" #include "util/MockLoadBalancer.h" @@ -61,10 +60,7 @@ class RPCServerInfoHandlerTest : public HandlerBaseTest, MockSubscriptionManagerTest::SetUp(); MockCountersTest::SetUp(); - rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); } void @@ -156,16 +152,14 @@ class RPCServerInfoHandlerTest : public HandlerBaseTest, EXPECT_EQ(cache.at("object_hit_rate").as_double(), 1.0); EXPECT_EQ(cache.at("successor_hit_rate").as_double(), 1.0); } - - MockBackend* rawBackendPtr = nullptr; }; TEST_F(RPCServerInfoHandlerTest, NoLedgerInfoErrorsOutWithInternal) { - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(std::nullopt)); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { @@ -182,11 +176,11 @@ TEST_F(RPCServerInfoHandlerTest, NoLedgerInfoErrorsOutWithInternal) TEST_F(RPCServerInfoHandlerTest, NoFeesErrorsOutWithInternal) { auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(std::nullopt)); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { @@ -207,10 +201,10 @@ TEST_F(RPCServerInfoHandlerTest, DefaultOutputIsPresent) MockETLService* rawETLServicePtr = mockETLServicePtr.get(); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(feeBlob)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(feeBlob)); EXPECT_CALL(*rawBalancerPtr, forwardToRippled(testing::_, testing::Eq(CLIENTIP), testing::_)) .WillOnce(Return(std::nullopt)); @@ -220,7 +214,7 @@ TEST_F(RPCServerInfoHandlerTest, DefaultOutputIsPresent) EXPECT_CALL(*rawETLServicePtr, isAmendmentBlocked).WillOnce(Return(false)); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { @@ -244,10 +238,10 @@ TEST_F(RPCServerInfoHandlerTest, AmendmentBlockedIsPresentIfSet) MockETLService* rawETLServicePtr = mockETLServicePtr.get(); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(feeBlob)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(feeBlob)); EXPECT_CALL(*rawBalancerPtr, forwardToRippled(testing::_, testing::Eq(CLIENTIP), testing::_)) .WillOnce(Return(std::nullopt)); @@ -257,7 +251,7 @@ TEST_F(RPCServerInfoHandlerTest, AmendmentBlockedIsPresentIfSet) EXPECT_CALL(*rawETLServicePtr, isAmendmentBlocked).WillOnce(Return(true)); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { @@ -281,10 +275,10 @@ TEST_F(RPCServerInfoHandlerTest, AdminSectionPresentWhenAdminFlagIsSet) auto const empty = json::object{}; auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(feeBlob)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(feeBlob)); EXPECT_CALL(*rawBalancerPtr, forwardToRippled).WillOnce(Return(empty)); @@ -300,7 +294,7 @@ TEST_F(RPCServerInfoHandlerTest, AdminSectionPresentWhenAdminFlagIsSet) EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty)); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { @@ -321,10 +315,10 @@ TEST_F(RPCServerInfoHandlerTest, BackendCountersPresentWhenRequestWithParam) auto const empty = json::object{}; auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(feeBlob)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(feeBlob)); EXPECT_CALL(*rawBalancerPtr, forwardToRippled).WillOnce(Return(empty)); @@ -339,10 +333,10 @@ TEST_F(RPCServerInfoHandlerTest, BackendCountersPresentWhenRequestWithParam) EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty)); - EXPECT_CALL(*rawBackendPtr, stats).WillOnce(Return(boost::json::object{{"read_cout", 10}, {"write_count", 3}})); + EXPECT_CALL(*backend, stats).WillOnce(Return(boost::json::object{{"read_cout", 10}, {"write_count", 3}})); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { @@ -367,10 +361,10 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent) auto const empty = json::object{}; auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(feeBlob)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(feeBlob)); EXPECT_CALL(*rawCountersPtr, uptime).WillOnce(Return(std::chrono::seconds{1234})); @@ -396,7 +390,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent) EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty)); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { @@ -418,10 +412,10 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown) auto const empty = json::object{}; auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(ledgerinfo)); auto const feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).WillOnce(Return(feeBlob)); + EXPECT_CALL(*backend, doFetchLedgerObject).WillOnce(Return(feeBlob)); EXPECT_CALL(*rawCountersPtr, uptime).WillOnce(Return(std::chrono::seconds{1234})); @@ -442,7 +436,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown) EXPECT_CALL(*rawETLServicePtr, getInfo).WillOnce(Return(empty)); auto const handler = AnyHandler{TestServerInfoHandler{ - mockBackendPtr, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr + backend, mockSubscriptionManagerPtr, mockLoadBalancerPtr, mockETLServicePtr, *mockCountersPtr }}; runSpawn([&](auto yield) { diff --git a/unittests/rpc/handlers/SubscribeTests.cpp b/unittests/rpc/handlers/SubscribeTests.cpp index d7467dfc9..a67c078c4 100644 --- a/unittests/rpc/handlers/SubscribeTests.cpp +++ b/unittests/rpc/handlers/SubscribeTests.cpp @@ -25,7 +25,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/Subscribe.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/MockPrometheus.h" #include "util/MockWsBase.h" #include "util/Taggable.h" @@ -71,9 +70,9 @@ class RPCSubscribeHandlerTest : public util::prometheus::WithPrometheus, public SetUp() override { HandlerBaseTest::SetUp(); - util::Config const cfg; - subManager_ = feed::SubscriptionManager::make_SubscriptionManager(cfg, mockBackendPtr); - util::TagDecoratorFactory const tagDecoratorFactory{cfg}; + + subManager_ = std::make_shared(ctx, backend); + util::TagDecoratorFactory const tagDecoratorFactory{util::Config{}}; session_ = std::make_shared(tagDecoratorFactory); } void @@ -588,7 +587,7 @@ TEST_P(SubscribeParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -601,7 +600,7 @@ TEST_P(SubscribeParameterTest, InvalidParams) TEST_F(RPCSubscribeHandlerTest, EmptyResponse) { runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(json::parse(R"({})"), Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -617,7 +616,7 @@ TEST_F(RPCSubscribeHandlerTest, StreamsWithoutLedger) })" ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -643,18 +642,16 @@ TEST_F(RPCSubscribeHandlerTest, StreamsLedger) "reserve_base":3, "reserve_inc":2 })"; - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(MINSEQ, MAXSEQ); + + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); // return valid ledgerinfo auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ); - ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo)); + ON_CALL(*backend, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo)); // fee auto feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(feeBlob)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1); + ON_CALL(*backend, doFetchLedgerObject).WillByDefault(Return(feeBlob)); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(1); // ledger stream returns information about the ledgers on hand and current // fee schedule. @@ -664,7 +661,7 @@ TEST_F(RPCSubscribeHandlerTest, StreamsLedger) })" ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_EQ(output->as_object(), json::parse(expectedOutput)); @@ -685,7 +682,7 @@ TEST_F(RPCSubscribeHandlerTest, Accounts) ACCOUNT2 )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -707,7 +704,7 @@ TEST_F(RPCSubscribeHandlerTest, AccountsProposed) ACCOUNT2 )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -740,7 +737,7 @@ TEST_F(RPCSubscribeHandlerTest, JustBooks) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -773,7 +770,7 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSet) ACCOUNT )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -807,10 +804,8 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSnapshotSet) }})", ACCOUNT )); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const issuer = GetAccountIDWithString(ACCOUNT); auto const getsXRPPaysUSDBook = getBookBase(std::get( @@ -821,44 +816,40 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSnapshotSet) rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), issuer) )); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(getsXRPPaysUSDBook, MAXSEQ, _)) + ON_CALL(*backend, doFetchSuccessorKey(getsXRPPaysUSDBook, MAXSEQ, _)) .WillByDefault(Return(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR})); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) + ON_CALL(*backend, doFetchSuccessorKey(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) .WillByDefault(Return(std::nullopt)); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(reversedBook, MAXSEQ, _)) + ON_CALL(*backend, doFetchSuccessorKey(reversedBook, MAXSEQ, _)) .WillByDefault(Return(ripple::uint256{PAYS20XRPGETS10USDBOOKDIR})); - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(4); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(4); // 2 book dirs + 2 issuer global freeze + 2 transferRate + 1 owner root + 1 fee - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(8); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(8); auto const indexes = std::vector(10, ripple::uint256{INDEX2}); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) .WillByDefault(Return(CreateOwnerDirLedgerObject(indexes, INDEX1).getSerializer().peekData())); // for reverse auto const indexes2 = std::vector(10, ripple::uint256{INDEX1}); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{PAYS20XRPGETS10USDBOOKDIR}, MAXSEQ, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{PAYS20XRPGETS10USDBOOKDIR}, MAXSEQ, _)) .WillByDefault(Return(CreateOwnerDirLedgerObject(indexes2, INDEX2).getSerializer().peekData())); // offer owner account root - ON_CALL( - *rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, MAXSEQ, _) - ) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, MAXSEQ, _)) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT2, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); // issuer account root - ON_CALL( - *rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, MAXSEQ, _) - ) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, MAXSEQ, _)) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); // fee auto feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, MAXSEQ, _)).WillByDefault(Return(feeBlob)); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, MAXSEQ, _)).WillByDefault(Return(feeBlob)); auto const gets10XRPPays20USDOffer = CreateOfferLedgerObject( ACCOUNT2, @@ -885,13 +876,13 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSnapshotSet) ); std::vector const bbs(10, gets10XRPPays20USDOffer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects(indexes, MAXSEQ, _)).WillByDefault(Return(bbs)); + ON_CALL(*backend, doFetchLedgerObjects(indexes, MAXSEQ, _)).WillByDefault(Return(bbs)); // for reverse std::vector const bbs2(10, gets10USDPays20XRPOffer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects(indexes2, MAXSEQ, _)).WillByDefault(Return(bbs2)); + ON_CALL(*backend, doFetchLedgerObjects(indexes2, MAXSEQ, _)).WillByDefault(Return(bbs2)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(2); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(2); static auto const expectedOffer = fmt::format( R"({{ @@ -946,7 +937,7 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothSnapshotSet) ACCOUNT ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_EQ(output->as_object().at("bids").as_array().size(), 10); @@ -982,10 +973,8 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothUnsetSnapshotSet) }})", ACCOUNT )); - mockBackendPtr->updateRange(MINSEQ); - mockBackendPtr->updateRange(MAXSEQ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + backend->setRange(MINSEQ, MAXSEQ); + auto const issuer = GetAccountIDWithString(ACCOUNT); auto const getsXRPPaysUSDBook = getBookBase(std::get( @@ -996,43 +985,39 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothUnsetSnapshotSet) rpc::parseBook(ripple::xrpCurrency(), ripple::xrpAccount(), ripple::to_currency("USD"), issuer) )); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(getsXRPPaysUSDBook, MAXSEQ, _)) + ON_CALL(*backend, doFetchSuccessorKey(getsXRPPaysUSDBook, MAXSEQ, _)) .WillByDefault(Return(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR})); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) + ON_CALL(*backend, doFetchSuccessorKey(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) .WillByDefault(Return(std::nullopt)); - ON_CALL(*rawBackendPtr, doFetchSuccessorKey(reversedBook, MAXSEQ, _)) + ON_CALL(*backend, doFetchSuccessorKey(reversedBook, MAXSEQ, _)) .WillByDefault(Return(ripple::uint256{PAYS20XRPGETS10USDBOOKDIR})); - EXPECT_CALL(*rawBackendPtr, doFetchSuccessorKey).Times(2); + EXPECT_CALL(*backend, doFetchSuccessorKey).Times(2); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(5); + EXPECT_CALL(*backend, doFetchLedgerObject).Times(5); auto const indexes = std::vector(10, ripple::uint256{INDEX2}); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{PAYS20USDGETS10XRPBOOKDIR}, MAXSEQ, _)) .WillByDefault(Return(CreateOwnerDirLedgerObject(indexes, INDEX1).getSerializer().peekData())); // for reverse auto const indexes2 = std::vector(10, ripple::uint256{INDEX1}); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::uint256{PAYS20XRPGETS10USDBOOKDIR}, MAXSEQ, _)) + ON_CALL(*backend, doFetchLedgerObject(ripple::uint256{PAYS20XRPGETS10USDBOOKDIR}, MAXSEQ, _)) .WillByDefault(Return(CreateOwnerDirLedgerObject(indexes2, INDEX2).getSerializer().peekData())); // offer owner account root - ON_CALL( - *rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, MAXSEQ, _) - ) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT2)).key, MAXSEQ, _)) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT2, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); // issuer account root - ON_CALL( - *rawBackendPtr, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, MAXSEQ, _) - ) + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::account(GetAccountIDWithString(ACCOUNT)).key, MAXSEQ, _)) .WillByDefault(Return(CreateAccountRootObject(ACCOUNT, 0, 2, 200, 2, INDEX1, 2).getSerializer().peekData())); // fee auto feeBlob = CreateFeeSettingBlob(1, 2, 3, 4, 0); - ON_CALL(*rawBackendPtr, doFetchLedgerObject(ripple::keylet::fees().key, MAXSEQ, _)).WillByDefault(Return(feeBlob)); + ON_CALL(*backend, doFetchLedgerObject(ripple::keylet::fees().key, MAXSEQ, _)).WillByDefault(Return(feeBlob)); auto const gets10XRPPays20USDOffer = CreateOfferLedgerObject( ACCOUNT2, @@ -1059,13 +1044,13 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothUnsetSnapshotSet) ); std::vector const bbs(10, gets10XRPPays20USDOffer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects(indexes, MAXSEQ, _)).WillByDefault(Return(bbs)); + ON_CALL(*backend, doFetchLedgerObjects(indexes, MAXSEQ, _)).WillByDefault(Return(bbs)); // for reverse std::vector const bbs2(10, gets10USDPays20XRPOffer.getSerializer().peekData()); - ON_CALL(*rawBackendPtr, doFetchLedgerObjects(indexes2, MAXSEQ, _)).WillByDefault(Return(bbs2)); + ON_CALL(*backend, doFetchLedgerObjects(indexes2, MAXSEQ, _)).WillByDefault(Return(bbs2)); - EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1); + EXPECT_CALL(*backend, doFetchLedgerObjects).Times(1); static auto const expectedOffer = fmt::format( R"({{ @@ -1095,7 +1080,7 @@ TEST_F(RPCSubscribeHandlerTest, BooksBothUnsetSnapshotSet) ); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{SubscribeHandler{mockBackendPtr, subManager_}}; + auto const handler = AnyHandler{SubscribeHandler{backend, subManager_}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_EQ(output->as_object().at("offers").as_array().size(), 10); diff --git a/unittests/rpc/handlers/TransactionEntryTests.cpp b/unittests/rpc/handlers/TransactionEntryTests.cpp index 3a9bb56a9..fd9c751b7 100644 --- a/unittests/rpc/handlers/TransactionEntryTests.cpp +++ b/unittests/rpc/handlers/TransactionEntryTests.cpp @@ -23,7 +23,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/TransactionEntry.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/TestObject.h" #include @@ -50,7 +49,7 @@ class RPCTransactionEntryHandlerTest : public HandlerBaseTest {}; TEST_F(RPCTransactionEntryHandlerTest, TxHashNotProvide) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const output = handler.process(json::parse("{}"), Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -62,7 +61,7 @@ TEST_F(RPCTransactionEntryHandlerTest, TxHashNotProvide) TEST_F(RPCTransactionEntryHandlerTest, TxHashWrongFormat) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const output = handler.process(json::parse(R"({"tx_hash":"123"})"), Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -73,12 +72,10 @@ TEST_F(RPCTransactionEntryHandlerTest, TxHashWrongFormat) TEST_F(RPCTransactionEntryHandlerTest, NonExistLedgerViaLedgerHash) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); // mock fetchLedgerByHash return empty - ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{INDEX}, _)) + ON_CALL(*backend, fetchLedgerByHash(ripple::uint256{INDEX}, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerByHash).Times(1); + EXPECT_CALL(*backend, fetchLedgerByHash).Times(1); auto const input = json::parse(fmt::format( R"({{ @@ -89,7 +86,7 @@ TEST_F(RPCTransactionEntryHandlerTest, NonExistLedgerViaLedgerHash) TXNID )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -101,13 +98,10 @@ TEST_F(RPCTransactionEntryHandlerTest, NonExistLedgerViaLedgerHash) // error case ledger non exist via index TEST_F(RPCTransactionEntryHandlerTest, NonExistLedgerViaLedgerIndex) { - MockBackend* rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max + backend->setRange(10, 30); // mock fetchLedgerBySequence return empty - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(std::optional{})); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); auto const input = json::parse(fmt::format( R"({{ "ledger_index": "4", @@ -116,7 +110,7 @@ TEST_F(RPCTransactionEntryHandlerTest, NonExistLedgerViaLedgerIndex) TXNID )); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const output = handler.process(input, Context{yield}); ASSERT_FALSE(output); auto const err = rpc::makeError(output.error()); @@ -127,17 +121,14 @@ TEST_F(RPCTransactionEntryHandlerTest, NonExistLedgerViaLedgerIndex) TEST_F(RPCTransactionEntryHandlerTest, TXNotFound) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(CreateLedgerInfo(INDEX, 30))); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); - ON_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)) + backend->setRange(10, 30); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(CreateLedgerInfo(INDEX, 30))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); + ON_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)) .WillByDefault(Return(std::optional{})); - EXPECT_CALL(*rawBackendPtr, fetchTransaction).Times(1); + EXPECT_CALL(*backend, fetchTransaction).Times(1); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "tx_hash": "{}" @@ -154,24 +145,21 @@ TEST_F(RPCTransactionEntryHandlerTest, TXNotFound) TEST_F(RPCTransactionEntryHandlerTest, LedgerSeqNotMatch) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 10; - ON_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillByDefault(Return(tx)); - EXPECT_CALL(*rawBackendPtr, fetchTransaction).Times(1); + ON_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillByDefault(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction).Times(1); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(CreateLedgerInfo(INDEX, 30))); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(10, 30); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(CreateLedgerInfo(INDEX, 30))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "tx_hash": "{}", @@ -234,24 +222,22 @@ TEST_F(RPCTransactionEntryHandlerTest, NormalPath) "ledger_hash": "E6DBAFC99223B42257915A63DFC6B0C032D4070F9A574B255AD97466726FC322", "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 30; - ON_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillByDefault(Return(tx)); - EXPECT_CALL(*rawBackendPtr, fetchTransaction).Times(1); + ON_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillByDefault(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction).Times(1); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(tx.ledgerSequence); // max - ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(CreateLedgerInfo(INDEX, tx.ledgerSequence))); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1); + backend->setRange(10, tx.ledgerSequence); + ON_CALL(*backend, fetchLedgerBySequence).WillByDefault(Return(CreateLedgerInfo(INDEX, tx.ledgerSequence))); + EXPECT_CALL(*backend, fetchLedgerBySequence).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "tx_hash": "{}", @@ -314,22 +300,20 @@ TEST_F(RPCTransactionEntryHandlerTest, NormalPathV2) "hash": "2E2FBAAFF767227FE4381C4BE9855986A6B9F96C62F6E443731AB36F7BBB8A08", "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 30; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(tx.ledgerSequence); // max - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).WillOnce(Return(CreateLedgerInfo(INDEX, tx.ledgerSequence))); + backend->setRange(10, tx.ledgerSequence); + EXPECT_CALL(*backend, fetchLedgerBySequence).WillOnce(Return(CreateLedgerInfo(INDEX, tx.ledgerSequence))); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TransactionEntryHandler{mockBackendPtr}}; + auto const handler = AnyHandler{TransactionEntryHandler{backend}}; auto const req = json::parse(fmt::format( R"({{ "tx_hash": "{}", diff --git a/unittests/rpc/handlers/TxTests.cpp b/unittests/rpc/handlers/TxTests.cpp index 3658971fe..e9d9fda5a 100644 --- a/unittests/rpc/handlers/TxTests.cpp +++ b/unittests/rpc/handlers/TxTests.cpp @@ -24,7 +24,6 @@ #include "rpc/common/Types.h" #include "rpc/handlers/Tx.h" #include "util/Fixtures.h" -#include "util/MockBackend.h" #include "util/MockETLService.h" #include "util/TestObject.h" @@ -140,7 +139,7 @@ class RPCTxTest : public HandlerBaseTest {}; TEST_F(RPCTxTest, ExcessiveLgrRange) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -161,22 +160,20 @@ TEST_F(RPCTxTest, ExcessiveLgrRange) TEST_F(RPCTxTest, InvalidBinaryV1) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -193,7 +190,7 @@ TEST_F(RPCTxTest, InvalidBinaryV1) TEST_F(RPCTxTest, InvalidBinaryV2) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -214,7 +211,7 @@ TEST_F(RPCTxTest, InvalidBinaryV2) TEST_F(RPCTxTest, InvalidLgrRange) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -235,9 +232,7 @@ TEST_F(RPCTxTest, InvalidLgrRange) TEST_F(RPCTxTest, TxnNotFound) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)) + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)) .WillOnce(Return(std::optional{})); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); @@ -245,7 +240,7 @@ TEST_F(RPCTxTest, TxnNotFound) EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -264,11 +259,8 @@ TEST_F(RPCTxTest, TxnNotFound) TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllFalse) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(10); // min - mockBackendPtr->updateRange(30); // max - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)) + backend->setRange(10, 30); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)) .WillOnce(Return(std::optional{})); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); @@ -276,7 +268,7 @@ TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllFalse) EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -298,11 +290,8 @@ TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllFalse) TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllTrue) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(1); // min - mockBackendPtr->updateRange(1000); // max - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)) + backend->setRange(1, 1000); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)) .WillOnce(Return(std::optional{})); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); @@ -310,7 +299,7 @@ TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllTrue) EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -333,11 +322,8 @@ TEST_F(RPCTxTest, TxnNotFoundInGivenRangeSearchAllTrue) // when ledger range and ctid are provided, searched_all should not be present, because the seq is specified in ctid TEST_F(RPCTxTest, CtidNotFoundSearchAllFalse) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - mockBackendPtr->updateRange(1); // min - mockBackendPtr->updateRange(1000); // max - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ_FROM_CTID, _)) + backend->setRange(1, 1000); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger(SEQ_FROM_CTID, _)) .WillOnce(Return(std::vector{})); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); @@ -345,7 +331,7 @@ TEST_F(RPCTxTest, CtidNotFoundSearchAllFalse) EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{2})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "ctid": "{}", @@ -366,9 +352,6 @@ TEST_F(RPCTxTest, CtidNotFoundSearchAllFalse) TEST_F(RPCTxTest, DefaultParameter_API_v1) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = @@ -376,14 +359,14 @@ TEST_F(RPCTxTest, DefaultParameter_API_v1) tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -400,23 +383,20 @@ TEST_F(RPCTxTest, DefaultParameter_API_v1) TEST_F(RPCTxTest, PaymentTx_API_v1) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - TransactionAndMetadata tx; tx.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 2, 3, 300).getSerializer().peekData(); tx.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -433,24 +413,21 @@ TEST_F(RPCTxTest, PaymentTx_API_v1) TEST_F(RPCTxTest, PaymentTx_API_v2) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - TransactionAndMetadata tx; tx.transaction = CreatePaymentTransactionObject(ACCOUNT, ACCOUNT2, 2, 3, 300).getSerializer().peekData(); tx.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(tx.ledgerSequence, _)).WillOnce(Return(std::nullopt)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchLedgerBySequence(tx.ledgerSequence, _)).WillOnce(Return(std::nullopt)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -468,9 +445,6 @@ TEST_F(RPCTxTest, PaymentTx_API_v2) TEST_F(RPCTxTest, DefaultParameter_API_v2) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); - TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = @@ -478,16 +452,16 @@ TEST_F(RPCTxTest, DefaultParameter_API_v2) tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, tx.ledgerSequence); - EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence(tx.ledgerSequence, _)).WillOnce(Return(ledgerinfo)); + EXPECT_CALL(*backend, fetchLedgerBySequence(tx.ledgerSequence, _)).WillOnce(Return(ledgerinfo)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -513,22 +487,21 @@ TEST_F(RPCTxTest, ReturnBinary) "inLedger": 100, "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -557,22 +530,21 @@ TEST_F(RPCTxTest, ReturnBinaryWithCTID) "ctid": "C000006400640002", "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{.networkID = 2})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -649,18 +621,17 @@ TEST_F(RPCTxTest, MintNFT) NFTID ); TransactionAndMetadata tx = CreateMintNFTTxWithMetadata(ACCOUNT, 1, 50, 123, NFTID); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -677,18 +648,17 @@ TEST_F(RPCTxTest, MintNFT) TEST_F(RPCTxTest, NFTAcceptOffer) { TransactionAndMetadata tx = CreateAcceptNFTOfferTxWithMetadata(ACCOUNT, 1, 50, NFTID); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -706,18 +676,17 @@ TEST_F(RPCTxTest, NFTCancelOffer) { std::vector ids{NFTID, NFTID2}; TransactionAndMetadata tx = CreateCancelNFTOffersTxWithMetadata(ACCOUNT, 1, 50, ids); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this, &ids](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -742,18 +711,17 @@ TEST_F(RPCTxTest, NFTCancelOffer) TEST_F(RPCTxTest, NFTCreateOffer) { TransactionAndMetadata tx = CreateCreateNFTOfferTxWithMetadata(ACCOUNT, 1, 50, NFTID, 123, NFTID2); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); - ASSERT_NE(rawBackendPtr, nullptr); + tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -770,7 +738,7 @@ TEST_F(RPCTxTest, NFTCreateOffer) TEST_F(RPCTxTest, CTIDAndTransactionBothProvided) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -792,7 +760,7 @@ TEST_F(RPCTxTest, CTIDAndTransactionBothProvided) TEST_F(RPCTxTest, CTIDAndTransactionBothNotProvided) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(R"({ "command": "tx"})"); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -806,7 +774,7 @@ TEST_F(RPCTxTest, CTIDAndTransactionBothNotProvided) TEST_F(RPCTxTest, CTIDInvalidType) { runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(R"({ "command": "tx", "ctid": 123})"); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -824,7 +792,7 @@ TEST_F(RPCTxTest, CTIDInvalidString) EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{.networkID = 5})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(R"({ "command": "tx", "ctid": "B002807000010002"})"); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -842,7 +810,7 @@ TEST_F(RPCTxTest, CTIDNotMatch) EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{.networkID = 5})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -908,21 +876,21 @@ TEST_F(RPCTxTest, ReturnCTIDForTxInput) "inLedger":100, "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); + TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{.networkID = 2})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -981,21 +949,21 @@ TEST_F(RPCTxTest, NotReturnCTIDIfETLNotAvaiable) "inLedger":100, "validated": true })"; - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); + TransactionAndMetadata tx; tx.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 100, 200, 300).getSerializer().peekData(); tx.transaction = CreateCreateOfferTransactionObject(ACCOUNT, 2, 100, CURRENCY, ACCOUNT2, 200, 300).getSerializer().peekData(); tx.date = 123456; tx.ledgerSequence = 100; - EXPECT_CALL(*rawBackendPtr, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); + EXPECT_CALL(*backend, fetchTransaction(ripple::uint256{TXNID}, _)).WillOnce(Return(tx)); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(std::nullopt)); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -1060,7 +1028,7 @@ TEST_F(RPCTxTest, ViaCTID) SEQ_FROM_CTID, SEQ_FROM_CTID ); - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); + TransactionAndMetadata tx1; tx1.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 1, 200, 300).getSerializer().peekData(); tx1.transaction = @@ -1073,14 +1041,14 @@ TEST_F(RPCTxTest, ViaCTID) tx2.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); tx2.ledgerSequence = SEQ_FROM_CTID; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ_FROM_CTID, _)).WillOnce(Return(std::vector{tx1, tx2})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger(SEQ_FROM_CTID, _)).WillOnce(Return(std::vector{tx1, tx2})); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); EXPECT_CALL(*rawETLPtr, getETLState).WillOnce(Return(etl::ETLState{.networkID = 2})); runSpawn([this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", @@ -1096,7 +1064,6 @@ TEST_F(RPCTxTest, ViaCTID) TEST_F(RPCTxTest, ViaLowercaseCTID) { - auto const rawBackendPtr = dynamic_cast(mockBackendPtr.get()); TransactionAndMetadata tx1; tx1.metadata = CreateMetaDataForCreateOffer(CURRENCY, ACCOUNT, 1, 200, 300).getSerializer().peekData(); tx1.transaction = @@ -1109,7 +1076,7 @@ TEST_F(RPCTxTest, ViaLowercaseCTID) tx2.metadata = CreatePaymentTransactionMetaObject(ACCOUNT, ACCOUNT2, 110, 30).getSerializer().peekData(); tx2.ledgerSequence = SEQ_FROM_CTID; - EXPECT_CALL(*rawBackendPtr, fetchAllTransactionsInLedger(SEQ_FROM_CTID, _)).WillOnce(Return(std::vector{tx1, tx2})); + EXPECT_CALL(*backend, fetchAllTransactionsInLedger(SEQ_FROM_CTID, _)).WillOnce(Return(std::vector{tx1, tx2})); auto const rawETLPtr = dynamic_cast(mockETLServicePtr.get()); ASSERT_NE(rawETLPtr, nullptr); @@ -1119,7 +1086,7 @@ TEST_F(RPCTxTest, ViaLowercaseCTID) std::transform(ctid.begin(), ctid.end(), ctid.begin(), ::tolower); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestTxHandler{mockBackendPtr, mockETLServicePtr}}; + auto const handler = AnyHandler{TestTxHandler{backend, mockETLServicePtr}}; auto const req = json::parse(fmt::format( R"({{ "command": "tx", diff --git a/unittests/rpc/handlers/UnsubscribeTests.cpp b/unittests/rpc/handlers/UnsubscribeTests.cpp index 6d3601d33..78fd16716 100644 --- a/unittests/rpc/handlers/UnsubscribeTests.cpp +++ b/unittests/rpc/handlers/UnsubscribeTests.cpp @@ -532,7 +532,7 @@ TEST_P(UnsubscribeParameterTest, InvalidParams) { auto const testBundle = GetParam(); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestUnsubscribeHandler{mockBackendPtr, mockSubscriptionManagerPtr}}; + auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}}; auto const req = json::parse(testBundle.testJson); auto const output = handler.process(req, Context{yield}); ASSERT_FALSE(output); @@ -545,7 +545,7 @@ TEST_P(UnsubscribeParameterTest, InvalidParams) TEST_F(RPCUnsubscribeTest, EmptyResponse) { runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestUnsubscribeHandler{mockBackendPtr, mockSubscriptionManagerPtr}}; + auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}}; auto const output = handler.process(json::parse(R"({})"), Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -569,7 +569,7 @@ TEST_F(RPCUnsubscribeTest, Streams) EXPECT_CALL(*rawSubscriptionManagerPtr, unsubProposedTransactions).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestUnsubscribeHandler{mockBackendPtr, mockSubscriptionManagerPtr}}; + auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -591,7 +591,7 @@ TEST_F(RPCUnsubscribeTest, Accounts) EXPECT_CALL(*rawSubscriptionManagerPtr, unsubAccount(rpc::accountFromStringStrict(ACCOUNT2).value(), _)).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestUnsubscribeHandler{mockBackendPtr, mockSubscriptionManagerPtr}}; + auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -615,7 +615,7 @@ TEST_F(RPCUnsubscribeTest, AccountsProposed) .Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestUnsubscribeHandler{mockBackendPtr, mockSubscriptionManagerPtr}}; + auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -650,7 +650,7 @@ TEST_F(RPCUnsubscribeTest, Books) EXPECT_CALL(*rawSubscriptionManagerPtr, unsubBook(ripple::reversed(book), _)).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestUnsubscribeHandler{mockBackendPtr, mockSubscriptionManagerPtr}}; + auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); @@ -683,7 +683,7 @@ TEST_F(RPCUnsubscribeTest, SingleBooks) EXPECT_CALL(*rawSubscriptionManagerPtr, unsubBook(book, _)).Times(1); runSpawn([&, this](auto yield) { - auto const handler = AnyHandler{TestUnsubscribeHandler{mockBackendPtr, mockSubscriptionManagerPtr}}; + auto const handler = AnyHandler{TestUnsubscribeHandler{backend, mockSubscriptionManagerPtr}}; auto const output = handler.process(input, Context{yield, session_}); ASSERT_TRUE(output); EXPECT_TRUE(output->as_object().empty()); diff --git a/unittests/rpc/handlers/impl/FakesAndMocks.h b/unittests/rpc/handlers/impl/FakesAndMocks.h index be28fe14e..2f3c4817f 100644 --- a/unittests/rpc/handlers/impl/FakesAndMocks.h +++ b/unittests/rpc/handlers/impl/FakesAndMocks.h @@ -70,8 +70,8 @@ class HandlerFake { using Output = TestOutput; using Result = rpc::HandlerReturnType; - rpc::RpcSpecConstRef - spec([[maybe_unused]] uint32_t apiVersion) const + static rpc::RpcSpecConstRef + spec([[maybe_unused]] uint32_t apiVersion) { using namespace rpc::validation; @@ -83,8 +83,8 @@ class HandlerFake { return rpcSpec; } - Result - process(Input input, [[maybe_unused]] rpc::Context const& ctx) const + static Result + process(Input input, [[maybe_unused]] rpc::Context const& ctx) { return Output{input.hello + '_' + std::to_string(input.limit.value_or(0))}; } @@ -95,8 +95,8 @@ class NoInputHandlerFake { using Output = TestOutput; using Result = rpc::HandlerReturnType; - Result - process([[maybe_unused]] rpc::Context const& ctx) const + static Result + process([[maybe_unused]] rpc::Context const& ctx) { return Output{"test"}; } @@ -109,8 +109,8 @@ class FailingHandlerFake { using Output = TestOutput; using Result = rpc::HandlerReturnType; - rpc::RpcSpecConstRef - spec([[maybe_unused]] uint32_t apiVersion) const + static rpc::RpcSpecConstRef + spec([[maybe_unused]] uint32_t apiVersion) { using namespace rpc::validation; @@ -122,8 +122,8 @@ class FailingHandlerFake { return rpcSpec; } - Result - process([[maybe_unused]] Input input, [[maybe_unused]] rpc::Context const& ctx) const + static Result + process([[maybe_unused]] Input input, [[maybe_unused]] rpc::Context const& ctx) { // always fail return rpc::Error{rpc::Status{"Very custom error"}}; diff --git a/unittests/util/BatchingTests.cpp b/unittests/util/BatchingTests.cpp new file mode 100644 index 000000000..d9f1cedd6 --- /dev/null +++ b/unittests/util/BatchingTests.cpp @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "util/Batching.h" + +#include + +#include +#include +#include + +TEST(BatchingTests, simpleBatch) +{ + std::vector const input{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::vector output; + + util::forEachBatch(input, 3, [&](auto begin, auto end) { + std::copy(begin, end, std::back_inserter(output)); + EXPECT_LE(std::distance(begin, end), 3); + }); + + EXPECT_EQ(input, output); +} + +TEST(BatchingTests, simpleBatchEven) +{ + std::vector const input{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::vector output; + + util::forEachBatch(input, 2, [&](auto begin, auto end) { + std::copy(begin, end, std::back_inserter(output)); + EXPECT_LE(std::distance(begin, end), 2); + }); + + EXPECT_EQ(input, output); +} + +TEST(BatchingTests, batchSizeBiggerThanInput) +{ + std::vector const input{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::vector output; + + util::forEachBatch(input, 20, [&](auto begin, auto end) { + std::copy(begin, end, std::back_inserter(output)); + EXPECT_LE(std::distance(begin, end), 20); + }); + + EXPECT_EQ(input, output); +} + +TEST(BatchingTests, emptyInput) +{ + std::vector const input{}; + std::vector output; + + util::forEachBatch(input, 20, [&](auto begin, auto end) { + std::copy(begin, end, std::back_inserter(output)); + ASSERT_FALSE(true) << "Should not be called"; + }); + + EXPECT_EQ(input, output); +} diff --git a/unittests/util/FakeAmendmentBlockAction.h b/unittests/util/FakeAmendmentBlockAction.h index d49fec5f6..639f9f7b2 100644 --- a/unittests/util/FakeAmendmentBlockAction.h +++ b/unittests/util/FakeAmendmentBlockAction.h @@ -25,7 +25,7 @@ struct FakeAmendmentBlockAction { std::reference_wrapper callCount; void - operator()() + operator()() const { ++(callCount.get()); } diff --git a/unittests/util/FakeFetchResponse.h b/unittests/util/FakeFetchResponse.h index d6d0d675e..12a5fd3ec 100644 --- a/unittests/util/FakeFetchResponse.h +++ b/unittests/util/FakeFetchResponse.h @@ -21,6 +21,7 @@ #include #include +#include #include class FakeBook { @@ -135,7 +136,7 @@ class FakeTransactionsList { public: std::size_t - transactions_size() + transactions_size() const { return size_; } @@ -146,7 +147,7 @@ class FakeObjectsList { public: std::size_t - objects_size() + objects_size() const { return size_; } @@ -165,7 +166,7 @@ struct FakeFetchResponse { } FakeFetchResponse(std::string blob, uint32_t id = 0, bool objectNeighborsIncluded = false) - : id{id}, objectNeighborsIncluded{objectNeighborsIncluded}, ledgerHeader{blob} + : id{id}, objectNeighborsIncluded{objectNeighborsIncluded}, ledgerHeader{std::move(blob)} { } @@ -175,14 +176,14 @@ struct FakeFetchResponse { return other.id == id; } - FakeTransactionsList - transactions_list() const + static FakeTransactionsList + transactions_list() { return {}; } - FakeObjectsList - ledger_objects() const + static FakeObjectsList + ledger_objects() { return {}; } diff --git a/unittests/util/Fixtures.h b/unittests/util/Fixtures.h index cc1cd31b6..baf8b3e70 100644 --- a/unittests/util/Fixtures.h +++ b/unittests/util/Fixtures.h @@ -19,6 +19,7 @@ #pragma once +#include "data/BackendInterface.h" #include "util/MockBackend.h" #include "util/MockCounters.h" #include "util/MockETLService.h" @@ -26,10 +27,24 @@ #include "util/MockSubscriptionManager.h" #include "util/log/Logger.h" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include +#include +#include +#include #include /** @@ -173,27 +188,86 @@ struct SyncAsioContextTest : virtual public NoLoggerFixture { boost::asio::io_context ctx; }; -/** - * @brief Fixture with a mock backend - */ -struct MockBackendTest : virtual public NoLoggerFixture { +template