【问题标题】:Azure pipeline hosted agent connection to Azure SQL database in unit testing of the databaseAzure 管道托管代理在数据库单元测试中连接到 Azure SQL 数据库
【发布时间】:2022-11-28 21:11:18
【问题描述】:

我正在使用 Azure Pipelines 将数据库部署到 Azure SQL Server。部署工作得很好。所以我添加了一个临时数据库的创建和部署(一个在管道末端被删除的数据库)用于我的 USP 的单元测试。

我用 SSDT 创建了一个单元测试 .dll。我配置了 app.config 并在笔记本电脑上的 Visual Studio 中对其进行了测试。在我的笔记本电脑上它可以工作,单元测试全部通过。

我尝试使用 SSMS 中 app.config 的凭据连接到服务器。连接已建立。

但是,我无法让管道(或托管代理)任务从管道内连接到数据库。

我尝试将代理的 IP 添加到服务器白名单中。我检查了“允许 azure 服务访问数据库”。这些都没有解决问题。

我得到的错误是这样的:

初始化方法 BuilEnDeployTest_Unittest.SqlServerUnitTest001.TestInitialize 抛出 例外。系统.Data.SqlClient.SqlException: System.Data.SqlClient.SqlException:传输级错误 从服务器接收结果时发生。 (提供者:TCP 提供商,错误:0 - 现有连接被强行关闭 远程主机。) ---> System.ComponentModel.Win32Exception: 一个现有的 连接被远程主机强行关闭。

管道 yml:

trigger:
- test

name: $(TeamProject)_$(Date:yyyyMMdd)$(Rev:_r)

variables:
- group: "DatabaseDeploy"
- name:  databaseName
  value: sqldb-AzureDevOps_$(Build.BuildNumber)
#- name: ExecutionContext.__Database__
#  value: $(variables.databaseName)

stages:

### Building the code in the Pull-Request

- stage: Build
  displayName: Build the project

  jobs:
  - job: Build
    displayName: Build DB project
    pool:
      vmImage: windows-latest

    steps:


    - script: echo '$(Build.BuildNumber)'
      displayName: BuildName

    #- powershell: 
    #    Get-ChildItem -Path $(Agent.WorkFolder)\1\s\BuilEnDeployTest_Unittest -recurse
    #  displayName: Folder structure

    #- script: echo '$(Agent.WorkFolder)\1\s\BuilEnDeployTest_Unittest\app.config'
    #  displayName: app.config

    - powershell: 
         Get-Content -path $(Agent.WorkFolder)/1/s/BuilEnDeployTest_Unittest/app.config
      displayName: app.config

    - powershell: >
         (Get-Content -path $(Agent.WorkFolder)/1/s/BuilEnDeployTest_Unittest/app.config -Raw) 
         -replace 'MyDatabase', '$(databaseName)' 
         -replace 'MyServer', '$(ServerName_unittst).database.windows.net'
         -replace 'MyUser', '$(DatabaseUser_unittst)'
         -replace 'MyPassword', '$(DatabasePassword_unittst)'| Set-Content -Force -Path $(Agent.WorkFolder)/1/s/BuilEnDeployTest_Unittest/app.config

    - powershell: 
         Get-Content -path $(Agent.WorkFolder)/1/s/BuilEnDeployTest_Unittest/app.config
      displayName: app.config
    
    - task: VSBuild@1
      displayName: Building the database project
      inputs:
        solution: '**\*.sln'

    - task: CopyFiles@2
      displayName: Copy Build Artifacts
      inputs:
        SourceFolder: '$(agent.builddirectory)\s'
        Contents: '**'
        TargetFolder: '$(build.artifactstagingdirectory)'

         
        
   ### In the commands below, 'pipeline' is used instead of 'Container', allthough
   ### 'Container' is often seen in the online documentation. 
   ### I have noticed that changing 'pipeline' to 'Container' breaks my code
   ### I haven't spend time in figuring out why. It could be because of the path I use 
   ### down the line. 

    - task: PublishPipelineArtifact@1
      displayName: Publish Build Artifacts
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'database'
        publishLocation: 'pipeline'

#### Unit testing the Pull-Request

