Skip to content

Commit

Permalink
[MetricsAdvisor] Made NotificationHook abstract (#22345)
Browse files Browse the repository at this point in the history
  • Loading branch information
kinelski authored Jul 1, 2021
1 parent 064858d commit 4d0e869
Show file tree
Hide file tree
Showing 9 changed files with 182 additions and 100 deletions.
1 change: 1 addition & 0 deletions sdk/metricsadvisor/Azure.AI.MetricsAdvisor/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
- Optional properties `GetAllFeedbackOptions.Filter`, `GetAnomalyDimensionValuesOptions.DimensionToFilter`, and `FeedbackDimensionFilter.DimensionFilter` must now be manually added with setters to be used.
- Moved property `DataFeed.SourceType` to `DataFeedSource.DataSourceType`.
- In `MetricsAdvisorKeyCredential`, merged `UpdateSubscriptionKey` and `UpdateApiKey` into a single method, `Update`, to make it an atomic operation.
- The class `NotificationHook` is now abstract.

## 1.0.0-beta.4 (2021-06-07)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ public MySqlDataFeedSource(string connectionString, string query) { }
public string Query { get { throw null; } set { } }
public void UpdateConnectionString(string connectionString) { }
}
public partial class NotificationHook
public abstract partial class NotificationHook
{
internal NotificationHook() { }
public System.Collections.Generic.IReadOnlyList<string> AdministratorEmails { get { throw null; } }
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Text.Json;
using Azure.AI.MetricsAdvisor.Models;
using Azure.Core;

Expand All @@ -12,7 +13,7 @@ namespace Azure.AI.MetricsAdvisor.Administration
/// An alert notification to be triggered after an anomaly is detected by Metrics Advisor.
/// </summary>
[CodeGenModel("HookInfo")]
public partial class NotificationHook
public abstract partial class NotificationHook
{
internal NotificationHook(string name)
{
Expand Down Expand Up @@ -85,15 +86,88 @@ internal static HookInfoPatch GetPatchModel(NotificationHook hook)
Headers = h.Headers
}
},
_ => throw new InvalidOperationException("Unknown hook type.")
_ => new HookInfoPatch()
};

patch.HookType = hook.HookType;
patch.HookName = hook.Name;
patch.Description = hook.Description;
patch.ExternalLink = hook.ExternalUri?.AbsoluteUri;
patch.Admins = hook.AdministratorEmails;

return patch;
}

internal static NotificationHook DeserializeNotificationHook(JsonElement element)
{
if (element.TryGetProperty("hookType", out JsonElement discriminator))
{
switch (discriminator.GetString())
{
case "Email":
return EmailNotificationHook.DeserializeEmailNotificationHook(element);
case "Webhook":
return WebNotificationHook.DeserializeWebNotificationHook(element);
}
}
HookType hookType = default;
Optional<string> hookId = default;
string hookName = default;
Optional<string> description = default;
Optional<string> externalLink = default;
Optional<IReadOnlyList<string>> admins = default;
foreach (var property in element.EnumerateObject())
{
if (property.NameEquals("hookType"))
{
hookType = new HookType(property.Value.GetString());
continue;
}
if (property.NameEquals("hookId"))
{
hookId = property.Value.GetString();
continue;
}
if (property.NameEquals("hookName"))
{
hookName = property.Value.GetString();
continue;
}
if (property.NameEquals("description"))
{
description = property.Value.GetString();
continue;
}
if (property.NameEquals("externalLink"))
{
externalLink = property.Value.GetString();
continue;
}
if (property.NameEquals("admins"))
{
if (property.Value.ValueKind == JsonValueKind.Null)
{
property.ThrowNonNullablePropertyIsNull();
continue;
}
List<string> array = new List<string>();
foreach (var item in property.Value.EnumerateArray())
{
array.Add(item.GetString());
}
admins = array;
continue;
}
}
return new UnknownNotificationHook(hookType, hookId.Value, hookName, description.Value, externalLink.Value, Optional.ToList(admins));
}

