├── .editorconfig ├── .gitattributes ├── .gitignore ├── Automation.StorageEmulator.sln ├── LICENSE.txt ├── NuGet.config ├── README.md ├── appveyor.yml ├── build.cmd ├── src └── Core │ ├── AzureStorageEmulatorAutomation.cs │ ├── Core.csproj │ └── ProcessHelper.cs └── tests └── Core.Tests ├── AzureStorageEmulatorAutomationTests.cs ├── Core.Tests.csproj ├── StopAzureStorageEmulatorFixture.cs └── TestHelper.cs /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | # Get the Visual Studio extension: http://visualstudiogallery.msdn.microsoft.com/c8bccfe2-650c-4b42-bc5c-845e21f96328 3 | 4 | # Top-most EditorConfig file 5 | root = true 6 | 7 | # Unix-style newlines with a newline ending every file 8 | [*] 9 | insert_final_newline = true 10 | 11 | [*.bat] 12 | end_of_line = crlf 13 | 14 | [*.cmd] 15 | end_of_line = crlf 16 | 17 | [*.cs] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # Visual Studio will trim newlines from the end of a file 22 | [*.csproj] 23 | end_of_line = crlf 24 | insert_final_newline = false 25 | 26 | [*.sln] 27 | end_of_line = crlf 28 | insert_final_newline = false 29 | 30 | [*.sql] 31 | end_of_line = crlf 32 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.bat text=auto eol=crlf 4 | *.cmd text=auto eol=crlf 5 | *.config text=auto 6 | *.cs text=auto diff=csharp 7 | *.cshtml text=auto 8 | *.css text=auto 9 | *.htm text=auto 10 | *.html text=auto 11 | *.js text=auto 12 | *.msbuild text=auto 13 | *.resx text=auto 14 | *.props text=auto 15 | *.pubxml text=auto 16 | *.ruleset text=auto 17 | *.StyleCop text=auto 18 | *.sql text=auto eol=crlf 19 | *.svg text=auto 20 | *.txt text=auto 21 | *.xml text=auto 22 | *.targets text=auto 23 | 24 | *.proj text=auto merge=union 25 | *.csproj text=auto merge=union eol=crlf 26 | *.vbproj text=auto merge=union eol=crlf 27 | *.fsproj text=auto merge=union eol=crlf 28 | *.dbproj text=auto merge=union eol=crlf 29 | *.sln text=auto merge=union eol=crlf 30 | 31 | *.jpg binary 32 | *.png binary 33 | *.gif binary 34 | *.ico binary 35 | *.otf binary 36 | *.eot binary 37 | *.ttf binary 38 | *.woff binary 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and files generated by 2 | ## popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | .vs/ 9 | 10 | # Build results 11 | [Dd]ebug/ 12 | [Dd]ebugPublic/ 13 | [Rr]elease/ 14 | [Rr]eleases/ 15 | x64/ 16 | bld/ 17 | [Bb]in/ 18 | [Oo]bj/ 19 | App_Data/ 20 | artifacts/ 21 | 22 | # Roslyn cache directories 23 | *.ide/ 24 | 25 | # MSTest test Results 26 | [Tt]est[Rr]esult*/ 27 | [Bb]uild[Ll]og.* 28 | 29 | #NUNIT 30 | *.VisualState.xml 31 | TestResult.xml 32 | 33 | # Build Results of an ATL Project 34 | [Dd]ebugPS/ 35 | [Rr]eleasePS/ 36 | dlldata.c 37 | 38 | *_i.c 39 | *_p.c 40 | *_i.h 41 | *.ilk 42 | *.meta 43 | *.obj 44 | *.pch 45 | *.pdb 46 | *.pgc 47 | *.pgd 48 | *.rsp 49 | *.sbr 50 | *.tlb 51 | *.tli 52 | *.tlh 53 | *.tmp 54 | *.tmp_proj 55 | *.log 56 | *.vspscc 57 | *.vssscc 58 | .builds 59 | *.pidb 60 | *.svclog 61 | *.scc 62 | *.exe 63 | *.dll 64 | *.pdb 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | 133 | # NuGet Packages 134 | .nuget/ 135 | packages/* 136 | *.nupkg 137 | 138 | # Windows Azure Build Output 139 | csx/ 140 | *.build.csdef 141 | 142 | # Windows Store app package directory 143 | AppPackages/ 144 | 145 | # Others 146 | sql/ 147 | *.Cache 148 | ClientBin/ 149 | [Ss]tyle[Cc]op.* 150 | ~$* 151 | *~ 152 | *.dbmdl 153 | *.dbproj.schemaview 154 | *.pfx 155 | *.publishsettings 156 | node_modules/ 157 | 158 | # RIA/Silverlight projects 159 | Generated_Code/ 160 | 161 | # Backup & report files from converting an old project file 162 | # to a newer Visual Studio version. Backup files are not needed, 163 | # because we have git ;-) 164 | _UpgradeReport_Files/ 165 | Backup*/ 166 | UpgradeLog*.XML 167 | UpgradeLog*.htm 168 | 169 | # SQL Server files 170 | *.mdf 171 | *.ldf 172 | 173 | # Business Intelligence projects 174 | *.rdl.data 175 | *.bim.layout 176 | *.bim_*.settings 177 | 178 | # Microsoft Fakes 179 | FakesAssemblies/ 180 | 181 | # NCrunch 182 | _NCrunch_* 183 | .*crunch*.local.xml 184 | *.ncrunchsolution 185 | *.ncrunchproject 186 | -------------------------------------------------------------------------------- /Automation.StorageEmulator.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.28010.2046 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C552E461-996F-4741-B1C8-52F01A698D91}" 6 | EndProject 7 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{B7C6D934-CE8C-434E-8778-7BA96C2F56F8}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Tests", "tests\Core.Tests\Core.Tests.csproj", "{37AF5A2D-467B-4FA2-AFBE-53AB652737FA}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Any CPU = Debug|Any CPU 14 | Release|Any CPU = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {B7C6D934-CE8C-434E-8778-7BA96C2F56F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {B7C6D934-CE8C-434E-8778-7BA96C2F56F8}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {B7C6D934-CE8C-434E-8778-7BA96C2F56F8}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {B7C6D934-CE8C-434E-8778-7BA96C2F56F8}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {37AF5A2D-467B-4FA2-AFBE-53AB652737FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {37AF5A2D-467B-4FA2-AFBE-53AB652737FA}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {37AF5A2D-467B-4FA2-AFBE-53AB652737FA}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {37AF5A2D-467B-4FA2-AFBE-53AB652737FA}.Release|Any CPU.Build.0 = Release|Any CPU 25 | EndGlobalSection 26 | GlobalSection(SolutionProperties) = preSolution 27 | HideSolutionNode = FALSE 28 | EndGlobalSection 29 | GlobalSection(NestedProjects) = preSolution 30 | {37AF5A2D-467B-4FA2-AFBE-53AB652737FA} = {C552E461-996F-4741-B1C8-52F01A698D91} 31 | EndGlobalSection 32 | GlobalSection(ExtensibilityGlobals) = postSolution 33 | SolutionGuid = {BB641CA7-132B-42E4-A209-62CF5E380C0B} 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ritter Insurance Marketing, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automation : Windows Azure Storage Emulator 2 | 3 | This library enables programmatic control of the Windows Azure Storage Emulator from .NET. This can be useful during integration testing, or anytime you need to work with the Windows Azure Storage Emulator from .NET code. 4 | 5 | ![NuGet Version](https://img.shields.io/nuget/v/RimDev.Automation.StorageEmulator.svg) 6 | ![NuGet Download Count](https://img.shields.io/nuget/dt/RimDev.Automation.StorageEmulator.svg) 7 | 8 | ## Prerequisites 9 | 10 | - .NET Framework 4.5.2 or .Net Standard 2.0 11 | - Windows Azure Storage Emulator installed 12 | - It's been tested with Windows Azure Storage Emulator 4.1.0.0 locally by @kendaleiv and the build passes with Windows Azure Storage Emulator 3.3.0.0 on a build agent -- it may work with other versions, or, it may not. 13 | 14 | ## Installation 15 | 16 | Install the [RimDev.Automation.StorageEmulator](https://www.nuget.org/packages/RimDev.Automation.StorageEmulator/) package from NuGet: 17 | 18 | ``` 19 | PM> Install-Package RimDev.Automation.StorageEmulator 20 | ``` 21 | 22 | ## Quick Start (C#) 23 | 24 | To start the Windows Azure Storage Emulator: 25 | 26 | ```csharp 27 | new AzureStorageEmulatorAutomation().Start(); 28 | ``` 29 | 30 | You can also do some other things, like: 31 | 32 | ```csharp 33 | var automation = new AzureStorageEmulatorAutomation(); 34 | 35 | automation.Start(); 36 | 37 | AzureStorageEmulatorAutomation.IsEmulatorRunning(); // should be true 38 | 39 | automation.ClearAll(); 40 | 41 | // Or, clear only certain things: 42 | automation.ClearBlobs(); 43 | automation.ClearTables(); 44 | automation.ClearQueues(); 45 | 46 | automation.Stop(); 47 | 48 | AzureStorageEmulatorAutomation.IsEmulatorRunning(); // should be false 49 | ``` 50 | `AzureStorageEmulatorAutomation` implements `IDisposable`. The `Dispose` method will only stop the Windows Azure Storage Emulator if it was started by the `AzureStorageEmulatorAutomation` instance. We're nice and don't close it if it was opened by a different instance (or, a user opening it manually on their machine). 51 | 52 | An example `IDispoable` implementation might look like: 53 | 54 | ```csharp 55 | using (var automation = new AzureStorageEmulatorAutomation()) 56 | { 57 | automation.Start(); 58 | 59 | // Work with the running Azure Storage Emulator here. 60 | } 61 | 62 | // Outside the scope of the using, if the Azure Storage Emulator was 63 | // started by `automation.Start();` above, then it should be shut down. 64 | // If it was already running, it should remain running. 65 | ``` 66 | 67 | In certain scenarios the Storage Emulator might not be initialized yet, for example running tests on a hosted build agent. 68 | In those cases, `Start` might time-out and you will encounter this error in your log: 69 | 70 | ```log 71 | No available SQL Instance was found. 72 | One or more initialization actions have failed. Resolve these errors before attempting to run the storage emulator again. 73 | Error: The storage emulator needs to be initialized. Please run the 'init' command. 74 | ``` 75 | 76 | In that case, make sure you call `Init` once before calling `Start`: 77 | 78 | ```csharp 79 | automation.Init(); 80 | automation.Start(); 81 | ``` 82 | 83 | ## Thanks 84 | 85 | Thanks to [Ritter IM](http://ritterim.com) for supporting OSS. 86 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | 3 | cache: 4 | - packages -> **\packages.config 5 | 6 | install: 7 | - ps: md -force .nuget >$null 2>&1 8 | - ps: "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/latest/nuget.exe' -OutFile '.nuget/nuget.exe'" 9 | 10 | configuration: Release 11 | 12 | build_script: 13 | - ./build.cmd /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" 14 | 15 | test: off 16 | 17 | artifacts: 18 | - path: ./msbuild.log 19 | - path: ./artifacts/*.nupkg 20 | 21 | deploy: 22 | - provider: Environment 23 | name: NuGet 24 | on: 25 | branch: master 26 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @echo Off 2 | pushd %~dp0 3 | setlocal enabledelayedexpansion 4 | 5 | rmdir /s /q "artifacts" 6 | 7 | :Build 8 | echo. 9 | echo *** STARTING BUILD *** 10 | echo. 11 | 12 | dotnet build src/core/core.csproj --configuration Release 13 | if %ERRORLEVEL% neq 0 goto :BuildFail 14 | 15 | echo. 16 | echo *** BUILD SUCCEEDED *** 17 | echo. 18 | 19 | echo. 20 | echo *** STARTING TESTS *** 21 | echo. 22 | 23 | dotnet test tests/core.tests/core.tests.csproj --configuration Release 24 | if %ERRORLEVEL% neq 0 goto :TestFail 25 | 26 | echo. 27 | echo *** TESTS SUCCEEDED *** 28 | echo. 29 | 30 | echo. 31 | echo *** STARTING PACK *** 32 | echo. 33 | 34 | dotnet pack src/core/core.csproj --configuration Release --no-build --output ../../artifacts 35 | if %ERRORLEVEL% neq 0 goto :PackFail 36 | 37 | echo. 38 | echo *** PACK SUCCEEDED *** 39 | echo. 40 | goto End 41 | 42 | :BuildFail 43 | echo. 44 | echo *** BUILD FAILED *** 45 | goto End 46 | 47 | :TestFail 48 | echo. 49 | echo *** TEST FAILED *** 50 | goto End 51 | 52 | :PackFail 53 | echo. 54 | echo *** PACK FAILED *** 55 | goto End 56 | 57 | :End 58 | echo. 59 | popd 60 | exit /B %ERRORLEVEL% 61 | -------------------------------------------------------------------------------- /src/Core/AzureStorageEmulatorAutomation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace RimDev.Automation.StorageEmulator 5 | { 6 | public class AzureStorageEmulatorAutomation : IDisposable 7 | { 8 | public bool StartedByAutomation { get; private set; } 9 | 10 | public void Dispose() 11 | { 12 | if (StartedByAutomation) 13 | { 14 | Stop(); 15 | } 16 | } 17 | 18 | /// 19 | /// Do one-time initialization needed by the emulator. 20 | /// Use this before if you find error "The storage emulator needs to be initialized. Please run the 'init' command." 21 | /// 22 | public void Init() 23 | { 24 | if (!IsEmulatorRunning()) 25 | { 26 | RunWithParameter("init"); 27 | } 28 | } 29 | 30 | public void Start() 31 | { 32 | if (!IsEmulatorRunning()) 33 | { 34 | RunWithParameter("start"); 35 | StartedByAutomation = true; 36 | } 37 | } 38 | 39 | public void Stop() 40 | { 41 | RunWithParameter("stop"); 42 | } 43 | 44 | public void ClearAll() 45 | { 46 | RunWithParameter("clear all"); 47 | } 48 | 49 | public void ClearBlobs() 50 | { 51 | RunWithParameter("clear blob"); 52 | } 53 | 54 | public void ClearTables() 55 | { 56 | RunWithParameter("clear table"); 57 | } 58 | 59 | public void ClearQueues() 60 | { 61 | RunWithParameter("clear queue"); 62 | } 63 | 64 | public static bool IsEmulatorRunning() 65 | { 66 | var path = GetPathToStorageEmulatorExecutable(); 67 | 68 | var output = ProcessHelper.RunAndGetStandardOutputAsString(path, "status"); 69 | 70 | if (output.Contains("IsRunning: True")) 71 | { 72 | return true; 73 | } 74 | else if (output.Contains("IsRunning: False")) 75 | { 76 | return false; 77 | } 78 | 79 | throw new ApplicationException("Unable to determine if Azure Storage Emulator is running."); 80 | } 81 | 82 | private static void RunWithParameter(string parameter) 83 | { 84 | var path = GetPathToStorageEmulatorExecutable(); 85 | 86 | ProcessHelper.RunAndGetStandardOutputAsString(path, parameter); 87 | } 88 | 89 | private static string AzureSdkDirectory 90 | { 91 | get 92 | { 93 | var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); 94 | var path = Path.Combine(programFilesX86, @"Microsoft SDKs\Azure"); 95 | 96 | return path; 97 | } 98 | } 99 | 100 | private static string GetPathToStorageEmulatorExecutable() 101 | { 102 | var paths = new[] 103 | { 104 | Path.Combine(AzureSdkDirectory, @"Storage Emulator\AzureStorageEmulator.exe"), 105 | Path.Combine(AzureSdkDirectory, @"Storage Emulator\WAStorageEmulator.exe") 106 | }; 107 | 108 | foreach (var path in paths) 109 | { 110 | if (File.Exists(path)) 111 | { 112 | return path; 113 | } 114 | } 115 | 116 | throw new FileNotFoundException( 117 | "Unable to locate Azure storage emulator at any of the expected paths.", 118 | string.Join(", ", paths)); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/Core/Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;net452 5 | 6 | 7 | 8 | RimDev.Automation.StorageEmulator 9 | RimDev.Automation.StorageEmulator 10 | RimDev.Automation.StorageEmulator 11 | Programatically control Azure Storage Emulator. 12 | Ritter Insurance Marketing 13 | https://raw.githubusercontent.com/ritterim/automation-storage-emulator/master/LICENSE.txt 14 | https://github.com/ritterim/automation-storage-emulator 15 | azure storage emulator automation 16 | 17 | 18 | 19 | 0.3.1 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Core/ProcessHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace RimDev.Automation.StorageEmulator 4 | { 5 | public class ProcessHelper 6 | { 7 | public static string RunAndGetStandardOutputAsString(string path, string parameter) 8 | { 9 | var process = new Process 10 | { 11 | StartInfo = new ProcessStartInfo(path, parameter) 12 | { 13 | CreateNoWindow = true, 14 | RedirectStandardOutput = true, 15 | UseShellExecute = false, 16 | WindowStyle = ProcessWindowStyle.Hidden 17 | } 18 | }; 19 | 20 | process.Start(); 21 | 22 | var sr = process.StandardOutput; 23 | var output = sr.ReadToEnd(); 24 | 25 | process.WaitForExit(); 26 | 27 | return output; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/Core.Tests/AzureStorageEmulatorAutomationTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Xunit; 4 | 5 | namespace RimDev.Automation.StorageEmulator.Tests 6 | { 7 | public class AzureStorageEmulatorAutomationTests : IClassFixture 8 | { 9 | private readonly AzureStorageEmulatorAutomation storageEm; 10 | 11 | public AzureStorageEmulatorAutomationTests() 12 | { 13 | storageEm = new AzureStorageEmulatorAutomation(); 14 | } 15 | 16 | [Fact] 17 | public void Dispose_ClosesStorageEmulatorIfStartedByAutomation() 18 | { 19 | new AzureStorageEmulatorAutomation().Stop(); 20 | 21 | storageEm.Start(); 22 | 23 | storageEm.Dispose(); 24 | 25 | TestHelper.VerifyAzureStorageEmulatorIsNotRunning(); 26 | } 27 | 28 | [Fact] 29 | public async Task Dispose_DoesNotCloseStorageEmulatorIfNotStartedByAutomation() 30 | { 31 | // Use a different instance of automation 32 | new AzureStorageEmulatorAutomation().Start(); 33 | 34 | Assert.False(storageEm.StartedByAutomation, "StartedByAutomation should be false before calling dispose"); 35 | 36 | storageEm.Dispose(); 37 | 38 | await TestHelper.VerifyAzureStorageEmulatorIsRunningAsync(); 39 | } 40 | 41 | [Fact] 42 | public async Task Start_StartsStorageEmulator() 43 | { 44 | new AzureStorageEmulatorAutomation().Stop(); 45 | 46 | storageEm.Start(); 47 | 48 | await TestHelper.VerifyAzureStorageEmulatorIsRunningAsync(); 49 | } 50 | 51 | [Fact] 52 | public async Task Start_DoesNotThrowIfRanTwice() 53 | { 54 | storageEm.Start(); 55 | 56 | await TestHelper.VerifyAzureStorageEmulatorIsRunningAsync(); 57 | 58 | storageEm.Start(); 59 | 60 | await TestHelper.VerifyAzureStorageEmulatorIsRunningAsync(); 61 | } 62 | 63 | [Fact] 64 | public async Task Init_DoesNotClearBlobs() 65 | { 66 | const string testBlobContainer = "testcontainer"; 67 | const string testTableName = "testtable"; 68 | const string testQueueName = "testqueue"; 69 | 70 | new AzureStorageEmulatorAutomation().Start(); 71 | 72 | await TestHelper.AddTestBlobToContainerAsync(testBlobContainer); 73 | await TestHelper.AddTestRowToTableAsync(testTableName); 74 | await TestHelper.AddTestQueueItemToAsync(testQueueName); 75 | 76 | async Task BlobContainerContainsTestBlob() => await TestHelper.BlobContainerExistsAndContainsTestBlobAsync(testBlobContainer); 77 | async Task TableContainsTestRow() => await TestHelper.TableExistsAndContainsTestRowAsync(testTableName); 78 | async Task QueueContainsTestMessage() => await TestHelper.QueueExistsAndContainsTestMessageAsync(testQueueName); 79 | 80 | Assert.True(await BlobContainerContainsTestBlob()); 81 | Assert.True(await TableContainsTestRow()); 82 | Assert.True(await QueueContainsTestMessage()); 83 | 84 | storageEm.Init(); 85 | storageEm.Start(); 86 | 87 | Assert.True(await BlobContainerContainsTestBlob()); 88 | Assert.True(await TableContainsTestRow()); 89 | Assert.True(await QueueContainsTestMessage()); 90 | 91 | storageEm.ClearAll(); 92 | } 93 | 94 | [Fact] 95 | public async Task Stop_StopsStorageEmulatorIfStartedByAutomation() 96 | { 97 | new AzureStorageEmulatorAutomation().Stop(); 98 | 99 | storageEm.Start(); 100 | 101 | await TestHelper.VerifyAzureStorageEmulatorIsRunningAsync(); 102 | 103 | storageEm.Stop(); 104 | 105 | TestHelper.VerifyAzureStorageEmulatorIsNotRunning(); 106 | } 107 | 108 | [Fact] 109 | public void Stop_StopsStorageEmulatorIfNotStartedByAutomation() 110 | { 111 | // Use a different instance of automation 112 | new AzureStorageEmulatorAutomation().Start(); 113 | 114 | storageEm.Stop(); 115 | 116 | TestHelper.VerifyAzureStorageEmulatorIsNotRunning(); 117 | } 118 | 119 | [Fact] 120 | public async Task ClearAll_RemovesAllData() 121 | { 122 | const string testBlobContainer = "testcontainer"; 123 | const string testTableName = "testtable"; 124 | const string testQueueName = "testqueue"; 125 | 126 | storageEm.Start(); 127 | 128 | await TestHelper.AddTestBlobToContainerAsync(testBlobContainer); 129 | await TestHelper.AddTestRowToTableAsync(testTableName); 130 | await TestHelper.AddTestQueueItemToAsync(testQueueName); 131 | 132 | async Task BlobContainerContainsTestBlob() => await TestHelper.BlobContainerExistsAndContainsTestBlobAsync(testBlobContainer); 133 | async Task TableContainsTestRow() => await TestHelper.TableExistsAndContainsTestRowAsync(testTableName); 134 | async Task QueueContainsTestMessage() => await TestHelper.QueueExistsAndContainsTestMessageAsync(testQueueName); 135 | 136 | Assert.True(await BlobContainerContainsTestBlob()); 137 | Assert.True(await TableContainsTestRow()); 138 | Assert.True(await QueueContainsTestMessage()); 139 | 140 | storageEm.ClearAll(); 141 | 142 | Assert.False(await BlobContainerContainsTestBlob()); 143 | Assert.False(await TableContainsTestRow()); 144 | Assert.False(await QueueContainsTestMessage()); 145 | } 146 | 147 | [Fact] 148 | public async Task ClearBlobs_RemovesBlobData() 149 | { 150 | const string testBlobContainer = "testcontainer"; 151 | 152 | storageEm.Start(); 153 | 154 | await TestHelper.AddTestBlobToContainerAsync(testBlobContainer); 155 | 156 | async Task BlobContainerContainsTestBlob() => await TestHelper.BlobContainerExistsAndContainsTestBlobAsync(testBlobContainer); 157 | 158 | Assert.True(await BlobContainerContainsTestBlob()); 159 | 160 | storageEm.ClearBlobs(); 161 | 162 | Assert.False(await BlobContainerContainsTestBlob()); 163 | } 164 | 165 | [Fact] 166 | public async Task ClearTables_RemovesTableData() 167 | { 168 | const string testTableName = "testtable"; 169 | 170 | storageEm.Start(); 171 | 172 | await TestHelper.AddTestRowToTableAsync(testTableName); 173 | 174 | async Task TableContainsTestRow() => await TestHelper.TableExistsAndContainsTestRowAsync(testTableName); 175 | 176 | Assert.True(await TableContainsTestRow()); 177 | 178 | storageEm.ClearTables(); 179 | 180 | Assert.False(await TableContainsTestRow()); 181 | } 182 | 183 | [Fact] 184 | public async Task ClearQueues_RemovesQueueData() 185 | { 186 | const string testQueueName = "testqueue"; 187 | 188 | storageEm.Start(); 189 | 190 | await TestHelper.AddTestQueueItemToAsync(testQueueName); 191 | 192 | async Task QueueContainsTestMessage() => await TestHelper.QueueExistsAndContainsTestMessageAsync(testQueueName); 193 | 194 | Assert.True(await QueueContainsTestMessage()); 195 | 196 | storageEm.ClearQueues(); 197 | 198 | Assert.False(await QueueContainsTestMessage()); 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /tests/Core.Tests/Core.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net452;netcoreapp2.1 5 | RimDev.Automation.StorageEmulator.Tests 6 | RimDev.Automation.StorageEmulator.Tests 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /tests/Core.Tests/StopAzureStorageEmulatorFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RimDev.Automation.StorageEmulator.Tests 4 | { 5 | public class StopAzureStorageEmulatorFixture : IDisposable 6 | { 7 | public StopAzureStorageEmulatorFixture() 8 | { 9 | var automation = new AzureStorageEmulatorAutomation(); 10 | 11 | automation.Stop(); 12 | 13 | TestHelper.VerifyAzureStorageEmulatorIsNotRunning(); 14 | } 15 | 16 | public void Dispose() 17 | { 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/Core.Tests/TestHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Blob; 3 | using Microsoft.WindowsAzure.Storage.Queue; 4 | using Microsoft.WindowsAzure.Storage.Table; 5 | using System; 6 | using System.Threading.Tasks; 7 | 8 | namespace RimDev.Automation.StorageEmulator.Tests 9 | { 10 | public class TestHelper 11 | { 12 | private const string TestBlobName = "TestBlob"; 13 | private const string TestQueueMessage = "test-queue-message"; 14 | 15 | private static readonly CloudStorageAccount StorageAccount = 16 | CloudStorageAccount.DevelopmentStorageAccount; 17 | 18 | public static async Task VerifyAzureStorageEmulatorIsRunningAsync() 19 | { 20 | var tableName = "test" + Guid.NewGuid().ToString().Replace("-", ""); 21 | var cloudTable = GetCloudTable(tableName); 22 | 23 | var tableExists = await cloudTable.ExistsAsync(); 24 | if (tableExists) 25 | { 26 | throw new ApplicationException("Table unexpectedly exists."); 27 | } 28 | } 29 | 30 | public static void VerifyAzureStorageEmulatorIsNotRunning() 31 | { 32 | var isRunning = AzureStorageEmulatorAutomation.IsEmulatorRunning(); 33 | 34 | if (isRunning) 35 | { 36 | throw new ApplicationException("The Azure Storage Emulator is running."); 37 | } 38 | } 39 | 40 | public static async Task AddTestRowToTableAsync(string tableName) 41 | { 42 | var cloudTable = GetCloudTable(tableName); 43 | await cloudTable.CreateIfNotExistsAsync(); 44 | 45 | var testTableEntity = new TestTableEntity 46 | { 47 | PartitionKey = Guid.NewGuid().ToString(), 48 | RowKey = Guid.NewGuid().ToString(), 49 | TestProperty = "test" 50 | }; 51 | 52 | await cloudTable.ExecuteAsync(TableOperation.Insert(testTableEntity)); 53 | } 54 | 55 | public static async Task AddTestBlobToContainerAsync(string blobContainer) 56 | { 57 | var cloudBlobContainer = GetCloudBlobContainer(blobContainer); 58 | await cloudBlobContainer.CreateIfNotExistsAsync(); 59 | 60 | var blockBlob = cloudBlobContainer.GetBlockBlobReference(TestBlobName); 61 | 62 | await blockBlob.UploadTextAsync("test"); 63 | } 64 | 65 | public static async Task AddTestQueueItemToAsync(string queueName) 66 | { 67 | var cloudQueue = GetCloudQueue(queueName); 68 | await cloudQueue.CreateIfNotExistsAsync(); 69 | 70 | var cloudQueueMessage = new CloudQueueMessage(TestQueueMessage); 71 | 72 | await cloudQueue.AddMessageAsync(cloudQueueMessage); 73 | } 74 | 75 | public static async Task BlobContainerExistsAndContainsTestBlobAsync(string blobContainer) 76 | { 77 | var cloudBlobContainer = GetCloudBlobContainer(blobContainer); 78 | 79 | if (!await cloudBlobContainer.ExistsAsync()) 80 | { 81 | return false; 82 | } 83 | 84 | var cloudBlob = await cloudBlobContainer.GetBlobReferenceFromServerAsync(TestBlobName); 85 | return await cloudBlob.ExistsAsync(); 86 | } 87 | 88 | public static async Task TableExistsAndContainsTestRowAsync(string tableName) 89 | { 90 | var cloudTable = GetCloudTable(tableName); 91 | 92 | if (!await cloudTable.ExistsAsync()) 93 | { 94 | return false; 95 | } 96 | 97 | var results = (await cloudTable.ExecuteQuerySegmentedAsync(new TableQuery(), new TableContinuationToken())).Results; 98 | 99 | if (results?.Count > 1 ) 100 | { 101 | throw new ApplicationException(string.Format( 102 | "count of test rows was {0}.", 103 | results?.Count)); 104 | } 105 | 106 | return results?.Count == 1; 107 | } 108 | 109 | public static async Task QueueExistsAndContainsTestMessageAsync(string queueName) 110 | { 111 | var cloudQueue = GetCloudQueue(queueName); 112 | 113 | if (!await cloudQueue.ExistsAsync()) 114 | { 115 | return false; 116 | } 117 | 118 | var queueMessage = await cloudQueue.PeekMessageAsync(); 119 | 120 | if (queueMessage != null && queueMessage.AsString == TestQueueMessage) 121 | { 122 | return true; 123 | } 124 | 125 | return false; 126 | } 127 | 128 | private static CloudTable GetCloudTable(string tableName) 129 | { 130 | var tableClient = StorageAccount.CreateCloudTableClient(); 131 | 132 | var table = tableClient.GetTableReference(tableName); 133 | return table; 134 | } 135 | 136 | private static CloudBlobContainer GetCloudBlobContainer(string containerName) 137 | { 138 | var blobClient = StorageAccount.CreateCloudBlobClient(); 139 | 140 | var blobContainer = blobClient.GetContainerReference(containerName); 141 | return blobContainer; 142 | } 143 | 144 | private static CloudQueue GetCloudQueue(string queueName) 145 | { 146 | var queueClient = StorageAccount.CreateCloudQueueClient(); 147 | 148 | var cloudQueue = queueClient.GetQueueReference(queueName); 149 | return cloudQueue; 150 | } 151 | 152 | private class TestTableEntity : TableEntity 153 | { 154 | public string TestProperty { get; set; } 155 | } 156 | } 157 | } 158 | --------------------------------------------------------------------------------