From 3f59b2759101cdf7c012c4193f12283c880b26bb Mon Sep 17 00:00:00 2001 From: Hualiang Xie Date: Fri, 25 Oct 2019 18:48:42 +0800 Subject: [PATCH] [ITSM] add tests * ServiceNowServiceTests * TicketCreateFlowTests, TicketShowFlowTests, TicketUpdateFlowTests, TicketCloseUtterances * KnowledgeShowTests --- skills/csharp/Skills.sln | 11 + .../itsmskill/Content/Knowledge.1.0.json | 2 +- .../itsmskill/Content/Knowledge.json | 2 +- .../itsmskill/Content/TicketUpdate.1.0.json | 2 +- .../itsmskill/Content/TicketUpdate.json | 2 +- .../Content/TicketUpdateClose.1.0.json | 2 +- .../itsmskill/Content/TicketUpdateClose.json | 2 +- .../Resources/LU/en/secondary/TicketClose.lu | 2 + .../Resources/LU/en/secondary/TicketCreate.lu | 5 + .../Services/ServiceNow/Management.cs | 8 +- .../itsmskill.tests/API/Fakes/MockData.cs | 62 +++++ .../API/Fakes/MockServiceNowRestClient.cs | 185 ++++++++++++++ .../API/ServiceNowServiceTests.cs | 138 ++++++++++ .../Flow/Fakes/BaseMockLuisRecognizer.cs | 69 +++++ .../Flow/Fakes/MockServiceManager.cs | 26 ++ .../itsmskill.tests/Flow/GeneralFlowTests.cs | 33 +++ .../Flow/KnowledgeShowTests.cs | 77 ++++++ .../itsmskill.tests/Flow/SkillTestBase.cs | 239 ++++++++++++++++++ .../Flow/Strings/CardStrings.cs | 20 ++ .../Flow/Strings/ContextStrings.cs | 13 + .../Flow/TicketCloseFlowTests.cs | 57 +++++ .../Flow/TicketCreateFlowTests.cs | 148 +++++++++++ .../Flow/TicketShowFlowTests.cs | 85 +++++++ .../Flow/TicketUpdateFlowTests.cs | 68 +++++ .../Flow/Utterances/BaseTestUtterances.cs | 16 ++ .../Flow/Utterances/GeneralTestUtterances.cs | 58 +++++ .../Flow/Utterances/ITSMTestUtterances.cs | 53 ++++ .../Utterances/KnowledgeShowUtterances.cs | 19 ++ .../Flow/Utterances/NonLuisUtterances.cs | 24 ++ .../Flow/Utterances/TicketCloseUtterances.cs | 22 ++ .../Flow/Utterances/TicketCreateUtterances.cs | 22 ++ .../Flow/Utterances/TicketShowUtterances.cs | 22 ++ .../Flow/Utterances/TicketUpdateUtterances.cs | 23 ++ .../itsmskill.tests/ITSMSkill.Tests.csproj | 24 ++ 34 files changed, 1531 insertions(+), 10 deletions(-) create mode 100644 skills/csharp/tests/itsmskill.tests/API/Fakes/MockData.cs create mode 100644 skills/csharp/tests/itsmskill.tests/API/Fakes/MockServiceNowRestClient.cs create mode 100644 skills/csharp/tests/itsmskill.tests/API/ServiceNowServiceTests.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Fakes/BaseMockLuisRecognizer.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Fakes/MockServiceManager.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/GeneralFlowTests.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/KnowledgeShowTests.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/SkillTestBase.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Strings/CardStrings.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Strings/ContextStrings.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/TicketCloseFlowTests.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/TicketCreateFlowTests.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/TicketShowFlowTests.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/TicketUpdateFlowTests.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/BaseTestUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/GeneralTestUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/ITSMTestUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/KnowledgeShowUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/NonLuisUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCloseUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCreateUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketShowUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketUpdateUtterances.cs create mode 100644 skills/csharp/tests/itsmskill.tests/ITSMSkill.Tests.csproj diff --git a/skills/csharp/Skills.sln b/skills/csharp/Skills.sln index 3b3801f58a..282a9af7e2 100644 --- a/skills/csharp/Skills.sln +++ b/skills/csharp/Skills.sln @@ -49,6 +49,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PointOfInterestSkill.Tests" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ToDoSkill.Tests", "tests\todoskill.tests\ToDoSkill.Tests.csproj", "{5882D204-F86A-47D1-8685-BFD357E5EBF6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ITSMSkill.Tests", "tests\itsmskill.tests\ITSMSkill.Tests.csproj", "{C3304FB4-D4D5-412F-9312-1ECE4DE573DA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU @@ -217,6 +219,14 @@ Global {5882D204-F86A-47D1-8685-BFD357E5EBF6}.Documentation|Any CPU.Build.0 = Debug|Any CPU {5882D204-F86A-47D1-8685-BFD357E5EBF6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5882D204-F86A-47D1-8685-BFD357E5EBF6}.Release|Any CPU.Build.0 = Release|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Documentation|Any CPU.Build.0 = Debug|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -242,6 +252,7 @@ Global {D579437F-2F4A-47D3-9052-A0F2D89AA462} = {15B08548-1311-4749-8816-186C3268386E} {60C61091-17E1-46B7-A358-190843D3AFE7} = {15B08548-1311-4749-8816-186C3268386E} {5882D204-F86A-47D1-8685-BFD357E5EBF6} = {15B08548-1311-4749-8816-186C3268386E} + {C3304FB4-D4D5-412F-9312-1ECE4DE573DA} = {15B08548-1311-4749-8816-186C3268386E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7B849B7E-CCF5-4031-91F7-CA835433B457} diff --git a/skills/csharp/experimental/itsmskill/Content/Knowledge.1.0.json b/skills/csharp/experimental/itsmskill/Content/Knowledge.1.0.json index f8acf66881..7ea9f1d22d 100644 --- a/skills/csharp/experimental/itsmskill/Content/Knowledge.1.0.json +++ b/skills/csharp/experimental/itsmskill/Content/Knowledge.1.0.json @@ -1,6 +1,6 @@ { "type": "AdaptiveCard", - "id": "TicketCard", + "id": "KnowledgeCard", "body": [ { "type": "Container", diff --git a/skills/csharp/experimental/itsmskill/Content/Knowledge.json b/skills/csharp/experimental/itsmskill/Content/Knowledge.json index 89137f88df..2822397b78 100644 --- a/skills/csharp/experimental/itsmskill/Content/Knowledge.json +++ b/skills/csharp/experimental/itsmskill/Content/Knowledge.json @@ -1,6 +1,6 @@ { "type": "AdaptiveCard", - "id": "TicketCard", + "id": "KnowledgeCard", "body": [ { "type": "Container", diff --git a/skills/csharp/experimental/itsmskill/Content/TicketUpdate.1.0.json b/skills/csharp/experimental/itsmskill/Content/TicketUpdate.1.0.json index c3b1ed5ce3..3f1fc6407a 100644 --- a/skills/csharp/experimental/itsmskill/Content/TicketUpdate.1.0.json +++ b/skills/csharp/experimental/itsmskill/Content/TicketUpdate.1.0.json @@ -1,6 +1,6 @@ { "type": "AdaptiveCard", - "id": "TicketNoCloseCard", + "id": "TicketUpdateCard", "body": [ { "type": "Container", diff --git a/skills/csharp/experimental/itsmskill/Content/TicketUpdate.json b/skills/csharp/experimental/itsmskill/Content/TicketUpdate.json index 45ddf79f62..213988390c 100644 --- a/skills/csharp/experimental/itsmskill/Content/TicketUpdate.json +++ b/skills/csharp/experimental/itsmskill/Content/TicketUpdate.json @@ -1,6 +1,6 @@ { "type": "AdaptiveCard", - "id": "TicketNoCloseCard", + "id": "TicketUpdateCard", "body": [ { "type": "Container", diff --git a/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.1.0.json b/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.1.0.json index c93505dce0..2b2339ed5c 100644 --- a/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.1.0.json +++ b/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.1.0.json @@ -1,6 +1,6 @@ { "type": "AdaptiveCard", - "id": "TicketCard", + "id": "TicketUpdateCloseCard", "body": [ { "type": "Container", diff --git a/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.json b/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.json index 4a9c6f3103..c52db3948b 100644 --- a/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.json +++ b/skills/csharp/experimental/itsmskill/Content/TicketUpdateClose.json @@ -1,6 +1,6 @@ { "type": "AdaptiveCard", - "id": "TicketCard", + "id": "TicketUpdateCloseCard", "body": [ { "type": "Container", diff --git a/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketClose.lu b/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketClose.lu index 5e5fb1dfa6..a07ba3b7b1 100644 --- a/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketClose.lu +++ b/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketClose.lu @@ -12,6 +12,7 @@ - Ticket can be closed by {CloseReason} - Ticket can be closed - Close the ticket with {CloseReason} +- close [the] [ticket] {TicketNumber} ((by|with)|(because|due to)) {CloseReason} > resolve @@ -24,3 +25,4 @@ - i would like to resolve an issue - i would like to resolve an incident - Resolve the ticket with {CloseReason} +- resolve [the] [ticket] {TicketNumber} ((by|with)|(because|due to)) {CloseReason} diff --git a/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketCreate.lu b/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketCreate.lu index 0ef2b9501d..b2d244f072 100644 --- a/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketCreate.lu +++ b/skills/csharp/experimental/itsmskill/Deployment/Resources/LU/en/secondary/TicketCreate.lu @@ -12,6 +12,7 @@ - i would like to add a ticket - please add a new issue for {TicketTitle} - please add a new ticket about {TicketTitle} +- add an urgency {UrgencyLevel} (ticket|incident|issue) (about|for|to) {TicketTitle} > create @@ -24,6 +25,7 @@ - create an issue for {TicketTitle} - i would like to create for {TicketTitle} - i'd like to create a ticket +- create an urgency {UrgencyLevel} (ticket|incident|issue) (about|for|to) {TicketTitle} > open @@ -33,6 +35,7 @@ - open a ticket about {TicketTitle} - open a ticket for {TicketTitle} - open an incident about {TicketTitle} +- open an urgency {UrgencyLevel} (ticket|incident|issue) (about|for|to) {TicketTitle} > raise @@ -40,8 +43,10 @@ - raise an incident - raise an issue - raise an issue for {TicketTitle} +- raise an urgency {UrgencyLevel} (ticket|incident|issue) (about|for|to) {TicketTitle} > submit - submit issue about {TicketTitle} - submit issue for {TicketTitle} +- submit an urgency {UrgencyLevel} (ticket|incident|issue) (about|for|to) {TicketTitle} diff --git a/skills/csharp/experimental/itsmskill/Services/ServiceNow/Management.cs b/skills/csharp/experimental/itsmskill/Services/ServiceNow/Management.cs index b4d5d8bce3..15d314c4dc 100644 --- a/skills/csharp/experimental/itsmskill/Services/ServiceNow/Management.cs +++ b/skills/csharp/experimental/itsmskill/Services/ServiceNow/Management.cs @@ -27,7 +27,7 @@ public class Management : IITServiceManagement private static readonly Dictionary StringToUrgency; private static readonly Dictionary TicketStateToString; private static readonly Dictionary StringToTicketState; - private readonly RestClient client; + private readonly IRestClient client; private readonly string getUserIdResource; private readonly string token; private readonly int limitSize; @@ -56,9 +56,9 @@ static Management() StringToTicketState = new Dictionary(TicketStateToString.Select(pair => KeyValuePair.Create(pair.Value, pair.Key))); } - public Management(string url, string token, int limitSize, string getUserIdResource) + public Management(string url, string token, int limitSize, string getUserIdResource, IRestClient restClient = null) { - this.client = new RestClient($"{url}/api/"); + this.client = restClient ?? new RestClient($"{url}/api/"); this.getUserIdResource = getUserIdResource; this.token = token; this.limitSize = limitSize; @@ -359,7 +359,7 @@ private Ticket ConvertTicket(TicketResponse ticketResponse) { if (!string.IsNullOrEmpty(ticketResponse.close_notes)) { - ticket.ResolvedReason = $"{ticketResponse.close_code}:\n{ticketResponse.close_notes}"; + ticket.ResolvedReason = $"{ticketResponse.close_code}:\r\n{ticketResponse.close_notes}"; } else { diff --git a/skills/csharp/tests/itsmskill.tests/API/Fakes/MockData.cs b/skills/csharp/tests/itsmskill.tests/API/Fakes/MockData.cs new file mode 100644 index 0000000000..eac1a0f958 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/API/Fakes/MockData.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using ITSMSkill.Models; + +namespace ITSMSkill.Tests.API.Fakes +{ + public static class MockData + { + public const string ServiceNowProvider = "ServiceNow"; + + public const string ServiceNowUrl = "MockServiceNowUrl"; + + public const string Token = "MockToken"; + + public const int LimitSize = 1; + + public const string ServiceNowGetUserId = "MockServiceNowGetUserId"; + + public const int TicketCount = 1; + + public const string CreateTicketTitle = "MockCreateTicketTitle"; + + public const string CreateTicketDescription = "MockCreateTicketDescription"; + + public const string CreateTicketUrgency = "3"; + + public const UrgencyLevel CreateTicketUrgencyLevel = UrgencyLevel.Low; + + public const string CreateTicketState = "1"; + + public const TicketState CreateTicketTicketState = TicketState.New; + + public const string CreateTicketOpenedTime = "2016-12-12 12:12:12"; + + public const string CreateTicketNumber = "INC0000001"; + + public const string CreateTicketId = "MockCreateTicketId"; + + public const string CloseTicketNumber = "INC0000002"; + + public const string CloseTicketId = "MockCloseTicketId"; + + public const string CloseTicketReason = "MockCloseTicketReason"; + + public const string CloseTicketState = "7"; + + public const string CloseTicketCloseCode = "Closed/Resolved by Caller"; + + public const string KnowledgeTitle = "MockKnowledgeTitle"; + + public const string KnowledgeUpdatedTime = "2016-12-12 12:12:12"; + + public const string KnowledgeNumber = "MockKnowledgeNumber"; + + public const string KnowledgeContent = "MockKnowledgeContent"; + + public const int KnowledgeCount = 1; + + public static string KnowledgeUrl { get => $"{ServiceNowUrl}/kb_view.do?sysparm_article={KnowledgeNumber}"; } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/API/Fakes/MockServiceNowRestClient.cs b/skills/csharp/tests/itsmskill.tests/API/Fakes/MockServiceNowRestClient.cs new file mode 100644 index 0000000000..1d36218af6 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/API/Fakes/MockServiceNowRestClient.cs @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using ITSMSkill.Models.ServiceNow; +using Moq; +using Moq.Protected; +using RestSharp; + +namespace ITSMSkill.Tests.API.Fakes +{ + public class MockServiceNowRestClient + { + private static readonly GetUserIdResponse GetUserIdResponse = new GetUserIdResponse + { + result = "MockUserId" + }; + + private static readonly SingleAggregateResponse CountTicketResponse = new SingleAggregateResponse + { + result = new AggregateResponse + { + stats = new StatsResponse + { + count = MockData.TicketCount + } + } + }; + + private static readonly SingleTicketResponse CreateTicketResponse = new SingleTicketResponse + { + result = new TicketResponse + { + state = MockData.CreateTicketState, + opened_at = MockData.CreateTicketOpenedTime, + short_description = MockData.CreateTicketTitle, + description = MockData.CreateTicketDescription, + sys_id = MockData.CreateTicketId, + urgency = MockData.CreateTicketUrgency, + number = MockData.CreateTicketNumber + } + }; + + private static readonly MultiTicketsResponse SearchTicketResponse = new MultiTicketsResponse + { + result = new List + { + new TicketResponse + { + state = MockData.CreateTicketState, + opened_at = MockData.CreateTicketOpenedTime, + short_description = MockData.CreateTicketTitle, + description = MockData.CreateTicketDescription, + sys_id = MockData.CreateTicketId, + urgency = MockData.CreateTicketUrgency, + number = MockData.CreateTicketNumber + } + } + }; + + private static readonly MultiTicketsResponse SearchTicketToCloseResponse = new MultiTicketsResponse + { + result = new List + { + new TicketResponse + { + state = MockData.CreateTicketState, + opened_at = MockData.CreateTicketOpenedTime, + short_description = MockData.CreateTicketTitle, + description = MockData.CreateTicketDescription, + sys_id = MockData.CloseTicketId, + urgency = MockData.CreateTicketUrgency, + number = MockData.CloseTicketNumber + } + } + }; + + private static readonly SingleTicketResponse CloseTicketResponse = new SingleTicketResponse + { + result = new TicketResponse + { + state = MockData.CloseTicketState, + opened_at = MockData.CreateTicketOpenedTime, + short_description = MockData.CreateTicketTitle, + description = MockData.CreateTicketDescription, + close_code = MockData.CloseTicketCloseCode, + close_notes = MockData.CloseTicketReason, + sys_id = MockData.CloseTicketId, + urgency = MockData.CreateTicketUrgency, + number = MockData.CloseTicketNumber + } + }; + + private static readonly MultiKnowledgesResponse SearchKnowledgeResponse = new MultiKnowledgesResponse + { + result = new List + { + new KnowledgeResponse + { + short_description = MockData.KnowledgeTitle, + sys_updated_on = MockData.KnowledgeUpdatedTime, + text = MockData.KnowledgeContent, + number = MockData.KnowledgeNumber + } + } + }; + + private static readonly SingleAggregateResponse CountKnowledgeResponse = new SingleAggregateResponse + { + result = new AggregateResponse + { + stats = new StatsResponse + { + count = MockData.TicketCount + } + } + }; + + public MockServiceNowRestClient() + { + var mockClient = new Mock(MockBehavior.Strict); + + // TODO use Execute*TaskAsync instead of extension methods + mockClient + .Setup(c => c.ExecuteGetTaskAsync(It.IsAny())) + .ReturnsAsync(CreateIRestResponse(GetUserIdResponse)); + + mockClient + .Setup(c => c.ExecuteGetTaskAsync(It.Is(r => r.Resource.StartsWith("now/v1/stats/incident") && r.Parameters.Any(p => p.Name == "sysparm_count" && p.Value is bool && (bool)p.Value)))) + .ReturnsAsync(CreateIRestResponse(CountTicketResponse)); + + mockClient + .Setup(c => c.ExecutePostTaskAsync(It.Is(r => r.Resource.StartsWith("now/v1/table/incident")))) + .ReturnsAsync(CreateIRestResponse(CreateTicketResponse)); + + mockClient + .Setup(c => c.ExecuteGetTaskAsync(It.Is(r => r.Resource.StartsWith("now/v1/table/incident")))) + .ReturnsAsync(CreateIRestResponse(SearchTicketResponse)); + + // The last wins + mockClient + .Setup(c => c.ExecuteGetTaskAsync(It.Is(r => r.Resource.StartsWith("now/v1/table/incident") && IsTicketToClose(r)))) + .ReturnsAsync(CreateIRestResponse(SearchTicketToCloseResponse)); + + // TODO use id is not an ideal way to distinguish + mockClient + .Setup(c => c.ExecuteTaskAsync(It.Is(r => r.Resource.StartsWith($"now/v1/table/incident/{MockData.CreateTicketId}")), It.IsIn(Method.PATCH))) + .ReturnsAsync(CreateIRestResponse(CreateTicketResponse)); + + mockClient + .Setup(c => c.ExecuteTaskAsync(It.Is(r => r.Resource.StartsWith($"now/v1/table/incident/{MockData.CloseTicketId}")), It.IsIn(Method.PATCH))) + .ReturnsAsync(CreateIRestResponse(CloseTicketResponse)); + + mockClient + .Setup(c => c.ExecuteGetTaskAsync(It.Is(r => r.Resource.StartsWith("now/v1/table/kb_knowledge")))) + .ReturnsAsync(CreateIRestResponse(SearchKnowledgeResponse)); + + mockClient + .Setup(c => c.ExecuteGetTaskAsync(It.Is(r => r.Resource.StartsWith("now/v1/stats/kb_knowledge") && r.Parameters.Any(p => p.Name == "sysparm_count" && p.Value is bool && (bool)p.Value)))) + .ReturnsAsync(CreateIRestResponse(CountKnowledgeResponse)); + + MockRestClient = mockClient.Object; + } + + public IRestClient MockRestClient { get; } + + private IRestResponse CreateIRestResponse(T data) + { + var mockResponse = new Mock>(MockBehavior.Strict); + mockResponse.Setup(r => r.Data).Returns(data); + mockResponse.Setup(r => r.ResponseStatus).Returns(ResponseStatus.Completed); + return mockResponse.Object; + } + + private static bool IsTicketToClose(IRestRequest restRequest) + { + return restRequest.Parameters.Any(p => p.Name == "sysparm_query" && p.Value is string && ((string)p.Value).Contains(MockData.CloseTicketNumber)); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/API/ServiceNowServiceTests.cs b/skills/csharp/tests/itsmskill.tests/API/ServiceNowServiceTests.cs new file mode 100644 index 0000000000..efc547d48d --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/API/ServiceNowServiceTests.cs @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Net.Http; +using System.Threading.Tasks; +using ITSMSkill.Models; +using ITSMSkill.Services.ServiceNow; +using ITSMSkill.Tests.API.Fakes; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using RestSharp; + +namespace ITSMSkill.Tests.API +{ + [TestClass] + public class ServiceNowServiceTests + { + private IRestClient mockClient; + + [TestInitialize] + public void Initialize() + { + mockClient = new MockServiceNowRestClient().MockRestClient; + } + + [TestMethod] + public async Task CreateTicketTest() + { + var service = new Management(MockData.ServiceNowUrl, MockData.Token, MockData.LimitSize, MockData.ServiceNowGetUserId, mockClient); + + var result = await service.CreateTicket(MockData.CreateTicketTitle, MockData.CreateTicketDescription, MockData.CreateTicketUrgencyLevel); + + Assert.AreEqual(result.Success, true); + Assert.AreEqual(result.Tickets.Length, 1); + Assert.AreEqual(result.Tickets[0].Title, MockData.CreateTicketTitle); + Assert.AreEqual(result.Tickets[0].Description, MockData.CreateTicketDescription); + Assert.AreEqual(result.Tickets[0].Urgency, MockData.CreateTicketUrgencyLevel); + Assert.AreEqual(result.Tickets[0].State, MockData.CreateTicketTicketState); + Assert.AreEqual(result.Tickets[0].OpenedTime, DateTime.Parse(MockData.CreateTicketOpenedTime)); + Assert.AreEqual(result.Tickets[0].Number, MockData.CreateTicketNumber); + Assert.AreEqual(result.Tickets[0].Provider, MockData.ServiceNowProvider); + } + + [TestMethod] + public async Task SearchTicketTest() + { + var service = new Management(MockData.ServiceNowUrl, MockData.Token, MockData.LimitSize, MockData.ServiceNowGetUserId, mockClient); + + var result = await service.SearchTicket(0); + + Assert.AreEqual(result.Success, true); + Assert.AreEqual(result.Tickets.Length, MockData.TicketCount); + Assert.AreEqual(result.Tickets[0].Title, MockData.CreateTicketTitle); + Assert.AreEqual(result.Tickets[0].Description, MockData.CreateTicketDescription); + Assert.AreEqual(result.Tickets[0].Urgency, MockData.CreateTicketUrgencyLevel); + Assert.AreEqual(result.Tickets[0].State, MockData.CreateTicketTicketState); + Assert.AreEqual(result.Tickets[0].OpenedTime, DateTime.Parse(MockData.CreateTicketOpenedTime)); + Assert.AreEqual(result.Tickets[0].Number, MockData.CreateTicketNumber); + Assert.AreEqual(result.Tickets[0].Provider, MockData.ServiceNowProvider); + } + + [TestMethod] + public async Task CountTicketTest() + { + var service = new Management(MockData.ServiceNowUrl, MockData.Token, MockData.LimitSize, MockData.ServiceNowGetUserId, mockClient); + + var result = await service.CountTicket(); + + Assert.AreEqual(result.Success, true); + Assert.AreEqual(result.Tickets.Length, MockData.TicketCount); + } + + [TestMethod] + public async Task UpdateTicketTest() + { + var service = new Management(MockData.ServiceNowUrl, MockData.Token, MockData.LimitSize, MockData.ServiceNowGetUserId, mockClient); + + var result = await service.UpdateTicket(MockData.CreateTicketId); + + Assert.AreEqual(result.Success, true); + Assert.AreEqual(result.Tickets.Length, 1); + Assert.AreEqual(result.Tickets[0].Title, MockData.CreateTicketTitle); + Assert.AreEqual(result.Tickets[0].Description, MockData.CreateTicketDescription); + Assert.AreEqual(result.Tickets[0].Urgency, MockData.CreateTicketUrgencyLevel); + Assert.AreEqual(result.Tickets[0].State, MockData.CreateTicketTicketState); + Assert.AreEqual(result.Tickets[0].OpenedTime, DateTime.Parse(MockData.CreateTicketOpenedTime)); + Assert.AreEqual(result.Tickets[0].Number, MockData.CreateTicketNumber); + Assert.AreEqual(result.Tickets[0].Provider, MockData.ServiceNowProvider); + } + + [TestMethod] + public async Task CloseTicketTest() + { + var service = new Management(MockData.ServiceNowUrl, MockData.Token, MockData.LimitSize, MockData.ServiceNowGetUserId, mockClient); + + var result = await service.CloseTicket(MockData.CloseTicketId, MockData.CloseTicketReason); + + Assert.AreEqual(result.Success, true); + Assert.AreEqual(result.Tickets.Length, 1); + Assert.AreEqual(result.Tickets[0].Title, MockData.CreateTicketTitle); + Assert.AreEqual(result.Tickets[0].Description, MockData.CreateTicketDescription); + Assert.AreEqual(result.Tickets[0].Urgency, MockData.CreateTicketUrgencyLevel); + Assert.AreEqual(result.Tickets[0].State, TicketState.Closed); + Assert.AreEqual(result.Tickets[0].OpenedTime, DateTime.Parse(MockData.CreateTicketOpenedTime)); + Assert.AreEqual(result.Tickets[0].Number, MockData.CloseTicketNumber); + Assert.AreEqual(result.Tickets[0].ResolvedReason, $"{MockData.CloseTicketCloseCode}:\r\n{MockData.CloseTicketReason}"); + Assert.AreEqual(result.Tickets[0].Provider, MockData.ServiceNowProvider); + } + + [TestMethod] + public async Task SearchKnowledgeTest() + { + var service = new Management(MockData.ServiceNowUrl, MockData.Token, MockData.LimitSize, MockData.ServiceNowGetUserId, mockClient); + + var result = await service.SearchKnowledge(MockData.KnowledgeTitle, 0); + + Assert.AreEqual(result.Success, true); + Assert.AreEqual(result.Knowledges.Length, 1); + Assert.AreEqual(result.Knowledges[0].Title, MockData.KnowledgeTitle); + Assert.AreEqual(result.Knowledges[0].UpdatedTime, DateTime.Parse(MockData.KnowledgeUpdatedTime)); + Assert.AreEqual(result.Knowledges[0].Content, MockData.KnowledgeContent); + Assert.AreEqual(result.Knowledges[0].Number, MockData.KnowledgeNumber); + Assert.AreEqual(result.Knowledges[0].Url, MockData.KnowledgeUrl); + Assert.AreEqual(result.Knowledges[0].Provider, MockData.ServiceNowProvider); + } + + [TestMethod] + public async Task CountKnowledgeTest() + { + var service = new Management(MockData.ServiceNowUrl, MockData.Token, MockData.LimitSize, MockData.ServiceNowGetUserId, mockClient); + + var result = await service.CountKnowledge(MockData.KnowledgeTitle); + + Assert.AreEqual(result.Success, true); + Assert.AreEqual(result.Knowledges.Length, MockData.KnowledgeCount); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Fakes/BaseMockLuisRecognizer.cs b/skills/csharp/tests/itsmskill.tests/Flow/Fakes/BaseMockLuisRecognizer.cs new file mode 100644 index 0000000000..c50693eb4b --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Fakes/BaseMockLuisRecognizer.cs @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using ITSMSkill.Tests.Flow.Utterances; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.AI.Luis; +using Microsoft.Bot.Builder.Dialogs; + +namespace ITSMSkill.Tests.Flow.Fakes +{ + public class BaseMockLuisRecognizer : ITelemetryRecognizer + { + private readonly BaseTestUtterances utterancesManager; + + public BaseMockLuisRecognizer(params BaseTestUtterances[] utterancesManagers) + { + utterancesManager = utterancesManagers[0]; + + for (int i = 1; i < utterancesManagers.Length; ++i) + { + foreach (var pair in utterancesManagers[i]) + { + if (!utterancesManager.TryAdd(pair.Key, pair.Value)) + { + throw new Exception($"Key:{pair.Key} already exists!"); + } + } + } + } + + public bool LogPersonalInformation { get; set; } = false; + + public IBotTelemetryClient TelemetryClient { get; set; } = new NullBotTelemetryClient(); + + public Task RecognizeAsync(ITurnContext turnContext, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + public Task RecognizeAsync(ITurnContext turnContext, CancellationToken cancellationToken) + where T : IRecognizerConvert, new() + { + var text = turnContext.Activity.Text; + var mockResult = (T)(utterancesManager.GetValueOrDefault(text, utterancesManager.NoneIntent) as object); + return Task.FromResult(mockResult); + } + + public Task RecognizeAsync(DialogContext dialogContext, CancellationToken cancellationToken = default(CancellationToken)) + where T : IRecognizerConvert, new() + { + throw new NotImplementedException(); + } + + public Task RecognizeAsync(ITurnContext turnContext, Dictionary telemetryProperties, Dictionary telemetryMetrics, CancellationToken cancellationToken = default(CancellationToken)) + { + throw new NotImplementedException(); + } + + public Task RecognizeAsync(ITurnContext turnContext, Dictionary telemetryProperties, Dictionary telemetryMetrics, CancellationToken cancellationToken = default(CancellationToken)) + where T : IRecognizerConvert, new() + { + throw new NotImplementedException(); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Fakes/MockServiceManager.cs b/skills/csharp/tests/itsmskill.tests/Flow/Fakes/MockServiceManager.cs new file mode 100644 index 0000000000..a79753e548 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Fakes/MockServiceManager.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using ITSMSkill.Services; +using ITSMSkill.Services.ServiceNow; +using ITSMSkill.Tests.API.Fakes; +using Microsoft.Bot.Schema; + +namespace ITSMSkill.Tests.Flow.Fakes +{ + public class MockServiceManager : IServiceManager + { + public IITServiceManagement CreateManagement(BotSettings botSettings, TokenResponse tokenResponse) + { + // TODO check tokenResponse.ConnectionName == "ServiceNow" + if (!string.IsNullOrEmpty(botSettings.ServiceNowUrl) && !string.IsNullOrEmpty(botSettings.ServiceNowGetUserId)) + { + return new Management(botSettings.ServiceNowUrl, tokenResponse.Token, botSettings.LimitSize, botSettings.ServiceNowGetUserId, new MockServiceNowRestClient().MockRestClient); + } + else + { + return null; + } + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/GeneralFlowTests.cs b/skills/csharp/tests/itsmskill.tests/Flow/GeneralFlowTests.cs new file mode 100644 index 0000000000..3e26f4d471 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/GeneralFlowTests.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Threading.Tasks; +using ITSMSkill.Responses.Main; +using ITSMSkill.Tests.Flow.Utterances; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ITSMSkill.Tests.Flow +{ + [TestClass] + public class GeneralFlowTests : SkillTestBase + { + [TestMethod] + public async Task HelpTest() + { + await this.GetTestFlow() + .Send(GeneralTestUtterances.Help) + .AssertReply(AssertContains(MainResponses.HelpMessage)) + .StartTestAsync(); + } + + [TestMethod] + public async Task CancelTest() + { + await this.GetTestFlow() + .Send(GeneralTestUtterances.Cancel) + .AssertReply(AssertContains(MainResponses.CancelMessage)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/KnowledgeShowTests.cs b/skills/csharp/tests/itsmskill.tests/Flow/KnowledgeShowTests.cs new file mode 100644 index 0000000000..d23c24ab1e --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/KnowledgeShowTests.cs @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Specialized; +using System.Threading.Tasks; +using ITSMSkill.Responses.Knowledge; +using ITSMSkill.Responses.Shared; +using ITSMSkill.Responses.Ticket; +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using ITSMSkill.Tests.Flow.Utterances; +using ITSMSkill.Utilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ITSMSkill.Tests.Flow +{ + [TestClass] + public class KnowledgeShowTests : SkillTestBase + { + [TestMethod] + public async Task ShowTest() + { + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + await this.GetTestFlow() + .Send(KnowledgeShowUtterances.Show) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(SharedResponses.InputSearch)) + .Send(MockData.CreateTicketTitle) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.Knowledge)) + .AssertReply(AssertStartsWith(KnowledgeResponses.IfFindWanted, navigate)) + .Send(GeneralTestUtterances.Confirm) + .AssertReply(AssertContains(SharedResponses.ActionEnded)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + + [TestMethod] + public async Task ShowThenCreateTest() + { + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + var confirmTitle = new StringDictionary + { + { "Title", MockData.CreateTicketTitle } + }; + + await this.GetTestFlow() + .Send(KnowledgeShowUtterances.Show) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(SharedResponses.InputSearch)) + .Send(MockData.CreateTicketTitle) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.Knowledge)) + .AssertReply(AssertStartsWith(KnowledgeResponses.IfFindWanted, navigate)) + .Send(GeneralTestUtterances.Reject) + .AssertReply(AssertStartsWith(KnowledgeResponses.IfCreateTicket)) + .Send(NonLuisUtterances.Yes) + .AssertReply(AssertStartsWith(SharedResponses.ConfirmTitle, confirmTitle)) + .Send(NonLuisUtterances.Yes) + .AssertReply(AssertContains(SharedResponses.InputDescription)) + .Send(MockData.CreateTicketDescription) + .AssertReply(AssertStartsWith(SharedResponses.InputUrgency)) + .Send(NonLuisUtterances.CreateTicketUrgency) + .AssertReply(AssertContains(TicketResponses.TicketCreated, null, CardStrings.TicketUpdateClose)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/SkillTestBase.cs b/skills/csharp/tests/itsmskill.tests/Flow/SkillTestBase.cs new file mode 100644 index 0000000000..cdc219d930 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/SkillTestBase.cs @@ -0,0 +1,239 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Threading; +using ITSMSkill.Bots; +using ITSMSkill.Dialogs; +using ITSMSkill.Responses.Knowledge; +using ITSMSkill.Responses.Main; +using ITSMSkill.Responses.Shared; +using ITSMSkill.Responses.Ticket; +using ITSMSkill.Services; +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Fakes; +using ITSMSkill.Tests.Flow.Utterances; +using Luis; +using Microsoft.Bot.Builder; +using Microsoft.Bot.Builder.Adapters; +using Microsoft.Bot.Builder.AI.Luis; +using Microsoft.Bot.Builder.Skills.Auth; +using Microsoft.Bot.Builder.Solutions; +using Microsoft.Bot.Builder.Solutions.Authentication; +using Microsoft.Bot.Builder.Solutions.Responses; +using Microsoft.Bot.Builder.Solutions.TaskExtensions; +using Microsoft.Bot.Builder.Solutions.Testing; +using Microsoft.Bot.Connector; +using Microsoft.Bot.Schema; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json.Linq; + +namespace ITSMSkill.Tests.Flow +{ + public class SkillTestBase : BotTestBase + { + public static readonly string AuthenticationName = "ServiceNow"; + + public static readonly string AuthenticationProvider = "Generic Oauth 2"; + + public static readonly string MagicCode = "000000"; + + public static readonly string TestToken = "TestToken"; + + public IServiceCollection Services { get; set; } + + [TestInitialize] + public override void Initialize() + { + // Initialize service collection + Services = new ServiceCollection(); + + // Load settings + var settings = new BotSettings(); + settings.OAuthConnections = new List() + { + new OAuthConnection() { Name = AuthenticationProvider, Provider = AuthenticationProvider } + }; + settings.LimitSize = MockData.LimitSize; + settings.ServiceNowUrl = MockData.ServiceNowUrl; + settings.ServiceNowGetUserId = MockData.ServiceNowGetUserId; + Services.AddSingleton(settings); + Services.AddSingleton(settings); + + // Configure credentials + + // Configure telemetry + Services.AddSingleton(); + + // Configure bot services + Services.AddSingleton(); + Services.AddSingleton(new BotServices() + { + CognitiveModelSets = new Dictionary + { + { + "en", new CognitiveModelSet() + { + LuisServices = new Dictionary + { + { + "General", new BaseMockLuisRecognizer( + new GeneralTestUtterances()) + }, + { + "ITSM", new BaseMockLuisRecognizer( + new TicketCloseUtterances(), + new TicketCreateUtterances(), + new TicketShowUtterances(), + new TicketUpdateUtterances(), + new KnowledgeShowUtterances()) + } + } + } + } + } + }); + + // Configure storage + Services.AddSingleton(); + Services.AddSingleton(); + Services.AddSingleton(); + Services.AddSingleton(sp => + { + var userState = sp.GetService(); + var conversationState = sp.GetService(); + return new BotStateSet(userState, conversationState); + }); + + // Configure proactive + Services.AddSingleton(); + Services.AddHostedService(); + + // Configure responses + ResponseManager = new ResponseManager( + new string[] { "en", "de", "es", "fr", "it", "zh" }, + new MainResponses(), + new TicketResponses(), + new KnowledgeResponses(), + new SharedResponses()); + Services.AddSingleton(ResponseManager); + + // Configure service + Services.AddSingleton(); + + // Register dialogs + Services.AddTransient(); + Services.AddTransient(); + Services.AddTransient(); + Services.AddTransient(); + Services.AddTransient(); + Services.AddTransient(); + + // Configure adapters + Services.AddSingleton(); + + // Register WhiteListAuthProvider + Services.AddSingleton(); + + // Configure bot + Services.AddTransient>(); + } + + protected TestFlow GetTestFlow() + { + var sp = Services.BuildServiceProvider(); + var adapter = sp.GetService(); + adapter.AddUserToken(AuthenticationProvider, adapter.Conversation.ChannelId, adapter.Conversation.User.Id, TestToken, MagicCode); + + var testFlow = new TestFlow(adapter, async (context, token) => + { + var bot = sp.GetService(); + await bot.OnTurnAsync(context, CancellationToken.None); + }); + + return testFlow; + } + + protected Action ActionEndMessage() + { + return activity => + { + Assert.AreEqual(activity.Type, ActivityTypes.Handoff); + }; + } + + protected Action ShowAuth() + { + return activity => + { + var message = activity.AsMessageActivity(); + Assert.AreEqual(1, message.Attachments.Count); + Assert.AreEqual("application/vnd.microsoft.card.oauth", message.Attachments[0].ContentType); + }; + } + + protected Action AssertStartsWith(string response, StringDictionary tokens = null, params string[] cardIds) + { + return activity => + { + var messageActivity = activity.AsMessageActivity(); + + if (response == null) + { + Assert.IsTrue(string.IsNullOrEmpty(messageActivity.Text)); + } + else + { + var collection = ParseReplies(response, tokens ?? new StringDictionary()); + Assert.IsTrue(collection.Any((reply) => + { + return messageActivity.Text.StartsWith(reply); + })); + } + + AssertSameId(messageActivity, cardIds); + }; + } + + protected Action AssertContains(string response, StringDictionary tokens = null, params string[] cardIds) + { + return activity => + { + var messageActivity = activity.AsMessageActivity(); + + if (response == null) + { + Assert.IsTrue(string.IsNullOrEmpty(messageActivity.Text)); + } + else + { + var collection = ParseReplies(response, tokens ?? new StringDictionary()); + CollectionAssert.Contains(collection, messageActivity.Text); + } + + AssertSameId(messageActivity, cardIds); + }; + } + + private void AssertSameId(IMessageActivity activity, string[] cardIds = null) + { + if (cardIds == null) + { + Assert.AreEqual(activity.Attachments.Count, 0); + return; + } + + Assert.AreEqual(activity.Attachments.Count, cardIds.Length); + + for (int i = 0; i < cardIds.Length; ++i) + { + var card = activity.Attachments[i].Content as JObject; + Assert.AreEqual(card["id"], cardIds[i]); + } + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Strings/CardStrings.cs b/skills/csharp/tests/itsmskill.tests/Flow/Strings/CardStrings.cs new file mode 100644 index 0000000000..0009e8d056 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Strings/CardStrings.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ITSMSkill.Tests.Flow.Strings +{ + public static class CardStrings + { + public static readonly string Knowledge = "KnowledgeCard"; + + public static readonly string Ticket = "TicketCard"; + + public static readonly string TicketUpdate = "TicketUpdateCard"; + + public static readonly string TicketUpdateClose = "TicketUpdateCloseCard"; + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Strings/ContextStrings.cs b/skills/csharp/tests/itsmskill.tests/Flow/Strings/ContextStrings.cs new file mode 100644 index 0000000000..43b60c7c46 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Strings/ContextStrings.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ITSMSkill.Tests.Flow.Strings +{ + public static class ContextStrings + { + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/TicketCloseFlowTests.cs b/skills/csharp/tests/itsmskill.tests/Flow/TicketCloseFlowTests.cs new file mode 100644 index 0000000000..2633e841d4 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/TicketCloseFlowTests.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Specialized; +using System.Threading.Tasks; +using ITSMSkill.Responses.Knowledge; +using ITSMSkill.Responses.Shared; +using ITSMSkill.Responses.Ticket; +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using ITSMSkill.Tests.Flow.Utterances; +using ITSMSkill.Utilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ITSMSkill.Tests.Flow +{ + [TestClass] + public class TicketCloseFlowTests : SkillTestBase + { + [TestMethod] + public async Task CloseTest() + { + await this.GetTestFlow() + .Send(TicketCloseUtterances.Close) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(SharedResponses.InputTicketNumber)) + .Send(MockData.CloseTicketNumber) + .AssertReply(AssertContains(TicketResponses.TicketTarget, null, CardStrings.Ticket)) + .AssertReply(AssertContains(SharedResponses.InputReason)) + .Send(MockData.CloseTicketReason) + .AssertReply(AssertContains(TicketResponses.TicketClosed, null, CardStrings.TicketUpdate)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + + [TestMethod] + public async Task CloseWithNumberReasonTest() + { + var confirmReason = new StringDictionary + { + { "Reason", MockData.CloseTicketReason } + }; + + await this.GetTestFlow() + .Send(TicketCloseUtterances.CloseWithNumberReason) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(TicketResponses.TicketTarget, null, CardStrings.Ticket)) + .AssertReply(AssertStartsWith(SharedResponses.ConfirmReason, confirmReason)) + .Send(NonLuisUtterances.Yes) + .AssertReply(AssertContains(TicketResponses.TicketClosed, null, CardStrings.TicketUpdate)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/TicketCreateFlowTests.cs b/skills/csharp/tests/itsmskill.tests/Flow/TicketCreateFlowTests.cs new file mode 100644 index 0000000000..363826be1a --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/TicketCreateFlowTests.cs @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Specialized; +using System.Threading.Tasks; +using ITSMSkill.Responses.Knowledge; +using ITSMSkill.Responses.Shared; +using ITSMSkill.Responses.Ticket; +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using ITSMSkill.Tests.Flow.Utterances; +using ITSMSkill.Utilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ITSMSkill.Tests.Flow +{ + [TestClass] + public class TicketCreateFlowTests : SkillTestBase + { + [TestMethod] + public async Task CreateTest() + { + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + await this.GetTestFlow() + .Send(TicketCreateUtterances.Create) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(SharedResponses.InputTitle)) + .Send(MockData.CreateTicketTitle) + .AssertReply(AssertContains(KnowledgeResponses.ShowExistingToSolve)) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.Knowledge)) + .AssertReply(AssertStartsWith(KnowledgeResponses.IfExistingSolve, navigate)) + .Send(GeneralTestUtterances.Reject) + .AssertReply(AssertContains(SharedResponses.InputDescription)) + .Send(MockData.CreateTicketDescription) + .AssertReply(AssertStartsWith(SharedResponses.InputUrgency)) + .Send(NonLuisUtterances.CreateTicketUrgency) + .AssertReply(AssertContains(TicketResponses.TicketCreated, null, CardStrings.TicketUpdateClose)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + + [TestMethod] + public async Task CreateExistingSolveTest() + { + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + await this.GetTestFlow() + .Send(TicketCreateUtterances.Create) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(SharedResponses.InputTitle)) + .Send(MockData.CreateTicketTitle) + .AssertReply(AssertContains(KnowledgeResponses.ShowExistingToSolve)) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.Knowledge)) + .AssertReply(AssertStartsWith(KnowledgeResponses.IfExistingSolve, navigate)) + .Send(GeneralTestUtterances.Confirm) + .AssertReply(AssertContains(SharedResponses.ActionEnded)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + + [TestMethod] + public async Task CreateWithTitleUrgencyTest() + { + var confirmTitle = new StringDictionary + { + { "Title", MockData.CreateTicketTitle } + }; + + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + var confirmUrgency = new StringDictionary + { + { "Urgency", MockData.CreateTicketUrgencyLevel.ToLocalizedString() } + }; + + await this.GetTestFlow() + .Send(TicketCreateUtterances.CreateWithTitleUrgency) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertStartsWith(SharedResponses.ConfirmTitle, confirmTitle)) + .Send(NonLuisUtterances.Yes) + .AssertReply(AssertContains(KnowledgeResponses.ShowExistingToSolve)) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.Knowledge)) + .AssertReply(AssertStartsWith(KnowledgeResponses.IfExistingSolve, navigate)) + .Send(GeneralTestUtterances.Reject) + .AssertReply(AssertContains(SharedResponses.InputDescription)) + .Send(MockData.CreateTicketDescription) + .AssertReply(AssertStartsWith(SharedResponses.ConfirmUrgency, confirmUrgency)) + .Send(NonLuisUtterances.Yes) + .AssertReply(AssertContains(TicketResponses.TicketCreated, null, CardStrings.TicketUpdateClose)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + + [TestMethod] + public async Task CreateWithTitleUrgencyNotConfirmTest() + { + var confirmTitle = new StringDictionary + { + { "Title", MockData.CreateTicketTitle } + }; + + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + var confirmUrgency = new StringDictionary + { + { "Urgency", MockData.CreateTicketUrgencyLevel.ToLocalizedString() } + }; + + await this.GetTestFlow() + .Send(TicketCreateUtterances.CreateWithTitleUrgency) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertStartsWith(SharedResponses.ConfirmTitle, confirmTitle)) + .Send(NonLuisUtterances.No) + .AssertReply(AssertContains(SharedResponses.InputTitle)) + .Send(MockData.CreateTicketTitle) + .AssertReply(AssertContains(KnowledgeResponses.ShowExistingToSolve)) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.Knowledge)) + .AssertReply(AssertStartsWith(KnowledgeResponses.IfExistingSolve, navigate)) + .Send(GeneralTestUtterances.Reject) + .AssertReply(AssertContains(SharedResponses.InputDescription)) + .Send(MockData.CreateTicketDescription) + .AssertReply(AssertStartsWith(SharedResponses.ConfirmUrgency, confirmUrgency)) + .Send(NonLuisUtterances.No) + .AssertReply(AssertStartsWith(SharedResponses.InputUrgency)) + .Send(NonLuisUtterances.CreateTicketUrgency) + .AssertReply(AssertContains(TicketResponses.TicketCreated, null, CardStrings.TicketUpdateClose)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/TicketShowFlowTests.cs b/skills/csharp/tests/itsmskill.tests/Flow/TicketShowFlowTests.cs new file mode 100644 index 0000000000..20a716890e --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/TicketShowFlowTests.cs @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Specialized; +using System.Threading.Tasks; +using ITSMSkill.Responses.Knowledge; +using ITSMSkill.Responses.Shared; +using ITSMSkill.Responses.Ticket; +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using ITSMSkill.Tests.Flow.Utterances; +using ITSMSkill.Utilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ITSMSkill.Tests.Flow +{ + [TestClass] + public class TicketShowFlowTests : SkillTestBase + { + [TestMethod] + public async Task ShowTest() + { + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + var attribute = new StringDictionary + { + { "Attributes", string.Empty } + }; + + await this.GetTestFlow() + .Send(TicketShowUtterances.Show) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.TicketUpdateClose)) + .AssertReply(AssertStartsWith(TicketResponses.TicketShow, navigate)) + .Send(GeneralTestUtterances.Confirm) + .AssertReply(AssertStartsWith(TicketResponses.ShowAttribute)) + .Send(NonLuisUtterances.Text) + .AssertReply(AssertContains(SharedResponses.InputSearch)) + .Send(MockData.CreateTicketTitle) + .AssertReply(AssertStartsWith(TicketResponses.ShowAttribute)) + .Send(NonLuisUtterances.Urgency) + .AssertReply(AssertStartsWith(SharedResponses.InputUrgency)) + .Send(NonLuisUtterances.CreateTicketUrgency) + .AssertReply(AssertStartsWith(TicketResponses.ShowAttribute)) + .Send(NonLuisUtterances.No) + .AssertReply(AssertStartsWith(TicketResponses.ShowConstraints, attribute)) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.TicketUpdateClose)) + .AssertReply(AssertStartsWith(TicketResponses.TicketShow, navigate)) + .Send(GeneralTestUtterances.Reject) + .AssertReply(AssertContains(SharedResponses.ActionEnded)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + + [TestMethod] + public async Task ShowWithTitleTest() + { + var navigate = new StringDictionary + { + { "Navigate", string.Empty } + }; + + var attribute = new StringDictionary + { + { "Attributes", string.Empty } + }; + + await this.GetTestFlow() + .Send(TicketShowUtterances.ShowWithTitle) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertStartsWith(TicketResponses.ShowConstraints, attribute)) + .AssertReply(AssertContains(SharedResponses.ResultIndicator, null, CardStrings.TicketUpdateClose)) + .AssertReply(AssertStartsWith(TicketResponses.TicketShow, navigate)) + .Send(GeneralTestUtterances.Reject) + .AssertReply(AssertContains(SharedResponses.ActionEnded)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/TicketUpdateFlowTests.cs b/skills/csharp/tests/itsmskill.tests/Flow/TicketUpdateFlowTests.cs new file mode 100644 index 0000000000..2c8339852f --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/TicketUpdateFlowTests.cs @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Specialized; +using System.Threading.Tasks; +using ITSMSkill.Responses.Knowledge; +using ITSMSkill.Responses.Shared; +using ITSMSkill.Responses.Ticket; +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using ITSMSkill.Tests.Flow.Utterances; +using ITSMSkill.Utilities; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ITSMSkill.Tests.Flow +{ + [TestClass] + public class TicketUpdateFlowTests : SkillTestBase + { + [TestMethod] + public async Task UpdateTest() + { + var attribute = new StringDictionary() + { + { "Attributes", string.Empty } + }; + + await this.GetTestFlow() + .Send(TicketUpdateUtterances.Update) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(SharedResponses.InputTicketNumber)) + .Send(MockData.CreateTicketNumber) + .AssertReply(AssertContains(TicketResponses.TicketTarget, null, CardStrings.Ticket)) + .AssertReply(AssertContains(TicketResponses.UpdateAttribute)) + .Send(NonLuisUtterances.Title) + .AssertReply(AssertContains(SharedResponses.InputTitle)) + .Send(MockData.CreateTicketTitle) + .AssertReply(AssertStartsWith(TicketResponses.ShowUpdates, attribute)) + .AssertReply(AssertContains(TicketResponses.UpdateAttribute)) + .Send(NonLuisUtterances.No) + .AssertReply(AssertContains(TicketResponses.TicketUpdated, null, CardStrings.TicketUpdateClose)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + + [TestMethod] + public async Task UpdateWithNumberUrgencyTest() + { + var attribute = new StringDictionary() + { + { "Attributes", string.Empty } + }; + + await this.GetTestFlow() + .Send(TicketUpdateUtterances.UpdateWithNumberUrgency) + .AssertReply(ShowAuth()) + .Send(MagicCode) + .AssertReply(AssertContains(TicketResponses.TicketTarget, null, CardStrings.Ticket)) + .AssertReply(AssertStartsWith(TicketResponses.ShowUpdates, attribute)) + .AssertReply(AssertContains(TicketResponses.UpdateAttribute)) + .Send(NonLuisUtterances.No) + .AssertReply(AssertContains(TicketResponses.TicketUpdated, null, CardStrings.TicketUpdateClose)) + .AssertReply(ActionEndMessage()) + .StartTestAsync(); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/BaseTestUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/BaseTestUtterances.cs new file mode 100644 index 0000000000..a0dd4bad1a --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/BaseTestUtterances.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public abstract class BaseTestUtterances : Dictionary + { + public static double TopIntentScore { get; } = 0.9; + + public abstract T NoneIntent { get; } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/GeneralTestUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/GeneralTestUtterances.cs new file mode 100644 index 0000000000..df968cd48f --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/GeneralTestUtterances.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using Luis; +using Microsoft.Bot.Builder; +using static Luis.GeneralLuis; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public class GeneralTestUtterances : BaseTestUtterances + { + public static readonly string Cancel = "cancel"; + + public static readonly string Help = "help"; + + public static readonly string Logout = "log out"; + + public static readonly string None = "hello"; + + public static readonly string Confirm = "yeah go ahead"; + + public static readonly string Reject = "negative"; + + public GeneralTestUtterances() + { + AddIntent(Cancel, Intent.Cancel); + AddIntent(Help, Intent.Help); + AddIntent(Logout, Intent.Logout); + AddIntent(Confirm, Intent.Confirm); + AddIntent(Reject, Intent.Reject); + } + + public override GeneralLuis NoneIntent { get; } = new GeneralLuis + { + Intents = new Dictionary + { + { Intent.None, new IntentScore() { Score = TopIntentScore } } + } + }; + + protected void AddIntent( + string userInput, + Intent intent) + { + var generalIntent = new GeneralLuis + { + Text = userInput, + Intents = new Dictionary + { + { intent, new IntentScore() { Score = TopIntentScore } } + } + }; + + Add(userInput, generalIntent); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/ITSMTestUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/ITSMTestUtterances.cs new file mode 100644 index 0000000000..8912454d9b --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/ITSMTestUtterances.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using Luis; +using Microsoft.Bot.Builder; +using static Luis.ITSMLuis; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public class ITSMTestUtterances : BaseTestUtterances + { + public override ITSMLuis NoneIntent { get; } = new ITSMLuis + { + Intents = new Dictionary + { + { Intent.None, new IntentScore() { Score = TopIntentScore } } + } + }; + + protected void AddIntent( + string userInput, + Intent intent, + string[][] attributeType = null, + string[][] ticketState = null, + string[][] urgencyLevel = null, + string[] ticketNumber = null, + string[] closeReason = null, + string[] ticketTitle = null) + { + var resultIntent = new ITSMLuis + { + Text = userInput, + Intents = new Dictionary + { + { intent, new IntentScore() { Score = TopIntentScore } } + } + }; + + resultIntent.Entities = new _Entities + { + AttributeType = attributeType, + TicketState = ticketState, + UrgencyLevel = urgencyLevel, + TicketNumber = ticketNumber, + CloseReason = closeReason, + TicketTitle = ticketTitle + }; + + Add(userInput, resultIntent); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/KnowledgeShowUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/KnowledgeShowUtterances.cs new file mode 100644 index 0000000000..3b07f0b6d6 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/KnowledgeShowUtterances.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using static Luis.ITSMLuis; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public class KnowledgeShowUtterances : ITSMTestUtterances + { + public static readonly string Show = "search knowledgebase"; + + public KnowledgeShowUtterances() + { + AddIntent(Show, Intent.KnowledgeShow); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/NonLuisUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/NonLuisUtterances.cs new file mode 100644 index 0000000000..81d6e1e4e2 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/NonLuisUtterances.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public static class NonLuisUtterances + { + public static readonly string CreateTicketUrgency = "low"; + + public static readonly string Yes = "yes"; + + public static readonly string No = "no"; + + public static readonly string Text = "text"; + + public static readonly string Urgency = "urgency"; + + public static readonly string Title = "title"; + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCloseUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCloseUtterances.cs new file mode 100644 index 0000000000..22f49b7c76 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCloseUtterances.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using static Luis.ITSMLuis; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public class TicketCloseUtterances : ITSMTestUtterances + { + public static readonly string Close = "close my ticket"; + + public static readonly string CloseWithNumberReason = $"close {MockData.CloseTicketNumber} because {MockData.CloseTicketReason}"; + + public TicketCloseUtterances() + { + AddIntent(Close, Intent.TicketClose); + AddIntent(CloseWithNumberReason, Intent.TicketClose, closeReason: new string[] { MockData.CloseTicketReason }, ticketNumber: new string[] { MockData.CloseTicketNumber }); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCreateUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCreateUtterances.cs new file mode 100644 index 0000000000..086cc3282f --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketCreateUtterances.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using static Luis.ITSMLuis; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public class TicketCreateUtterances : ITSMTestUtterances + { + public static readonly string Create = "create a ticket"; + + public static readonly string CreateWithTitleUrgency = $"create an urgency {NonLuisUtterances.CreateTicketUrgency} ticket about {MockData.CreateTicketTitle}"; + + public TicketCreateUtterances() + { + AddIntent(Create, Intent.TicketCreate); + AddIntent(CreateWithTitleUrgency, Intent.TicketCreate, urgencyLevel: new string[][] { new string[] { MockData.CreateTicketUrgencyLevel.ToString() } }, ticketTitle: new string[] { MockData.CreateTicketTitle }); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketShowUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketShowUtterances.cs new file mode 100644 index 0000000000..fa496bf9f5 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketShowUtterances.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using static Luis.ITSMLuis; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public class TicketShowUtterances : ITSMTestUtterances + { + public static readonly string Show = "show my tickets"; + + public static readonly string ShowWithTitle = $"show my tickets about {MockData.CreateTicketTitle}"; + + public TicketShowUtterances() + { + AddIntent(Show, Intent.TicketShow); + AddIntent(ShowWithTitle, Intent.TicketShow, ticketTitle: new string[] { MockData.CreateTicketTitle }); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketUpdateUtterances.cs b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketUpdateUtterances.cs new file mode 100644 index 0000000000..6e16ee1155 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/Flow/Utterances/TicketUpdateUtterances.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using ITSMSkill.Models; +using ITSMSkill.Tests.API.Fakes; +using ITSMSkill.Tests.Flow.Strings; +using static Luis.ITSMLuis; + +namespace ITSMSkill.Tests.Flow.Utterances +{ + public class TicketUpdateUtterances : ITSMTestUtterances + { + public static readonly string Update = "i would like to update a ticket"; + + public static readonly string UpdateWithNumberUrgency = $"update ticket {MockData.CreateTicketNumber}'s urgency to {MockData.CreateTicketUrgency}"; + + public TicketUpdateUtterances() + { + AddIntent(Update, Intent.TicketUpdate); + AddIntent(UpdateWithNumberUrgency, Intent.TicketUpdate, attributeType: new string[][] { new string[] { AttributeType.Urgency.ToString() } }, urgencyLevel: new string[][] { new string[] { MockData.CreateTicketUrgencyLevel.ToString() } }, ticketNumber: new string[] { MockData.CreateTicketNumber }); + } + } +} diff --git a/skills/csharp/tests/itsmskill.tests/ITSMSkill.Tests.csproj b/skills/csharp/tests/itsmskill.tests/ITSMSkill.Tests.csproj new file mode 100644 index 0000000000..e8a8f04f37 --- /dev/null +++ b/skills/csharp/tests/itsmskill.tests/ITSMSkill.Tests.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp2.2 + + false + + ITSMSkill.Tests + + ITSMSkill.Tests + + + + + + + + + + + + + +