private class UnknownNotificationHook : NotificationHook
{
public UnknownNotificationHook(HookType hookType, string id, string name, string description, string internalExternalLink, IReadOnlyList<string> administrators)
: base(hookType, id, name, description, internalExternalLink, administrators)
{
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public void CreateHookValidatesArguments()
var name = "hookName";
var endpoint = new Uri("http://fakeendpoint.com");

var genericHook = new NotificationHook(name);
var emailHook = new EmailNotificationHook(name) { Name = null, EmailsToAlert = { "fake@email.com" } };
var webHook = new WebNotificationHook(name, endpoint) { Name = null };

Expand Down Expand Up @@ -57,9 +56,6 @@ public void CreateHookValidatesArguments()
webHook.Endpoint = null;
Assert.That(() => adminClient.CreateHookAsync(webHook), Throws.InstanceOf<ArgumentNullException>());
Assert.That(() => adminClient.CreateHook(webHook), Throws.InstanceOf<ArgumentNullException>());

Assert.That(() => adminClient.CreateHookAsync(genericHook), Throws.InstanceOf<ArgumentException>());
Assert.That(() => adminClient.CreateHook(genericHook), Throws.InstanceOf<ArgumentException>());
}

[Test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
using System;
using System.IO;
using System.Text;
using System.Threading;
using Azure.AI.MetricsAdvisor.Administration;
using Azure.Core;
using Azure.Core.TestFramework;
using Newtonsoft.Json;
using NUnit.Framework;
using NUnit.Framework.Constraints;

namespace Azure.AI.MetricsAdvisor.Tests
{
Expand Down Expand Up @@ -75,5 +79,20 @@ public Stream CreateIncidentJsonStream(double valueOfRootNode = default, double?

return new MemoryStream(Encoding.UTF8.GetBytes(jsonStr));
}

public string ReadContent(Request request)
{
using MemoryStream stream = new MemoryStream();
request.Content.WriteTo(stream, CancellationToken.None);

return Encoding.UTF8.GetString(stream.ToArray());
}

public SubstringConstraint ContainsJsonString(string propertyName, string propertyValue) =>
Contains.Substring($"\"{propertyName}\":\"{propertyValue}\"");

// Currently only supports a single-element array.
public SubstringConstraint ContainsJsonStringArray(string propertyName, string elementValue) =>
Contains.Substring($"\"{propertyName}\":[\"{elementValue}\"]");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
// Licensed under the MIT License.

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.MetricsAdvisor.Administration;
using Azure.AI.MetricsAdvisor.Models;
Expand Down Expand Up @@ -93,9 +90,8 @@ public async Task DataFeedSourceSendsSecretDuringCreation(DataFeedSource dataSou

MockRequest request = mockTransport.Requests.First();
string content = ReadContent(request);
string expectedSubstring = $"\"{secretPropertyName}\":\"secret\"";

Assert.That(content, Contains.Substring(expectedSubstring));
Assert.That(content, ContainsJsonString(secretPropertyName, "secret"));
}

[Test]
Expand Down Expand Up @@ -125,7 +121,7 @@ public async Task DataFeedSourceSendsSecretDuringUpdate(DataFeedSource dataSourc
MockRequest request = mockTransport.Requests.First();
string content = ReadContent(request);

Assert.That(content, Contains.Substring($"\"{secretPropertyName}\":\"new_secret\""));
Assert.That(content, ContainsJsonString(secretPropertyName, "new_secret"));
}

private void UpdateSecret(DataFeedSource dataSource, string secretPropertyName)
Expand Down Expand Up @@ -176,13 +172,5 @@ private void UpdateSecret(DataFeedSource dataSource, string secretPropertyName)
throw new ArgumentOutOfRangeException($"Unknown data source type: {dataSource.GetType()}");
};
}

private string ReadContent(Request request)
{
using MemoryStream stream = new MemoryStream();
request.Content.WriteTo(stream, CancellationToken.None);

return Encoding.UTF8.GetString(stream.ToArray());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
// Licensed under the MIT License.

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Azure.AI.MetricsAdvisor.Administration;
using Azure.AI.MetricsAdvisor.Models;
Expand Down Expand Up @@ -83,7 +80,7 @@ public async Task DataLakeSharedKeyCredentialEntitySendsSecretDuringUpdate()
MockRequest request = mockTransport.Requests.First();
string content = ReadContent(request);

Assert.That(content, Contains.Substring("\"accountKey\":\"secret\""));
Assert.That(content, ContainsJsonString("accountKey", "secret"));
}

[Test]
Expand All @@ -107,7 +104,7 @@ public async Task ServicePrincipalCredentialEntitySendsSecretDuringUpdate()
MockRequest request = mockTransport.Requests.First();
string content = ReadContent(request);

Assert.That(content, Contains.Substring("\"clientSecret\":\"secret\""));
Assert.That(content, ContainsJsonString("clientSecret", "secret"));
}

[Test]
Expand All @@ -131,7 +128,7 @@ public async Task ServicePrincipalInKeyVaultCredentialEntitySendsSecretDuringUpd
MockRequest request = mockTransport.Requests.First();
string content = ReadContent(request);

Assert.That(content, Contains.Substring("\"keyVaultClientSecret\":\"secret\""));
Assert.That(content, ContainsJsonString("keyVaultClientSecret", "secret"));
}

[Test]
Expand All @@ -155,15 +152,7 @@ public async Task SqlConnectionStringCredentialEntitySendsSecretDuringUpdate()
MockRequest request = mockTransport.Requests.First();
string content = ReadContent(request);

Assert.That(content, Contains.Substring("\"connectionString\":\"secret\""));
}

private string ReadContent(Request request)
{
using MemoryStream stream = new MemoryStream();
request.Content.WriteTo(stream, CancellationToken.None);

return Encoding.UTF8.GetString(stream.ToArray());
Assert.That(content, ContainsJsonString("connectionString", "secret"));
}
}
}
Loading

0 comments on commit 4d0e869

Please sign in to comment.