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

Extend end-to-end tests #983

Merged
merged 7 commits into from
Dec 2, 2023
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
10 changes: 10 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ jobs:
run: dotnet test ./test/LondonTravel.Skill.EndToEndTests --configuration Release --logger "GitHubActions;report-warnings=false"
env:
LAMBDA_FUNCTION_NAME: ${{ env.LAMBDA_FUNCTION }}-dev
LWA_CLIENT_ID: ${{ secrets.LWA_CLIENT_ID }}
LWA_CLIENT_SECRET: ${{ secrets.LWA_CLIENT_SECRET }}
LWA_REFRESH_TOKEN: ${{ secrets.LWA_REFRESH_TOKEN }}
SKILL_ID: ${{ secrets.SKILL_ID }}
SKILL_STAGE: development

deploy-prod:
name: production
Expand Down Expand Up @@ -327,3 +332,8 @@ jobs:
run: dotnet test ./test/LondonTravel.Skill.EndToEndTests --configuration Release --logger "GitHubActions;report-warnings=false"
env:
LAMBDA_FUNCTION_NAME: ${{ env.LAMBDA_FUNCTION }}
LWA_CLIENT_ID: ${{ secrets.LWA_CLIENT_ID }}
LWA_CLIENT_SECRET: ${{ secrets.LWA_CLIENT_SECRET }}
LWA_REFRESH_TOKEN: ${{ secrets.LWA_REFRESH_TOKEN }}
SKILL_ID: ${{ secrets.SKILL_ID }}
SKILL_STAGE: live
5 changes: 5 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,12 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
LAMBDA_FUNCTION_NAME: ${{ needs.setup.outputs.function-name }}
LWA_CLIENT_ID: ${{ secrets.LWA_CLIENT_ID }}
LWA_CLIENT_SECRET: ${{ secrets.LWA_CLIENT_SECRET }}
LWA_REFRESH_TOKEN: ${{ secrets.LWA_REFRESH_TOKEN }}
PULL_NUMBER: ${{ github.event.issue.number }}
SKILL_ID: ${{ secrets.SKILL_ID }}
SKILL_STAGE: development

