【问题标题】:Azure DevOps Hosted Build Controller - Is the Azure Storage Emulator supported?Azure DevOps 托管构建控制器 - 是否支持 Azure 存储模拟器?
【发布时间】:2015-11-15 19:13:03
【问题描述】:

我想运行使用 Azure 存储模拟器而不是来自 Azure DevOps 构建的真实存储的单元/集成测试。

模拟器安装在 Hosted Build Controller 上,作为 Azure SDK 的一部分,位于其通常的位置 (C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\AzureStorageEmulator.exe)。

但是,模拟器在构建控制器上处于未初始化状态。尝试从命令行运行命令Init 时,出现以下错误:

This operation requires an interactive window station

是否有已知的解决方法或计划在 Azure DevOps 构建中支持模拟器?

【问题讨论】:

  • 请注意,除了下面的答案之外,即使 VSTS 托管的构建代理支持交互模式,Azure 存储模拟器仍然由于权限不足而无法工作。见github.com/Microsoft/vso-agent/issues/72

标签: azure azure-devops azure-sdk-.net azure-storage-emulator


【解决方案1】:

尽管所有答案都相反,我已经在 VS2017 托管的构建代理上运行 Azure 存储模拟器一年多了。

诀窍是先初始化 SQL LocalDB(模拟器使用它),然后启动模拟器。您可以使用运行的命令行任务来执行此操作:

sqllocaldb create MSSQLLocalDB
sqllocaldb start MSSQLLocalDB
sqllocaldb info MSSQLLocalDB

"C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator\AzureStorageEmulator.exe" start

【讨论】:

    【解决方案2】:

    如前所述,您无法运行 Azure 存储模拟器。您可以运行的是 Azurite 一个开源替代方案。

    请注意:Azurite 可以模拟 blob、表和队列。但是我只以这种方式使用了 blob 存储仿真。

    在您的构建配置开始时添加一个运行自定义 nuget 命令install Azurite -version 2.2.2 的 nuget 步骤。然后添加一个运行start /b $(Build.SourcesDirectory)\Azurite.2.2.2\tools\blob.exe 的命令行步骤。

    它与 Azure 存储模拟器在同一端口上运行,因此您可以使用标准连接字符串。

    【讨论】:

      【解决方案3】:

      不,Hosted Build Controller 不在交互模式下运行,因此模拟器无法在该环境下运行。详情见Hosted build controller for XAML builds问答。

      问:您需要在交互模式下运行构建服务吗?

      答:不。那么您可以使用托管的构建控制器。

      我建议您设置本地构建控制器并在交互模式下运行构建服务器。详情请参考Setup Build ServerSetup Build Controller

      【讨论】:

        【解决方案4】:

        似乎答案可能来自 Visual Studio Online。如果有人遇到类似问题,可以使用 User Voice 条目。

        不太清楚为什么模拟器没有非交互模式,我个人 99% 的时间都不使用它的 UI。有一个通用的 User Voice 条目可让 Azure 存储更易于单元测试。

        【讨论】:

          【解决方案5】:

          如果您想直接在 C# 中的集成测试代码中启动 Azure 存储模拟器,您可以将其放入您的测试初始化​​(启动)代码中(示例适用于 xUnit):

          [Collection("Database collection")]
          public sealed class IntegrationTests
          {
              public IntegrationTests(DatabaseFixture fixture)
              {
                  this.fixture = fixture;
              }
          
              [Fact]
              public async Task TestMethod1()
              {
                  // use fixture.Table to run tests on the Azure Storage
              }
          
              private readonly DatabaseFixture fixture;
          }
          
          public class DatabaseFixture : IDisposable
          {
              public DatabaseFixture()
              {
                  StartProcess("SqlLocalDB.exe", "create MSSQLLocalDB");
                  StartProcess("SqlLocalDB.exe", "start MSSQLLocalDB");
                  StartProcess("SqlLocalDB.exe", "info MSSQLLocalDB");
                  StartProcess(EXE_PATH, "start");
          
                  var client = CloudStorageAccount.DevelopmentStorageAccount.CreateCloudTableClient();
                  Table = client.GetTableReference("tablename");
                  InitAsync().Wait();
              }
          
              public void Dispose()
              {
                  Table.DeleteIfExistsAsync().Wait();
                  StartProcess(EXE_PATH, "stop");
              }
          
              private async Task InitAsync()
              {
                  await Table.DeleteIfExistsAsync();
                  await Table.CreateAsync();
              }
          
              static void StartProcess(string path, string arguments, int waitTime = WAIT_FOR_EXIT) => 
                  Process.Start(path, arguments).WaitForExit(waitTime);
          
              public CloudTable Table { get; }
          
              private const string EXE_PATH = 
              "C:\\Program Files (x86)\\Microsoft SDKs\\Azure\\Storage Emulator\\AzureStorageEmulator.exe";
              private const int WAIT_FOR_EXIT = 60_000;
          }
          
          [CollectionDefinition("Database collection")]
          public class DatabaseCollection : ICollectionFixture<DatabaseFixture>
          {
              // This class has no code, and is never created. Its purpose is simply
              // to be the place to apply [CollectionDefinition] and all the
              // ICollectionFixture<> interfaces.
          }
          

          【讨论】:

            猜你喜欢
            • 2019-01-15
            • 2018-03-27
            • 2021-06-15
            • 2020-10-01
            • 1970-01-01
            • 2017-05-14
            • 2018-07-13
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多