Skip to content

Commit 6958689

Browse files
maitre-mattHenrik Frystyk Nielsen
authored and
Henrik Frystyk Nielsen
committed
Enforce mandatory properties in Azure Alert payload
- Tag mandatory properties with Required.Always so JSON.NET enforces the requirement during (de)serialization - Fix a couple of comment typos on KuduNotification - Add required 'resourceRegion' property to AlertMessage1.json test content - Add AlertMessage3.json to validate change against sample payload in Azure docs - Add unit tests
1 parent 1567075 commit 6958689

File tree

8 files changed

+80
-16
lines changed

8 files changed

+80
-16
lines changed

src/Microsoft.AspNet.WebHooks.Receivers.Azure/WebHooks/AzureAlertContext.cs

+13-12
Original file line numberDiff line numberDiff line change
@@ -14,79 +14,80 @@ public class AzureAlertContext
1414
/// <summary>
1515
/// Gets or sets the unique ID for this alert.
1616
/// </summary>
17-
[JsonProperty("id")]
17+
[JsonProperty("id", Required = Required.Always)]
1818
public string Id { get; set; }
1919

2020
/// <summary>
2121
/// Gets or sets the name of the alert.
2222
/// </summary>
23-
[JsonProperty("name")]
23+
[JsonProperty("name", Required = Required.Always)]
2424
public string Name { get; set; }
2525

2626
/// <summary>
2727
/// Gets or sets the description of the alert.
2828
/// </summary>
29-
[JsonProperty("description")]
29+
[JsonProperty("description", Required = Required.Always)]
3030
public string Description { get; set; }
3131

3232
/// <summary>
3333
/// Gets or sets the condition type, e.g. '<c>Metric</c>' or '<c>Event</c>'.
3434
/// </summary>
35-
[JsonProperty("conditionType")]
35+
[JsonProperty("conditionType", Required = Required.Always)]
3636
public string ConditionType { get; set; }
3737

3838
/// <summary>
3939
/// Gets or sets the Azure subscription ID.
4040
/// </summary>
41-
[JsonProperty("subscriptionId")]
41+
[JsonProperty("subscriptionId", Required = Required.Always)]
4242
public string SubscriptionId { get; set; }
4343

4444
/// <summary>
4545
/// Gets or sets the time at which the alert was triggered. The alert is triggered as soon as
4646
/// the metric is read from the diagnostics storage.
4747
/// </summary>
48-
[JsonProperty("timestamp")]
48+
[JsonProperty("timestamp", Required = Required.Always)]
4949
public DateTime Timestamp { get; set; }
5050

5151
/// <summary>
5252
/// Gets or sets information about the condition causing the event.
5353
/// </summary>
54+
[JsonProperty("condition", Required = Required.Always)]
5455
public AzureAlertCondition Condition { get; set; }
5556

5657
/// <summary>
5758
/// Gets or sets the resource group name of the impacted resource causing the alert.
5859
/// </summary>
59-
[JsonProperty("resourceGroupName")]
60+
[JsonProperty("resourceGroupName", Required = Required.Always)]
6061
public string ResourceGroupName { get; set; }
6162

6263
/// <summary>
6364
/// Gets or sets the name of the resource causing the alert.
6465
/// </summary>
65-
[JsonProperty("resourceName")]
66+
[JsonProperty("resourceName", Required = Required.Always)]
6667
public string ResourceName { get; set; }
6768

6869
/// <summary>
6970
/// Gets or sets the type of the impacted resource.
7071
/// </summary>
71-
[JsonProperty("resourceType")]
72+
[JsonProperty("resourceType", Required = Required.Always)]
7273
public string ResourceType { get; set; }
7374

7475
/// <summary>
7576
/// Gets or sets the ID of the resource.
7677
/// </summary>
77-
[JsonProperty("resourceId")]
78+
[JsonProperty("resourceId", Required = Required.Always)]
7879
public string ResourceId { get; set; }
7980