- name: Post comment
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
Expand Down
56 changes: 56 additions & 0 deletions static/interaction-model.json
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,62 @@
]
}
]
},
"_nameFreeInteraction": {
"ingressPoints": [
{
"type": "INTENT",
"sampleUtterances": [
{
"format": "RAW_TEXT",
"value": "Are there any problems with London Underground"
},
{
"format": "RAW_TEXT",
"value": "Are there any engineering works on the tube today"
},
{
"format": "RAW_TEXT",
"value": "Are there delays on the underground right now"
},
{
"format": "RAW_TEXT",
"value": "Is there any disruption on the tube"
},
{
"format": "RAW_TEXT",
"value": "Tube delays"
}
],
"name": "DisruptionIntent"
},
{
"type": "INTENT",
"sampleUtterances": [
{
"format": "RAW_TEXT",
"value": "Are there any delays on the Central Line"
},
{
"format": "RAW_TEXT",
"value": "Are there any engineering works on the Victoria Line this weekend"
},
{
"format": "RAW_TEXT",
"value": "Is the Northern Line suspended"
},
{
"format": "RAW_TEXT",
"value": "Is there any disruption on the District Line today"
},
{
"format": "RAW_TEXT",
"value": "What problems are there on the Piccadilly line"
}
],
"name": "StatusIntent"
}
]
}
}
}
58 changes: 58 additions & 0 deletions static/skill.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"manifest": {
"publishingInformation": {
"locales": {
"en-GB": {
"summary": "Find out the current status of public transport in London.",
"examplePhrases": [
"Alexa, ask London Travel what\u0027s the status of the Northern line",
"Alexa, ask London Travel are there any line closures",
"Alexa, ask London Travel about my commute"
],
"keywords": [
"london",
"travel",
"tube",
"tfl",
"dlr",
"underground",
"overground"
],
"name": "London Travel",
"description": "This skill allows you to ask Alexa for information about disruption on public transport in London.\n\nFor example, you can ask about disruption affecting London Underground, London Overground, the Docklands Light Railway (DLR) and TfL Rail as a whole, or you can ask for information about a specific line.\n\nIf you create an account with London Travel and link it with the Alexa app, you can also ask about your commute for your favourite lines. You can create an account with London Travel using a login for existing accounts with other services, such as Amazon, Facebook and Twitter.\n\nYou can manage your London Travel account and set up your preferences at https://londontravel.martincostello.com/.",
"smallIconUri": "file://icon-108x108.png",
"largeIconUri": "file://icon-512x512.png"
}
},
"isAvailableWorldwide": false,
"testingInstructions": "To create an account for testing account linking, you must have an existing account with any of the following services:\n\nAmazon\nFacebook\nMicrosoft\nTwitter\n\nGoogle can be used to create an account in the website, but it cannot be used to link an account from the skill due to Google restrictions on sign-in from in-app browsers.\n\nTo test the \"commute\" intent, you must have created an account, selected at least one favourite tube line, and linked it to the Alexa app.",
"category": "PUBLIC_TRANSPORTATION",
"distributionCountries": [
"GB"
]
},
"apis": {
"custom": {
"endpoint": {
"uri": ""
},
"interfaces": []
}
},
"manifestVersion": "1.0",
"permissions": [],
"privacyAndCompliance": {
"allowsPurchases": false,
"locales": {
"en-GB": {
"termsOfUseUrl": "https://londontravel.martincostello.com/terms-of-service/",
"privacyPolicyUrl": "https://londontravel.martincostello.com/privacy-policy/"
}
},
"containsAds": false,
"isExportCompliant": true,
"isChildDirected": false,
"usesPersonalInfo": true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

using System.Net.Http.Json;
using System.Reflection;
using Amazon;
using Amazon.CloudWatchLogs;
using Xunit.Sdk;
Expand All @@ -24,9 +23,9 @@ public async Task DisposeAsync()
return;
}

var credentials = AwsConfiguration.GetCredentials();
string functionName = AwsConfiguration.FunctionName;
string regionName = AwsConfiguration.RegionName;
var credentials = TestConfiguration.GetCredentials();
string functionName = TestConfiguration.FunctionName;
string regionName = TestConfiguration.RegionName;

if (functionName is not null &&
regionName is not null &&
Expand Down Expand Up @@ -205,7 +204,7 @@ private static async Task TryPostLogsToPullRequestAsync(IEnumerable<LogEvent> ev
{
Accept = { new("application/vnd.github+json") },
Authorization = new("Bearer", token),
UserAgent = { new("LondonTravel.Skill.EndToEndTests", typeof(CloudWatchLogsFixture).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion) },
UserAgent = { TestConfiguration.UserAgent },
},
};

Expand Down
104 changes: 104 additions & 0 deletions test/LondonTravel.Skill.EndToEndTests/LambdaTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) Martin Costello, 2017. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

using System.Net;
using System.Text.Json;
using Amazon;
using Amazon.Lambda;
using Amazon.Lambda.Model;
using LondonTravel.Skill.EndToEndTests;

namespace MartinCostello.LondonTravel.Skill;

[Collection(CloudWatchLogsFixtureCollection.Name)]
public class LambdaTests(CloudWatchLogsFixture fixture, ITestOutputHelper outputHelper)
{
public static IEnumerable<object[]> Payloads
{
get
{
return Directory.GetFiles("Payloads")
.Select(Path.GetFileNameWithoutExtension)
.Order()
.Select((p) => new object[] { p })
.ToArray();
}
}

[SkippableTheory]
[MemberData(nameof(Payloads))]
public async Task Can_Invoke_Intent_Can_Get_Json_Response(string payloadName)
{
var credentials = TestConfiguration.GetCredentials();

Skip.If(credentials is null, "No AWS credentials are configured.");

string functionName = TestConfiguration.FunctionName;
string regionName = TestConfiguration.RegionName;

Skip.If(string.IsNullOrEmpty(functionName), "No Lambda function name is configured.");
Skip.If(string.IsNullOrEmpty(regionName), "No AWS region name is configured.");

// Arrange
string payload = await File.ReadAllTextAsync(Path.Combine("Payloads", $"{payloadName}.json"));

var region = RegionEndpoint.GetBySystemName(regionName);

using var client = new AmazonLambdaClient(credentials, region);

var request = new InvokeRequest()
{
FunctionName = functionName,
InvocationType = InvocationType.RequestResponse,
LogType = LogType.None,
Payload = payload,
};

outputHelper.WriteLine($"FunctionName: {request.FunctionName}");
outputHelper.WriteLine($"Payload: {request.Payload}");

// Act
InvokeResponse invocation = await client.InvokeAsync(request);

// Assert
invocation.ShouldNotBeNull();
invocation.ResponseMetadata.ShouldNotBeNull();

fixture.Requests[invocation.ResponseMetadata.RequestId] = payloadName;

using var reader = new StreamReader(invocation.Payload);
string responsePayload = await reader.ReadToEndAsync();

outputHelper.WriteLine($"ExecutedVersion: {invocation.ExecutedVersion}");
outputHelper.WriteLine($"FunctionError: {invocation.FunctionError}");
outputHelper.WriteLine($"HttpStatusCode: {invocation.HttpStatusCode}");
outputHelper.WriteLine($"RequestId: {invocation.ResponseMetadata.RequestId}");
outputHelper.WriteLine($"StatusCode: {invocation.StatusCode}");
outputHelper.WriteLine($"Payload: {responsePayload}");

invocation.HttpStatusCode.ShouldBe(HttpStatusCode.OK);
invocation.StatusCode.ShouldBe(200);
invocation.FunctionError.ShouldBeNull();
invocation.ExecutedVersion.ShouldBe("$LATEST");

using var document = JsonDocument.Parse(responsePayload);

document.RootElement.ValueKind.ShouldBe(JsonValueKind.Object);
document.RootElement.ToString().ShouldNotContain("Sorry, something went wrong.");

document.RootElement.TryGetProperty("version", out var version).ShouldBeTrue();
version.GetString().ShouldBe("1.0");

document.RootElement.TryGetProperty("response", out var response).ShouldBeTrue();
response.TryGetProperty("shouldEndSession", out _).ShouldBeTrue();

if (response.TryGetProperty("outputSpeech", out var speech))
{
speech.TryGetProperty("type", out var type).ShouldBeTrue();
type.GetString().ShouldBe("SSML");

speech.TryGetProperty("ssml", out var ssml).ShouldBeTrue();
ssml.GetString().ShouldNotBeNullOrWhiteSpace();
}
}
}
Loading