From b15d643ede43c63270e5f3f7590bec2b58c78935 Mon Sep 17 00:00:00 2001 From: "Marcelo C." Date: Fri, 23 May 2025 15:15:43 -0300 Subject: [PATCH] Add Cloudstack CI --- .github/workflows/backendtests.yml | 65 ++++++++++++++++++- .../CloudStack/CloudStackTests.cs | 58 +++++++++++++++++ 2 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 LiveTests/Duplicati.Backend.Tests/CloudStack/CloudStackTests.cs diff --git a/.github/workflows/backendtests.yml b/.github/workflows/backendtests.yml index 776f149c8..3b4cad84e 100644 --- a/.github/workflows/backendtests.yml +++ b/.github/workflows/backendtests.yml @@ -19,6 +19,7 @@ jobs: filejump_secrets_available: "${{ steps.check_filejump.outputs.available }}" onedrive_secrets_available: "${{ steps.check_onedrive.outputs.available }}" idrivee2_secrets_available: "${{ steps.check_idrivee2.outputs.available }}" + cloudstack_secrets_available: "${{ steps.check_cloudstack.outputs.available }}" steps: - id: check_pcloud name: Check pCloud secrets @@ -198,7 +199,25 @@ jobs: echo "available=false" >> $GITHUB_OUTPUT fi echo "iDrivee2 check completed" - + - id: check_cloudstack + name: Check CloudStack secrets + shell: bash + run: | + echo "Starting CloudStack secrets check..." + if [[ -n "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_USERNAME }}" ]] && \ + [[ -n "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_PASSWORD }}" ]] && \ + [[ -n "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_LOCATION }}" ]] && \ + [[ -n "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_TENANT }}" ]] && \ + [[ -n "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_DOMAIN }}" ]] && \ + [[ -n "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_REGION }}" ]] && \ + [[ -n "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_FOLDER }}" ]]; then + echo "All CloudStack secrets found" + echo "available=true" >> $GITHUB_OUTPUT + else + echo "Missing some CloudStack secrets" + echo "available=false" >> $GITHUB_OUTPUT + fi + echo "CloudStack check completed" - name: Debug Output shell: bash run: | @@ -214,6 +233,7 @@ jobs: echo "Filejump Available: ${{ steps.check_filejump.outputs.available }}" echo "OneDrive Available: ${{ steps.check_onedrive.outputs.available }}" echo "iDrivee2 Available: ${{ steps.check_idrivee2.outputs.available }}" + echo "CloudStack Available: ${{ steps.check_cloudstack.outputs.available }}" test_ftp: needs: check_secrets if: needs.check_secrets.outputs.testcontainers_secrets_available == 'true' @@ -763,7 +783,7 @@ jobs: run: >- dotnet build --no-restore LiveTests/Duplicati.Backend.Tests/Duplicati.Backend.Tests.sln - - name: Run OneDrive tests + - name: Run iDrivee2 tests env: TESTCREDENTIAL_IDRIVEE2_BUCKET: "${{ secrets.TESTCREDENTIAL_IDRIVEE2_BUCKET }}" TESTCREDENTIAL_IDRIVEE2_ACCESS_KEY: "${{ secrets.TESTCREDENTIAL_IDRIVEE2_ACCESS_KEY }}" @@ -774,3 +794,44 @@ jobs: dotnet test --no-build --filter="ClassName~iDrivee2.iDrivee2Tests" --logger:"console;verbosity=detailed" LiveTests/Duplicati.Backend.Tests/Duplicati.Backend.Tests.sln + test_cloudstack: + needs: check_secrets + if: needs.check_secrets.outputs.cloudstack_secrets_available == 'true' + name: CloudStack Tests + runs-on: "${{ matrix.os }}" + strategy: + max-parallel: 1 + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + - macos-latest + steps: + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.x + - name: Checkout source + uses: actions/checkout@v4 + - name: Restore NuGet dependencies + run: >- + dotnet restore + LiveTests/Duplicati.Backend.Tests/Duplicati.Backend.Tests.sln + - name: Build project + run: >- + dotnet build --no-restore + LiveTests/Duplicati.Backend.Tests/Duplicati.Backend.Tests.sln + - name: Run CloudStack tests + env: + TESTCREDENTIAL_CLOUDSTACK_USERNAME: "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_USERNAME }}" + TESTCREDENTIAL_CLOUDSTACK_PASSWORD: "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_PASSWORD }}" + TESTCREDENTIAL_CLOUDSTACK_LOCATION: "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_LOCATION }}" + TESTCREDENTIAL_CLOUDSTACK_TENANT: "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_TENANT }}" + TESTCREDENTIAL_CLOUDSTACK_DOMAIN: "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_DOMAIN }}" + TESTCREDENTIAL_CLOUDSTACK_REGION: "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_REGION }}" + TESTCREDENTIAL_CLOUDSTACK_FOLDER: "${{ secrets.TESTCREDENTIAL_CLOUDSTACK_FOLDER }}" + run: >- + dotnet test --no-build --filter="ClassName~CloudStack.CloudStackTests" + --logger:"console;verbosity=detailed" + LiveTests/Duplicati.Backend.Tests/Duplicati.Backend.Tests.sln diff --git a/LiveTests/Duplicati.Backend.Tests/CloudStack/CloudStackTests.cs b/LiveTests/Duplicati.Backend.Tests/CloudStack/CloudStackTests.cs new file mode 100644 index 000000000..961497677 --- /dev/null +++ b/LiveTests/Duplicati.Backend.Tests/CloudStack/CloudStackTests.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2025, The Duplicati Team +// https://duplicati.com, hello@duplicati.com +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +namespace Duplicati.Backend.Tests.CloudStack; + +/// +/// OneDrive Tests +/// +[TestClass] +public sealed class CloudStackTests : BaseTest +{ + [TestMethod] + public Task TestCloudStack() + { + CheckRequiredEnvironment( + ["TESTCREDENTIAL_CLOUDSTACK_USERNAME", + "TESTCREDENTIAL_CLOUDSTACK_PASSWORD", + "TESTCREDENTIAL_CLOUDSTACK_LOCATION", + "TESTCREDENTIAL_CLOUDSTACK_TENANT", + "TESTCREDENTIAL_CLOUDSTACK_DOMAIN", + "TESTCREDENTIAL_CLOUDSTACK_REGION", + "TESTCREDENTIAL_CLOUDSTACK_FOLDER"]); + var exitCode = CommandLine.BackendTester.Program.Main( + new[] + { + $"openstack://{Environment.GetEnvironmentVariable("TESTCREDENTIAL_CLOUDSTACK_FOLDER")}" + + $"?openstack-domain-name={Uri.EscapeDataString(Environment.GetEnvironmentVariable("TESTCREDENTIAL_IDRIVEE2_ACCESS_KEY")!)}" + + $"&openstack-authuri={Uri.EscapeDataString(Environment.GetEnvironmentVariable("TESTCREDENTIAL_CLOUDSTACK_LOCATION")!)}" + + $"&openstack-version=v3" + + $"&openstack-tenant-name={Uri.EscapeDataString(Environment.GetEnvironmentVariable("TESTCREDENTIAL_CLOUDSTACK_TENANT")!)}" + + $"&openstack-region={Uri.EscapeDataString(Environment.GetEnvironmentVariable("TESTCREDENTIAL_CLOUDSTACK_REGION")!)}" + + $"&auth-username={Uri.EscapeDataString(Environment.GetEnvironmentVariable("TESTCREDENTIAL_CLOUDSTACK_USERNAME")!)}" + + $"&auth-password={Uri.EscapeDataString(Environment.GetEnvironmentVariable("TESTCREDENTIAL_CLOUDSTACK_PASSWORD")!)}" + }.Concat(Parameters.GlobalTestParameters).ToArray()); + + if (exitCode != 0) Assert.Fail("BackendTester is returning non-zero exit code, check logs for details"); + + return Task.CompletedTask; + } +} \ No newline at end of file