8081
/// <summary>
8182
/// Gets or sets the region where the resource is located.
8283
/// </summary>
83-
[JsonProperty("resourceRegion")]
84+
[JsonProperty("resourceRegion", Required = Required.Always)]
8485
public string ResourceRegion { get; set; }
8586

8687
/// <summary>
8788
/// Gets or sets a direct link to the resource summary page on the Azure portal.
8889
/// </summary>
89-
[JsonProperty("portalLink")]
90+
[JsonProperty("portalLink", Required = Required.Always)]
9091
public string PortalLink { get; set; }
9192
}
9293
}

src/Microsoft.AspNet.WebHooks.Receivers.Azure/WebHooks/AzureAlertNotification.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ public class AzureAlertNotification
1717
/// Gets or sets the kind of alert. Azure automatically sends activated and resolved alerts for the condition sets.
1818
/// Examples of values include '<c>Activated</c>' and '<c>Resolved</c>'.
1919
/// </summary>
20-
[JsonProperty("status")]
20+
[JsonProperty("status", Required = Required.Always)]
2121
public string Status { get; set; }
2222

2323
/// <summary>
2424
/// Gets or sets context information for this alert.
2525
/// </summary>
26-
[JsonProperty("context")]
26+
[JsonProperty("context", Required = Required.Always)]
2727
public AzureAlertContext Context { get; set; }
2828

2929
/// <summary>