- stage: Unit_testing
  displayName: Database UnitTest
  condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))


  jobs:
  - job: Deploy_to_temporary_database
    displayName: Deploy to temporary database
    pool:
      vmImage: windows-latest

 

    steps:

    ############ Create the Azure Resources as defined in the AzureSQLARMTemplate.json

    ## When the Azure SQL server does not exist it is also created by the ARM deployment.
    
    ## NOTE: I experienced errors when deleting and recreating the Azure SQL server. This could be 
    ## because of the little time between deletion and creation. 
    ## Deployment through the ARM template can deal with an existing server. In that case
    ## the server creation is skipped. So best to not delete the Azure SQL server untill the project
    ## is abandoned. 

    - task: AzurePowerShell@5
      displayName: 'Create unittest DB'
      inputs:
        azureSubscription: $(connectedServiceNameARM)
        ScriptType: 'FilePath'
        ScriptPath: './ARMtemplate/CreateAzureSQLAndDB.ps1'
        ScriptArguments: -azuresqlserverName $(ServerName_unittst) -sqlserverAdminLogin $(DatabaseUser_unittst) -sqlserverAdminPassword $(DatabasePassword_unittst) -databaseName $(databaseName) -Location 'northeurope' -ResourceGroupName 'rg-temp' -TemplateFile ARMtemplate\AzureSQLARMTemplate.json
        azurePowerShellVersion: 'LatestVersion'





    ############ Download the build artifacts from the build stage

    - task: DownloadPipelineArtifact@2
      displayName: 'Download artifacts'
      inputs: 
        buildType: 'current'
        artifactName: 'database'
        targetPath: '$(Pipeline.Workspace)/database'

    - powershell: 
        Get-ChildItem -Path $(Pipeline.Workspace)/database -recurse
      displayName: Folder structure

    - powershell: 
         Get-Content -path $(Pipeline.Workspace)/database/a/BuilEnDeployTest_Unittest/bin/Debug/BuilEnDeployTest_Unittest.dll.config
      displayName: BuilEnDeployTest_Unittest.dll.config

    ############ Deploy the database dacpac file to the newly created database

    - task: SqlAzureDacpacDeployment@1
      displayName: 'Deploy unittest DB'
      inputs:
        connectedServiceNameARM: $(connectedServiceNameARM)
        ServerName: $(ServerName_unittst).database.windows.net
        DatabaseName: $(databaseName)
        SqlUsername: $(DatabaseUser_unittst)
        SqlPassword: $(DatabasePassword_unittst)
        DacpacFile: $(Pipeline.Workspace)/database/a/$(dacpacfile_location)
        PublishProfile: $(Pipeline.Workspace)/database/a/$(publishprofile_location)

    ## Create a firewall rule for the IP adress of the build agent

    - task: AzurePowerShell@5
      displayName: 'Add buildserver public ip'
      inputs:
        azureSubscription: $(connectedServiceNameARM)
        ScriptType: InlineScript
        Inline: |
          $ip = (Invoke-WebRequest -uri "http://ifconfig.me/ip").Content
          $AzureSQLFirewallRule = Get-AzSqlServerFirewallRule -ResourceGroupName 'rg-temp' -ServerName $(ServerName_unittst) -FirewallRuleName "azuredevops"
          if ($AzureSQLFirewallRule -eq $null) {New-AzSqlServerFirewallRule -ResourceGroupName 'rg-temp' -ServerName $(ServerName_unittst) -FirewallRuleName "azuredevops" -StartIpAddress $ip -EndIpAddress $ip}
        azurePowerShellVersion: 'LatestVersion'     

    ############ Run the unittest

    - task: VSTest@2
      inputs:
        testAssemblyVer2: $(Pipeline.Workspace)/database/a/$(Unittestdll_location)
        testConfiguration: 'Debug'
        runOnlyImpactedTests: true
        runInParallel: false

    ############ Delete the newly created database
         
    - task: AzurePowerShell@5
      displayName: 'Delete unittest DB'
      inputs:
        azureSubscription: $(connectedServiceNameARM)
        ScriptType: 'FilePath'
        ScriptPath: './ARMtemplate/CleanupAzureSQLAndDB.ps1'
        ScriptArguments: -azuresqlserverName $(ServerName_unittst) -databaseName $(databaseName) -ResourceGroupName 'rg-temp'
        azurePowerShellVersion: 'LatestVersion'

     ## Delete a firewall rule for the IP adress of the build agent

    - task: AzurePowerShell@5
      displayName: 'remove buildserver public ip'
      inputs:
        azureSubscription: $(connectedServiceNameARM)
        ScriptType: InlineScript
        Inline: |
          $ip = (Invoke-WebRequest -uri "http://ifconfig.me/ip").Content
          Remove-AzSqlServerFirewallRule -ResourceGroupName 'rg-temp' -ServerName $(ServerName_unittst) -FirewallRuleName "azuredevops"
        azurePowerShellVersion: 'LatestVersion'


## Deploying the merged result to the database

- stage: Deploy_to_tst
  displayName: Deploy
  condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))

  jobs:
  - job: Deploy
    displayName: Deploy
    pool:
      vmImage: windows-latest
  
    steps:
    - task: DownloadPipelineArtifact@2
      inputs: 
        buildType: 'current'
        artifactName: 'database'
        targetPath: '$(Pipeline.Workspace)/database'

    - powershell: 
        #Get-ChildItem -Path $(Pipeline.Workspace)/database -recurse
        #Get-ChildItem -Path $(Agent.Workspace) -recurse

    - task: SqlAzureDacpacDeployment@1
      displayName: 'Deploying the database to Azure'
      inputs:
        connectedServiceNameARM: $(connectedServiceNameARM)
        ServerName: $(Server_tst)
        DatabaseName: $(DatabaseName_tst)
        SqlUsername: $(DatabaseUser_tst)
        SqlPassword: $(DatabasePassword_tst)
        DacpacFile: $(Pipeline.Workspace)/database/a/$(dacpacfile_location)
        PublishProfile: $(Pipeline.Workspace)/database/a/$(publishprofile_location)

【问题讨论】:

    标签: azure unit-testing azure-devops azure-pipelines azure-sql-server


    【解决方案1】:

    对于托管代理,检查您是否可以使用管理员用户名和密码创建本地数据库。您稍后可以使用这些凭据连接到数据库。 正常方法通常只是测试您的 sql 项目是否可部署。您创建本地数据库并对其进行核对。

    对于单元测试,您始终可以在运行测试用例的发布管道中保留一个开发人员数据库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-02
      • 1970-01-01
      • 2020-01-08
      • 2020-12-14
      • 2022-01-07
      • 2017-07-02
      • 2021-06-10
      • 2021-12-23
      相关资源
      最近更新 更多