parameters:
- name: Location
  type: string
  default: ''
- name: ServiceDirectory
  type: string
  default: not-specified
- name: CtestRegex
  type: string
  default: .*
- name: Coverage
  type: string
  default: 'enabled'
- name: CoverageReportPath
  type: string
  default: sdk/*/*/*cov_xml.xml
- name: TimeoutInMinutes
  type: number
  default: 120
- name: DependsOn
  type: string
  default: ''
# Matrix generation:
# https://github.com/Azure/azure-sdk-tools/blob/main/eng/common/scripts/job-matrix/README.md
- name: Matrix
  type: string
- name: MaxParallel
  type: number
  default: 0
- name: CloudConfig
  type: object
  default: {}
- name: UsePlatformContainer
  type: boolean
  default: false
- name: PreTestSteps
  type: stepList
  default: []
- name: PostTestSteps
  type: stepList
  default: []
- name: OSName
  type: string
  default: ''
- name: EnvVars
  type: object
  default: {}
- name: UseFederatedAuth
  type: boolean
  default: true

jobs:
- job:
  displayName: ValidateLive
  dependsOn: ${{ parameters.DependsOn }}
  condition: and(ne(variables['Skip.LiveTest'], 'true'), ne(${{ parameters.Matrix }}, '{}'))
  timeoutInMinutes: ${{ parameters.TimeoutInMinutes }}
  pool:
    name: $(Pool)
    # 1es pipeline templates converts `image` to demands: ImageOverride under the hood
    # which is incompatible with image selection in the default non-1es hosted pools
    ${{ if eq(parameters.OSName, 'macOS') }}:
      vmImage: $(OSVmImage)
    ${{ else }}:
      image: $(OSVmImage)
    os: ${{ parameters.OSName }}


  ${{ if eq(parameters.UsePlatformContainer, 'true') }}:
    # Add a default so the job doesn't fail when the matrix is empty
    container: $[ variables['Container'] ]

  strategy:
    maxParallel: ${{ parameters.MaxParallel }}
    matrix: $[ ${{ parameters.Matrix }} ]

  variables:
    - template: /eng/pipelines/templates/variables/globals.yml@self
    - template: /eng/pipelines/templates/variables/image.yml@self
    - name: CMOCKA_XML_FILE
      value: "%g-test-results.xml"
    - name: CMOCKA_MESSAGE_OUTPUT
      value: "xml"
    - name: BuildArgs
      value: ""
    - name: VcpkgArgs
      value: ""
    - name: WindowsCtestConfig
      value: ""
    - name: CmakeEnvArg
      value: ""
    - name: CmakeArgs
      value: ""
    - name: AZURE_TEST_MODE
      value: "LIVE"
    - name: AZURE_LOG_LEVEL
      value: "verbose"
      # Surface the ServiceDirectory parameter as an environment variable so tests can take advantage of it.
    - name: AZURE_SERVICE_DIRECTORY
      value: ${{ parameters.ServiceDirectory }}

  steps:
  - checkout: self
    submodules: recursive

  - template: /eng/common/pipelines/templates/steps/verify-agent-os.yml
    parameters:
      AgentImage: $(OSVmImage)

  - template: /eng/pipelines/templates/steps/fix-1es-image-apt-azure-sources.yml

  # Add g++5 repo to ubuntu
  - bash: sudo sh -c "echo 'deb http://ftp.debian.org/debian/ stretch main' >> /etc/apt/sources.list"
    displayName: Add g++ 5
    condition: >-
      and(
        succeeded(),
        contains(variables['OSVmImage'], 'Ubuntu'),
        contains(variables['CmakeEnvArg'], 'CC=/usr/bin/gcc-5 CXX=/usr/bin/g++-5 cmake')
      )

  # Install g++5
  - bash: sudo apt-get update & sudo apt-get install g++-5
    displayName: Install g++ 5
    condition: >-
      and(
        succeeded(),
        contains(variables['OSVmImage'], 'Ubuntu'),
        contains(variables['CmakeEnvArg'], 'CC=/usr/bin/gcc-5 CXX=/usr/bin/g++-5 cmake')
      )

  # Install apt dependencies (if appropriate)
  - bash: sudo apt install -y $(AptDependencies)
    retryCountOnTaskFailure: 10
    condition: and(succeededOrFailed(), ne(variables['AptDependencies'], ''))
    displayName: Install dependencies from apt

  - template: /eng/pipelines/templates/steps/vcpkg.yml

  - script: |
      dotnet tool install -g dotnet-reportgenerator-globaltool
      dotnet tool install dotnet-reportgenerator-globaltool --tool-path tools
    displayName: Install coverage tools
    # CODE_COVERAGE variable is '' (do-not-generate) in all matrix but linux-gcc
    # It is 'enabled' by default on linux-gcc but it can be opt-out by each pipeline (disabled)
    condition: and(succeededOrFailed(), ne(variables['CODE_COVERAGE'], 'disabled'), ne(variables['CODE_COVERAGE'], ''))

  - template: /eng/pipelines/templates/steps/cmake-build.yml
    parameters:
      ServiceDirectory: ${{ parameters.ServiceDirectory }}
      GenerateArgs: $(CmakeArgs)
      VcpkgArgs: "$(VcpkgArgs)"
      BuildArgs: "$(BuildArgs)"
      Env: "$(CmakeEnvArg)"

  - template: /eng/pipelines/templates/steps/show-failure-logs.yml

  - template: /eng/common/TestResources/build-test-resource-config.yml
    parameters:
      SubscriptionConfiguration: ${{ parameters.CloudConfig.SubscriptionConfiguration }}
      SubscriptionConfigurations: ${{ parameters.CloudConfig.SubscriptionConfigurations }}
      EnvVars:
        Pool: $(Pool)
        ${{ insert }}: ${{ parameters.EnvVars }}
      ${{ if parameters.UseFederatedAuth }}:
        SubscriptionConfigurationFilePaths: ${{ parameters.CloudConfig.SubscriptionConfigurationFilePaths }}

  - template: /eng/common/TestResources/deploy-test-resources.yml
    parameters:
      ServiceDirectory: ${{ parameters.ServiceDirectory }}
      Location: ${{ coalesce(parameters.Location, parameters.CloudConfig.Location) }}
      SubscriptionConfiguration: $(SubscriptionConfiguration)
      EnvVars:
        Pool: $(Pool)
        ${{ insert }}: ${{ parameters.EnvVars }}
      UseFederatedAuth: ${{ parameters.UseFederatedAuth }}
      ServiceConnection: ${{ parameters.CloudConfig.ServiceConnection }}

  - template: /eng/common/testproxy/test-proxy-tool.yml
    parameters:
      runProxy: false

  - ${{ parameters.PreTestSteps }}

  - ${{ if parameters.UseFederatedAuth }}:
    - task: AzurePowerShell@5
      displayName: ctest
      condition: and(succeeded(), ne(variables['RunSamples'], '1'))
      inputs:
        azureSubscription: ${{ parameters.CloudConfig.ServiceConnection }}
        azurePowerShellVersion: LatestVersion
        ScriptType: InlineScript
        Inline: |
          $account = (Get-AzContext).Account
          $env:AZURESUBSCRIPTION_CLIENT_ID = $account.Id
          $env:AZURESUBSCRIPTION_TENANT_ID = $account.Tenants

          ctest $(WindowsCtestConfig) -V --tests-regex "${{ parameters.CtestRegex }}" --no-compress-output -T Test
          exit $LASTEXITCODE
        workingDirectory: build
      env:
        SYSTEM_ACCESSTOKEN: $(System.AccessToken)
        ${{ insert }}: ${{ parameters.EnvVars }}

  - ${{ else }}:
      # For non multi-config generator use the same build configuration to run tests
      # We don't need to set it to invoke ctest
      # Visual Studio generator used in CI is a multi-config generator.
      # As such, it requires the configuration argument for building and invoking ctest
    - bash: |
        export AZURE_CLIENT_ID=$(${{parameters.ServiceDirectory}}_CLIENT_ID)
        export AZURE_TENANT_ID=$(${{parameters.ServiceDirectory}}_TENANT_ID)
        export AZURE_CLIENT_SECRET=$(${{parameters.ServiceDirectory}}_CLIENT_SECRET)

        ctest $(WindowsCtestConfig) -V --tests-regex "${{ parameters.CtestRegex }}" --no-compress-output -T Test
      workingDirectory: build
      displayName: ctest
      # Runs only if test-resources are happily deployed.
      # unit-tests runs for those configs where samples are not ran.
      # This enables to run tests and samples at the same time as different matrix configuration.
      # Then unit-tests runs, samples should not run.
      condition: and(succeeded(), ne(variables['RunSamples'], '1'))
      env:
        ${{ insert }}: ${{ parameters.EnvVars }}

  - ${{ parameters.PostTestSteps }}

  - task: PublishTestResults@2
    inputs:
      testResultsFormat: cTest
      testResultsFiles: Testing/*/Test.xml
      testRunTitle: $(Agent.JobName)
      searchFolder: build
      mergeTestResults: true
      publishRunAttachments: true
    displayName: Publish test results
    # this step only makes sense when ctest has run
    condition: and(succeededOrFailed(), ne(variables['RunSamples'], '1'))


  - ${{ if parameters.UseFederatedAuth }}:
      # Running Samples step.
      # Will run samples described on a file name [service]-samples.txt within the build directory.
      # For example keyvault-samples.txt.
      # The file is written by CMake during configuration when building samples.
    - task: AzureCLI@2
      displayName: "Run Samples for : ${{ parameters.ServiceDirectory }}"
      condition: and(succeeded(), eq(variables['RunSamples'], '1'))
      inputs:
        azureSubscription: ${{ parameters.CloudConfig.ServiceConnection }}
        scriptType: 'pscore'
        scriptLocation: 'inlineScript'
        inlineScript: |
          if (Test-Path -Path "${{ parameters.ServiceDirectory }}-samples.txt") {
            $samples = Get-Content "${{ parameters.ServiceDirectory }}-samples.txt"
            foreach ($sample in $samples) {
              Write-Host "**********Running sample: $sample"
              & "$sample"
              if ($LASTEXITCODE) {
                Write-Host "Sample failed with exit code $LASTEXITCODE"
                exit 1
              }
              Write-Host "**********Sample completed"
            }
          }
        workingDirectory: build
        useGlobalConfig: true
      env:
        ${{ insert }}: ${{ parameters.EnvVars }}

  - ${{ else }}:
    - bash: |
        IFS=$'\n'
        if [[ -f "./${{ parameters.ServiceDirectory }}-samples.txt" ]]; then
          for sample in `cat ./${{ parameters.ServiceDirectory }}-samples.txt`
          do
            export AZURE_CLIENT_ID=$(${{parameters.ServiceDirectory}}_CLIENT_ID)
            export AZURE_TENANT_ID=$(${{parameters.ServiceDirectory}}_TENANT_ID)
            export AZURE_CLIENT_SECRET=$(${{parameters.ServiceDirectory}}_CLIENT_SECRET)
            echo "**********Running sample: ${sample}"
            bash -c "$sample"
            status=$?
            if [[ $status -eq 0 ]]; then
              echo "*********Sample completed*********"
            else
              echo "*Sample returned a failed code: $status"
              exit 1
            fi
          done
        fi
      workingDirectory: build
      displayName: "Run Samples for : ${{ parameters.ServiceDirectory }}"
      condition: and(succeeded(), eq(variables['RunSamples'], '1'))
      env:
        ${{ insert }}: ${{ parameters.EnvVars }}      

  # Make coverage targets (specified in coverage_targets.txt) and assemble
  # coverage report
  - bash: |
      make `cat ${{ parameters.ServiceDirectory }}-targets-coverage.txt`
      ../tools/reportgenerator "-reports:${{ parameters.CoverageReportPath }}" "-targetdir:." "-reporttypes:Cobertura"
    workingDirectory: build
    displayName: Generate Code Coverage Data
    condition: and(succeeded(), ne(variables['CODE_COVERAGE'], 'disabled'), ne(variables['CODE_COVERAGE'], ''))

  - task: PublishCodeCoverageResults@1
    inputs:
      codeCoverageTool: Cobertura
      summaryFileLocation: '$(Build.SourcesDirectory)/**/Cobertura.xml'
    displayName: Publish Code Coverage to DevOps
    condition: and(succeededOrFailed(), ne(variables['CODE_COVERAGE'], 'disabled'), ne(variables['CODE_COVERAGE'], ''))

  - template: /eng/common/TestResources/remove-test-resources.yml
    parameters:
      ServiceDirectory: ${{ parameters.ServiceDirectory }}
      SubscriptionConfiguration: $(SubscriptionConfiguration)
      UseFederatedAuth: ${{ parameters.UseFederatedAuth }}
      EnvVars: ${{ parameters.EnvVars }}
      ServiceConnection: ${{ parameters.CloudConfig.ServiceConnection }}
