diff --git a/.github/workflows/example-e2e-tests.json b/.github/workflows/example-e2e-tests.json new file mode 100644 index 000000000..40aa5b05a --- /dev/null +++ b/.github/workflows/example-e2e-tests.json @@ -0,0 +1,79 @@ +{ + "projects":[ + { + "project": "Cryptography.csproj", + "tests": [ + { + "name": "Encrypt & Decrypt Small File Stream", + "arguments": "1", + "expected_stdout_output": [ + "== APP == Original file contents:", + "== APP == # The Road Not Taken", + "== APP == ## By Robert Lee Frost", + "== APP == ", + "== APP == Two roads diverged in a yellow wood,", + "== APP == And sorry I could not travel both", + "== APP == And be one traveler, long I stood", + "== APP == And looked down one as far as I could", + "== APP == To where it bent in the undergrowth;", + "== APP == ", + "== APP == Then took the other, as just as fair", + "== APP == And having perhaps the better claim,", + "== APP == Because it was grassy and wanted wear;", + "== APP == Though as for that, the passing there", + "== APP == Had worn them really about the same,", + "== APP == ", + "== APP == And both that morning equally lay", + "== APP == In leaves no step had trodden black", + "== APP == Oh, I kept the first for another day!", + "== APP == Yet knowing how way leads on to way,", + "== APP == I doubted if I should ever come back.", + "== APP == ", + "== APP == I shall be telling this with a sigh", + "== APP == Somewhere ages and ages hence:", + "== APP == Two roads diverged in a wood, and I,", + "== APP == I took the one less traveled by,", + "== APP == And that has made all the difference.", + "== APP == ", + "== APP == Encrypted bytes: ZGFwci5pby9lbmMvdjEKeyJrdyI6NSwid2ZrIjoiVHRRUnNneVkyMDlQZGxaZkNxcW11UC9OQlRra1plajZ2c2tGbG1nN21uSUFtZlZ3R3YxYVhVajlyMGdCb1Q4UWh3SWZJNzNUdVc0WkFjQmlhK2V1QStPelBQQkdYbWpZYmhFQlZLandTTkNRa3l1TFVWZ0d4ZUJwbm03cDA2bHFFUkV6MGpRL0NiNnFPN0ZKc1Z0ZVh6dmF4dDFBK0dtSEVEd0ZLYmtydGZOaU", + "1aeHF2bS85Y0pOTVBpNm9Zcms1eGJkK1kwcmc5bU9vZ1hmL1RidW5IUWRvc3lhSGpzc082U0l3TVUzdVdIMEdIZEFzNU95ZEhCRDdhd0kvSFFXdzEya3c4ZGNOQzd4enFPd0RGSUh1NXc3cmx1aGZmZHZCeVBoWDNwMEdBQzR6eWtvY2dUOWdBcGF0VjV4ekFjRXBGVGdycUxGdXhDSWI1dG9veUZxZ25ESnVYYktLWWxSU2hkclhBeGJnbFVBOVQxVmFMUC9hakhGaEYwTEFwajhYM2dYUXo2RDhhSUE", + "zRlM4VEJPYTUrSDR5cXkyQzk4dzhZMUFFcS9vSzI4dVB3NFROUEttUUxwb0xUeFE3VzRya3drbDRLcy9ZdExXYnRpU2pUSUN1ODNYaXB4T1JsU0w4SmQwQjU0MG14dDlqTDJOZlBJK09QV0l0VzdtWTJVcWh1bGxWWGNoODNscCs0V01OZ2tVRjJraElGRVFlSkhEakpkdTJRZGRGQXdZVDd5S3RPem5MdktYRHFQRXgwMk5mODU3NlpNS0VCb0ZXdDZuU084ZGxXSEFPMCtsbFZEbUZrRnIyRTVUMVpl", + "UlppSGJMd21zanpzNlU5SkoxTENDaUg3VWk4WGNkN1gzZEgzaDV0LzJTWWRCSStWUENiZW42dDFJYlJxVVNMOXc9IiwiY3BoIjoxLCJucCI6Ik9NUTFRcHJHUHc9PSJ9Cnh0YzBGalluaEdRMmo2eXJLVTI3aEtBbTJtTkJaZCtwb1hUZTUwLzRiYW89CkIYDF5TkccFoiifujAE/TTDwaJCj3s1HQv2uaGpvg2+8xUwIgvfBD4C+Qxk6UObPNkGFSgUx+jhQcNt7zaBoAGw+x2bUmNHrxy0HjIk/nPKa", + "LasVRWyoNvNaqAHrn2yaxRzG7TggigJP6IenC1p40CvIZRPnr7RpjxoZrTeD5DKzrYB7IjCNF3PJ7lye3sw7F65/1HzF0nCGjZPZAfZUIItd8Q5jblh2y5RSrdCxZyLIMgsoHKDSSa+G1WHI9V4oYnduHFGt9c+uAsl103+/Q1JrPzZiMtvI1AVYl364CuhflUaqw/SQ4wrpfnjIZNNVhfItFAQcuNUxsQWz4rGyJDLwagLReCyP9dFJWCsUjuNK/9y+c+W2oK0xhmn0EOw7aMGpslsTb2jL+bClJAzme", + "/mVRpM294B97AabFhydlPUGV1ZTmQOo8q1ApuKfzIyG8ucMTYnssTbjW0V6038QTCIPpP97H1BGON3JjYBCtOQNI6FUhEHLfyrBcx0eWZ/QhxB0tywD7d+DWtnSx3Y4OBE7KjvLrEyaOQAlOspk4rhZBpub/g+yjc7T1q+HY+mBR6sHfSuLrFmyMEcOqgxBVaJPD0dWizhB/dTW6cVLVmXWWi9jJglMDF92wUi68c/5spEyNRJRabv1sEq4VJ2OJtRJlCvzWFfqrrw9ZjJSEoaLMqZjiLU9HyXB2VFTLM", + "PrzJFSdZO3ajViWbnrSqNZy/CBTEnKmGsr1E8LRSfXm/PpGrvo0OL3VZC+P8IxuCK43Qug1Qoymkc1K0i6UbzeLvyMuv3J11KKhQCss9+/O8GKqkRCWa/D2TCJ6RiG20+N/bBdv0T6AQK0RcAMj6RQt3WJlnFQ4OtrVTHKNnZCoQZbBid0u0UvccFWAbkm/Tk0IVUbMcEv5pFS64h7ePkbHo5ZEaoobXwpmzXrx6a+P41OkNokIcE28A06RIqMmRUpE4uA9vje+M0xv5fpB64qoUqSW0DXFwDCVDW21O12kl1PJcU4aLdc9FOk7T5cA/PdYLJSjAo6P4J5VEIRv8xakH5X4a8hYz+BWcfH3pdcfZRLnZsU9UGMIcaiLZsB/I=", + "== APP == ", + "== APP == Decrypted value: ", + "== APP == # The Road Not Taken", + "== APP == ## By Robert Lee Frost", + "== APP == ", + "== APP == Two roads diverged in a yellow wood,", + "== APP == And sorry I could not travel both", + "== APP == And be one traveler, long I stood", + "== APP == And looked down one as far as I could", + "== APP == To where it bent in the undergrowth;", + "== APP == ", + "== APP == Then took the other, as just as fair", + "== APP == And having perhaps the better claim,", + "== APP == Because it was grassy and wanted wear;", + "== APP == Though as for that, the passing there", + "== APP == Had worn them really about the same,", + "== APP == ", + "== APP == And both that morning equally lay", + "== APP == In leaves no step had trodden black", + "== APP == Oh, I kept the first for another day!", + "== APP == Yet knowing how way leads on to way,", + "== APP == I doubted if I should ever come back.", + "== APP == ", + "== APP == I shall be telling this with a sigh", + "== APP == Somewhere ages and ages hence:", + "== APP == Two roads diverged in a wood, and I,", + "== APP == I took the one less traveled by,", + "== APP == And that has made all the difference." + ], + "expectation_type": "startswith" + } + ] + } + ] +} \ No newline at end of file diff --git a/.github/workflows/example-tests.yml b/.github/workflows/example-tests.yml new file mode 100644 index 000000000..7de2ecffb --- /dev/null +++ b/.github/workflows/example-tests.yml @@ -0,0 +1,171 @@ +name: example-integration-test + +on: + push: + branches: + - master + - release-* + tags: + - v* + + pull_request: + branches: + - master + - release-* + +jobs: + build-and-test: + name: run example-based integration tests + + strategy: + fail-fast: false + matrix: + os: ['ubuntu-latest'] + dotnet-version: ['8.0'] #, '9.0'] + include: + - dotnet-version: '8.0' + display-name: '.NET 8.0' + framework: 'net8.0' + install-version: '8.0.x' + - dotnet-version: '9.0' + display-name: '.NET 9.0' + framework: 'net9.0' + install-version: '9.0.x' + + runs-on: 'ubuntu-latest' + + env: + NUPKG_OUTDIR: bin/Release/nugets + GOVER: 1.20.0 + GOOS: linux + GOARCH: amd64 + GOPROXY: https://proxy.golang.org + DAPR_CLI_VER: 1.14.0 + DAPR_RUNTIME_VER: 1.14.0 + DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/release-1.14/install/install.sh + DAPR_CLI_REF: '' + steps: + - name: Set up Dapr CLI + run: wget -q ${{ env.DAPR_INSTALL_URL }} -O - | /bin/bash -s ${{ env.DAPR_CLI_VER }} + - name: Checkout Dapr CLI repo to override dapr command. + uses: actions/checkout@v2 + if: env.DAPR_CLI_REF != '' + with: + repository: dapr/cli + ref: ${{ env.DAPR_CLI_REF }} + path: cli + - name: Checkout Dapr repo to override daprd. + uses: actions/checkout@v2 + if: env.DAPR_REF != '' + with: + repository: dapr/dapr + ref: ${{ env.DAPR_REF }} + path: dapr + - name: Set up Go from dapr/go.mod + if: env.DAPR_REF != '' + uses: actions/setup-go@v3 + with: + go-version-file: "dapr/go.mod" + - name: Set up Go from cli/go.mod + if: env.DAPR_REF == '' && env.DAPR_CLI_REF != '' + uses: actions/setup-go@v3 + with: + go-version-file: "cli/go.mod" + - name: Build and override dapr cli with referenced commit. + if: env.DAPR_CLI_REF != '' + run: | + cd cli + make + sudo cp dist/linux_amd64/release/dapr /usr/local/bin/dapr + cd .. + - name: Initialize Dapr runtime ${{ env.DAPR_RUNTIME_VER }} + run: | + dapr uninstall --all + dapr init --runtime-version ${{ env.DAPR_RUNTIME_VER }} + - name: Build and override daprd with referenced commit. + if: env.DAPR_REF != '' + run: | + cd dapr + make + mkdir -p $HOME/.dapr/bin/ + cp dist/linux_amd64/release/daprd $HOME/.dapr/bin/daprd + cd .. + - name: Override placement service. + if: env.DAPR_REF != '' + run: | + docker stop dapr_placement + cd dapr + ./dist/linux_amd64/release/placement & + - uses: actions/checkout@v1 + - name: Parse release version + run: python ./.github/scripts/get_release_version.py + - name: Setup ${{ matrix.display-name }} + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ matrix.install-version }} + dotnet-quality: 'ga' # Prefer a GA release, but use the RC if not available + - name: Check test coverage + run: | + sudo apt-get install jq + # Find all .csproj files in the ./examples directory + all_projects=$(find ./examples -name '*.csproj' -exec basename {} \; | sed 's/.csproj//') + # Get the list of projects from example-e2e-tests.json + tested_projects=$(jq -r '.projects[].project' ./.github/workflows/example-e2e-tests.json | sed 's/.csproj//') + # Compare the lists and find projects without tests + for project in $all_projects; do + if ! echo "$tested_projects" | grep -q "$project"; then + echo "Project $project does not have any tests in example-e2e-tests.json" + fi + done + + - name: Build & test projects + # disable deterministic builds, just for test run. Deterministic builds break coverage for some reason + run: | + # Parse the projects + projects=$(jq -c '.projects[]' ./.github/workflows/example-e2e-tests.json) + echo "Parsed project names:" + echo "$projects" | jq -r '.project' + + # Iterate over the projects + echo "$projects" | while read project; do + project_name=$(echo $project | jq -r '.project') + echo "Project name: $project_name" + + # Find the .csproj file in the ./examples directory + csproj_path=$(find ./examples/ -name $project_name) + echo "csproj path: $csproj_path" + + tests=$(echo $project | jq -c '.tests[]') + echo "$tests" | while read test; do + test_name=$(echo $test | jq -r '.name') + echo "test name: $test_name" + test_arguments=$(echo $test | jq -r '.arguments') + echo "args: $test_arguments" + expectedOutputs=$(echo $test | jq -r '.expected_stdout_output[]') + expectation_type=$(echo $test | jq -r '.expectation_type') + echo "expectation_type: $expectation_type" + + echo "Building and testing $project_name with .NET ${{ matrix.dotnet-version }}" + dotnet build $csproj_path --framework ${{ matrix.framework }} --configuration Release /p:GITHUB_ACTIONS=false + output=$(dotnet run --project $csproj_path --framework ${{ matrix.framework }} -- $test_arguments) + + for expected in $expectedOutputs; do + if [[ "$expectation_type" == "startswith" ]]; then + if [[ "$output" != "$expected"* ]]; then + echo "Test failed for $csproj_path with .NET ${{ matrix.dotnet-version }}: Expected '$expected' not found in output" + exit 1 + fi + elif [[ "$expectation_type" == "equals" ]]; then + if [[ "$output" != "$expected" ]]; then + echo "Test failed for $csproj_path with .NET ${{matrix.dotnet-version }}: Expected '$expected' not found in output" + exit 1 + fi + else + if [[ "$output" != *"$expected"* ]]; then + echo "Test failed for $csproj_path with .NET ${{ matrix.dotnet-version }}: Expected '$expected' not found in output" + exit 1 + fi + fi + done + done + done diff --git a/examples/Client/Cryptography/Cryptography.csproj b/examples/Client/Cryptography/Cryptography.csproj index 525c38562..58ec42b68 100644 --- a/examples/Client/Cryptography/Cryptography.csproj +++ b/examples/Client/Cryptography/Cryptography.csproj @@ -2,7 +2,7 @@ Exe - net6.0 + net6.0;net8.0;net9.0 enable enable latest @@ -16,10 +16,4 @@ - - - PreserveNewest - - - \ No newline at end of file diff --git a/examples/Client/Cryptography/Examples/EncryptDecryptFileStreamExample.cs b/examples/Client/Cryptography/Examples/EncryptDecryptFileStreamExample.cs index 19df06345..bab214150 100644 --- a/examples/Client/Cryptography/Examples/EncryptDecryptFileStreamExample.cs +++ b/examples/Client/Cryptography/Examples/EncryptDecryptFileStreamExample.cs @@ -24,17 +24,17 @@ public override async Task RunAsync(CancellationToken cancellationToken) { using var client = new DaprClientBuilder().Build(); - // The name of the file we're using as an example - const string fileName = "file.txt"; + //Create the small data file + var tempSmallFile = await CreateSmallFileAsync(); Console.WriteLine("Original file contents:"); - foreach (var line in await File.ReadAllLinesAsync(fileName, cancellationToken)) + foreach (var line in await File.ReadAllLinesAsync(tempSmallFile, cancellationToken)) { Console.WriteLine(line); } //Encrypt from a file stream and buffer the resulting bytes to an in-memory buffer - await using var encryptFs = new FileStream(fileName, FileMode.Open); + await using var encryptFs = new FileStream(tempSmallFile, FileMode.Open); var bufferedEncryptedBytes = new ArrayBufferWriter(); await foreach (var bytes in (await client.EncryptAsync(componentName, encryptFs, keyName, @@ -66,8 +66,45 @@ public override async Task RunAsync(CancellationToken cancellationToken) Console.WriteLine("Decrypted value: "); Console.WriteLine(decryptedValue); - //And some cleanup to delete our temp file + //And some cleanup to delete our temp files + File.Delete(tempSmallFile); File.Delete(tempDecryptedFile); } + + private static async Task CreateSmallFileAsync() + { + const string fileData = """ + # The Road Not Taken + ## By Robert Lee Frost + + Two roads diverged in a yellow wood, + And sorry I could not travel both + And be one traveler, long I stood + And looked down one as far as I could + To where it bent in the undergrowth; + + Then took the other, as just as fair + And having perhaps the better claim, + Because it was grassy and wanted wear; + Though as for that, the passing there + Had worn them really about the same, + + And both that morning equally lay + In leaves no step had trodden black + Oh, I kept the first for another day! + Yet knowing how way leads on to way, + I doubted if I should ever come back. + + I shall be telling this with a sigh + Somewhere ages and ages hence: + Two roads diverged in a wood, and I, + I took the one less traveled by, + And that has made all the difference. + """; + + var tempFileName = Path.GetTempFileName(); + await File.WriteAllTextAsync(tempFileName, fileData); + return tempFileName; + } } } diff --git a/examples/Client/Cryptography/Program.cs b/examples/Client/Cryptography/Program.cs index 5c63d7361..763ffc68a 100644 --- a/examples/Client/Cryptography/Program.cs +++ b/examples/Client/Cryptography/Program.cs @@ -45,5 +45,7 @@ static async Task Main(string[] args) Console.WriteLine(); return 1; } + + } } diff --git a/examples/Client/Cryptography/file.txt b/examples/Client/Cryptography/file.txt deleted file mode 100644 index 9e8638939..000000000 --- a/examples/Client/Cryptography/file.txt +++ /dev/null @@ -1,26 +0,0 @@ -# The Road Not Taken -## By Robert Lee Frost - -Two roads diverged in a yellow wood, -And sorry I could not travel both -And be one traveler, long I stood -And looked down one as far as I could -To where it bent in the undergrowth; - -Then took the other, as just as fair -And having perhaps the better claim, -Because it was grassy and wanted wear; -Though as for that, the passing there -Had worn them really about the same, - -And both that morning equally lay -In leaves no step had trodden black -Oh, I kept the first for another day! -Yet knowing how way leads on to way, -I doubted if I should ever come back. - -I shall be telling this with a sigh -Somewhere ages and ages hence: -Two roads diverged in a wood, and I, -I took the one less traveled by, -And that has made all the difference. \ No newline at end of file