Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MetricsAdvisor] Made NotificationHook abstract #22345

Merged
merged 2 commits into from
Jul 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -46,6 +46,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 @@ -493,7 +493,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)
{
}
}
kinelski marked this conversation as resolved.
Show resolved Hide resolved
}
}
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)
kinelski marked this conversation as resolved.
Show resolved Hide resolved
{
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}\"]");
Comment on lines +91 to +96
Copy link
Member Author

@kinelski kinelski Jun 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convenience methods to make Asserts prettier (examples in tests).

}
}
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 DataLakeGen2SharedKeyDataSourceCredentialEntitySendsSecretDuri
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 ServicePrincipalDataSourceCredentialEntitySendsSecretDuringUpd
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 ServicePrincipalInKeyVaultDataSourceCredentialEntitySendsSecre
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 SqlConnectionStringDataSourceCredentialEntitySendsSecretDuring
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