src/Microsoft.AspNet.WebHooks.Receivers.Azure/WebHooks/KuduNotification.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace Microsoft.AspNet.WebHooks
1212
public class KuduNotification
1313
{
1414
/// <summary>
15-
/// Gets or sets the ID or the WebHook.
15+
/// Gets or sets the ID of the WebHook.
1616
/// </summary>
1717
[JsonProperty("id")]
1818
public string Id { get; set; }
@@ -42,7 +42,7 @@ public class KuduNotification
4242
public string Author { get; set; }
4343

4444
/// <summary>
45-
/// Gets or set a message contained within the WebHook.
45+
/// Gets or sets a message contained within the WebHook.
4646
/// </summary>
4747
[JsonProperty("message")]
4848
public string Message { get; set; }

test/Microsoft.AspNet.WebHooks.Receivers.Azure.Test/Messages/AlertMessage1.json

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"timestamp": "2015-09-30T03:55:30.7037012Z",
2020
"resourceName": "testmachine",
2121
"resourceType": "microsoft.classiccompute/virtualmachines",
22+
"resourceRegion": "West US",
2223
"resourceId": "/subscriptions/aaaaaaa-bbbb-cccc-ddd-eeeeeeeeeeeee/resourceGroups/tests123/providers/Microsoft.ClassicCompute/virtualMachines/testmachine",
2324
"portalLink": "https://portal.azure.com/#resource/subscriptions/aaaaaaa-bbbb-cccc-ddd-eeeeeeeeeeeee/resourceGroups/tests123/providers/Microsoft.ClassicCompute/virtualMachines/testmachine"
2425
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Reference example from Azure documentation at https://azure.microsoft.com/en-us/documentation/articles/insights-webhooks-alerts/
2+
{
3+
"status": "Activated",
4+
"context": {
5+
"timestamp": "2015-08-14T22:26:41.9975398Z",
6+
"id": "/subscriptions/s1/resourceGroups/useast/providers/microsoft.insights/alertrules/ruleName1",
7+
"name": "ruleName1",
8+
"description": "some description",
9+
"conditionType": "Metric",
10+
"condition": {
11+
"metricName": "Requests",
12+
"metricUnit": "Count",
13+
"metricValue": "10",
14+
"threshold": "10",
15+
"windowSize": "15",
16+
"timeAggregation": "Average",
17+
"operator": "GreaterThanOrEqual"
18+
},
19+
"subscriptionId": "s1",
20+
"resourceGroupName": "useast",
21+
"resourceName": "mysite1",
22+
"resourceType": "microsoft.foo/sites",
23+
"resourceId": "/subscriptions/s1/resourceGroups/useast/providers/microsoft.foo/sites/mysite1",
24+
"resourceRegion": "centralus",
25+
"portalLink": "https://portal.azure.com/#resource/subscriptions/s1/resourceGroups/useast/providers/microsoft.foo/sites/mysite1"
26+
},
27+
"properties": {
28+
"key1": "value1",
29+
"key2": "value2"
30+
}
31+
}

test/Microsoft.AspNet.WebHooks.Receivers.Azure.Test/Microsoft.AspNet.WebHooks.Receivers.Azure.Test.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
<EmbeddedResource Include="Messages\KuduMessage.json" />
7676
<EmbeddedResource Include="Messages\AlertMessage2.json" />
7777
<EmbeddedResource Include="Messages\AlertMessage1.json" />
78+
<EmbeddedResource Include="Messages\AlertMessage3.json" />
7879
<None Include="packages.config" />
7980
</ItemGroup>
8081
<ItemGroup>

test/Microsoft.AspNet.WebHooks.Receivers.Azure.Test/WebHooks/AzureAlertContextTests.cs

+13
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public void AlertContext_Roundtrips()
4646
Timestamp = DateTime.Parse("2015-09-30T03:55:30.7037012Z").ToUniversalTime(),
4747
ResourceName = "testmachine",
4848
ResourceType = "microsoft.classiccompute/virtualmachines",
49+
ResourceRegion = "West US",
4950
ResourceId = "/subscriptions/aaaaaaa-bbbb-cccc-ddd-eeeeeeeeeeeee/resourceGroups/tests123/providers/Microsoft.ClassicCompute/virtualMachines/testmachine",
5051
PortalLink = "https://portal.azure.com/#resource/subscriptions/aaaaaaa-bbbb-cccc-ddd-eeeeeeeeeeeee/resourceGroups/tests123/providers/Microsoft.ClassicCompute/virtualMachines/testmachine",
5152
};
@@ -58,5 +59,17 @@ public void AlertContext_Roundtrips()
5859
string actualJson = JsonConvert.SerializeObject(actual, _serializerSettings);
5960
Assert.Equal(expectedJson, actualJson);
6061
}
62+
63+
[Fact]
64+
public void AlertContext_SubscriptionIdIsRequired()
65+
{
66+
// Arrange
67+
JObject data = EmbeddedResource.ReadAsJObject("Microsoft.AspNet.WebHooks.Messages.AlertMessage3.json");
68+
((JObject)data["context"]).Property("subscriptionId").Remove();
69+
var json = JsonConvert.SerializeObject(data["context"], _serializerSettings);
70+
71+
// Act / Assert
72+
Assert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<AzureAlertContext>(json));
73+
}
6174
}
6275
}

test/Microsoft.AspNet.WebHooks.Receivers.Azure.Test/WebHooks/AzureAlertNotificationTests.cs

+17
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,22 @@ public void AlertNotification_Roundtrips()
6565
string actualJson = JsonConvert.SerializeObject(actual, _serializerSettings);
6666
Assert.Equal(expectedJson, actualJson);
6767
}
68+
69+
[Theory]
70+
[InlineData("AlertMessage1.json", "Activated")]
71+
[InlineData("AlertMessage2.json", "Activated")]
72+
[InlineData("AlertMessage3.json", "Activated")]
73+
public void AlertContext_ParsesMessages(string fileName, string expected)
74+
{
75+
// Arrange
76+
string filePath = "Microsoft.AspNet.WebHooks.Messages." + fileName;
77+
JObject data = EmbeddedResource.ReadAsJObject(filePath);
78+
79+
// Act
80+
AzureAlertNotification actual = data.ToObject<AzureAlertNotification>();
81+
82+
// Assert
83+
Assert.Equal(expected, actual.Status);
84+
}
6885
}
6986
}

0 commit comments

Comments
 (0)