Skip to content

Commit efb2aa0

Browse files
author
John Paul Kee
committed
Updates to permissive record matcher to allow ignoring specific resource types
1 parent 9dcd58d commit efb2aa0

12 files changed

+179
-31
lines changed

src/Sql/Sql.Test/ScenarioTests/AdvancedDataSecurityManagedInstanceTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
using Microsoft.Azure.Commands.ScenarioTest.SqlTests;
1616
using Microsoft.WindowsAzure.Commands.ScenarioTest;
17+
using System.Collections.Generic;
1718
using Xunit;
1819
using Xunit.Abstractions;
1920
using RestTestFramework = Microsoft.Rest.ClientRuntime.Azure.TestFramework;
@@ -32,6 +33,9 @@ protected override void SetupManagementClients(RestTestFramework.MockContext con
3233

3334
public AdvancedDataSecurityManagedInstanceTests(ITestOutputHelper output) : base(output)
3435
{
36+
base.resourceTypesToIgnoreApiVersion = new string[] {
37+
"Microsoft.Sql/managedInstances"
38+
};
3539
}
3640

3741
[Fact]

src/Sql/Sql.Test/ScenarioTests/DataClassificationTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class DataClassificationTests : SqlTestsBase
2323
{
2424
public DataClassificationTests(ITestOutputHelper output) : base(output)
2525
{
26+
base.resourceTypesToIgnoreApiVersion = new string[] {
27+
"Microsoft.Sql/managedInstances"
28+
};
2629
}
2730

2831
protected override void SetupManagementClients(RestTestFramework.MockContext context)

src/Sql/Sql.Test/ScenarioTests/ManagedDatabaseBackupTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ protected override void SetupManagementClients(RestTestFramework.MockContext con
3333

3434
public ManagedDatabaseBackupTests(ITestOutputHelper output) : base(output)
3535
{
36+
base.resourceTypesToIgnoreApiVersion = new string[] {
37+
"Microsoft.Sql/managedInstances"
38+
};
3639
}
3740

3841
[Fact]

src/Sql/Sql.Test/ScenarioTests/ManagedDatabaseCrudScenarioTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ protected override void SetupManagementClients(RestTestFramework.MockContext con
3434

3535
public ManagedDatabaseCrudScenarioTests(ITestOutputHelper output) : base(output)
3636
{
37+
base.resourceTypesToIgnoreApiVersion = new string[] {
38+
"Microsoft.Sql/managedInstances"
39+
};
3740
}
3841

3942
[Fact]

src/Sql/Sql.Test/ScenarioTests/ManagedInstanceCrudScenarioTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ protected override void SetupManagementClients(RestTestFramework.MockContext con
3333

3434
public ManagedInstanceCrudScenarioTests(ITestOutputHelper output) : base(output)
3535
{
36+
base.resourceTypesToIgnoreApiVersion = new string[] { "Microsoft.Sql/managedInstances" };
3637
}
3738

3839
[Fact]

src/Sql/Sql.Test/ScenarioTests/ManagedInstanceKeyVaultKeyTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public class ManagedInstanceKeyVaultKeyTests : SqlTestsBase
2424
{
2525
public ManagedInstanceKeyVaultKeyTests(ITestOutputHelper output) : base(output)
2626
{
27+
base.resourceTypesToIgnoreApiVersion = new string[] {
28+
"Microsoft.Sql/managedInstances"
29+
};
2730
}
2831

2932
protected override void SetupManagementClients(RestTestFramework.MockContext context)

src/Sql/Sql.Test/ScenarioTests/ManagedInstanceProtectorTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ public class ManagedInstanceProtectorTests : SqlTestsBase
2424
{
2525
public ManagedInstanceProtectorTests(ITestOutputHelper output) : base(output)
2626
{
27+
base.resourceTypesToIgnoreApiVersion = new string[] {
28+
"Microsoft.Sql/managedInstances"
29+
};
2730
}
2831

2932
protected override void SetupManagementClients(RestTestFramework.MockContext context)

src/Sql/Sql.Test/ScenarioTests/SqlTestsBase.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace Microsoft.Azure.Commands.ScenarioTest.SqlTests
3939
public class SqlTestsBase : RMTestBase
4040
{
4141
protected EnvironmentSetupHelper Helper;
42+
protected string[] resourceTypesToIgnoreApiVersion;
4243

4344
protected SqlTestsBase(ITestOutputHelper output)
4445
{
@@ -70,14 +71,14 @@ protected void RunPowerShellTest(params string[] scripts)
7071
{"Microsoft.Authorization", null},
7172
{"Microsoft.Network", null},
7273
{"Microsoft.KeyVault", null},
73-
{"Microsoft.Sql", null }
7474
};
75+
7576
var providersToIgnore = new Dictionary<string, string>
7677
{
7778
{"Microsoft.Azure.Graph.RBAC.Version1_6.GraphRbacManagementClient", "1.42-previewInternal"},
7879
{"Microsoft.Azure.Management.Resources.ResourceManagementClient", "2016-02-01"}
7980
};
80-
HttpMockServer.Matcher = new PermissiveRecordMatcherWithApiExclusion(true, d, providersToIgnore);
81+
HttpMockServer.Matcher = new PermissiveRecordMatcherWithApiExclusion(true, d, providersToIgnore, resourceTypesToIgnoreApiVersion);
8182
HttpMockServer.RecordsDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SessionRecords");
8283

8384
// Enable undo functionality as well as mock recording

src/Sql/Sql.Test/ScenarioTests/VirtualClusterCrudScenarioTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ protected override void SetupManagementClients(RestTestFramework.MockContext con
3333

3434
public VirtualClusterCrudScenarioTests(ITestOutputHelper output) : base(output)
3535
{
36+
base.resourceTypesToIgnoreApiVersion = new string[] {
37+
"Microsoft.Sql/managedInstances"
38+
};
3639
}
3740

3841
[Fact]

src/Sql/Sql.Test/ScenarioTests/VulnerabilityAssessmentMiTests.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@ protected override void SetupManagementClients(RestTestFramework.MockContext con
2929
var newResourcesClient = GetResourcesClient(context);
3030
var networkClient = GetNetworkClient(context);
3131
Helper.SetupSomeOfManagementClients(sqlClient, storageV2Client, newResourcesClient, networkClient);
32-
3332
}
3433

3534
public VulnerabilityAssessmentMiTests(ITestOutputHelper output) : base(output)
3635
{
36+
base.resourceTypesToIgnoreApiVersion = new string[] {
37+
"Microsoft.Sql/managedInstances"
38+
};
3739
}
3840

3941
#region Managed Instance Policy Tests
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using Microsoft.WindowsAzure.Commands.ScenarioTest;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
using Xunit;
7+
8+
namespace Microsoft.Azure.Commands.Sql.Test.UnitTests
9+
{
10+
public class PermissiveRecordMatcherUnitTests
11+
{
12+
[Fact]
13+
[Trait(Category.AcceptanceType, Category.CheckIn)]
14+
public void PermissiveRecordMatcher_ShouldIgnoreApiVersion()
15+
{
16+
var testRequestUris = new string[]
17+
{
18+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/providers/Microsoft.Sql?api-version=2016-09-01",
19+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/resourcegroups/ps8625?api-version=2016-09-01",
20+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/providers/Microsoft.Sql/virtualClusters?api-version=2015-05-01-preview",
21+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/resourceGroups/ps8625/providers/Microsoft.Network/virtualNetworks/cl_initial?api-version=2018-12-01",
22+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/resourceGroups/ps8625/providers/Microsoft.Sql/managedInstances/ps8807?api-version=2015-05-01-preview",
23+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/resourceGroups/ps8625/providers/Microsoft.Sql/servers/ps8807?api-version=2015-05-01-preview",
24+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/resourceGroups/ps8625/providers/Microsoft.Sql/virtualClusters?api-version=2015-05-01-preview",
25+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/resourceGroups/ps8625/providers/Microsoft.Sql/managedInstances/ps8807/managedDatabases/db1?api-version=2017-03-01-preview",
26+
"/subscriptions/a8c9a924-06c0-4bde-9788-e7b1370969e1/resourceGroups/ps8625/providers/Microsoft.Sql/servers/ps8807/databases/testdb?api-version=2017-03-01-preview",
27+
"/subscriptions/4cac86b0-1e56-48c2-9df2-669a6d2d87c5/providers/Microsoft.Sql/managedInstances",
28+
"/subscriptions/4cac86b0-1e56-48c2-9df2-669a6d2d87c5/resourceGroups/ps8625/providers/Microsoft.Sql/managedInstances"
29+
};
30+
31+
TestShouldIgnoreApiVersion(
32+
requestUrisToTest: testRequestUris,
33+
resourcesToIgnore: new string[1]
34+
{
35+
"Microsoft.Sql/managedInstances",
36+
},
37+
expectedNumIgnored: 3);
38+
39+
TestShouldIgnoreApiVersion(
40+
requestUrisToTest: testRequestUris,
41+
resourcesToIgnore: new string[1]
42+
{
43+
"Microsoft.Sql/managedInstances/managedDatabases"
44+
},
45+
expectedNumIgnored: 1);
46+
}
47+
48+
private void TestShouldIgnoreApiVersion(
49+
IEnumerable<string> requestUrisToTest,
50+
string[] resourcesToIgnore,
51+
int expectedNumIgnored)
52+
{
53+
var numIgnored = 0;
54+
foreach (var testUri in requestUrisToTest)
55+
{
56+
var result = PermissiveRecordMatcherWithApiExclusion.ShouldIgnoreApiVersion(
57+
requestUri: testUri,
58+
shouldIgnoreGenericResource: false,
59+
providersToIgnore: new Dictionary<string, string>(),
60+
resourcesToIgnore: resourcesToIgnore,
61+
apiVersion: out var apiVersion);
62+
63+
Assert.Equal(String.Empty, apiVersion);
64+
if (result) numIgnored++;
65+
}
66+
Assert.Equal(expectedNumIgnored, numIgnored);
67+
}
68+
}
69+
}

tools/ScenarioTest.ResourceManager/PermissiveRecordMatcherWithApiExclusion.cs

Lines changed: 81 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using Microsoft.Azure.Management.Internal.Resources.Utilities.Models;
1516
using Microsoft.Azure.Test.HttpRecorder;
1617
using System;
1718
using System.Collections.Generic;
19+
using System.Diagnostics;
1820
using System.Linq;
1921
using System.Text;
2022
using System.Text.RegularExpressions;
@@ -25,38 +27,35 @@ namespace Microsoft.WindowsAzure.Commands.ScenarioTest
2527
// If alternate api version is provided, uses that to match records else removes the api-version matching.
2628
public class PermissiveRecordMatcherWithApiExclusion : IRecordMatcher
2729
{
28-
protected bool _ignoreGenericResource;
30+
protected bool _shouldIgnoreGenericResource;
2931
protected Dictionary<string, string> _providersToIgnore;
3032
protected Dictionary<string, string> _userAgentsToIgnore;
31-
32-
public PermissiveRecordMatcherWithApiExclusion(bool ignoreResourcesClient, Dictionary<string, string> providers)
33-
{
34-
_ignoreGenericResource = ignoreResourcesClient;
35-
_providersToIgnore = providers;
36-
}
33+
protected string[] _resourcesToIgnore;
3734

3835
public PermissiveRecordMatcherWithApiExclusion(
3936
bool ignoreResourcesClient,
4037
Dictionary<string, string> providers,
41-
Dictionary<string, string> userAgents)
38+
Dictionary<string, string> userAgents,
39+
string[] resourcesToIgnore = null)
4240
{
43-
_ignoreGenericResource = ignoreResourcesClient;
41+
_shouldIgnoreGenericResource = ignoreResourcesClient;
4442
_providersToIgnore = providers;
4543
_userAgentsToIgnore = userAgents;
44+
_resourcesToIgnore = resourcesToIgnore ?? new string[]{};
4645
}
4746

4847
public virtual string GetMatchingKey(System.Net.Http.HttpRequestMessage request)
4948
{
50-
var path = Uri.UnescapeDataString(request.RequestUri.PathAndQuery);
51-
if (path.Contains("?&"))
49+
var requestUri = request.RequestUri.PathAndQuery;
50+
if (requestUri.Contains("?&"))
5251
{
53-
path = path.Replace("?&", "?");
52+
requestUri = requestUri.Replace("?&", "?");
5453
}
5554

5655
string version;
57-
if (ContainsIgnoredProvider(path, out version))
56+
if (ShouldIgnoreApiVersion(requestUri, _shouldIgnoreGenericResource, _providersToIgnore, _resourcesToIgnore, out version))
5857
{
59-
path = RemoveOrReplaceApiVersion(path, version);
58+
requestUri = RemoveOrReplaceApiVersion(requestUri, version);
6059
}
6160
else if (_userAgentsToIgnore != null && _userAgentsToIgnore.Any())
6261
{
@@ -67,46 +66,57 @@ public virtual string GetMatchingKey(System.Net.Http.HttpRequestMessage request)
6766
{
6867
if (agent.Value.Any(v => v.StartsWith(userAgnet.Key, StringComparison.OrdinalIgnoreCase)))
6968
{
70-
path = RemoveOrReplaceApiVersion(path, userAgnet.Value);
69+
requestUri = RemoveOrReplaceApiVersion(requestUri, userAgnet.Value);
7170
break;
7271
}
7372
}
7473
}
7574
}
7675

77-
var encodedPath = Convert.ToBase64String(Encoding.UTF8.GetBytes(path));
76+
var encodedPath = Convert.ToBase64String(Encoding.UTF8.GetBytes(requestUri));
7877
return string.Format("{0} {1}", request.Method, encodedPath);
7978
}
8079

8180
public virtual string GetMatchingKey(RecordEntry recordEntry)
8281
{
8382
var encodedPath = recordEntry.EncodedRequestUri;
84-
var path = Uri.UnescapeDataString(recordEntry.RequestUri);
83+
var requestUri = recordEntry.RequestUri;
8584
var changed = false;
86-
if (path.Contains("?&"))
85+
if (requestUri.Contains("?&"))
8786
{
88-
path = recordEntry.RequestUri.Replace("?&", "?");
87+
requestUri = recordEntry.RequestUri.Replace("?&", "?");
8988
changed = true;
9089
}
9190

9291
string version;
93-
if (ContainsIgnoredProvider(path, out version))
92+
if (ShouldIgnoreApiVersion(requestUri, _shouldIgnoreGenericResource, _providersToIgnore, _resourcesToIgnore, out version))
9493
{
95-
path = RemoveOrReplaceApiVersion(path, version);
94+
requestUri = RemoveOrReplaceApiVersion(requestUri, version);
9695
changed = true;
9796
}
9897

9998
if (changed)
10099
{
101-
encodedPath = Convert.ToBase64String(Encoding.UTF8.GetBytes(path));
100+
encodedPath = Convert.ToBase64String(Encoding.UTF8.GetBytes(requestUri));
102101
}
103102

104103
return string.Format("{0} {1}", recordEntry.RequestMethod, encodedPath);
105104
}
106105

107-
protected bool ContainsIgnoredProvider(string requestUri, out string version)
106+
/// <summary>
107+
/// Helper method to determine whether or not this request api version should be ignored
108+
/// </summary>
109+
/// <param name="requestUri">The request uri</param>
110+
/// <param name="apiVersion">The api verison to use</paraam>
111+
/// <returns></returns>
112+
public static bool ShouldIgnoreApiVersion(
113+
string requestUri,
114+
bool shouldIgnoreGenericResource,
115+
Dictionary<string, string> providersToIgnore,
116+
string[] resourcesToIgnore,
117+
out string apiVersion)
108118
{
109-
if (_ignoreGenericResource &&
119+
if (shouldIgnoreGenericResource &&
110120
!requestUri.Contains("providers/") &&
111121
!requestUri.StartsWith("/certificates?", StringComparison.InvariantCultureIgnoreCase) &&
112122
!requestUri.StartsWith("/pools", StringComparison.InvariantCultureIgnoreCase) &&
@@ -116,22 +126,65 @@ protected bool ContainsIgnoredProvider(string requestUri, out string version)
116126
!requestUri.Contains("/servicePrincipals?") &&
117127
!requestUri.StartsWith("/webhdfs/v1/?aclspec", StringComparison.InvariantCultureIgnoreCase))
118128
{
119-
version = String.Empty;
129+
apiVersion = String.Empty;
120130
return true;
121131
}
122132

123-
foreach (var provider in _providersToIgnore)
133+
// Ignore resource providers
134+
foreach (var provider in providersToIgnore)
124135
{
125136
var providerString = string.Format("providers/{0}", provider.Key);
126137
if (requestUri.Contains(providerString))
127138
{
128-
version = provider.Value;
139+
apiVersion = provider.Value;
129140
return true;
130141
}
131142
}
132143

144+
// If we're looking at a specific provider and we have top level resource from this provider to ignore
145+
foreach (var resourceToIgnore in resourcesToIgnore)
146+
{
147+
var segments = requestUri.Split('/');
148+
149+
// /subscriptions/.../resourceGroups/.../providers/Microsoft.X/resourceType...?api-version=Y
150+
if (requestUri.Contains("resourceGroups/") && requestUri.Contains("providers/"))
151+
{
152+
if (segments.Length > 8)
153+
{
154+
var resourceIdentifier = new ResourceIdentifier(requestUri);
155+
if (resourceIdentifier.ResourceType == resourceToIgnore)
156+
{
157+
apiVersion = String.Empty;
158+
return true;
159+
}
160+
}
161+
else if (segments.Length == 8)
162+
{
163+
var resourceType = $"{segments[6]}/{segments[7]}";
164+
if (resourceType.Contains(resourceToIgnore))
165+
{
166+
apiVersion = String.Empty;
167+
return true;
168+
}
169+
}
170+
}
171+
172+
// /subscriptions/.../providers/Microsoft.Provider/resourceType
173+
if (requestUri.Contains("providers/"))
174+
{
175+
if (segments.Length == 6)
176+
{
177+
var resourceType = $"{segments[4]}/{segments[5]}";
178+
if (resourceType.Contains(resourceToIgnore))
179+
{
180+
apiVersion = String.Empty;
181+
return true;
182+
}
183+
}
184+
}
185+
}
133186

134-
version = string.Empty;
187+
apiVersion = string.Empty;
135188
return false;
136189
}
137190

0 commit comments

Comments
 (0)