diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..7f15cf68 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,20 @@ +# SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +# The sole reason of this file is to make github assign reviews to +# all team members explicitly. +# Every member in https://github.com/orgs/midokura/teams/device/members +# is responsible for review of any PRs in this repo. +# The each members are intentionally listed here instead of @midokura/device +# team because we want to assign reviews to individuals, not the team. +# +# https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners + +* @midokura/device + +# We need to ensure documentation is validated at PR time. +# The validation must be done before merging to ensure we can do a release and +# generate the documentation artifacts safely +*.md @jimken-mido @midokura/device +*.rst @jimken-mido @midokura/device diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..e82cfece --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,16 @@ + + + + + +## What? + +Include an explanation of what are the changes about. + +## Why? + +Include an explanation of why we need the changes. diff --git a/.github/workflows/build-modules.yml b/.github/workflows/build-modules.yml new file mode 100644 index 00000000..9ad19f9a --- /dev/null +++ b/.github/workflows/build-modules.yml @@ -0,0 +1,79 @@ +# SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +name: "WASM and native modules" +on: + workflow_call: + inputs: + ref: + type: string + required: true + builder-tag: + description: The builder tag to be used + default: latest + required: false + type: string + package-namespace: + description: The package namespace for docker images + default: ${{ github.repository }} + required: false + type: string + +jobs: + build-modules: + name: Modules (${{ matrix.name }}, ${{ matrix.platform }}) + runs-on: ${{ matrix.runner }} + container: + image: ghcr.io/${{ inputs.package-namespace }}/builder-${{ matrix.name }}:${{ inputs.builder-tag }} + credentials: + username: ${{ github.actor }} + password: ${{ github.token }} + options: ${{ startsWith(matrix.runner, 'buildjet') && '--user 1000:1001' || '--user 1001:127' }} + strategy: + fail-fast: false + matrix: + include: + - name: raspios-bookworm + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} + platform: arm64 + - name: ubuntu-noble + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} + platform: arm64 + - name: ubuntu-noble + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204' || 'ubuntu-24.04' }} + platform: amd64 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + + - name: Build all modules + run: | + make -j$((`nproc` * 2)) \ + KBUILD_DEFCONFIG=configs/unit-test-all-hubs-wasm.config \ + wasm_test_modules + make -j$((`nproc` * 2)) -C test_modules/python + + - uses: actions/upload-artifact@v4 + with: + name: test-modules-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }} + path: | + test_modules/*.elf + test_modules/*.wasm + test_modules/*.wasm.* + test_modules/python/*.zip diff --git a/.github/workflows/build-sdk.yml b/.github/workflows/build-sdk.yml new file mode 100644 index 00000000..47f1f7e2 --- /dev/null +++ b/.github/workflows/build-sdk.yml @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +on: + workflow_call: + inputs: + builder-tag: + description: The builder tag to be used + default: latest + required: false + type: string + package-namespace: + description: The package namespace for docker images + default: ${{ github.repository }} + required: false + type: string + ref: + type: string + required: true + +jobs: + build-sdk: + name: SDK (${{ matrix.name }}, ${{ matrix.platform }}) + runs-on: ${{ matrix.runner }} + container: + image: ghcr.io/${{ inputs.package-namespace }}/builder-${{ matrix.name }}:${{ inputs.builder-tag }} + credentials: + username: ${{ github.actor }} + password: ${{ github.token }} + options: ${{ startsWith(matrix.runner, 'buildjet') && '--user 1000:1001' || '--user 1001:127' }} + timeout-minutes: 8 # the worst case is 3 minutes + strategy: + fail-fast: false + matrix: + include: + - name: raspios-bookworm + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} + platform: arm64 + - name: ubuntu-noble + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} + platform: arm64 + - name: ubuntu-noble + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204' || 'ubuntu-24.04' }} + platform: amd64 + + steps: + - name: Checkout source + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + + - name: Build SDK + run: make -j$((`nproc` * 2)) sdk \ + CFLAGS="-O2 -Werror" \ + KBUILD_DEFCONFIG=configs/linux-docker.config + + - name: Install python test dependencies + working-directory: src/python-evp-app-sdk + run: | + python3 -m venv .venv + . .venv/bin/activate + pip install \ + -e . \ + -r requirements.test.txt + + - name: Run python SDK tests + working-directory: src/python-evp-app-sdk + run: | + . .venv/bin/activate + python -m pytest \ + --cov=evp.app \ + --cov-report="xml:pysdk-cov.xml" \ + --junit-xml="pysdk-test-res.xml" \ + -v + + - name: Publish pytest coverage + id: pysdk-cov + uses: MishaKav/pytest-coverage-comment@main + if: always() + with: + title: EVP Python Application SDK coverage report + badge-title: Python Application SDK + coverage-path-prefix: src/python-evp-app-sdk/evp/app/ + pytest-xml-coverage-path: src/python-evp-app-sdk/pysdk-cov.xml + junitxml-path: src/python-evp-app-sdk/pysdk-test-res.xml + junitxml-title: Python Application SDK test report + + - name: Publish pytest results to summary + if: steps.pysdk-cov.outputs.summaryReport + run: echo ${{ steps.pysdk-cov.outputs.summaryReport }} >> $GITHUB_STEP_SUMMARY + + - name: Build Python package + working-directory: src/python-evp-app-sdk + run: python3 -m build + + - name: SDK Debian package + working-directory: src/python-evp-app-sdk + run: python setup.py --command-packages=stdeb.command bdist_deb + + - uses: actions/upload-artifact@v4 + with: + name: python-sdk-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }} + path: src/python-evp-app-sdk/dist/* + + - uses: actions/upload-artifact@v4 + with: + name: python-sdk-deb-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }} + path: src/python-evp-app-sdk/deb_dist/*.deb diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 28e275ac..8824f401 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,10 +35,10 @@ jobs: matrix: include: - name: raspios-bookworm - runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-22.04-arm' }} + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} platform: arm64 - name: ubuntu-noble - runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-22.04-arm' }} + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} platform: arm64 - name: ubuntu-noble runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204' || 'ubuntu-24.04' }} @@ -83,94 +83,6 @@ jobs: sbom-files.txt sbom-tmp.txt - build-sdk: - name: SDK (${{ matrix.name }}, ${{ matrix.platform }}) - runs-on: ${{ matrix.runner }} - container: - image: ghcr.io/${{ inputs.package-namespace }}/builder-${{ matrix.name }}:${{ inputs.builder-tag }} - credentials: - username: ${{ github.actor }} - password: ${{ github.token }} - options: ${{ startsWith(matrix.runner, 'buildjet') && '--user 1000:1001' || '--user 1001:127' }} - timeout-minutes: 8 # the worst case is 3 minutes - strategy: - fail-fast: false - matrix: - include: - - name: raspios-bookworm - runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-22.04-arm' }} - platform: arm64 - - name: ubuntu-noble - runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204-arm' || 'ubuntu-22.04-arm' }} - platform: arm64 - - name: ubuntu-noble - runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204' || 'ubuntu-24.04' }} - platform: amd64 - - steps: - - name: Checkout source - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - - - name: Build SDK - run: make -j$((`nproc` * 2)) sdk \ - CFLAGS="-O2 -Werror" \ - KBUILD_DEFCONFIG=configs/linux-docker.config - - - name: Install python test dependencies - working-directory: src/python-evp-app-sdk - run: | - python3 -m venv .venv - . .venv/bin/activate - pip install \ - -e . \ - -r requirements.test.txt - - - name: Run python SDK tests - working-directory: src/python-evp-app-sdk - run: | - . .venv/bin/activate - python -m pytest \ - --cov=evp.app \ - --cov-report="xml:pysdk-cov.xml" \ - --junit-xml="pysdk-test-res.xml" \ - -v - - - name: Publish pytest coverage - id: pysdk-cov - uses: MishaKav/pytest-coverage-comment@main - if: always() - with: - title: EVP Python Application SDK coverage report - badge-title: Python Application SDK - coverage-path-prefix: src/python-evp-app-sdk/evp/app/ - pytest-xml-coverage-path: src/python-evp-app-sdk/pysdk-cov.xml - junitxml-path: src/python-evp-app-sdk/pysdk-test-res.xml - junitxml-title: Python Application SDK test report - - - name: Publish pytest results to summary - if: steps.pysdk-cov.outputs.summaryReport - run: echo ${{ steps.pysdk-cov.outputs.summaryReport }} >> $GITHUB_STEP_SUMMARY - - - name: Build Python package - working-directory: src/python-evp-app-sdk - run: python3 -m build - - - name: SDK Debian package - working-directory: src/python-evp-app-sdk - run: python setup.py --command-packages=stdeb.command bdist_deb - - - uses: actions/upload-artifact@v4 - with: - name: python-sdk-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }} - path: src/python-evp-app-sdk/dist/* - - - uses: actions/upload-artifact@v4 - with: - name: python-sdk-deb-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }} - path: src/python-evp-app-sdk/deb_dist/*.deb - run-static-analysis: name: Static Code Analysis runs-on: ubuntu-24.04 diff --git a/.github/workflows/builder.yml b/.github/workflows/builder.yml index e8fbea3b..b07dda9d 100644 --- a/.github/workflows/builder.yml +++ b/.github/workflows/builder.yml @@ -35,6 +35,7 @@ concurrency: group: ${{ github.workflow }} @ build-builders-${{ github.ref }} cancel-in-progress: true +# COMMENT TO TRIGGER A NEW BUILD jobs: builder-necessary: name: Is builder necessary? @@ -76,7 +77,7 @@ jobs: if: ${{ needs.builder-necessary.outputs.build == 'true' }} needs: - builder-necessary - runs-on: ${{ github.event.repository.private && 'buildjet-8vcpu-ubuntu-2204-arm' || 'ubuntu-22.04-arm' }} + runs-on: ${{ github.event.repository.private && 'buildjet-8vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} steps: - name: Checkout the code @@ -113,7 +114,7 @@ jobs: - platform: amd64 runner: ${{ github.event.repository.private && 'buildjet-8vcpu-ubuntu-2204' || 'ubuntu-24.04' }} - platform: arm64 - runner: ${{ github.event.repository.private && 'buildjet-8vcpu-ubuntu-2204-arm' || 'ubuntu-22.04-arm' }} + runner: ${{ github.event.repository.private && 'buildjet-8vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} steps: - name: Checkout the code diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1654e9d3..6a7567f9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,13 +27,15 @@ on: type: string schedule: - - cron: 0 0 * * 1-5 + - cron: 0 0-6,20-23 * * 1-5 # every hour in no working ours + - cron: 0 */2 * * 6,0 # every 2 hours in weekends concurrency: group: ${{ github.repository }}-${{ github.workflow }}@main-${{ github.ref }} cancel-in-progress: true jobs: + infos: name: Infos runs-on: ubuntu-24.04 @@ -77,20 +79,33 @@ jobs: ref: ${{ inputs.ref || github.sha }} package-namespace: ${{ needs.infos.outputs.package-namespace }} - test-modules: - name: Test-modules + build-sdk: + name: Build + needs: + - checks + - builder + - infos + uses: ./.github/workflows/build-sdk.yml + secrets: inherit + with: + builder-tag: ${{ needs.builder.outputs.builder-tag }} + ref: ${{ inputs.ref || github.sha }} + package-namespace: ${{ needs.infos.outputs.package-namespace }} + + build-modules: + name: Build needs: - checks - builder - infos - uses: ./.github/workflows/test-modules.yml + uses: ./.github/workflows/build-modules.yml secrets: inherit with: builder-tag: ${{ needs.builder.outputs.builder-tag }} ref: ${{ inputs.ref || github.sha }} package-namespace: ${{ needs.infos.outputs.package-namespace }} - build: + build-agent: name: Build needs: - checks @@ -102,3 +117,34 @@ jobs: builder-tag: ${{ needs.builder.outputs.builder-tag }} ref: ${{ inputs.ref || github.sha }} package-namespace: ${{ needs.infos.outputs.package-namespace }} + + tests: + name: Tests + needs: + - checks + - build-sdk + - build-modules + - builder + - infos + uses: ./.github/workflows/test.yml + secrets: inherit + with: + builder-tag: ${{ needs.builder.outputs.builder-tag }} + ref: ${{ inputs.ref || github.sha }} + package-namespace: ${{ needs.infos.outputs.package-namespace }} + + checkpoint-success: + if: ${{ always() }} + runs-on: ubuntu-24.04 + needs: + - tests + - build-agent + steps: + - name: Check all previous jobs finished correctly + run: | + if [ "${{ needs.tests.result }}" = "success" ]; then + echo Requested jobs finished successfully. This PR can be merged + else + echo Requested jobs are failing. This PR can not be merged + exit 1 + fi diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..44698686 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,166 @@ +# SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +on: + workflow_call: + inputs: + builder-tag: + description: The builder tag to be used + default: ghcr.io/${{ inputs.package-namespace }}/builder-raspios-bookworm + required: false + type: string + ref: + type: string + required: true + package-namespace: + description: The package namespace for docker images + default: ${{ github.repository }} + required: false + type: string + +jobs: + test: + name: Unit tests (${{ matrix.name }}, ${{ matrix.platform }}) + runs-on: ${{ matrix.runner }} + container: + image: ghcr.io/${{ inputs.package-namespace }}/builder-${{ matrix.name }}:${{ inputs.builder-tag }} + credentials: + username: ${{ github.actor }} + password: ${{ github.token }} + options: ${{ startsWith(matrix.runner, 'buildjet') && '--user 1000:1001' || '--user 1001:127' }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - name: raspios-bookworm + runner: ${{ github.event.repository.private && 'buildjet-8vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} + platform: arm64 + - name: ubuntu-noble + runner: ${{ github.event.repository.private && 'buildjet-8vcpu-ubuntu-2204-arm' || 'ubuntu-24.04-arm' }} + platform: arm64 + - name: ubuntu-noble + runner: ${{ github.event.repository.private && 'buildjet-4vcpu-ubuntu-2204' || 'ubuntu-24.04' }} + platform: amd64 + + steps: + - name: Checkout source + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + + - name: Download test modules + uses: actions/download-artifact@v4 + with: + name: test-modules-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }} + path: test_modules/ + + - name: Download Python SDK + uses: actions/download-artifact@v4 + with: + name: python-sdk-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }} + path: py-sdk + + - name: Set permissions + run: chmod +x test_modules/*.elf + + - name: Build dependencies + run: | + make -j$((`nproc` * 2)) \ + KBUILD_DEFCONFIG=configs/unit-test-all-hubs-wasm.config \ + CFLAGS="-g" \ + TOOL=clang \ + depend + + - name: Build agent + run: | + make -j$((`nproc` * 2))\ + KBUILD_DEFCONFIG=configs/unit-test-all-hubs-wasm.config\ + TOOL=clang \ + SANITIZER=ENABLED \ + COVERAGE=ccov \ + CFLAGS="-g -Og -Werror" \ + + - name: Build tests + run: | + make -C test -j$((`nproc` * 2))\ + TOOL=clang \ + SANITIZER=ENABLED \ + COVERAGE=ccov \ + CFLAGS="-g -Og -Werror" \ + LDFLAGS="-fuse-ld=lld -g" \ + build + + - name: Install the Python SDK + run: | + python3 -m venv .venv + . .venv/bin/activate + pip3 install py-sdk/*.whl + + - name: Run tests + env: + ASAN_OPTIONS: detect_leaks=1:detect_stack_use_after_return=1 + UBSAN_OPTIONS: print_stacktrace=1 + TERM: xterm + run: . .venv/bin/activate && make -C test -j RUNFLAGS='-c -t 60' + + - name: Print failure logs + if: failure() + run: | + awk '/FAIL/ { + file = FILENAME + sub(/\.res/, ".log", file) + printf("::group::%s[%s] log\n", file, $2) + system("cat " file) + printf("::endgroup::\n") + }' test/logs/*/src/*/*.res + + - name: Generate coverage + run: | + make \ + TOOL=clang \ + COVERAGE=ccov \ + coverage-ci + + - name: Report HTTP upload performance + run: | + ./scripts/print-http-stats.sh >> $GITHUB_STEP_SUMMARY + + # Upload test logs upon failure. + - name: Upload logs + uses: actions/upload-artifact@v4 + if: always() + with: + name: test-log-${{ matrix.name }}-${{ matrix.platform }}-${{ github.run_id }}-${{ github.run_attempt }} + path: test/logs/**/*.log + retention-days: ${{ job.status == 'success' && '7' || '14' }} + + - name: Upload coverage results + uses: actions/upload-artifact@v4 + with: + # Use a specific folder to not overwrite log files + name: coverage-report-${{ matrix.name }}-${{ matrix.platform }}-${{github.run_id}} + path: coverage + retention-days: ${{ job.status == 'success' && '7' || '14' }} + + - name: Report code coverage + if: ${{ matrix.name == 'raspios-bookworm' && matrix.platform == 'arm64' }} + id: report-action-lcov + uses: zgosalvez/github-actions-report-lcov@v4.1.2 + with: + title-prefix: ${{ matrix.name }}-${{ matrix.platform }} + coverage-files: coverage/filtered.lcov + minimum-coverage: 55 + github-token: ${{ github.token }} + update-comment: true + + - name: Report summary coverage to status + if: ${{ matrix.name == 'raspios-bookworm' && matrix.platform == 'arm64' }} + uses: guibranco/github-status-action-v2@v1.1.13 + with: + authToken: ${{ github.token }} + context: "Coverage line level: " + description: ${{ steps.report-action-lcov.outputs.total-coverage }}% + state: success + sha: ${{ github.event.pull_request.head.sha || inputs.ref }} diff --git a/.gitignore b/.gitignore index 8736aeea..fa7fcb4b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,12 +29,15 @@ __pycache__ *.signed *.gcda *.gcno +*.log +*.res tools/module_key.bin deps.mk compile_commands.json analysis.txt /docs/build/ /docs/changelog.md +test/lorem-ipsum # Headers /include/* diff --git a/Makefile b/Makefile index cc8efc2c..65d42fec 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ sdk: FORCE lib bin: mkdir -p $@ -wasm_test_modules: libs +wasm_test_modules: sdk +cd test_modules && $(MAKE) elf wasm check: FORCE @@ -40,7 +40,7 @@ check_test_config: FORCE test: check_test_config libs test_modules -test_modules: libs +test_modules: sdk signed_test_modules: test_modules +cd test_modules && $(MAKE) signed diff --git a/check.mk b/check.mk index 74845dbf..f01719b8 100644 --- a/check.mk +++ b/check.mk @@ -26,7 +26,7 @@ UNFILTERED_FILES = $(shell git ls-files '*.[ch]') SOURCE_FILES = $(filter-out $(EXCLUDE), $(UNFILTERED_FILES)) # List all files under Sony and Apache license control -# exlude: +# exclude: # - json # - txt # - empty files @@ -37,8 +37,9 @@ ALL_FILES = $(shell git ls-files --exclude='*.json' --exclude='*.txt') JSON_FILES = $(shell git ls-files '*.json') TEXT_FILES = $(shell git ls-files '*.txt') CONFIG_FILES = $(shell git ls-files '*.config') +BINARY_FILES = $(shell git ls-files '*.wasm.x86_64') NOT_LICENSE_SUPPORTED += LICENSE -LICENSED_FILES = $(filter-out $(EXCLUDE) $(JSON_FILES) $(TEXT_FILES) $(CONFIG_FILES) $(NOT_LICENSE_SUPPORTED), $(ALL_FILES)) +LICENSED_FILES = $(filter-out $(EXCLUDE) $(JSON_FILES) $(TEXT_FILES) $(CONFIG_FILES) $(BINARY_FILES) $(NOT_LICENSE_SUPPORTED), $(ALL_FILES)) check: check-python check-format check-license check-make check-shell ## check code formatting .PHONY: check diff --git a/docs/testing/index.rst b/docs/testing/index.rst index 5766d6aa..a33130ef 100644 --- a/docs/testing/index.rst +++ b/docs/testing/index.rst @@ -293,7 +293,6 @@ The full list of checks enabled is: fsanitize=shift fsanitize=undefined fsanitize=unreachable - fsanitize=unsigned-integer-overflow fsanitize=vla-bound More information about every specific option can be found in the diff --git a/scripts/build/tool/ccov.mk b/scripts/build/tool/ccov.mk index 487f776f..36523bba 100644 --- a/scripts/build/tool/ccov.mk +++ b/scripts/build/tool/ccov.mk @@ -13,14 +13,17 @@ CI_FILTER=\ src/libevp-agent/hub/tb/*.c\ coverage/cov.lcov: FORCE + @echo [$@] trap "rm -f $$$$.tmp" EXIT INT TERM;\ find . -name '*.profraw' |\ xargs llvm-profdata merge -o coverage/cov.profdata -sparse + find . -name '*.elf' find . -name '*.elf' |\ xargs llvm-cov export --instr-profile coverage/cov.profdata --format lcov > $$$$.tmp &&\ mv $$$$.tmp $@ coverage/filtered.lcov: coverage/cov.lcov + @echo [$@] trap "rm -f $$$$.tmp" EXIT INT TERM;\ find . -name '*.elf' |\ xargs llvm-cov export --instr-profile coverage/cov.profdata --format lcov \ @@ -29,12 +32,14 @@ coverage/filtered.lcov: coverage/cov.lcov mv $$$$.tmp $@ coverage: FORCE + @echo [$@] rm -rf coverage mkdir -p coverage $(MAKE) coverage/cov.lcov genhtml --branch-coverage -o coverage coverage/cov.lcov coverage-ci: FORCE + @echo [$@] rm -rf coverage mkdir -p coverage $(MAKE) coverage/filtered.lcov diff --git a/scripts/build/tool/clang.mk b/scripts/build/tool/clang.mk index 0b219e32..09eb1f1a 100644 --- a/scripts/build/tool/clang.mk +++ b/scripts/build/tool/clang.mk @@ -25,7 +25,6 @@ SANITIZER_ENABLED=\ -fsanitize=shift\ -fsanitize=undefined\ -fsanitize=unreachable\ - -fsanitize=unsigned-integer-overflow\ -fsanitize=vla-bound\ TOOL_ASFLAGS = -c diff --git a/scripts/cmake-flatcc.sh b/scripts/cmake-flatcc.sh index 39914d01..bc487530 100755 --- a/scripts/cmake-flatcc.sh +++ b/scripts/cmake-flatcc.sh @@ -24,7 +24,8 @@ cmake \ -DCMAKE_C_COMPILER="${CC:-cc}" \ -DCMAKE_C_FLAGS="${CFLAGS} -DFLATCC_DEBUG_VERIFY=0" \ -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ - -DFLATCC_CXX_TEST=OFF \ + -DFLATCC_COVERAGE=0 \ + -DFLATCC_TEST=0 \ -DFLATCC_INSTALL=ON \ -DFLATCC_DEBUG_CLANG_SANITIZE=OFF \ .. diff --git a/scripts/rules.mk b/scripts/rules.mk index 6d379936..cca57f35 100644 --- a/scripts/rules.mk +++ b/scripts/rules.mk @@ -32,9 +32,6 @@ LDINCLUDES= -L$(LIBDIR) # Include optional personal preferences -include $(PROJECTDIR)/config.mk -# include kconfig configuration --include $(PROJECTDIR)/.config - # Include configuration definitions include $(SCRIPTDIR)/build/tool/$(TOOL).mk include $(SCRIPTDIR)/build/sys/$(SYS).mk diff --git a/src/libevp-agent/Makefile b/src/libevp-agent/Makefile index 8327ab23..e55d1644 100644 --- a/src/libevp-agent/Makefile +++ b/src/libevp-agent/Makefile @@ -5,6 +5,7 @@ PROJECTDIR = ../.. include $(PROJECTDIR)/scripts/rules.mk +-include $(PROJECTDIR)/.config MORE_CPPFLAGS = \ -IMQTT-C/include\ diff --git a/src/libevp-agent/connections.c b/src/libevp-agent/connections.c index f49ce394..3e2b2441 100644 --- a/src/libevp-agent/connections.c +++ b/src/libevp-agent/connections.c @@ -156,6 +156,9 @@ connections_webclient_perform(struct webclient_context *ctx) perform_again: ret = webclient_perform(ctx); + if (ret) + xlog_debug("webclient_perform returned %d", ret); + if (ret == -EAGAIN || ret == -EINPROGRESS) { struct webclient_poll_info info; struct pollfd pfd; diff --git a/src/libevp-agent/module_instance_impl.h b/src/libevp-agent/module_instance_impl.h index 8c76d2fe..21f9b5da 100644 --- a/src/libevp-agent/module_instance_impl.h +++ b/src/libevp-agent/module_instance_impl.h @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -94,7 +95,7 @@ struct module_instance { pthread_t wasm_runner; wasm_module_inst_t wasm_module_inst; char *wasm_runner_exception; - pthread_cond_t exit_condition; + sem_t sem; struct evp_lock lock; enum module_instance_status status; wasm_module_t wasm_module; diff --git a/src/libevp-agent/module_instance_impl_wasm.c b/src/libevp-agent/module_instance_impl_wasm.c index 85ebedf4..a78e4782 100644 --- a/src/libevp-agent/module_instance_impl_wasm.c +++ b/src/libevp-agent/module_instance_impl_wasm.c @@ -65,10 +65,10 @@ module_instance_set_status(struct module_instance *m, { xpthread_mutex_lock(&m->lock); m->status = status; - if (status == MODULE_INSTANCE_STATUS_STOPPED) { - xpthread_cond_signal(&m->exit_condition); - } xpthread_mutex_unlock(&m->lock); + if (status == MODULE_INSTANCE_STATUS_STOPPED && sem_post(&m->sem)) { + xlog_error("sem_post failed with errno %d", errno); + } } static enum module_instance_status @@ -139,7 +139,10 @@ static void impl_post_create(struct module_instance *m) { xpthread_mutex_init(&m->lock); - pthread_cond_init(&m->exit_condition, NULL); + + if (sem_init(&m->sem, 0, 0)) { + xlog_abort("sem_init failed with errno %d", errno); + } module_instance_set_status(m, MODULE_INSTANCE_STATUS_LOADING); @@ -541,40 +544,18 @@ impl_stop(struct module_instance *m) EVP_AGENT_WASM_STOPPED_GRACEFULLY; getrealtime(&max_wait); max_wait.tv_sec += MAX_EXIT_TIME_IN_SECONDS; - xpthread_mutex_lock(&m->lock); - ret = xpthread_cond_timedwait(&m->exit_condition, &m->lock, - &max_wait); - xpthread_mutex_unlock(&m->lock); - if (ret == ETIMEDOUT) { - // timeout: send WASM exception - xlog_warning("Raising WASM exception to exit %s", - m->name); - status = EVP_AGENT_WASM_STOPPED_EXCEPTION; - wasm_runtime_set_exception(m->wasm_module_inst, - "force terminated"); - // wait again for WASM module to exit - max_wait.tv_sec += MAX_EXIT_TIME_IN_SECONDS; - xpthread_mutex_lock(&m->lock); - ret = xpthread_cond_timedwait(&m->exit_condition, - &m->lock, &max_wait); - xpthread_mutex_unlock(&m->lock); - if (ret == ETIMEDOUT) { - // the module still didn't exit: cancel it - xlog_warning("Cancelling thread to exit %s", + while (sem_timedwait(&m->sem, &max_wait)) { + if (errno == ETIMEDOUT) { + xlog_warning("Terminating Wasm instance %s", m->name); - ret = pthread_cancel(m->wasm_runner); - - if (ret != 0) { - xlog_error("pthread_cancel failed: %d", - ret); - } + wasm_runtime_terminate(m->wasm_module_inst); status = EVP_AGENT_WASM_STOPPED_CANCELLED; - } else if (ret != 0) { - xlog_error("xpthread_cond_timedwait error %d", - ret); + break; + } else if (errno != EINTR) { + ret = errno; + xlog_warning("sem_timedwait error %d", ret); + return ret; } - } else if (ret != 0) { - xlog_error("xpthread_cond_timedwait error %d", ret); } ret = pthread_join(m->wasm_runner, NULL); @@ -592,7 +573,9 @@ impl_stop(struct module_instance *m) module_instance_set_status(m, MODULE_INSTANCE_STATUS_STOPPED); xpthread_mutex_destroy(&m->lock); - pthread_cond_destroy(&m->exit_condition); + if (sem_destroy(&m->sem)) { + xlog_abort("sem_destroy failed with errno %d", errno); + } } if (m->wasm_module_inst != NULL) { /* diff --git a/src/libevp-agent/module_log_cap.c b/src/libevp-agent/module_log_cap.c index 3f9999f7..96cf4c4f 100644 --- a/src/libevp-agent/module_log_cap.c +++ b/src/libevp-agent/module_log_cap.c @@ -97,8 +97,8 @@ capture_flush(struct log_entry *log) log->line = xrealloc(log->line, log->line_sz + 1); log->line[log->line_sz] = '\0'; - xlog_debug("wasm:%s/%s:%s", log->instance_id.ro, log->stream, - log->line); + xlog_info("wasm:%s/%s:%s", log->instance_id.ro, log->stream, + log->line); if (log->enabled) { module_log_queue_put(log->instance_id.ro, log->stream, diff --git a/src/libevp-agent/stream/stream.c b/src/libevp-agent/stream/stream.c index 497d2f4b..4e8e50f3 100644 --- a/src/libevp-agent/stream/stream.c +++ b/src/libevp-agent/stream/stream.c @@ -185,6 +185,17 @@ EVP_impl_streamOpen(struct EVP_client *h, const char *name, EVP_STREAM *out) goto end; } + struct notification *n = stream_notification(); + if (n == NULL) { + ret = EVP_ERROR; + goto end; + } + + if (notification_publish(n, "init/done", si)) { + ret = EVP_ERROR; + goto end; + } + *out = si->stream; end: if (ret != EVP_OK) { diff --git a/src/libevp-agent/sys/sys_collect_responses.c b/src/libevp-agent/sys/sys_collect_responses.c index af047b73..f67aa75f 100644 --- a/src/libevp-agent/sys/sys_collect_responses.c +++ b/src/libevp-agent/sys/sys_collect_responses.c @@ -26,9 +26,10 @@ process_response(struct chan_msg *msg) static int collect(struct SYS_client *c, sys_collect_cb cb, void *user) { - struct sys_response *r; + struct sys_response *r, *next; - for (r = c->resp_head; r; r = r->next) { + for (r = c->resp_head; r; r = next) { + next = r->next; if (cb(r->id, r->response, r->status, user)) { r->reason = SYS_REASON_ERROR; } else { diff --git a/src/libevp-app-sdk/Makefile b/src/libevp-app-sdk/Makefile index 8f736df8..fb7a63d8 100644 --- a/src/libevp-app-sdk/Makefile +++ b/src/libevp-app-sdk/Makefile @@ -6,6 +6,7 @@ PROJECTDIR = ../.. include $(PROJECTDIR)/scripts/rules.mk -include $(PROJECTDIR)/deps.mk +-include $(PROJECTDIR)/.config MORE_CPPFLAGS = \ -I../libevp-agent \ @@ -33,8 +34,6 @@ obj-$(CONFIG_EVP_SDK_SOCKET) += \ sdk.o \ sdkrpc/client.o \ -LDFLAGS = -L$(LIBDIR) - all: libevp-app-sdk.a libevp-app-sdk-bundle.a libevp-app-sdk.o: $(obj-y) @@ -46,7 +45,7 @@ libevp-app-sdk.a: libevp-app-sdk.o cp $@ $(LIBDIR) libevp-app-sdk-bundle.o: libevp-app-sdk.o - $(LD) -r -o $@ $(LDFLAGS) libevp-app-sdk.o $(DEPLIBS) + $(LD) -r -o $@ -L$(LIBDIR) libevp-app-sdk.o $(DEPLIBS) libevp-app-sdk-bundle.a: libevp-app-sdk-bundle.o $(AR) $(PROJ_ARFLAGS) $@ $? diff --git a/src/python-evp-app-sdk/evp/app/backend.i b/src/python-evp-app-sdk/evp/app/backend.i index fe071214..b957b534 100644 --- a/src/python-evp-app-sdk/evp/app/backend.i +++ b/src/python-evp-app-sdk/evp/app/backend.i @@ -36,7 +36,7 @@ static void PythonConfigCallback(const char *topic, const void *config, size_t c func = (PyObject *) userData; arglist = Py_BuildValue("(sO)", topic, PyUnicode_FromStringAndSize(config, configlen)); - PyObject *ret = PyEval_CallObject(func, arglist); + PyObject *ret = PyObject_Call(func, arglist, NULL); if (!ret) { // Handle any Python exceptions raised during the callback PyErr_Print(); @@ -63,7 +63,7 @@ static void PythonReasonCallback(int reason, void *userData) func = (PyObject *) userData; arglist = Py_BuildValue("(i)", reason); - PyObject *ret = PyEval_CallObject(func, arglist); + PyObject *ret = PyObject_Call(func, arglist, NULL); if (!ret) { // Handle any Python exceptions raised during the callback PyErr_Print(); @@ -108,7 +108,7 @@ static void PythonTelemetryCallback(int reason, void *userData) func = (PyObject *) data->PyHandler; arglist = Py_BuildValue("(i)", reason); - PyObject *ret = PyEval_CallObject(func, arglist); + PyObject *ret = PyObject_Call(func, arglist, NULL); if (!ret) { // Handle any Python exceptions raised during the callback PyErr_Print(); @@ -215,11 +215,10 @@ static EVP_RESULT PyEVP_sendTelemetry(struct EVP_client *h, PyObject *Telemetrie static void PythonRpcRequestCallback(unsigned long id, const char *methodName, const char *params, void *userData) { PyObject *func, *arglist; - double dres = 0; func = (PyObject *) userData; arglist = Py_BuildValue("(lss)", id, methodName, params); - PyObject *ret = PyEval_CallObject(func, arglist); + PyObject *ret = PyObject_Call(func, arglist, NULL); if (!ret) { // Handle any Python exceptions raised during the callback PyErr_Print(); diff --git a/test/Makefile b/test/Makefile index a240d2d7..00fb42fb 100644 --- a/test/Makefile +++ b/test/Makefile @@ -122,17 +122,11 @@ STESTS=\ src/systest/test_failed_wasm_load.elf\ src/systest/test_messaging.elf\ src/systest/test_mi_denied_requests.elf\ - src/systest/test_mod_download_evp_file.elf\ src/systest/test_module_log.elf\ src/systest/test_mstp.elf\ src/systest/test_mstp_null.elf\ - src/systest/test_python_mod_config_echo.elf\ - src/systest/test_python_mod_telemetry_echo2.elf\ - src/systest/test_python_mod_mdc.elf\ - src/systest/test_python_mod_upload_http_file.elf\ - src/systest/test_python_mod_upload_http_memory.elf\ - src/systest/test_python_mod_zombie.elf\ src/systest/test_spawn_mod_config_echo.elf\ + src/systest/test_spawn_mod_download_evp_file.elf\ src/systest/test_spawn_mod_mstp_cache_load.elf\ src/systest/test_spawn_mod_mstp_cache_store.elf\ src/systest/test_spawn_mod_telemetry_echo2.elf\ @@ -147,6 +141,8 @@ STESTS=\ src/systest/test_wasm_mod_backdoor_state_report.elf\ src/systest/test_wasm_mod_config_echo.elf\ src/systest/test_wasm_mod_deployment.elf\ + src/systest/test_wasm_mod_deployment_invalid_wamr.elf\ + src/systest/test_wasm_mod_download_evp_file.elf\ src/systest/test_wasm_mod_download_http_ext.elf\ src/systest/test_wasm_mod_failed_connect.elf\ src/systest/test_wasm_mod_health_check.elf\ @@ -166,14 +162,23 @@ STESTS=\ src/systest/test_wasm_mod_upload_evp_memory.elf\ src/systest/test_wasm_mod_upload_http_file.elf\ src/systest/test_wasm_mod_workspace.elf\ + src/systest/test_wasm_mod_zombie.elf\ src/systest/test_wasm_repeated_deploy.elf\ src/systest/test_wasm_rpc.elf\ src/systest/test_wasm_telemetry.elf\ +STESTS_PY=\ + src/systest/test_python_mod_config_echo.elf\ + src/systest/test_python_mod_telemetry_echo2.elf\ + src/systest/test_python_mod_mdc.elf\ + src/systest/test_python_mod_upload_http_file.elf\ + src/systest/test_python_mod_upload_http_memory.elf\ + src/systest/test_python_mod_zombie.elf\ + src/systest/test_python_mod_download_evp_file.elf\ + STESTS_NH=\ src/st-nohub/test_blob_type_http.elf\ src/st-nohub/test_blob_type_http_ext.elf\ - src/st-nohub/test_cancel_blob.elf\ src/st-nohub/test_connection_mode.elf\ src/st-nohub/test_connection_timeout.elf\ src/st-nohub/test_connections_disconnecting.elf\ @@ -186,7 +191,7 @@ STESTS_NH=\ src/st-nohub/test_sysapp_state.elf\ src/st-nohub/test_worker_manager.elf\ -TESTS=$(UTESTS_EVP1_TB) $(UTESTS_EVP2_TB) $(UTESTS_NH) $(STESTS) $(STESTS_NH) +TESTS=$(UTESTS_EVP1_TB) $(UTESTS_EVP2_TB) $(UTESTS_NH) $(STESTS) $(STESTS_NH) $(STESTS_PY) BINDEPS =\ $(LIBDIR)/libevp-agent.a\ @@ -256,10 +261,10 @@ test-helper: run-ut run-st .IGNORE: run-ut run-st .IGNORE: run-ut-evp1-tb run-ut-evp2-tb run-ut-nh -.IGNORE: run-st-evp1-tb run-st-evp2-tb run-st-nh +.IGNORE: run-st-evp1-tb run-st-evp2-tb run-st-nh run-st-py run-ut: run-ut-evp1-tb run-ut-evp2-tb run-ut-nh -run-st: run-st-evp1-tb run-st-evp2-tb run-st-nh +run-st: run-st-evp1-tb run-st-evp2-tb run-st-nh run-st-py run-ut-evp1-tb: $(UTESTS_EVP1_TB) FORCE @./run-tests.sh $(RUNFLAGS) -d logs/EVP1-TB -p EVP1 $(UTESTS_EVP1_TB) @@ -279,6 +284,9 @@ run-st-evp2-tb: $(STESTS) FORCE run-st-nh: $(STESTS_NH) FORCE @./run-tests.sh $(RUNFLAGS) -d logs/EVP2-TB -p TB $(STESTS_NH) +run-st-py: $(STESTS_PY) FORCE + @./run-tests.sh $(RUNFLAGS) -d logs/EVP2-TB -p TB $(STESTS_PY) + clean: test -f libweb/Makefile && cd libweb && $(MAKE) clean || true test -f libdynstr/Makefile && cd libdynstr && $(MAKE) clean || true diff --git a/test/libweb b/test/libweb index 80363c3e..bda2cae7 160000 --- a/test/libweb +++ b/test/libweb @@ -1 +1 @@ -Subproject commit 80363c3ed1a46e614f3b559b8efb87ba0c7c78ae +Subproject commit bda2cae7ccfe9f651970f31ab1ea691a5ad63071 diff --git a/test/mock_objects/agent_test.c b/test/mock_objects/agent_test.c index 923a4a87..65e528e6 100644 --- a/test/mock_objects/agent_test.c +++ b/test/mock_objects/agent_test.c @@ -167,11 +167,13 @@ int popen_print(FILE *fp, void *user) { size_t n; + size_t n_write; do { char str[BUFSIZ]; n = fread(str, 1, BUFSIZ, fp); - write(1, str, n); + n_write = write(1, str, n); + assert_int_equal(n, n_write); if (n != BUFSIZ) { int err = ferror(fp); if (err) { @@ -964,6 +966,8 @@ agent_test_setup(void) putenv("EVP_DOCKER_HOST=http://dockerd"); putenv("EVP_MQTT_CLIENTID=10001"); putenv("EVP_MQTT_DEVICE_ID=10001"); + putenv("EVP_REPORT_STATUS_INTERVAL_MIN_SEC=1"); + putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=1"); /* This expects "EVP_IOT_PLATFORM" to not be null */ char *iot_platform = getenv("EVP_IOT_PLATFORM"); @@ -1108,38 +1112,73 @@ agent_write_to_pipe(const char *data) } } -/** - * Wait for data to arrive in test data pipe, and validate with callback - * function. - * @param[in] verify_callback user provided function to validate test data - * @param[in] user_data provided to verify_callback along with test data - */ -void -agent_poll(agent_test_verify_t verify_callback, const void *user_data, ...) +static char * +vagent_poll_fetch(agent_test_verify_t verify_callback, const void *user_data, + va_list ud_va) { int r, fds = g_agent_test.pipe[0]; char *payload, c; size_t cnt; - va_list va; payload = NULL; for (cnt = 1;; cnt++) { - va_start(va, user_data); r = read(fds, &c, 1); assert_int_equal(r, 1); payload = xrealloc(payload, cnt); payload[cnt - 1] = c; if (c == '\0') { - if (verify_callback(payload, user_data, va)) { - free(payload); - va_end(va); - return; + va_list apc; + int result; + + va_copy(apc, ud_va); + result = verify_callback(payload, user_data, apc); + va_end(apc); + + if (result) { + break; } cnt = 0; } - va_end(va); } + return payload; +} + +/** + * Wait for data to arrive in test data pipe, and validate with callback + * function. + * @param[in] verify_callback user provided function to validate test data + * @param[in] user_data provided to verify_callback along with test data + */ +void +agent_poll(agent_test_verify_t verify_callback, const void *user_data, ...) +{ + char *msg; + va_list v_args; + va_start(v_args, user_data); + msg = vagent_poll_fetch(verify_callback, user_data, v_args); + free(msg); + va_end(v_args); +} + +/** + * Wait for data to arrive in test data pipe, and validate with callback + * function. + * @param[in] verify_callback user provided function to validate test data + * @param[in] user_data provided to verify_callback along with test data + * + * @return A copy of the message that matched with `verify_callback` + */ +char * +agent_poll_fetch(agent_test_verify_t verify_callback, const void *user_data, + ...) +{ + char *msg; + va_list v_args; + va_start(v_args, user_data); + msg = vagent_poll_fetch(verify_callback, user_data, v_args); + va_end(v_args); + return msg; } void @@ -1261,7 +1300,8 @@ agent_send_storagetoken_response(struct evp_agent_context *ctxt, // send the STP response (with the token) char *topic; if (evp1_topic_reqid == NULL) { - evp1_topic_reqid = "10004"; + xlog_error("reqid can not be NULL"); + assert_non_null(evp1_topic_reqid); } xasprintf(&topic, "v1/devices/me/rpc/response/%s", evp1_topic_reqid); evp_agent_send(ctxt, topic, payload); diff --git a/test/mock_objects/agent_test.h b/test/mock_objects/agent_test.h index 3fa1bc99..9670fa07 100644 --- a/test/mock_objects/agent_test.h +++ b/test/mock_objects/agent_test.h @@ -250,6 +250,9 @@ void agent_write_to_pipe(const char *data); void agent_poll(agent_test_verify_t verify_callback, const void *user_data, ...); +char *agent_poll_fetch(agent_test_verify_t verify_callback, + const void *user_data, ...); + void agent_register_payload(unsigned int id, enum evp_hub_type hub_type, const char *payload); diff --git a/test/resources/invalid_wamr_modules/wamr_1.3.1_config_echo.wasm.x86_64 b/test/resources/invalid_wamr_modules/wamr_1.3.1_config_echo.wasm.x86_64 new file mode 100644 index 00000000..62e89c47 Binary files /dev/null and b/test/resources/invalid_wamr_modules/wamr_1.3.1_config_echo.wasm.x86_64 differ diff --git a/test/src/st-nohub/test_blob_type_http.c b/test/src/st-nohub/test_blob_type_http.c index 9e22aaa0..4b2c29f4 100644 --- a/test/src/st-nohub/test_blob_type_http.c +++ b/test/src/st-nohub/test_blob_type_http.c @@ -25,6 +25,13 @@ #define HTTP_STATUS_OK 200 +struct test { + struct evp_agent_context *agent; + struct EVP_client *client; +}; + +static struct test test; + static void blob_cb(EVP_BLOB_CALLBACK_REASON reason, const void *vp, void *userData) { @@ -36,31 +43,21 @@ blob_cb(EVP_BLOB_CALLBACK_REASON reason, const void *vp, void *userData) } void -blob_type_http_test(void **state) +test_http_get_memory(void **state) { - // start agent - struct evp_agent_context *ctxt = agent_test_start(); - - // create backdoor instance - struct EVP_client *sdk_handle = - evp_agent_add_instance(ctxt, "backdoor"); - assert_non_null(sdk_handle); + // test HTTP GET to memory + struct test *ctxt = *state; - // prepare tests EVP_RESULT result; - static struct EVP_BlobRequestHttp request; - static struct EVP_BlobLocalStore localstore; - static char cb_data; - localstore.io_cb = 0; - localstore.blob_len = 0; - localstore.filename = NULL; - request.url = TEST_HTTP_GET_URL; + struct EVP_BlobRequestHttp request = {.url = TEST_HTTP_GET_URL}; + struct EVP_BlobLocalStore localstore = {0}; + char cb_data; - // test HTTP GET to memory - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP, + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP, EVP_BLOB_OP_GET, &request, &localstore, blob_cb, &cb_data); assert_int_equal(result, EVP_OK); + agent_poll(verify_equals, "GET " TEST_HTTP_GET_URL); // Blob download to memory is allowed // Expect processed blob to succeed @@ -68,19 +65,31 @@ blob_type_http_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); +} +void +test_http_get_file(void **state) +{ // test HTTP GET to file - request.url = TEST_HTTP_GET_URL; - xasprintf((char **)&localstore.filename, "%s/%s", - path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_GET_FILE); + struct test *ctxt = *state; + + char *filename; + xasprintf(&filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), + TEST_HTTP_GET_FILE); + + EVP_RESULT result; + struct EVP_BlobRequestHttp request = {.url = TEST_HTTP_GET_URL}; + struct EVP_BlobLocalStore localstore = {.filename = filename}; + char cb_data; + /* we can't use expect_string because webclient_perform will be called * from a different thread */ - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP, + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP, EVP_BLOB_OP_GET, &request, &localstore, blob_cb, &cb_data); - free(__UNCONST(localstore.filename)); + free(filename); assert_int_equal(result, EVP_OK); agent_poll(verify_equals, "GET " TEST_HTTP_GET_URL); @@ -89,17 +98,29 @@ blob_type_http_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); +} +void +test_http_put_file(void **state) +{ // test HTTP PUT to file - request.url = TEST_HTTP_PUT_URL; - xasprintf((char **)&localstore.filename, "%s/%s", - path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_PUT_FILE); - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP, + struct test *ctxt = *state; + + char *filename; + xasprintf(&filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), + TEST_HTTP_PUT_FILE); + + EVP_RESULT result; + struct EVP_BlobRequestHttp request = {.url = TEST_HTTP_PUT_URL}; + struct EVP_BlobLocalStore localstore = {.filename = filename}; + char cb_data; + + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP, EVP_BLOB_OP_PUT, &request, &localstore, blob_cb, &cb_data); - free(__UNCONST(localstore.filename)); + free(filename); assert_int_equal(result, EVP_OK); agent_poll(verify_equals, "PUT " TEST_HTTP_PUT_URL); @@ -108,7 +129,7 @@ blob_type_http_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); } @@ -121,6 +142,13 @@ setup(void **state) assert_int_equal(0, systemf("touch %s/%s", path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_PUT_FILE)); + // start agent + test.agent = agent_test_start(); + + // create backdoor instance + test.client = evp_agent_add_instance(test.agent, "backdoor"); + assert_non_null(test.client); + *state = &test; return 0; } @@ -136,7 +164,9 @@ main(void) { // define tests const struct CMUnitTest tests[] = { - cmocka_unit_test(blob_type_http_test), + cmocka_unit_test(test_http_get_memory), + cmocka_unit_test(test_http_get_file), + cmocka_unit_test(test_http_put_file), }; // setup and run tests return cmocka_run_group_tests(tests, setup, teardown); diff --git a/test/src/st-nohub/test_blob_type_http_ext.c b/test/src/st-nohub/test_blob_type_http_ext.c index d16d04ee..2251abcb 100644 --- a/test/src/st-nohub/test_blob_type_http_ext.c +++ b/test/src/st-nohub/test_blob_type_http_ext.c @@ -26,6 +26,13 @@ #define HTTP_STATUS_OK 200 +struct test { + struct evp_agent_context *agent; + struct EVP_client *client; +}; + +static struct test test; + static void blob_cb(EVP_BLOB_CALLBACK_REASON reason, const void *vp, void *userData) { @@ -37,7 +44,7 @@ blob_cb(EVP_BLOB_CALLBACK_REASON reason, const void *vp, void *userData) } void -blob_type_http_ext_test(void **state) +test_http_ext_get_memory(void **state) { /* This should test the HttpExt blob type. * @@ -46,31 +53,22 @@ blob_type_http_ext_test(void **state) * Finally we test the headers limit and the free function. */ - // start agent - struct evp_agent_context *ctxt = agent_test_start(); - - // create backdoor instance - struct EVP_client *sdk_handle = - evp_agent_add_instance(ctxt, "backdoor"); - assert_non_null(sdk_handle); + // test HTTP GET to memory + struct test *ctxt = *state; - // prepare tests EVP_RESULT result; - static struct EVP_BlobLocalStore localstore; - static char cb_data; - localstore.io_cb = 0; - localstore.blob_len = 0; - localstore.filename = NULL; + struct EVP_BlobLocalStore localstore = {0}; + char cb_data; struct EVP_BlobRequestHttpExt *request = EVP_BlobRequestHttpExt_initialize(); EVP_BlobRequestHttpExt_setUrl(request, TEST_HTTP_GET_URL); - // test HTTP GET to memory - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP_EXT, + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP_EXT, EVP_BLOB_OP_GET, request, &localstore, blob_cb, &cb_data); assert_int_equal(result, EVP_OK); + agent_poll(verify_equals, "GET " TEST_HTTP_GET_URL); // Blob download to memory is allowed // Expect processed blob to succeed @@ -78,19 +76,35 @@ blob_type_http_ext_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); + EVP_BlobRequestHttpExt_free(request); +} + +void +test_http_ext_get_file(void **state) +{ // test HTTP GET to file + struct test *ctxt = *state; + + char *filename; + xasprintf(&filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), + TEST_HTTP_GET_FILE); + EVP_RESULT result; + struct EVP_BlobLocalStore localstore = {.filename = filename}; + char cb_data; + + struct EVP_BlobRequestHttpExt *request = + EVP_BlobRequestHttpExt_initialize(); EVP_BlobRequestHttpExt_setUrl(request, TEST_HTTP_GET_URL); - xasprintf((char **)&localstore.filename, "%s/%s", - path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_GET_FILE); + /* we can't use expect_string because webclient_perform will be called * from a different thread */ - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP_EXT, + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP_EXT, EVP_BLOB_OP_GET, request, &localstore, blob_cb, &cb_data); - free(__UNCONST(localstore.filename)); + free(filename); assert_int_equal(result, EVP_OK); agent_poll(verify_equals, "GET " TEST_HTTP_GET_URL); @@ -99,17 +113,33 @@ blob_type_http_ext_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); - // test HTTP PUT to file + EVP_BlobRequestHttpExt_free(request); +} + +void +test_http_ext_put_file(void **state) +{ + // test HTTP PUT file + struct test *ctxt = *state; + + char *filename; + xasprintf(&filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), + TEST_HTTP_GET_FILE); + EVP_RESULT result; + struct EVP_BlobLocalStore localstore = {.filename = filename}; + char cb_data; + + struct EVP_BlobRequestHttpExt *request = + EVP_BlobRequestHttpExt_initialize(); EVP_BlobRequestHttpExt_setUrl(request, TEST_HTTP_PUT_URL); - xasprintf((char **)&localstore.filename, "%s/%s", - path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_PUT_FILE); - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP_EXT, + + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP_EXT, EVP_BLOB_OP_PUT, request, &localstore, blob_cb, &cb_data); - free(__UNCONST(localstore.filename)); + free(filename); assert_int_equal(result, EVP_OK); agent_poll(verify_equals, "PUT " TEST_HTTP_PUT_URL); @@ -118,19 +148,36 @@ blob_type_http_ext_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); + EVP_BlobRequestHttpExt_free(request); +} + +void +test_http_ext_get_file_range(void **state) +{ // test HTTP GET with RANGE + struct test *ctxt = *state; + + char *filename; + xasprintf(&filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), + TEST_HTTP_GET_FILE); + EVP_RESULT result; + struct EVP_BlobLocalStore localstore = {.filename = filename}; + char cb_data; + + struct EVP_BlobRequestHttpExt *request = + EVP_BlobRequestHttpExt_initialize(); EVP_BlobRequestHttpExt_setUrl(request, TEST_HTTP_GET_URL); EVP_BlobRequestHttpExt_addHeader(request, "Range", TEST_HTTP_GET_RANGE); - xasprintf((char **)&localstore.filename, "%s/%s", - path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_GET_FILE); - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP_EXT, + + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP_EXT, EVP_BLOB_OP_GET, request, &localstore, blob_cb, &cb_data); + free(filename); assert_int_equal(result, EVP_OK); agent_poll(verify_equals, "GET " TEST_HTTP_GET_URL); // make sure range header is present @@ -141,19 +188,37 @@ blob_type_http_ext_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); + EVP_BlobRequestHttpExt_free(request); +} + +void +test_http_ext_get_file_range_azure(void **state) +{ // test HTTP GET with RANGE and Azure header + struct test *ctxt = *state; + + char *filename; + xasprintf(&filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), + TEST_HTTP_GET_FILE); + EVP_RESULT result; + struct EVP_BlobLocalStore localstore = {.filename = filename}; + char cb_data; + + struct EVP_BlobRequestHttpExt *request = + EVP_BlobRequestHttpExt_initialize(); + EVP_BlobRequestHttpExt_setUrl(request, TEST_HTTP_GET_URL); EVP_BlobRequestHttpExt_addHeader(request, "Range", TEST_HTTP_GET_RANGE); EVP_BlobRequestHttpExt_addAzureHeader(request); - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP_EXT, + + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP_EXT, EVP_BLOB_OP_GET, request, &localstore, blob_cb, &cb_data); - free(__UNCONST(localstore.filename)); - + free(filename); assert_int_equal(result, EVP_OK); agent_poll(verify_equals, "GET " TEST_HTTP_GET_URL); // make sure range header is present @@ -166,13 +231,30 @@ blob_type_http_ext_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); + EVP_BlobRequestHttpExt_free(request); +} + +void +test_http_ext_get_null_memory_range_azure(void **state) +{ // Test download to null memory - localstore.filename = NULL; - localstore.io_cb = NULL; - result = EVP_blobOperation(sdk_handle, EVP_BLOB_TYPE_HTTP_EXT, + struct test *ctxt = *state; + + EVP_RESULT result; + struct EVP_BlobLocalStore localstore = {0}; + char cb_data; + + struct EVP_BlobRequestHttpExt *request = + EVP_BlobRequestHttpExt_initialize(); + EVP_BlobRequestHttpExt_setUrl(request, TEST_HTTP_GET_URL); + EVP_BlobRequestHttpExt_addHeader(request, "Range", + TEST_HTTP_GET_RANGE); + EVP_BlobRequestHttpExt_addAzureHeader(request); + + result = EVP_blobOperation(ctxt->client, EVP_BLOB_TYPE_HTTP_EXT, EVP_BLOB_OP_GET, request, &localstore, blob_cb, &cb_data); @@ -188,13 +270,20 @@ blob_type_http_ext_test(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(ctxt->client, 5000); assert_int_equal(result, EVP_OK); + EVP_BlobRequestHttpExt_free(request); +} + +void +test_http_ext_header_limits(void **state) +{ + struct EVP_BlobRequestHttpExt *request = + EVP_BlobRequestHttpExt_initialize(); // Test the headers limit and the free function unsigned int i; - // We start with 2 because there are already 2 headers in the request - for (i = 2; i < 200; i++) { + for (i = 0; i < 200; i++) { if (EVP_OK != EVP_BlobRequestHttpExt_addHeader( request, "Dummy", "dummy")) { break; @@ -202,7 +291,7 @@ blob_type_http_ext_test(void **state) } // i should be the maximum number of headers - assert_int_equal(i, 100); + assert_int_equal(i, 101); EVP_BlobRequestHttpExt_free(request); } @@ -216,6 +305,13 @@ setup(void **state) assert_int_equal(0, systemf("touch %s/%s", path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_PUT_FILE)); + // start agent + test.agent = agent_test_start(); + + // create backdoor instance + test.client = evp_agent_add_instance(test.agent, "backdoor"); + assert_non_null(test.client); + *state = &test; return 0; } @@ -231,7 +327,13 @@ main(void) { // define tests const struct CMUnitTest tests[] = { - cmocka_unit_test(blob_type_http_ext_test), + cmocka_unit_test(test_http_ext_get_memory), + cmocka_unit_test(test_http_ext_get_file), + cmocka_unit_test(test_http_ext_put_file), + cmocka_unit_test(test_http_ext_get_file_range), + cmocka_unit_test(test_http_ext_get_file_range_azure), + cmocka_unit_test(test_http_ext_get_null_memory_range_azure), + cmocka_unit_test(test_http_ext_header_limits), }; // setup and run tests return cmocka_run_group_tests(tests, setup, teardown); diff --git a/test/src/st-nohub/test_connection_mode.c b/test/src/st-nohub/test_connection_mode.c index 0c7c6576..a027dde9 100644 --- a/test/src/st-nohub/test_connection_mode.c +++ b/test/src/st-nohub/test_connection_mode.c @@ -27,9 +27,15 @@ #define TEST_HTTP_GET_FILE "foobar.txt" #define TEST_HTTP_PUT_FILE "boofar.bin" -#define HTTP_STATUS_OK 200 +#define HTTP_STATUS_OK 200 +#define PROCESS_EVENT_TIMEOUT 3000 -static struct sync_ctxt g_sync_conns; +struct test { + struct sync_ctxt sync_cons; + char *filename; +}; + +static struct test g_test; int __real_connections_webclient_perform(FAR struct webclient_context *ctx); @@ -38,7 +44,7 @@ __wrap_connections_webclient_perform(FAR struct webclient_context *ctx) { // Sync point with test thread. If enabled, will wait for other // call to `sync_join` from the other thread. - sync_join(&g_sync_conns); + sync_join(&g_test.sync_cons); return __real_connections_webclient_perform(ctx); } @@ -55,6 +61,8 @@ blob_cb(EVP_BLOB_CALLBACK_REASON reason, const void *vp, void *userData) void test_disconnect_reconnect(void **state) { + struct test *t = *state; + // start agent struct evp_agent_context *ctxt = agent_test_start(); agent_poll_status(ctxt, EVP_AGENT_STATUS_CONNECTED, 10); @@ -67,17 +75,16 @@ test_disconnect_reconnect(void **state) // prepare tests EVP_RESULT result; char cb_data; - char *filename; - xasprintf(&filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), + xasprintf(&t->filename, "%s/%s", path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_GET_FILE); - assert_non_null(filename); + assert_non_null(t->filename); struct EVP_BlobLocalStore localstore = { - .filename = filename, + .filename = t->filename, }; // Start blocking blob work - sync_activate(&g_sync_conns, 2); + sync_activate(&t->sync_cons, 2); // test HTTP GET to file struct EVP_BlobRequestHttp request = { @@ -95,14 +102,14 @@ test_disconnect_reconnect(void **state) // Control race condition: wait for blob work to be started and before // http operation is performed. - sync_join(&g_sync_conns); + sync_join(&t->sync_cons); // Expect processed blob to have failed expect_value(blob_cb, reason, EVP_BLOB_CALLBACK_REASON_DONE); expect_value(blob_cb, result->result, EVP_BLOB_RESULT_ERROR); expect_value(blob_cb, result->http_status, 0); expect_value(blob_cb, result->error, ENETDOWN); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(sdk_handle, PROCESS_EVENT_TIMEOUT); assert_int_equal(result, EVP_OK); // Blob download cannot be performed when disconnected @@ -116,7 +123,7 @@ test_disconnect_reconnect(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_ERROR); expect_value(blob_cb, result->http_status, 0); expect_value(blob_cb, result->error, ENETDOWN); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(sdk_handle, PROCESS_EVENT_TIMEOUT); assert_int_equal(result, EVP_OK); result = evp_agent_connect(ctxt); @@ -134,17 +141,17 @@ test_disconnect_reconnect(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(sdk_handle, 1000); + result = EVP_processEvent(sdk_handle, PROCESS_EVENT_TIMEOUT); assert_int_equal(result, EVP_OK); - - free(filename); } int setup(void **state) { + struct test *t = &g_test; + int rv; - rv = sync_init(&g_sync_conns); + rv = sync_init(&t->sync_cons); assert_int_equal(0, rv); agent_test_setup(); rv = systemf("mkdir -p %s", path_get(MODULE_INSTANCE_PATH_ID)); @@ -152,12 +159,18 @@ setup(void **state) rv = systemf("touch %s/%s", path_get(MODULE_INSTANCE_PATH_ID), TEST_HTTP_GET_FILE); assert_int_equal(0, rv); + + *state = t; return 0; } int teardown(void **state) { + struct test *t = *state; + + free(t->filename); + agent_test_exit(); return 0; } diff --git a/test/src/systest/test_backdoor_instance_config_early.c b/test/src/systest/test_backdoor_instance_config_early.c index f672ec52..a5a1b21b 100644 --- a/test/src/systest/test_backdoor_instance_config_early.c +++ b/test/src/systest/test_backdoor_instance_config_early.c @@ -166,8 +166,6 @@ test_backdoor_instance_config_early(void **state) int setup(void **state) { - // be sure that the periodic report is send every 3 seconds - putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=3"); agent_test_setup(); // EVP1 diff --git a/test/src/systest/test_capture_mode.c b/test/src/systest/test_capture_mode.c index 9b1c55c3..4a1ddd6f 100644 --- a/test/src/systest/test_capture_mode.c +++ b/test/src/systest/test_capture_mode.c @@ -109,7 +109,7 @@ test_capture_mode(void **state) expect_value(blob_cb, result->result, EVP_BLOB_RESULT_SUCCESS); expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); - result = EVP_processEvent(ctxt->sdk_handle, 1000); + result = EVP_processEvent(ctxt->sdk_handle, 3000); assert_int_equal(result, EVP_OK); // Ensure no mqtt transmission occured diff --git a/test/src/systest/test_connection_error.c b/test/src/systest/test_connection_error.c index 1d7b57cf..73483368 100644 --- a/test/src/systest/test_connection_error.c +++ b/test/src/systest/test_connection_error.c @@ -289,11 +289,6 @@ setup(void **state) { static struct test_context ctxt; - // Force max time to 3 because the test is checking the report 2 times - // consecutivily. Otherwise we will get a timeout, since - // default value is defined by MAX_REPORT_INTERVAL_SEC - putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=3"); - assert_int_equal(sem_init(&ctxt.sem, 0, 0), 0); agent_test_setup(); diff --git a/test/src/systest/test_device_config.c b/test/src/systest/test_device_config.c index bf0de1b3..7b882225 100644 --- a/test/src/systest/test_device_config.c +++ b/test/src/systest/test_device_config.c @@ -103,6 +103,10 @@ int setup(void **state) { agent_test_setup(); + // This test expects the default value when no value + // is set via env var. So be sure that there is not any + // value as max report + putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC="); return 0; } diff --git a/test/src/systest/test_instance_state.c b/test/src/systest/test_instance_state.c index 48ed858b..fe0809b6 100644 --- a/test/src/systest/test_instance_state.c +++ b/test/src/systest/test_instance_state.c @@ -285,13 +285,14 @@ setup(void **state) struct evp_agent_context *ctxt; static struct state st; + agent_test_setup(); + // Set periodic report intervals putenv("EVP_REPORT_STATUS_INTERVAL_MIN_SEC=" ___STRING( REPORT_STATUS_INTERVAL_MIN)); putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=" ___STRING( REPORT_STATUS_INTERVAL_MAX)); - agent_test_setup(); agent_register_payload(DEPLOYMENT_MANIFEST_1, EVP_HUB_TYPE_EVP1_TB, EVP1_DEPLOYMENT_MANIFEST_1); agent_register_payload(DEPLOYMENT_MANIFEST_2, EVP_HUB_TYPE_EVP1_TB, diff --git a/test/src/systest/test_mi_denied_requests.c b/test/src/systest/test_mi_denied_requests.c index c7b0401e..3a7b3219 100644 --- a/test/src/systest/test_mi_denied_requests.c +++ b/test/src/systest/test_mi_denied_requests.c @@ -6,7 +6,10 @@ #include +#include +#include #include +#include #include #include #include @@ -17,6 +20,8 @@ #include +#include "webclient/webclient.h" + #include "../sync.h" #include "agent_test.h" #include "global.h" @@ -30,6 +35,7 @@ struct test_context { struct EVP_client *h; struct evp_agent_context *agent; + sem_t sem; }; enum test_payloads { DEPLOYMENT_MANIFEST_1 }; @@ -130,6 +136,8 @@ static struct sync_ctxt sdk_complete_collect_telemetry_sync; "Dui_faucibus_in_ornare_quam_viverra_orci_sagittis_eu_volutpat__Et_" \ "netus_et_malesuada_fames_ac" +static struct test_context test; + void __real_sdk_collect_telemetry(void (*)(const char *, const struct EVP_telemetry_entry *, size_t, void *, @@ -146,6 +154,13 @@ __wrap_sdk_collect_telemetry(void (*cb)(const char *, __real_sdk_collect_telemetry(cb, user); } +int +__wrap_webclient_perform(FAR struct webclient_context *ctx) +{ + assert(!sem_wait(&test.sem)); + return 0; +} + /* * Instance state tests */ @@ -289,16 +304,21 @@ test_blob_max_ongoing_requests(void **state) i++) { EVP_RESULT res; + // We only need to trigger a webclient_perform call so the + // mocked call will block and ensure operations remain ongoing. + // So the blob type does not matter. + // Here Azure blob is used arbitrarily. struct EVP_BlobRequestAzureBlob request = { .url = "", }; - - // make a local store struct EVP_BlobLocalStore localStore = {.filename = FILENAME}; - // the blob operation should fire an mSTP token request + // 3 blob operations will be queued and remain ongoing until + // smaphore releases each ones. + // The 4th iteration shall return EVP_DENIED as the blob + // operation queue limit has been reached. res = EVP_blobOperation(ctxt->h, EVP_BLOB_TYPE_AZURE_BLOB, - EVP_BLOB_OP_PUT, &request, &localStore, + EVP_BLOB_OP_GET, &request, &localStore, blob_cb, userdata); if (i < CONFIG_EVP_AGENT_MAX_LIVE_BLOBS_PER_INSTANCE) { assert_int_equal(res, EVP_OK); @@ -307,10 +327,12 @@ test_blob_max_ongoing_requests(void **state) } } + // Now release all ongoing blob operations. for (int i = 0; i < CONFIG_EVP_AGENT_MAX_LIVE_BLOBS_PER_INSTANCE; i++) { expect_value(blob_cb, reason, EVP_BLOB_CALLBACK_REASON_DONE); expect_value(blob_cb, userData, userdata); + assert_int_equal(0, sem_post(&ctxt->sem)); // wait for the blob_cb EVP_RESULT res = EVP_processEvent(ctxt->h, 1000); assert_int_equal(res, EVP_OK); @@ -348,13 +370,20 @@ test_direct_command(void **state) int setup(void **state) { - static struct test_context ctxt; + struct test_context *ctxt = &test; + + agent_test_setup(); putenv("EVP_REPORT_STATUS_INTERVAL_MIN_SEC=3"); putenv("EVP_TRANSPORT_QUEUE_LIMIT=1024"); info("Set EVP_TRANSPORT_QUEUE_LIMIT=%s\n", getenv("EVP_TRANSPORT_QUEUE_LIMIT")); + if (sem_init(&ctxt->sem, 0, 0)) { + fprintf(stderr, "%s: sem_init(3) sem: %s\n", __func__, + strerror(errno)); + } + sync_init(&sdk_collect_telemetry_sync); sync_init(&sdk_complete_collect_telemetry_sync); @@ -363,29 +392,35 @@ setup(void **state) agent_register_payload(DEPLOYMENT_MANIFEST_1, EVP_HUB_TYPE_EVP2_TB, EVP2_DEPLOYMENT_MANIFEST_1); - agent_test_setup(); - // start agent - ctxt.agent = agent_test_start(); + ctxt->agent = agent_test_start(); - struct agent_deployment d = {.ctxt = ctxt.agent}; + struct agent_deployment d = {.ctxt = ctxt->agent}; // create backdoor instance - ctxt.h = evp_agent_add_instance(ctxt.agent, MODULE_NAME); - assert_non_null(ctxt.h); + ctxt->h = evp_agent_add_instance(ctxt->agent, MODULE_NAME); + assert_non_null(ctxt->h); // send deployment manifest agent_ensure_deployment(&d, agent_get_payload(DEPLOYMENT_MANIFEST_1), TEST_DEPLOYMENT_ID1); - *state = &ctxt; + *state = ctxt; return 0; } int teardown(void **state) { + struct test_context *ctxt = *state; + agent_test_exit(); + + if (sem_destroy(&ctxt->sem)) { + fprintf(stderr, "%s: sem_destroy(3) sem: %s\n", __func__, + strerror(errno)); + } + return 0; } diff --git a/test/src/systest/test_mod_download_evp_file.c b/test/src/systest/test_mod_download_evp_file.c index c3cd1d4f..d4a45392 100644 --- a/test/src/systest/test_mod_download_evp_file.c +++ b/test/src/systest/test_mod_download_evp_file.c @@ -393,16 +393,3 @@ test_download_http_blob_python(void **state) { test_download_http_blob(*state, PYTHON); } - -int -main(void) -{ - // define tests - const struct CMUnitTest tests[] = { - cmocka_unit_test(test_download_http_blob_wasm), - cmocka_unit_test(test_download_http_blob_spawn), - cmocka_unit_test(test_download_http_blob_python), - }; - // setup, run tests and teardown - return cmocka_run_group_tests(tests, setup, teardown); -} diff --git a/test/src/systest/test_mstp_null.c b/test/src/systest/test_mstp_null.c index 6ea4a2f7..85bdd884 100644 --- a/test/src/systest/test_mstp_null.c +++ b/test/src/systest/test_mstp_null.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define _GNU_SOURCE + #include #include #include @@ -26,16 +28,14 @@ "moduleInstanceId=17cef5e7-037a-41e3-9e11-d41d47d0a1eb] does not " \ "exist" -#define REQID_EVP1_TB "10004" -#define REQID_EVP2_TB "10004" +#define REQID_FMT "%s" +#define REQID_EVP1_TB REQID_FMT +#define REQID_EVP2_TB REQID_FMT -enum test_mstp_null_payloads { MSTP_REQ_TOPIC, MSTP_REQ, MSTP_RES }; +enum test_mstp_null_payloads { MSTP_REQ, MSTP_RES }; static void *user_data = "some-user-data"; -static const char mstp_request_topic_tb[] = - "v1/devices/me/rpc/request/" REQID_EVP2_TB; - static const char mstp_request_tb[] = "{" "\"method\":\"evp-d2c\"," @@ -113,12 +113,32 @@ test_mstp_null_evp2(void) assert_int_equal(result, EVP_OK); + // Wait for the rpc request and get the reqid from topic (compatible + // between EVP1 and EVP2) + char *msg; + uintmax_t reqid; + msg = agent_poll_fetch(verify_contains, "v1/devices/me/rpc/request/"); + assert_int_equal(sscanf(msg, "v1/devices/me/rpc/request/%ju", &reqid), + 1); + assert_non_null(msg); + free(msg); + + char *reqid_str; + assert_int_not_equal(asprintf(&reqid_str, "%ju", reqid), -1); + // wait for the mstp request on mqtt - agent_poll(verify_equals, agent_get_payload(MSTP_REQ_TOPIC)); - agent_poll(verify_equals, agent_get_payload(MSTP_REQ)); + char *payload; + payload = agent_get_payload_formatted(MSTP_REQ, reqid_str); + agent_poll(verify_equals, payload); + free(payload); + + // send mstp response + payload = agent_get_payload_formatted(MSTP_RES, reqid_str); + agent_send_storagetoken_response(ctxt, payload, reqid_str); + free(payload); + + free(reqid_str); - agent_send_storagetoken_response(ctxt, agent_get_payload(MSTP_RES), - REQID_EVP1_TB); // wait for the blob_cb expect_value(blob_cb, reason, EVP_BLOB_CALLBACK_REASON_DONE); expect_value(blob_cb, lvp->result, EVP_BLOB_CALLBACK_REASON_EXIT); @@ -151,9 +171,6 @@ setup(void **state) { agent_test_setup(); - agent_register_payload(MSTP_REQ_TOPIC, EVP_HUB_TYPE_EVP2_TB, - mstp_request_topic_tb); - agent_register_payload(MSTP_REQ, EVP_HUB_TYPE_EVP2_TB, mstp_request_tb); diff --git a/test/src/systest/test_python_mod_download_evp_file.c b/test/src/systest/test_python_mod_download_evp_file.c new file mode 100644 index 00000000..bac3f1d9 --- /dev/null +++ b/test/src/systest/test_python_mod_download_evp_file.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_mod_download_evp_file.c" + +int +main(void) +{ + // define tests + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_download_http_blob_python), + }; + // setup, run tests and teardown + return cmocka_run_group_tests(tests, setup, teardown); +} diff --git a/test/src/systest/test_python_mod_zombie.c b/test/src/systest/test_python_mod_zombie.c index 8309afa6..39cc75fd 100644 --- a/test/src/systest/test_python_mod_zombie.c +++ b/test/src/systest/test_python_mod_zombie.c @@ -152,9 +152,6 @@ teardown(void **state) static int setup(void **state) { - // Enforce reporting every 3 secs to check minimal agent activity - putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=3"); - agent_test_setup(); xasprintf(&deployment1, EVP1_DEPLOYMENT_MANIFEST_1, MODULE_PATH); diff --git a/test/src/systest/test_spawn_mod_download_evp_file.c b/test/src/systest/test_spawn_mod_download_evp_file.c new file mode 100644 index 00000000..5cb266aa --- /dev/null +++ b/test/src/systest/test_spawn_mod_download_evp_file.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_mod_download_evp_file.c" + +int +main(void) +{ + // define tests + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_download_http_blob_spawn), + }; + // setup, run tests and teardown + return cmocka_run_group_tests(tests, setup, teardown); +} diff --git a/test/src/systest/test_system_info.c b/test/src/systest/test_system_info.c index 5d17dafe..7d3f18b0 100644 --- a/test/src/systest/test_system_info.c +++ b/test/src/systest/test_system_info.c @@ -112,11 +112,6 @@ test_instance_state(void **state) int setup(void **state) { - // Force max time to 3 because the test is checking the report 2 times - // consecutivily. Otherwise we will get a timeout, since - // default value is defined by MAX_REPORT_INTERVAL_SEC - putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=3"); - agent_test_setup(); agent_register_payload(DEPLOYMENT_MANIFEST_1, EVP_HUB_TYPE_EVP1_TB, EVP1_DEPLOYMENT_MANIFEST_1); diff --git a/test/src/systest/test_wasm_blob_http.c b/test/src/systest/test_wasm_blob_http.c index 448875b0..4d3b7ca5 100644 --- a/test/src/systest/test_wasm_blob_http.c +++ b/test/src/systest/test_wasm_blob_http.c @@ -378,7 +378,7 @@ blob_http_get_memory(void **state) expect_value(blob_cb, result->http_status, HTTP_STATUS_OK); expect_value(blob_cb, result->error, 0); result = EVP_processEvent_wasm(ctxt->wasm_exec_env, ctxt->wasm_handle, - 1000); + 3000); assert_int_equal(result, EVP_OK); assert_int_equal(on_blob_result_mock.call, 0); diff --git a/test/src/systest/test_wasm_blobs_tls.c b/test/src/systest/test_wasm_blobs_tls.c index 388f20a2..4e8501c7 100644 --- a/test/src/systest/test_wasm_blobs_tls.c +++ b/test/src/systest/test_wasm_blobs_tls.c @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define _GNU_SOURCE + #include #include #include @@ -91,10 +93,6 @@ struct context { // WEB server uint16_t backend_port; uint16_t frontend_port; - - // Requests - char *reqid; - EVP_RPC_ID reqid_offset; }; /* @@ -217,6 +215,20 @@ __wrap_webclient_perform(FAR struct webclient_context *ctx) return __real_webclient_perform(ctx); } +enum MQTTErrors +__wrap_mqtt_publish(struct mqtt_client *client, const char *topic_name, + const void *application_message, + size_t application_message_size, uint8_t publish_flags) +{ + agent_write_to_pipe(topic_name); + char *payload = xstrndup((char *)application_message, + application_message_size); + xlog_info("MQTT publish %s: %s", topic_name, payload); + agent_write_to_pipe(payload); + free(payload); + return MQTT_OK; +} + static void blob_cb(EVP_BLOB_CALLBACK_REASON reason, const void *vp, void *userData) { @@ -368,8 +380,6 @@ suite_setup(void **state) { struct context *ctxt = *state = malloc(sizeof(*ctxt)); - ctxt->reqid_offset = 0; - xasprintf(&ctxt->put_file, "%s/%s/boofar.bin", path_get(MODULE_INSTANCE_PATH_ID), TEST_MODULE_INSTANCE_ID1); xasprintf(&ctxt->get_file, "%s/%s/boofar.txt", @@ -461,17 +471,8 @@ suite_teardown(void **state) int setup_test(void **state) { - struct context *ctxt = *state; g_network_ssl_timeout_error = false; - // Allocate request id to get the current value. - // Next agent used request will be +1 - // Add offset of reqid due to suite setup requests - EVP_RPC_ID reqid = request_id_alloc() + 1 + ctxt->reqid_offset; - // Clear requid_offset at first setup - ctxt->reqid_offset = 0; - - xasprintf(&ctxt->reqid, "%lu", reqid); return 0; } @@ -492,8 +493,6 @@ setup_test_ssl_timeout_error(void **state) int setup_teardown(void **state) { - struct context *ctxt = *state; - free(ctxt->reqid); return 0; } @@ -1019,6 +1018,16 @@ blob_evp_ext_put_file(void **state) TEST_BLOB_HTTP_CALLBACK_INDEX, MAGIC_USERDATA); assert_int_equal(result, EVP_OK); + // Wait for the rpc request and get the reqid from topic (compatible + // between EVP1 and EVP2) + char *msg; + uintmax_t reqid; + msg = agent_poll_fetch(verify_contains, "v1/devices/me/rpc/request/"); + assert_int_equal(sscanf(msg, "v1/devices/me/rpc/request/%ju", &reqid), + 1); + assert_non_null(msg); + free(msg); + // At this point the agent sends a StorageToken request, check it static struct multi_check test_set_device_state1[] = { {.value = TEST_EVP_PUT_REMOTE_NAME}, @@ -1028,10 +1037,13 @@ blob_evp_ext_put_file(void **state) agent_poll(verify_contains_in_unordered_set, test_set_device_state1); // Send the RPC reponse (as HUB does) + char *reqid_str; + assert_int_not_equal(asprintf(&reqid_str, "%ju", reqid), -1); char *payload; - payload = agent_get_payload_formatted( - STP_RESPONSE, ctxt->frontend_port, ctxt->reqid); - agent_send_storagetoken_response(ctxt->agent, payload, ctxt->reqid); + payload = agent_get_payload_formatted(STP_RESPONSE, + ctxt->frontend_port, reqid_str); + agent_send_storagetoken_response(ctxt->agent, payload, reqid_str); + free(reqid_str); free(payload); // Now the agent will do the blob operation @@ -1090,6 +1102,16 @@ blob_evp_ext_default_put_file(void **state) TEST_BLOB_HTTP_CALLBACK_INDEX, MAGIC_USERDATA); assert_int_equal(result, EVP_OK); + // Wait for the rpc request and get the reqid from topic (compatible + // between EVP1 and EVP2) + char *msg; + uintmax_t reqid; + msg = agent_poll_fetch(verify_contains, "v1/devices/me/rpc/request/"); + assert_int_equal(sscanf(msg, "v1/devices/me/rpc/request/%ju", &reqid), + 1); + assert_non_null(msg); + free(msg); + // At this point the agent sends a StorageToken request WITHOUT // storage_name, check it expect_unexpect_t val = {.expect = TEST_EVP_PUT_REMOTE_NAME, @@ -1097,10 +1119,13 @@ blob_evp_ext_default_put_file(void **state) agent_poll(verify_contains_except, &val); // Send the RPC response (as HUB does) + char *reqid_str; + assert_int_not_equal(asprintf(&reqid_str, "%ju", reqid), -1); char *payload; - payload = agent_get_payload_formatted( - STP_RESPONSE, ctxt->frontend_port, ctxt->reqid); - agent_send_storagetoken_response(ctxt->agent, payload, ctxt->reqid); + payload = agent_get_payload_formatted(STP_RESPONSE, + ctxt->frontend_port, reqid_str); + agent_send_storagetoken_response(ctxt->agent, payload, reqid_str); + free(reqid_str); free(payload); // Now the agent will dot he blob operation diff --git a/test/src/systest/test_wasm_mod_deployment_invalid_wamr.c b/test/src/systest/test_wasm_mod_deployment_invalid_wamr.c new file mode 100644 index 00000000..fc1800f9 --- /dev/null +++ b/test/src/systest/test_wasm_mod_deployment_invalid_wamr.c @@ -0,0 +1,192 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "agent_test.h" +#include "fsutil.h" +#include "hub.h" +#include "module_instance.h" +#include "mqtt_custom.h" +#include "path.h" + +enum test_wasm_config_echo_payloads { + DEPLOYMENT_MANIFEST_1, + EMPTY_DEPLOYMENT_MANIFEST_1, + INSTANCE_CONFIG_1, + EXPECTED_STATE, +}; + +#define TEST_DEPLOYMENT_ID1 "4fa905ae-e103-46ab-a8b9-73be07599708" +#define TEST_EMPTY_DEPLOYMENT_ID1 "4fa905ae-e103-46ab-a8b9-73be07599709" +#define TEST_INSTANCE_ID1 "b218f90b-9228-423f-8e02-000000000001" + +#define MODULE_PATH_AOT_AMD64_OLD \ + "resources/invalid_wamr_modules/wamr_1.3.1_config_echo.wasm.x86_64" +#define MODULE_PATH MODULE_PATH_AOT_AMD64_OLD +#define DEPLOYMENT_STATUS_ERR_INVALID_WAMR_VER \ + "wasm_runtime_load failed with AOT module load failed: unexpected " \ + "end" + +#define MODULE_HASH \ + "579fca500ec9f67a661e8b1a3a59a114a97029c46776d6ad9502fb183f1a1f7d" + +#define EVP1_DEPLOYMENT_MANIFEST_1 \ + "\"{ " \ + " \\\"deploymentId\\\": " \ + "\\\"" TEST_DEPLOYMENT_ID1 "\\\"," \ + " \\\"instanceSpecs\\\": {" \ + " \\\"" TEST_INSTANCE_ID1 "\\\": {" \ + " \\\"moduleId\\\": " \ + "\\\"b218f90b-9228-423f-8e02-a6d3527bc15d\\\"," \ + " \\\"entryPoint\\\": \\\"main\\\"," \ + " \\\"version\\\": 1," \ + " \\\"publish\\\": {}," \ + " \\\"subscribe\\\": {}" \ + " }" \ + " }," \ + " \\\"modules\\\": {" \ + " \\\"b218f90b-9228-423f-8e02-a6d3527bc15d\\\": {" \ + " \\\"moduleImpl\\\": \\\"wasm\\\"," \ + " \\\"downloadUrl\\\": \\\"file://%s\\\"," \ + " \\\"hash\\\": \\\"" MODULE_HASH "\\\"" \ + " }" \ + " }," \ + " \\\"publishTopics\\\": {}," \ + " \\\"subscribeTopics\\\": {}" \ + "}\"" + +#define EVP1_EMPTY_DEPLOYMENT_MANIFEST_1 \ + "\"{ " \ + " \\\"deploymentId\\\": " \ + "\\\"" TEST_EMPTY_DEPLOYMENT_ID1 "\\\"," \ + " \\\"instanceSpecs\\\": {}," \ + " \\\"modules\\\": {}," \ + " \\\"publishTopics\\\": {}," \ + " \\\"subscribeTopics\\\": {}" \ + "}\"" + +#define EVP2_DEPLOYMENT_MANIFEST_1 \ + "{" \ + " \"deploymentId\": \"" TEST_DEPLOYMENT_ID1 "\"," \ + " \"instanceSpecs\": {" \ + " \"" TEST_INSTANCE_ID1 "\": {" \ + " \"moduleId\": " \ + "\"b218f90b-9228-423f-8e02-a6d3527bc15d\"," \ + " \"publish\": {}," \ + " \"subscribe\": {}" \ + " }" \ + " }," \ + " \"modules\": {" \ + " \"b218f90b-9228-423f-8e02-a6d3527bc15d\": {" \ + " \"entryPoint\": \"main\"," \ + " \"moduleImpl\": \"wasm\"," \ + " \"downloadUrl\": " \ + "\"file://%s\"," \ + " \"hash\": " \ + "\"" MODULE_HASH "" \ + "\"" \ + " }" \ + " }," \ + " \"publishTopics\": {}," \ + " \"subscribeTopics\": {}" \ + "}" + +#define EVP2_EMPTY_DEPLOYMENT_MANIFEST_1 \ + "{" \ + " \"deploymentId\": \"" TEST_EMPTY_DEPLOYMENT_ID1 "\"," \ + " \"instanceSpecs\": {}," \ + " \"modules\": {}," \ + " \"publishTopics\": {}," \ + " \"subscribeTopics\": {}" \ + "}" + +#define EVP2_INSTANCE_CONFIG_1 \ + "{" \ + " \"configuration/" TEST_INSTANCE_ID1 "/" DUMMY_KEY \ + "\": \"" EVP2_DUMMY_VALUE "\"" \ + "}" + +/* + * The goal of this test is to be sure that the agent report an error message + * when the wasm aot module is build with a different version from the + * supported one. See ADI-406 + */ +void +test_wasm_mod_deployment_invalid_wamr_version(void **state) +{ + // start agent + struct evp_agent_context *ctxt = agent_test_start(); + struct agent_deployment d = {.ctxt = ctxt}; + + // deploy + agent_send_initial(ctxt, agent_get_payload(DEPLOYMENT_MANIFEST_1), + NULL, NULL); + + agent_poll(verify_contains, DEPLOYMENT_STATUS_ERR_INVALID_WAMR_VER); + d.init = true; + + agent_ensure_deployment(&d, + agent_get_payload(EMPTY_DEPLOYMENT_MANIFEST_1), + TEST_EMPTY_DEPLOYMENT_ID1); +} + +static char *deployment1; +static char *deployment2; + +static int +teardown(void **state) +{ + agent_test_exit(); + free(deployment1); + free(deployment2); + return 0; +} + +static int +setup(void **state) +{ + agent_test_setup(); + + xasprintf(&deployment1, EVP1_DEPLOYMENT_MANIFEST_1, MODULE_PATH); + + xasprintf(&deployment2, EVP2_DEPLOYMENT_MANIFEST_1, MODULE_PATH); + + agent_register_payload(DEPLOYMENT_MANIFEST_1, EVP_HUB_TYPE_EVP1_TB, + deployment1); + agent_register_payload(DEPLOYMENT_MANIFEST_1, EVP_HUB_TYPE_EVP2_TB, + deployment2); + + agent_register_payload(EMPTY_DEPLOYMENT_MANIFEST_1, + EVP_HUB_TYPE_EVP2_TB, + EVP2_EMPTY_DEPLOYMENT_MANIFEST_1); + agent_register_payload(EMPTY_DEPLOYMENT_MANIFEST_1, + EVP_HUB_TYPE_EVP1_TB, + EVP1_EMPTY_DEPLOYMENT_MANIFEST_1); + + return 0; +} + +int +main(void) +{ + // define tests + const struct CMUnitTest tests[] = { + cmocka_unit_test( + test_wasm_mod_deployment_invalid_wamr_version), + }; + // setup, run tests and teardown + return cmocka_run_group_tests(tests, setup, teardown); +} diff --git a/test/src/systest/test_wasm_mod_download_evp_file.c b/test/src/systest/test_wasm_mod_download_evp_file.c new file mode 100644 index 00000000..8cc3a0c9 --- /dev/null +++ b/test/src/systest/test_wasm_mod_download_evp_file.c @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "test_mod_download_evp_file.c" + +int +main(void) +{ + // define tests + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_download_http_blob_wasm), + }; + // setup, run tests and teardown + return cmocka_run_group_tests(tests, setup, teardown); +} diff --git a/test/src/systest/test_wasm_mod_instance_state.c b/test/src/systest/test_wasm_mod_instance_state.c index 15c5a532..9ea36563 100644 --- a/test/src/systest/test_wasm_mod_instance_state.c +++ b/test/src/systest/test_wasm_mod_instance_state.c @@ -57,13 +57,14 @@ setup(void **state) { static struct test_context ctxt; + agent_test_setup(); + // Set periodic report intervals putenv("EVP_REPORT_STATUS_INTERVAL_MIN_SEC=" ___STRING( REPORT_STATUS_INTERVAL_MIN)); putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=" ___STRING( REPORT_STATUS_INTERVAL_MAX)); - agent_test_setup(); agent_register_payload(MESSAGE_1, EVP_HUB_TYPE_EVP1_TB, STATE_1_B64); agent_register_payload(MESSAGE_1, EVP_HUB_TYPE_EVP2_TB, STATE_1); agent_register_payload(MESSAGE_2, EVP_HUB_TYPE_EVP1_TB, STATE_2_B64); diff --git a/test/src/systest/test_wasm_mod_pause_deployment.c b/test/src/systest/test_wasm_mod_pause_deployment.c index 4fef785d..cc665684 100644 --- a/test/src/systest/test_wasm_mod_pause_deployment.c +++ b/test/src/systest/test_wasm_mod_pause_deployment.c @@ -20,7 +20,6 @@ #include "webclient/webclient.h" -#include "../sync.h" #include "agent_test.h" #include "hub.h" #include "module_instance.h" @@ -36,9 +35,9 @@ enum test_wasm_config_echo_payloads { #define DEPLOYMENT_ID0 "4fa905ae-e103-46ab-a8b9-73be07599708" #define DEPLOYMENT_ID1 "8543e017-2d93-444b-bd4c-bcaa39c46095" -#define DEPLOYMENT_ID2 "4fa905ae-e103-46ab-a8b9-73be07599709" +#define DEPLOYMENT_ID2 "e46f226e-3f8a-42fa-a2dd-d287ef64809b" #define INSTANCE_ID1 "b218f90b-9228-423f-8e02-000000000001" -#define INSTANCE_ID2 "b218f90b-9228-423f-8e02-000000000002" +#define INSTANCE_ID2 "f0fe8678-acf9-4979-8e8b-43c495698593" #define RECONCILE_EVENT(Id, Event) "on_reconcileStatus/" Id "/" __STRING(Event) @@ -122,8 +121,8 @@ enum test_wasm_config_echo_payloads { " \"subscribeTopics\": {}" \ "}" -static struct sync_ctxt sync_download; unsigned short backend_port; +static struct agent_deployment g_deployment; int __real_webclient_perform(FAR struct webclient_context *ctx); int @@ -163,7 +162,6 @@ on_get_file(const struct http_payload *p, struct http_response *r, void *user) .n = statbuf.st_size, }; - sync_join(&sync_download); return 0; } @@ -189,13 +187,9 @@ on_reconcileStatus(const void *args, void *user_data) int test_teardown(void **state) { - struct evp_agent_context *ctxt = *state; - const char *deployment; - - // send empty deployment - deployment = agent_get_payload(EMPTY_DEPLOYMENT_MANIFEST); - agent_send_deployment(ctxt, deployment); - agent_poll(verify_contains, DEPLOYMENT_ID0); + agent_ensure_deployment(&g_deployment, + agent_get_payload(EMPTY_DEPLOYMENT_MANIFEST), + DEPLOYMENT_ID0); return 0; } @@ -213,7 +207,6 @@ static int suite_setup(void **state) { agent_test_setup(); - sync_init(&sync_download); assert_int_equal(websrv_setup(0), 0); assert_int_equal( @@ -241,14 +234,12 @@ suite_setup(void **state) ctxt, "deployment/reconcileStatus", on_reconcileStatus, NULL), 0); - const char *deployment; // Send initial empty deployment - deployment = agent_get_payload(EMPTY_DEPLOYMENT_MANIFEST); - agent_send_initial(ctxt, deployment, NULL, NULL); - - // wait for reconcile status ok - agent_poll(verify_contains, RECONCILE_EVENT(DEPLOYMENT_ID0, ok)); + g_deployment.ctxt = ctxt; + agent_ensure_deployment(&g_deployment, + agent_get_payload(EMPTY_DEPLOYMENT_MANIFEST), + DEPLOYMENT_ID0); print_message("[ INFO ] Deployment ok\n"); return 0; @@ -271,37 +262,27 @@ void pause_deployment_not_in_progress(void **state) { struct evp_agent_context *ctxt = *state; - int ret; // Request pause when no module is being downloaded - ret = evp_agent_request_pause_deployment(ctxt); - assert_int_equal(ret, 0); + assert_int_equal(evp_agent_request_pause_deployment(ctxt), 0); // Send a new deployment with a module to download send_deployment(ctxt, DEPLOYMENT_ID1, INSTANCE_ID1, MODULE_1, MODULE_1_HASH); // wait for the deployment status to be paused - agent_poll(verify_contains, RECONCILE_EVENT(DEPLOYMENT_ID1, paused)); + agent_poll(verify_equals, RECONCILE_EVENT(DEPLOYMENT_ID1, paused)); print_message("[ INFO ] Paused\n"); - // Block download to simulate a web download - sync_activate(&sync_download, 2); - // Resume deployment capability assert_int_equal(evp_agent_resume_deployment(ctxt), 0); // wait for the deployment status to be resumed - agent_poll(verify_contains, RECONCILE_EVENT(DEPLOYMENT_ID1, applying)); - - // Achieve an on going operation - sync_join(&sync_download); - - print_message("[ INFO ] Download completed\n"); + agent_poll(verify_equals, RECONCILE_EVENT(DEPLOYMENT_ID1, applying)); // wait for the deployment - agent_poll(verify_contains, RECONCILE_EVENT(DEPLOYMENT_ID1, ok)); + agent_poll(verify_equals, RECONCILE_EVENT(DEPLOYMENT_ID1, ok)); agent_poll(verify_contains, INSTANCE_ID1); } @@ -309,38 +290,24 @@ void pause_deployment_in_progress(void **state) { struct evp_agent_context *ctxt = *state; - int ret; - - // Block download to simulate a web download - sync_activate(&sync_download, 2); // Send a new deployment with a module to download send_deployment(ctxt, DEPLOYMENT_ID2, INSTANCE_ID2, MODULE_2, MODULE_2_HASH); // wait for the deployment status to be applying - agent_poll(verify_contains, RECONCILE_EVENT(DEPLOYMENT_ID2, applying)); + agent_poll(verify_equals, RECONCILE_EVENT(DEPLOYMENT_ID2, applying)); // Request pause when no module is being downloaded - ret = evp_agent_request_pause_deployment(ctxt); - assert_int_equal(ret, EAGAIN); - - // Achieve an on going operation - sync_join(&sync_download); - - print_message("[ INFO ] Download completed\n"); + assert_int_equal(evp_agent_request_pause_deployment(ctxt), EAGAIN); // Request pause when no module is being downloaded - int timeout = 20; - while ((ret = evp_agent_request_pause_deployment(ctxt)) != 0 && - timeout--) - sleep(1); - assert_int_equal(ret, 0); - - // wait for the deployment status to be paused - agent_poll(verify_contains, RECONCILE_EVENT(DEPLOYMENT_ID2, paused)); + while (evp_agent_request_pause_deployment(ctxt)) { + agent_poll(verify_equals, + RECONCILE_EVENT(DEPLOYMENT_ID2, paused)); + } - print_message("[ INFO ] Paused in %ds\n", 20 - timeout); + print_message("[ INFO ] Paused\n"); // Send a new deployment with a module to download send_deployment(ctxt, DEPLOYMENT_ID1, INSTANCE_ID1, MODULE_1, @@ -350,7 +317,7 @@ pause_deployment_in_progress(void **state) assert_int_equal(evp_agent_resume_deployment(ctxt), 0); // wait for the deployment - agent_poll(verify_contains, RECONCILE_EVENT(DEPLOYMENT_ID1, ok)); + agent_poll(verify_equals, RECONCILE_EVENT(DEPLOYMENT_ID1, ok)); agent_poll(verify_contains, INSTANCE_ID1); } diff --git a/test/src/systest/test_wasm_mod_performance_boot_mstp.c b/test/src/systest/test_wasm_mod_performance_boot_mstp.c index c11341df..a04f1ca3 100644 --- a/test/src/systest/test_wasm_mod_performance_boot_mstp.c +++ b/test/src/systest/test_wasm_mod_performance_boot_mstp.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define _GNU_SOURCE #include #include #include @@ -155,6 +156,20 @@ enum test_wasm_config_echo_payloads { "}" \ "}" +enum MQTTErrors +__wrap_mqtt_publish(struct mqtt_client *client, const char *topic_name, + const void *application_message, + size_t application_message_size, uint8_t publish_flags) +{ + agent_write_to_pipe(topic_name); + char *payload = xstrndup((char *)application_message, + application_message_size); + xlog_info("MQTT publish %s: %s", topic_name, payload); + agent_write_to_pipe(payload); + free(payload); + return MQTT_OK; +} + /* * The goal of this test is validate the module MODULE_PATH * Send the storageName (key) configuration, and wait for a mSTP blob operation @@ -175,11 +190,24 @@ test_wasm_mod_performance_boot_mstp(void **state) // send config agent_send_instance_config(ctxt, agent_get_payload(INSTANCE_CONFIG_1)); - // wait for the mstp request on mqtt - agent_poll(verify_contains, "test.txt"); - - char *payload = agent_get_payload_formatted(MSTP_RESPONSE_1, "10007"); - agent_send_storagetoken_response(ctxt, payload, "10007"); + // Wait for the rpc request and get the reqid from topic (compatible + // between EVP1 and EVP2) + char *msg; + uintmax_t reqid; + msg = agent_poll_fetch(verify_contains, "v1/devices/me/rpc/request/"); + assert_int_equal(sscanf(msg, "v1/devices/me/rpc/request/%ju", &reqid), + 1); + assert_non_null(msg); + free(msg); + + // Send the RPC response + char *reqid_str; + asprintf(&reqid_str, "%ju", reqid); + + char *payload = + agent_get_payload_formatted(MSTP_RESPONSE_1, reqid_str); + agent_send_storagetoken_response(ctxt, payload, reqid_str); + free(reqid_str); free(payload); // wait for the http request diff --git a/test/src/systest/test_wasm_mod_streams.c b/test/src/systest/test_wasm_mod_streams.c index 868ea224..c180bc00 100644 --- a/test/src/systest/test_wasm_mod_streams.c +++ b/test/src/systest/test_wasm_mod_streams.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -158,6 +159,12 @@ on_port(const void *args, void *user) return 0; } +static int +on_init(const void *args, void *user) +{ + return sem_post(user); +} + static void send_deployment(struct evp_agent_context *ctxt, const char *payload) { @@ -185,12 +192,18 @@ test_wasm_mod_streams_posix(void **state) } struct stream_port p; - struct notification_entry *e; + struct notification_entry *eport, *edone; struct notification *n = stream_notification(); + sem_t sem; + assert_int_equal(sem_init(&sem, 0, 0), 0); assert_non_null(n); assert_int_equal( - notification_subscribe(n, "init/port", on_port, &p, &e), 0); + notification_subscribe(n, "init/port", on_port, &p, &eport), + 0); + assert_int_equal( + notification_subscribe(n, "init/done", on_init, &sem, &edone), + 0); send_deployment(ctxt, agent_get_payload(DEPLOYMENT_MANIFEST_1)); @@ -199,6 +212,8 @@ test_wasm_mod_streams_posix(void **state) "deploymentStatus.reconcileStatus=%s", TEST_DEPLOYMENT_ID1, "ok"); + assert_int_equal(sem_wait(&sem), 0); + sdk_lock(); struct EVP_client *h = sdk_handle_from_name(READER_INSTANCE_ID); sdk_unlock(); @@ -223,7 +238,9 @@ test_wasm_mod_streams_posix(void **state) TEST_DEPLOYMENT_ID2, "ok"); agent_poll(verify_contains, "stream-read-ok"); - assert_int_equal(notification_unsubscribe(n, e), 0); + assert_int_equal(notification_unsubscribe(n, edone), 0); + assert_int_equal(notification_unsubscribe(n, eport), 0); + assert_int_equal(sem_destroy(&sem), 0); // send empty deployment send_deployment(ctxt, agent_get_payload(EMPTY_DEPLOYMENT_MANIFEST_1)); diff --git a/test/src/systest/test_wasm_mod_undeploy_all.c b/test/src/systest/test_wasm_mod_undeploy_all.c index c103eb04..1ef519e4 100644 --- a/test/src/systest/test_wasm_mod_undeploy_all.c +++ b/test/src/systest/test_wasm_mod_undeploy_all.c @@ -47,6 +47,8 @@ setup(void **state) static struct test_context ctxt; // Set periodic report intervals + agent_test_setup(); + putenv("EVP_REPORT_STATUS_INTERVAL_MIN_SEC=" ___STRING( REPORT_STATUS_INTERVAL_MIN)); putenv("EVP_REPORT_STATUS_INTERVAL_MAX_SEC=" ___STRING( @@ -57,8 +59,6 @@ setup(void **state) agent_register_payload(JSON_STATUS_CHECK, EVP_HUB_TYPE_EVP2_TB, JSON_STATUS_CHECK_TB); - agent_test_setup(); - ctxt.agent = agent_test_start(); agent_send_initial(ctxt.agent, NULL, NULL, NULL); diff --git a/test/src/systest/test_wasm_mod_zombie.c b/test/src/systest/test_wasm_mod_zombie.c new file mode 100644 index 00000000..0a671f55 --- /dev/null +++ b/test/src/systest/test_wasm_mod_zombie.c @@ -0,0 +1,179 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "agent_test.h" +#include "fsutil.h" +#include "hub.h" +#include "module_instance.h" +#include "mqtt_custom.h" +#include "path.h" + +enum test_wasm_config_echo_payloads { + DEPLOYMENT_MANIFEST_1, + EMPTY_DEPLOYMENT_MANIFEST_1, + INSTANCE_CONFIG_1, + EXPECTED_STATE, +}; + +#define TEST_DEPLOYMENT_ID1 "4fa905ae-e103-46ab-a8b9-73be07599708" +#define TEST_EMPTY_DEPLOYMENT_ID1 "4fa905ae-e103-46ab-a8b9-73be07599709" +#define TEST_INSTANCE_ID1 "b218f90b-9228-423f-8e02-000000000001" + +#define MODULE_PATH "../test_modules/zombie.wasm" + +#define MODULE_HASH \ + "579fca500ec9f67a661e8b1a3a59a114a97029c46776d6ad9502fb183f1a1f7d" + +#define RECONCILE_EVENT(Id, Event) "reconcileStatus/" Id "/" Event + +#define EVP1_DEPLOYMENT_MANIFEST_1 \ + "\"{ " \ + " \\\"deploymentId\\\": " \ + "\\\"" TEST_DEPLOYMENT_ID1 "\\\"," \ + " \\\"instanceSpecs\\\": {" \ + " \\\"" TEST_INSTANCE_ID1 "\\\": {" \ + " \\\"moduleId\\\": " \ + "\\\"b218f90b-9228-423f-8e02-a6d3527bc15d\\\"," \ + " \\\"entryPoint\\\": \\\"main\\\"," \ + " \\\"version\\\": 1," \ + " \\\"publish\\\": {}," \ + " \\\"subscribe\\\": {}" \ + " }" \ + " }," \ + " \\\"modules\\\": {" \ + " \\\"b218f90b-9228-423f-8e02-a6d3527bc15d\\\": {" \ + " \\\"moduleImpl\\\": \\\"wasm\\\"," \ + " \\\"downloadUrl\\\": \\\"file://%s\\\"," \ + " \\\"hash\\\": \\\"" MODULE_HASH "\\\"" \ + " }" \ + " }," \ + " \\\"publishTopics\\\": {}," \ + " \\\"subscribeTopics\\\": {}" \ + "}\"" + +#define EVP1_EMPTY_DEPLOYMENT_MANIFEST_1 \ + "\"{ " \ + " \\\"deploymentId\\\": " \ + "\\\"" TEST_EMPTY_DEPLOYMENT_ID1 "\\\"," \ + " \\\"instanceSpecs\\\": {}," \ + " \\\"modules\\\": {}," \ + " \\\"publishTopics\\\": {}," \ + " \\\"subscribeTopics\\\": {}" \ + "}\"" + +#define EVP2_DEPLOYMENT_MANIFEST_1 \ + "{" \ + " \"deploymentId\": \"" TEST_DEPLOYMENT_ID1 "\"," \ + " \"instanceSpecs\": {" \ + " \"" TEST_INSTANCE_ID1 "\": {" \ + " \"moduleId\": " \ + "\"b218f90b-9228-423f-8e02-a6d3527bc15d\"," \ + " \"publish\": {}," \ + " \"subscribe\": {}" \ + " }" \ + " }," \ + " \"modules\": {" \ + " \"b218f90b-9228-423f-8e02-a6d3527bc15d\": {" \ + " \"entryPoint\": \"main\"," \ + " \"moduleImpl\": \"python\"," \ + " \"downloadUrl\": \"file://%s\"," \ + " \"hash\": " \ + "\"" MODULE_HASH "" \ + "\"" \ + " }" \ + " }," \ + " \"publishTopics\": {}," \ + " \"subscribeTopics\": {}" \ + "}" + +#define EVP2_EMPTY_DEPLOYMENT_MANIFEST_1 \ + "{" \ + " \"deploymentId\": \"" TEST_EMPTY_DEPLOYMENT_ID1 "\"," \ + " \"instanceSpecs\": {}," \ + " \"modules\": {}," \ + " \"publishTopics\": {}," \ + " \"subscribeTopics\": {}" \ + "}" + +static void +test_mod_zombie(void **state) +{ + // start agent + struct evp_agent_context *ctxt = agent_test_start(); + struct agent_deployment d = {.ctxt = ctxt}; + + // deploy + message_info("Deploy"); + agent_ensure_deployment(&d, agent_get_payload(DEPLOYMENT_MANIFEST_1), + TEST_DEPLOYMENT_ID1); + + // Undeploy + message_info("Undeploy"); + agent_send_deployment(ctxt, + agent_get_payload(EMPTY_DEPLOYMENT_MANIFEST_1)); + + // Agent should force kill after 5 seconds + message_info("Wait for 'ok' status"); + agent_ensure_deployment_status(TEST_EMPTY_DEPLOYMENT_ID1, "ok"); + + // Module is still being undeployed but test is done at this point. + // The test has passed. +} + +static char *deployment1; +static char *deployment2; + +static int +teardown(void **state) +{ + agent_test_exit(); + free(deployment1); + free(deployment2); + return 0; +} + +static int +setup(void **state) +{ + agent_test_setup(); + xasprintf(&deployment1, EVP1_DEPLOYMENT_MANIFEST_1, MODULE_PATH); + + xasprintf(&deployment2, EVP2_DEPLOYMENT_MANIFEST_1, MODULE_PATH); + + agent_register_payload(DEPLOYMENT_MANIFEST_1, EVP_HUB_TYPE_EVP1_TB, + deployment1); + agent_register_payload(DEPLOYMENT_MANIFEST_1, EVP_HUB_TYPE_EVP2_TB, + deployment2); + agent_register_payload(EMPTY_DEPLOYMENT_MANIFEST_1, + EVP_HUB_TYPE_EVP2_TB, + EVP2_EMPTY_DEPLOYMENT_MANIFEST_1); + agent_register_payload(EMPTY_DEPLOYMENT_MANIFEST_1, + EVP_HUB_TYPE_EVP1_TB, + EVP1_EMPTY_DEPLOYMENT_MANIFEST_1); + return 0; +} + +int +main(void) +{ + // define tests + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_mod_zombie), + }; + // setup, run tests and teardown + return cmocka_run_group_tests(tests, setup, teardown); +} diff --git a/test/src/ut-nohub/azure_certs.h b/test/src/ut-nohub/azure_certs.h index 5b0e3d5a..cd4ace14 100644 --- a/test/src/ut-nohub/azure_certs.h +++ b/test/src/ut-nohub/azure_certs.h @@ -767,5 +767,5 @@ const char certificates[] = { 0x62, 0x70, 0x31, 0x5a, 0x57, 0x56, 0x62, 0x64, 0x34, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x0a}; -unsigned int certlist_crt_len = 9145; + 0x0a, 0x00}; +unsigned int certlist_crt_len = sizeof(certificates); diff --git a/test/src/ut-nohub/test_certificates.c b/test/src/ut-nohub/test_certificates.c index ab62b3e3..66722fb7 100644 --- a/test/src/ut-nohub/test_certificates.c +++ b/test/src/ut-nohub/test_certificates.c @@ -47,7 +47,7 @@ void test_certificates(void **state) { const char *test_cert = certificates; - size_t test_cert_size = strlen(test_cert) + 1; + size_t test_cert_size = certlist_crt_len; struct cert *cert1; struct cert *cert2; @@ -62,7 +62,7 @@ test_certificates(void **state) ret = cert_set("hoge", "broken", 7, &cert1); assert_true(ret == EINVAL); - ret = cert_set("hoge", test_cert, test_cert_size, &cert1); + ret = cert_set("hoge", certificates, test_cert_size, &cert1); assert_true(ret == 0); assert_true(cert_refcnt(cert1) == 2); cert_release(cert1); diff --git a/test_modules/Makefile b/test_modules/Makefile index a11a2386..31570516 100644 --- a/test_modules/Makefile +++ b/test_modules/Makefile @@ -41,6 +41,7 @@ MODULES =\ upload_evp_memory.$(EXT)\ upload_evp_mstp_file.$(EXT)\ upload_http_file.$(EXT)\ + zombie.$(EXT)\ HUB_OBJS =\ hub_scalability_test.$O\ diff --git a/test_modules/messaging.c b/test_modules/messaging.c index 50ab766d..4eafeb31 100644 --- a/test_modules/messaging.c +++ b/test_modules/messaging.c @@ -106,7 +106,9 @@ static void send_message_cb(EVP_MESSAGE_SENT_CALLBACK_REASON reason, void *userData) { static int send_msg; - log_module(module_name, "Send message number %d DONE\n", send_msg); + log_module(module_name, "Sent message number %d DONE. reason %d\n", + send_msg, reason); + assert(reason == EVP_MESSAGE_SENT_CALLBACK_REASON_SENT); send_msg++; struct send_message_cb_data *d = userData; diff --git a/test_modules/zombie.c b/test_modules/zombie.c new file mode 100644 index 00000000..8db92f73 --- /dev/null +++ b/test_modules/zombie.c @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#include "evp/sdk.h" +#include "log.h" + +static const char *module_name = "ZOMBIE"; + +int +main(void) +{ + log_module(module_name, "%s: started!\n", module_name); + struct EVP_client *h = EVP_initialize(); + + for (;;) { + log_module(module_name, "%s: main loop\n", module_name); + EVP_RESULT result; + + result = EVP_processEvent(h, 1000); + log_module(module_name, "EVP_processEvent returned %u\n", + result); + if (result == EVP_SHOULDEXIT) { + log_module(module_name, + "%s: received exit request. But ignoring " + "for 2 min :evil:\n", + module_name); + sleep(120); + break; + } + } + return 0; +} diff --git a/tools/fortify/filter-agent.txt b/tools/fortify/filter-agent.txt index 02ee3623..6952ec65 100644 --- a/tools/fortify/filter-agent.txt +++ b/tools/fortify/filter-agent.txt @@ -759,30 +759,30 @@ D0731D514166A49C8FFB53F1F9FD92A2 # False positive. # namedup is transferred to a compound literal, which is then # transferred to *dst. Otherwise, it is free(3)d. -# [E5BAF7C295BEB651FD2DBB5177CAC5CF : high : Memory Leak : controlflow ] -# -# libevp-agent/stream/stream.c(472) : start -> allocated : namedup = strdup(...) -# libevp-agent/stream/stream.c(472) : allocated -> allocated : namedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(476) : Branch not taken: (namedup != NULL) -# libevp-agent/stream/stream.c(484) : Branch taken: (src->type == 0) -# libevp-agent/stream/stream.c(484) : goto -# libevp-agent/stream/stream.c(530) : allocated -> allocated : namedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(538) : Branch not taken: (ret == 0) -# libevp-agent/stream/stream.c(543) : allocated -> allocated : namedup no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(543) : allocated -> allocated : .name no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(543) : allocated -> leak : end scope : Memory leaked -# -# libevp-agent/stream/stream.c(472) : start -> allocated : namedup = strdup(...) -# libevp-agent/stream/stream.c(472) : allocated -> allocated : namedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(476) : Branch not taken: (namedup != NULL) -# libevp-agent/stream/stream.c(486) : Branch taken: (src->type == 1) -# libevp-agent/stream/stream.c(486) : goto -# libevp-agent/stream/stream.c(491) : Branch taken: (connectiondup == NULL) -# libevp-agent/stream/stream.c(496) : goto -# libevp-agent/stream/stream.c(538) : Branch not taken: (ret == 0) -# libevp-agent/stream/stream.c(543) : allocated -> allocated : namedup no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(543) : allocated -> leak : namedup end scope : Memory leaked -E5BAF7C295BEB651FD2DBB5177CAC5CF +# [ADE750BBDBD6FD8493538AB75049712B : high : Memory Leak : controlflow ] +# +# stream/stream.c(484) : start -> allocated : namedup = strdup(...) +# stream/stream.c(484) : allocated -> allocated : namedup refers to dynamically allocated memory +# stream/stream.c(488) : Branch not taken: (namedup != NULL) +# stream/stream.c(496) : Branch taken: (src->type == 0) +# stream/stream.c(496) : goto +# stream/stream.c(523) : allocated -> allocated : namedup refers to dynamically allocated memory +# stream/stream.c(531) : Branch not taken: (ret == 0) +# stream/stream.c(536) : allocated -> allocated : namedup no longer refers to dynamically allocated memory +# stream/stream.c(536) : allocated -> allocated : .name no longer refers to dynamically allocated memory +# stream/stream.c(536) : allocated -> leak : end scope : Memory leaked +# +# stream/stream.c(484) : start -> allocated : namedup = strdup(...) +# stream/stream.c(484) : allocated -> allocated : namedup refers to dynamically allocated memory +# stream/stream.c(488) : Branch not taken: (namedup != NULL) +# stream/stream.c(498) : Branch taken: (src->type == 1) +# stream/stream.c(498) : goto +# stream/stream.c(503) : Branch taken: (hostnamedup == NULL) +# stream/stream.c(508) : goto +# stream/stream.c(531) : Branch not taken: (ret == 0) +# stream/stream.c(536) : allocated -> allocated : namedup no longer refers to dynamically allocated memory +# stream/stream.c(536) : allocated -> leak : namedup end scope : Memory leaked +ADE750BBDBD6FD8493538AB75049712B # False positive. # list is transferred to *dst if successful. Otherwise, it is free(3)d. @@ -801,29 +801,29 @@ E5BAF7C295BEB651FD2DBB5177CAC5CF # False positive. # Fortify fails to see the ownership for event is transferred to the # TAILQ. It is later freed by sdk_free_event. -# [FAB645EE0389BCEEDFF7466521CF7A24 : high : Memory Leak : controlflow ] -# -# libevp-agent/stream/stream.c(328) : start -> allocated : args = malloc(...) -# libevp-agent/stream/stream.c(328) : allocated -> allocated : args refers to dynamically allocated memory -# libevp-agent/stream/stream.c(329) : Branch not taken: (args != NULL) -# libevp-agent/stream/stream.c(339) : Branch not taken: (event != NULL) -# libevp-agent/stream/stream.c(345) : allocated -> allocated : args refers to dynamically allocated memory -# libevp-agent/stream/stream.c(357) : Branch not taken: (ret == 0) -# libevp-agent/stream/stream.c(361) : allocated -> allocated : args no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(361) : allocated -> allocated : .free_args no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(361) : allocated -> leak : end scope : Memory leaked -FAB645EE0389BCEEDFF7466521CF7A24 - -# False positive. Similar to FAB645EE0389BCEEDFF7466521CF7A24. -# [EC095B6EAD3150351E9E6E34CE065126 : high : Memory Leak : controlflow ] -# -# libevp-agent/stream/stream.c(329) : Branch not taken: (args != NULL) -# libevp-agent/stream/stream.c(338) : start -> allocated : event = malloc(...) -# libevp-agent/stream/stream.c(338) : allocated -> allocated : event refers to dynamically allocated memory -# libevp-agent/stream/stream.c(339) : Branch not taken: (event != NULL) -# libevp-agent/stream/stream.c(361) : allocated -> allocated : event no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(361) : allocated -> leak : event end scope : Memory leaked -EC095B6EAD3150351E9E6E34CE065126 +# [D3F2CC7293422B38A63196E89231D854 : high : Memory Leak : controlflow ] +# +# stream/stream.c(340) : start -> allocated : args = malloc(...) +# stream/stream.c(340) : allocated -> allocated : args refers to dynamically allocated memory +# stream/stream.c(341) : Branch not taken: (args != NULL) +# stream/stream.c(351) : Branch not taken: (event != NULL) +# stream/stream.c(357) : allocated -> allocated : args refers to dynamically allocated memory +# stream/stream.c(369) : Branch not taken: (ret == 0) +# stream/stream.c(373) : allocated -> allocated : args no longer refers to dynamically allocated memory +# stream/stream.c(373) : allocated -> allocated : .free_args no longer refers to dynamically allocated memory +# stream/stream.c(373) : allocated -> leak : end scope : Memory leaked +D3F2CC7293422B38A63196E89231D854 + +# False positive. Similar to D3F2CC7293422B38A63196E89231D854. +# [D2CB91D8DE70456F32CA8103BE32E947 : high : Memory Leak : controlflow ] +# +# stream/stream.c(341) : Branch not taken: (args != NULL) +# stream/stream.c(350) : start -> allocated : event = malloc(...) +# stream/stream.c(350) : allocated -> allocated : event refers to dynamically allocated memory +# stream/stream.c(351) : Branch not taken: (event != NULL) +# stream/stream.c(373) : allocated -> allocated : event no longer refers to dynamically allocated memory +# stream/stream.c(373) : allocated -> leak : event end scope : Memory leaked +D2CB91D8DE70456F32CA8103BE32E947 # False positive. # Fortify fails to see sem is a semaphore that would block until @@ -3174,20 +3174,20 @@ BA0F36F9B53D08073B3E0230D7DE21EB # False positive. # Yet again, Fortify fails to see the ownership for hostnamedup is transferred # to params.posix when the function is succesful. -# [74169ED2AA3FB0795C28912A9E687D77 : high : Memory Leak : controlflow ] -# -# stream/stream.c(477) : Branch not taken: (namedup != NULL) -# stream/stream.c(487) : Branch taken: (src->type == 1) -# stream/stream.c(487) : goto -# stream/stream.c(491) : start -> allocated : hostnamedup = strdup(...) -# stream/stream.c(491) : allocated -> allocated : hostnamedup refers to dynamically allocated memory -# stream/stream.c(492) : Branch not taken: (hostnamedup != NULL) -# stream/stream.c(501) : allocated -> allocated : hostnamedup refers to dynamically allocated memory -# stream/stream.c(505) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory -# stream/stream.c(520) : Branch not taken: (ret == 0) -# stream/stream.c(525) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory -# stream/stream.c(525) : allocated -> leak : hostnamedup end scope : Memory leaked -74169ED2AA3FB0795C28912A9E687D77 +# [86C572DDAE429AC6DBF9403CC30942EB : high : Memory Leak : controlflow ] +# +# stream/stream.c(488) : Branch not taken: (namedup != NULL) +# stream/stream.c(498) : Branch taken: (src->type == 1) +# stream/stream.c(498) : goto +# stream/stream.c(502) : start -> allocated : hostnamedup = strdup(...) +# stream/stream.c(502) : allocated -> allocated : hostnamedup refers to dynamically allocated memory +# stream/stream.c(503) : Branch not taken: (hostnamedup != NULL) +# stream/stream.c(512) : allocated -> allocated : hostnamedup refers to dynamically allocated memory +# stream/stream.c(516) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory +# stream/stream.c(531) : Branch not taken: (ret == 0) +# stream/stream.c(536) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory +# stream/stream.c(536) : allocated -> leak : hostnamedup end scope : Memory leaked +86C572DDAE429AC6DBF9403CC30942EB # Not an issue. # Even if the data type for sr->id is defined as EVP_STREAM_PEER_ID, @@ -3224,14 +3224,14 @@ B4D4885FB1057A4F2A586BA9DFB6B7E6 # __attribute__((__noreturn__)). Therefore, it is impossible that the goto # statement pointed out by Fortify is executed, and thus there is no risk for # a double-free condition. -# [AB82561AD6FCF66BC65E7AFFCCBCC835 : high : Double Free : controlflow ] -# -# libevp-agent/stream/stream.c(394) : Branch taken: __not_first_call -# libevp-agent/stream/stream.c(394) : nofree -> free : free(__cancel_arg) -# libevp-agent/stream/stream.c(394) : free -> free : Pointer __cancel_arg refers to a freed memory allocation -# libevp-agent/stream/stream.c(399) : goto -# libevp-agent/stream/stream.c(404) : free -> doublefree : free(__cancel_arg) : Pointer __cancel_arg freed a second time -AB82561AD6FCF66BC65E7AFFCCBCC835 +# [4BB661EC174DF3BF29E777D9042CDB59 : high : Double Free : controlflow ] +# +# stream/stream.c(406) : Branch taken: __not_first_call +# stream/stream.c(406) : nofree -> free : free(__cancel_arg) +# stream/stream.c(406) : free -> free : Pointer __cancel_arg refers to a freed memory allocation +# stream/stream.c(411) : goto +# stream/stream.c(416) : free -> doublefree : free(__cancel_arg) : Pointer __cancel_arg freed a second time +4BB661EC174DF3BF29E777D9042CDB59 # False positive. Similar to AB82561AD6FCF66BC65E7AFFCCBCC835. # [53786A8C3E915B54DB96ECC8DF3FFCF8 : high : Double Free : controlflow ] diff --git a/tools/fortify/filter-sdk.txt b/tools/fortify/filter-sdk.txt index 6ee618bc..06c270ab 100644 --- a/tools/fortify/filter-sdk.txt +++ b/tools/fortify/filter-sdk.txt @@ -88,41 +88,41 @@ F86380716072F498F0206FB2ADD37348 # False positive. # Yet again, Fortify fails to see the ownership for namedup is transferred # to dst->name only if the function is succesful, and is deallocated otherwise. -# [E5BAF7C295BEB651FD2DBB5177CAC5CF : high : Memory Leak : controlflow ] -# -# libevp-agent/stream/stream.c(472) : start -> allocated : namedup = strdup(...) -# libevp-agent/stream/stream.c(472) : allocated -> allocated : namedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(476) : Branch not taken: (namedup != NULL) -# libevp-agent/stream/stream.c(484) : Branch taken: (src->type == 0) -# libevp-agent/stream/stream.c(484) : goto -# libevp-agent/stream/stream.c(530) : allocated -> allocated : namedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(538) : Branch not taken: (ret == 0) -# libevp-agent/stream/stream.c(543) : allocated -> allocated : namedup no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(543) : allocated -> allocated : .name no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(543) : allocated -> leak : end scope : Memory leaked -# -# libevp-agent/stream/stream.c(472) : start -> allocated : namedup = strdup(...) -# libevp-agent/stream/stream.c(472) : allocated -> allocated : namedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(476) : Branch not taken: (namedup != NULL) -# libevp-agent/stream/stream.c(486) : Branch taken: (src->type == 1) -# libevp-agent/stream/stream.c(486) : goto -# libevp-agent/stream/stream.c(491) : Branch taken: (connectiondup == NULL) +# [ADE750BBDBD6FD8493538AB75049712B : high : Memory Leak : controlflow ] +# +# libevp-agent/stream/stream.c(484) : start -> allocated : namedup = strdup(...) +# libevp-agent/stream/stream.c(484) : allocated -> allocated : namedup refers to dynamically allocated memory +# libevp-agent/stream/stream.c(488) : Branch not taken: (namedup != NULL) +# libevp-agent/stream/stream.c(496) : Branch taken: (src->type == 0) # libevp-agent/stream/stream.c(496) : goto -# libevp-agent/stream/stream.c(538) : Branch not taken: (ret == 0) -# libevp-agent/stream/stream.c(543) : allocated -> allocated : namedup no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(543) : allocated -> leak : namedup end scope : Memory leaked -E5BAF7C295BEB651FD2DBB5177CAC5CF +# libevp-agent/stream/stream.c(523) : allocated -> allocated : namedup refers to dynamically allocated memory +# libevp-agent/stream/stream.c(531) : Branch not taken: (ret == 0) +# libevp-agent/stream/stream.c(536) : allocated -> allocated : namedup no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(536) : allocated -> allocated : .name no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(536) : allocated -> leak : end scope : Memory leaked +# +# libevp-agent/stream/stream.c(484) : start -> allocated : namedup = strdup(...) +# libevp-agent/stream/stream.c(484) : allocated -> allocated : namedup refers to dynamically allocated memory +# libevp-agent/stream/stream.c(488) : Branch not taken: (namedup != NULL) +# libevp-agent/stream/stream.c(498) : Branch taken: (src->type == 1) +# libevp-agent/stream/stream.c(498) : goto +# libevp-agent/stream/stream.c(503) : Branch taken: (hostnamedup == NULL) +# libevp-agent/stream/stream.c(508) : goto +# libevp-agent/stream/stream.c(531) : Branch not taken: (ret == 0) +# libevp-agent/stream/stream.c(536) : allocated -> allocated : namedup no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(536) : allocated -> leak : namedup end scope : Memory leaked +ADE750BBDBD6FD8493538AB75049712B -# False positive. Similar to E5BAF7C295BEB651FD2DBB5177CAC5CF. -# [EC095B6EAD3150351E9E6E34CE065126 : high : Memory Leak : controlflow ] -# -# libevp-agent/stream/stream.c(329) : Branch not taken: (args != NULL) -# libevp-agent/stream/stream.c(338) : start -> allocated : event = malloc(...) -# libevp-agent/stream/stream.c(338) : allocated -> allocated : event refers to dynamically allocated memory -# libevp-agent/stream/stream.c(339) : Branch not taken: (event != NULL) -# libevp-agent/stream/stream.c(361) : allocated -> allocated : event no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(361) : allocated -> leak : event end scope : Memory leaked -EC095B6EAD3150351E9E6E34CE065126 +# False positive. Similar to ADE750BBDBD6FD8493538AB75049712B. +# [D2CB91D8DE70456F32CA8103BE32E947 : high : Memory Leak : controlflow ] +# +# libevp-agent/stream/stream.c(341) : Branch not taken: (args != NULL) +# libevp-agent/stream/stream.c(350) : start -> allocated : event = malloc(...) +# libevp-agent/stream/stream.c(350) : allocated -> allocated : event refers to dynamically allocated memory +# libevp-agent/stream/stream.c(351) : Branch not taken: (event != NULL) +# libevp-agent/stream/stream.c(373) : allocated -> allocated : event no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(373) : allocated -> leak : event end scope : Memory leaked +D2CB91D8DE70456F32CA8103BE32E947 # [6BECED8E31EAFCD29B5E7BC15AAF1FDD : high : Memory Leak : controlflow ] # @@ -304,18 +304,18 @@ FE42DC481FA854957010E17498F565ED # False positive. # Fortify fails to see the ownership for event is transferred to the # TAILQ. It is later freed by sdk_free_event. -# [FAB645EE0389BCEEDFF7466521CF7A24 : high : Memory Leak : controlflow ] -# -# libevp-agent/stream/stream.c(328) : start -> allocated : args = malloc(...) -# libevp-agent/stream/stream.c(328) : allocated -> allocated : args refers to dynamically allocated memory -# libevp-agent/stream/stream.c(329) : Branch not taken: (args != NULL) -# libevp-agent/stream/stream.c(339) : Branch not taken: (event != NULL) -# libevp-agent/stream/stream.c(345) : allocated -> allocated : args refers to dynamically allocated memory -# libevp-agent/stream/stream.c(357) : Branch not taken: (ret == 0) -# libevp-agent/stream/stream.c(361) : allocated -> allocated : args no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(361) : allocated -> allocated : .free_args no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(361) : allocated -> leak : end scope : Memory leaked -FAB645EE0389BCEEDFF7466521CF7A24 +# [D3F2CC7293422B38A63196E89231D854 : high : Memory Leak : controlflow ] +# +# libevp-agent/stream/stream.c(340) : start -> allocated : args = malloc(...) +# libevp-agent/stream/stream.c(340) : allocated -> allocated : args refers to dynamically allocated memory +# libevp-agent/stream/stream.c(341) : Branch not taken: (args != NULL) +# libevp-agent/stream/stream.c(351) : Branch not taken: (event != NULL) +# libevp-agent/stream/stream.c(357) : allocated -> allocated : args refers to dynamically allocated memory +# libevp-agent/stream/stream.c(369) : Branch not taken: (ret == 0) +# libevp-agent/stream/stream.c(373) : allocated -> allocated : args no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(373) : allocated -> allocated : .free_args no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(373) : allocated -> leak : end scope : Memory leaked +D3F2CC7293422B38A63196E89231D854 # False positive. # Yet again, Fortify fails to see the ownership for si is transferred on the @@ -396,20 +396,20 @@ BA0F36F9B53D08073B3E0230D7DE21EB # False positive. # Yet again, Fortify fails to see the ownership for hostnamedup is transferred # to params.posix when the function is succesful. -# [74169ED2AA3FB0795C28912A9E687D77 : high : Memory Leak : controlflow ] -# -# libevp-agent/stream/stream.c(477) : Branch not taken: (namedup != NULL) -# libevp-agent/stream/stream.c(487) : Branch taken: (src->type == 1) -# libevp-agent/stream/stream.c(487) : goto -# libevp-agent/stream/stream.c(491) : start -> allocated : hostnamedup = strdup(...) -# libevp-agent/stream/stream.c(491) : allocated -> allocated : hostnamedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(492) : Branch not taken: (hostnamedup != NULL) -# libevp-agent/stream/stream.c(501) : allocated -> allocated : hostnamedup refers to dynamically allocated memory -# libevp-agent/stream/stream.c(505) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(520) : Branch not taken: (ret == 0) -# libevp-agent/stream/stream.c(525) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory -# libevp-agent/stream/stream.c(525) : allocated -> leak : hostnamedup end scope : Memory leaked -74169ED2AA3FB0795C28912A9E687D77 +# [86C572DDAE429AC6DBF9403CC30942EB : high : Memory Leak : controlflow ] +# +# libevp-agent/stream/stream.c(488) : Branch not taken: (namedup != NULL) +# libevp-agent/stream/stream.c(498) : Branch taken: (src->type == 1) +# libevp-agent/stream/stream.c(498) : goto +# libevp-agent/stream/stream.c(502) : start -> allocated : hostnamedup = strdup(...) +# libevp-agent/stream/stream.c(502) : allocated -> allocated : hostnamedup refers to dynamically allocated memory +# libevp-agent/stream/stream.c(503) : Branch not taken: (hostnamedup != NULL) +# libevp-agent/stream/stream.c(512) : allocated -> allocated : hostnamedup refers to dynamically allocated memory +# libevp-agent/stream/stream.c(516) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(531) : Branch not taken: (ret == 0) +# libevp-agent/stream/stream.c(536) : allocated -> allocated : hostnamedup no longer refers to dynamically allocated memory +# libevp-agent/stream/stream.c(536) : allocated -> leak : hostnamedup end scope : Memory leaked +86C572DDAE429AC6DBF9403CC30942EB # Not an issue. # Even if the data type for sr->id is defined as EVP_STREAM_PEER_ID, @@ -446,14 +446,14 @@ B4D4885FB1057A4F2A586BA9DFB6B7E6 # __attribute__((__noreturn__)). Therefore, it is impossible that the goto # statement pointed out by Fortify is executed, and thus there is no risk for # a double-free condition. -# [AB82561AD6FCF66BC65E7AFFCCBCC835 : high : Double Free : controlflow ] -# -# libevp-agent/stream/stream.c(394) : Branch taken: __not_first_call -# libevp-agent/stream/stream.c(394) : nofree -> free : free(__cancel_arg) -# libevp-agent/stream/stream.c(394) : free -> free : Pointer __cancel_arg refers to a freed memory allocation -# libevp-agent/stream/stream.c(399) : goto -# libevp-agent/stream/stream.c(404) : free -> doublefree : free(__cancel_arg) : Pointer __cancel_arg freed a second time -AB82561AD6FCF66BC65E7AFFCCBCC835 +# [4BB661EC174DF3BF29E777D9042CDB59 : high : Double Free : controlflow ] +# +# libevp-agent/stream/stream.c(406) : Branch taken: __not_first_call +# libevp-agent/stream/stream.c(406) : nofree -> free : free(__cancel_arg) +# libevp-agent/stream/stream.c(406) : free -> free : Pointer __cancel_arg refers to a freed memory allocation +# libevp-agent/stream/stream.c(411) : goto +# libevp-agent/stream/stream.c(416) : free -> doublefree : free(__cancel_arg) : Pointer __cancel_arg freed a second time +4BB661EC174DF3BF29E777D9042CDB59 # False positive. # Yet again, Fortify fails to see the ownership for buf is transferred to