| | 1 | | // Copyright (c) Microsoft Corporation. All rights reserved. |
| | 2 | | // Licensed under the MIT License. See License.txt in the project root for |
| | 3 | | // license information. |
| | 4 | |
|
| | 5 | | namespace Microsoft.Azure.Search.Tests.Utilities |
| | 6 | | { |
| | 7 | | using System; |
| | 8 | | using System.Linq; |
| | 9 | | using Microsoft.Azure.Management.Search; |
| | 10 | | using Microsoft.Azure.Management.Search.Models; |
| | 11 | | using Microsoft.Azure.Test.HttpRecorder; |
| | 12 | | using Microsoft.Rest.ClientRuntime.Azure.TestFramework; |
| | 13 | | using Xunit; |
| | 14 | |
|
| | 15 | | public class SearchServiceFixture : ResourceGroupFixture |
| | 16 | | { |
| 5798 | 17 | | public string SearchServiceName { get; private set; } |
| | 18 | |
|
| 1784 | 19 | | public string PrimaryApiKey { get; private set; } |
| | 20 | |
|
| 814 | 21 | | public string QueryApiKey { get; private set; } |
| | 22 | |
|
| 2598 | 23 | | public MockContext MockContext { get; private set; } |
| | 24 | |
|
| | 25 | | public override void Initialize(MockContext context) |
| | 26 | | { |
| 602 | 27 | | base.Initialize(context); |
| | 28 | |
|
| 602 | 29 | | MockContext = context; |
| | 30 | |
|
| 602 | 31 | | SearchManagementClient client = context.GetServiceClient<SearchManagementClient>(); |
| | 32 | |
|
| 602 | 33 | | SearchServiceName = EnsureSearchService(client); |
| | 34 | |
|
| 602 | 35 | | AdminKeyResult adminKeyResult = client.AdminKeys.Get(ResourceGroupName, SearchServiceName); |
| 602 | 36 | | Assert.NotNull(adminKeyResult); |
| | 37 | |
|
| 602 | 38 | | PrimaryApiKey = adminKeyResult.PrimaryKey; |
| | 39 | |
|
| 602 | 40 | | var queryKeys = client.QueryKeys.ListBySearchService(ResourceGroupName, SearchServiceName); |
| 602 | 41 | | Assert.NotNull(queryKeys); |
| 602 | 42 | | Assert.Single(queryKeys); |
| | 43 | |
|
| 602 | 44 | | QueryApiKey = queryKeys.First().Key; |
| 602 | 45 | | } |
| | 46 | |
|
| | 47 | | public override void Cleanup() |
| | 48 | | { |
| | 49 | | // Normally we could just rely on resource group deletion to clean things up for us. However, resource |
| | 50 | | // group deletion is asynchronous and can be slow, especially when we're running in test environments that |
| | 51 | | // aren't 100% reliable. To avoid interfering with other tests by exhausting free service quota, we |
| | 52 | | // eagerly delete the search service here. |
| 602 | 53 | | if (ResourceGroupName != null && SearchServiceName != null) |
| | 54 | | { |
| 602 | 55 | | SearchManagementClient client = MockContext.GetServiceClient<SearchManagementClient>(); |
| 602 | 56 | | client.Services.Delete(ResourceGroupName, SearchServiceName); |
| | 57 | | } |
| | 58 | |
|
| 602 | 59 | | base.Cleanup(); |
| 602 | 60 | | } |
| | 61 | |
|
| | 62 | | private string EnsureSearchService(SearchManagementClient client) |
| | 63 | | { |
| | 64 | | // Ensuring a search service involves creating it, and then waiting until its DNS resolves. The approach |
| | 65 | | // we take depends on what kind of test run this is. If it's a Record or Playback run, we need determinism |
| | 66 | | // since the mock server has no clue how many times we retried DNS lookup in the original test run. In |
| | 67 | | // this case, we can't just delete and re-create the search service if DNS doesn't resolve in a timely |
| | 68 | | // manner. However, we do fail fast in the interests of speeding up interactive dev cycles. |
| | 69 | | // |
| | 70 | | // If we're in None mode (i.e. -- no mock recording or playback), we assume we're running automated tests |
| | 71 | | // in batch. In this case, non-determinism is not a problem (because mocks aren't involved), and |
| | 72 | | // reliability is paramount. For this reason, we retry the entire sequence several times, deleting and |
| | 73 | | // trying to re-create the service each time. |
| 602 | 74 | | int maxAttempts = (HttpMockServer.Mode == HttpRecorderMode.None) ? 10 : 1; |
| | 75 | |
|
| 0 | 76 | | for (int attempt = 0; attempt < maxAttempts; attempt++) |
| | 77 | | { |
| 602 | 78 | | string searchServiceName = SearchTestUtilities.GenerateServiceName(); |
| | 79 | |
|
| 602 | 80 | | var service = |
| 602 | 81 | | new SearchService() |
| 602 | 82 | | { |
| 602 | 83 | | Location = Location, |
| 602 | 84 | | Sku = new Sku() { Name = SkuName.Free } |
| 602 | 85 | | }; |
| | 86 | |
|
| 602 | 87 | | client.Services.CreateOrUpdate(ResourceGroupName, searchServiceName, service); |
| | 88 | |
|
| | 89 | | // In the common case, DNS propagation happens in less than 15 seconds. In the uncommon case, it can |
| | 90 | | // take many minutes. The timeout we use depends on the mock mode. If we're in Playback, the delay is |
| | 91 | | // irrelevant. If we're in Record mode, we can't delete and re-create the service, so we get more |
| | 92 | | // reliable results if we wait longer. In "None" mode, we can delete and re-create, which is often |
| | 93 | | // faster than waiting a long time for DNS propagation. In that case, rather than force all tests to |
| | 94 | | // wait several minutes, we fail fast here. |
| 602 | 95 | | TimeSpan maxDelay = |
| 602 | 96 | | (HttpMockServer.Mode == HttpRecorderMode.Record) ? |
| 602 | 97 | | TimeSpan.FromMinutes(1) : TimeSpan.FromSeconds(15); |
| | 98 | |
|
| 602 | 99 | | if (SearchTestUtilities.WaitForSearchServiceDns(searchServiceName, maxDelay)) |
| | 100 | | { |
| 602 | 101 | | return searchServiceName; |
| | 102 | | } |
| | 103 | |
|
| | 104 | | // If the service DNS isn't resolvable in a timely manner, delete it and try to create another one. |
| | 105 | | // We need to delete it since there can be only one free service per subscription. |
| 0 | 106 | | client.Services.Delete(ResourceGroupName, searchServiceName); |
| | 107 | | } |
| | 108 | |
|
| 0 | 109 | | throw new InvalidOperationException("Failed to provision a search service in a timely manner."); |
| | 110 | | } |
| | 111 | | } |
| | 112 | | } |