Skip to content

Commit

Permalink
Update TestToolv2 Lambda Runtime API to partition the events per list…
Browse files Browse the repository at this point in the history
…ening function and support for RequestResponse invocation type.
  • Loading branch information
normj committed Dec 20, 2024
1 parent 8b90fa5 commit 9403f85
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@page "/"
@page "/"

@using Amazon.Lambda.TestTool.Commands
@using Amazon.Lambda.TestTool.Services
Expand All @@ -9,7 +9,7 @@
@using Microsoft.AspNetCore.Http;

@inject IHttpContextAccessor HttpContextAccessor
@inject IRuntimeApiDataStore RuntimeApiModel
@inject IRuntimeApiDataStoreManager DataStoreManager
@inject IDirectoryManager DirectoryManager

<PageTitle>Lambd Function Tester</PageTitle>
Expand Down Expand Up @@ -58,33 +58,33 @@
</div>
<div class="col-sm-6">
<h3>Active Event:</h3>
@if (RuntimeApiModel.ActiveEvent == null)
@if (DataStore.ActiveEvent == null)
{
<h2>No active event</h2>
}
else
{
<div>
<div style="cursor: pointer" @onclick="() => OnRequeue(RuntimeApiModel.ActiveEvent.AwsRequestId)">
<div style="cursor: pointer" @onclick="() => OnRequeue(DataStore.ActiveEvent.AwsRequestId)">
@((MarkupString)REBOOT_ICON)
</div>
<p><b>Request ID:</b> @RuntimeApiModel.ActiveEvent.AwsRequestId</p>
<p><b>Status:</b> <span style="@GetStatusStyle(RuntimeApiModel.ActiveEvent.EventStatus)">@RuntimeApiModel.ActiveEvent.EventStatus</span></p>
<p><b>Last Updated:</b> @RuntimeApiModel.ActiveEvent.LastUpdated</p>
<p><b>Event JSON:</b><span class="event-value"><span class="fake-link" @onclick="() => ShowEventJson(RuntimeApiModel.ActiveEvent)">@CreateSnippet(RuntimeApiModel.ActiveEvent.EventJson)</span></span></p>
@if (RuntimeApiModel.ActiveEvent.EventStatus == EventContainer.Status.Failure)
<p><b>Request ID:</b> @DataStore.ActiveEvent.AwsRequestId</p>
<p><b>Status:</b> <span style="@GetStatusStyle(DataStore.ActiveEvent.EventStatus)">@DataStore.ActiveEvent.EventStatus</span></p>
<p><b>Last Updated:</b> @DataStore.ActiveEvent.LastUpdated</p>
<p><b>Event JSON:</b><span class="event-value"><span class="fake-link" @onclick="() => ShowEventJson(DataStore.ActiveEvent)">@CreateSnippet(DataStore.ActiveEvent.EventJson)</span></span></p>
@if (DataStore.ActiveEvent.EventStatus == EventContainer.Status.Failure)
{
<p><b>Error Type:</b> @RuntimeApiModel.ActiveEvent.ErrorType</p>
<p><b>Error Type:</b> @DataStore.ActiveEvent.ErrorType</p>
<p>
<b>Error Response:</b>
<pre class="form-control" style="@Constants.ResponseErrorStyleSizeConstraint">@RuntimeApiModel.ActiveEvent.ErrorResponse</pre>
<pre class="form-control" style="@Constants.ResponseErrorStyleSizeConstraint">@DataStore.ActiveEvent.ErrorResponse</pre>
</p>
}
else
{
<p>
<b>Response:</b>
<pre class="form-control" style="@Constants.ResponseSuccessStyleSizeConstraint">@Utils.TryPrettyPrintJson(RuntimeApiModel.ActiveEvent.Response)</pre>
<pre class="form-control" style="@Constants.ResponseSuccessStyleSizeConstraint">@Utils.TryPrettyPrintJson(DataStore.ActiveEvent.Response)</pre>
</p>
}
</div>
Expand All @@ -97,7 +97,7 @@
<div class="col-sm-6">
<h3>Queued Events: <button class="btn btn-secondary btn-sm" @onclick="OnClearQueued">Clear</button></h3>
<div class="col-xs-5 event-list">
@foreach (var evnt in @RuntimeApiModel.QueuedEvents)
@foreach (var evnt in @DataStore.QueuedEvents)
{
<div class="event-list-item">
<div class="row" style="padding: 2px">
Expand All @@ -119,7 +119,7 @@
<div class="col-sm-6">
<h3>Executed Events: <button class="btn btn-secondary btn-sm" @onclick="OnClearExecuted">Clear</button></h3>
<div class="col-xs-5 event-list">
@foreach (var evnt in @RuntimeApiModel.ExecutedEvents.OrderByDescending(x => x.LastUpdated))
@foreach (var evnt in @DataStore.ExecutedEvents.OrderByDescending(x => x.LastUpdated))
{
<div class="event-list-item">
<div class="row" style="padding: 2px">
Expand Down Expand Up @@ -183,6 +183,8 @@

private IDictionary<string, IList<LambdaRequest>> SampleRequests { get; set; } = new Dictionary<string, IList<LambdaRequest>>();

private IRuntimeApiDataStore DataStore => DataStoreManager.GetLambdaRuntimeDataStore(LambdaRuntimeApi.DefaultFunctionName);

string? _selectedSampleRequestName;
string? SelectedSampleRequestName
{
Expand All @@ -209,7 +211,7 @@

protected override void OnInitialized()
{
RuntimeApiModel.StateChange += RuntimeApiModelOnStateChange;
DataStore.StateChange += RuntimeApiModelOnStateChange;
this.SampleRequestManager = new SampleRequestManager(DirectoryManager.GetCurrentDirectory());
this.SampleRequests = SampleRequestManager.GetSampleRequests();
}
Expand All @@ -221,46 +223,46 @@

void OnAddEventClick()
{
RuntimeApiModel.QueueEvent(this.FunctionInput);
DataStore.QueueEvent(this.FunctionInput, false);
this.FunctionInput = "";
this.SelectedSampleRequestName = NO_SAMPLE_SELECTED_ID;
this.StateHasChanged();
}

void OnClearQueued()
{
this.RuntimeApiModel.ClearQueued();
this.DataStore.ClearQueued();
this.StateHasChanged();
}

void OnClearExecuted()
{
this.RuntimeApiModel.ClearExecuted();
this.DataStore.ClearExecuted();
this.StateHasChanged();
}

void OnRequeue(string awsRequestId)
{
EventContainer? evnt = null;
if (string.Equals(this.RuntimeApiModel.ActiveEvent?.AwsRequestId, awsRequestId))
if (string.Equals(this.DataStore.ActiveEvent?.AwsRequestId, awsRequestId))
{
evnt = this.RuntimeApiModel.ActiveEvent;
evnt = this.DataStore.ActiveEvent;
}
else
{
evnt = this.RuntimeApiModel.ExecutedEvents.FirstOrDefault(x => string.Equals(x.AwsRequestId, awsRequestId));
evnt = this.DataStore.ExecutedEvents.FirstOrDefault(x => string.Equals(x.AwsRequestId, awsRequestId));
}

if (evnt == null)
return;

this.RuntimeApiModel.QueueEvent(evnt.EventJson);
this.DataStore.QueueEvent(evnt.EventJson, false);
this.StateHasChanged();
}

void OnDeleteEvent(string awsRequestId)
{
this.RuntimeApiModel.DeleteEvent(awsRequestId);
this.DataStore.DeleteEvent(awsRequestId);
this.StateHasChanged();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using Amazon.Lambda.TestTool.Services;

namespace Amazon.Lambda.TestTool.Models;

public class EventContainer
public class EventContainer : IDisposable
{
public enum Status { Queued, Executing, Success, Failure }

Expand All @@ -21,6 +21,9 @@ public enum Status { Queued, Executing, Success, Failure }
public DateTime LastUpdated { get; private set; }

private Status _status = Status.Queued;

private ManualResetEventSlim? _resetEvent;

public Status EventStatus
{
get => _status;
Expand All @@ -33,12 +36,17 @@ public Status EventStatus

private readonly RuntimeApiDataStore _dataStore;

public EventContainer(RuntimeApiDataStore dataStore, int eventCount, string eventJson)
public EventContainer(RuntimeApiDataStore dataStore, int eventCount, string eventJson, bool isRequestResponseMode)
{
LastUpdated = DateTime.Now;
_dataStore = dataStore;
AwsRequestId = eventCount.ToString("D12");
EventJson = eventJson;

if (isRequestResponseMode)
{
_resetEvent = new ManualResetEventSlim(false);
}
}

public string FunctionArn
Expand All @@ -51,6 +59,12 @@ public void ReportSuccessResponse(string response)
LastUpdated = DateTime.Now;
Response = response;
EventStatus = Status.Success;

if (_resetEvent != null)
{
_resetEvent.Set();
}

_dataStore.RaiseStateChanged();
}

Expand All @@ -60,6 +74,50 @@ public void ReportErrorResponse(string errorType, string errorBody)
ErrorType = errorType;
ErrorResponse = errorBody;
EventStatus = Status.Failure;

if (_resetEvent != null)
{
_resetEvent.Set();
}

_dataStore.RaiseStateChanged();
}

public bool WaitForCompletion()
{
if (_resetEvent == null)
{
return false;
}

// The 15 minutes is a fail safe so we at some point we unblock the thread. It is intentionally
// long to give the user time to debug the Lambda function.
return _resetEvent.Wait(TimeSpan.FromMinutes(15));
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}

if (disposing)
{
if (_resetEvent != null)
{
_resetEvent.Dispose();
_resetEvent = null;
}
}

_disposed = true;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using Amazon.Lambda.TestTool.Commands.Settings;
Expand Down Expand Up @@ -37,7 +37,7 @@ public static TestToolProcess Startup(RunCommandSettings settings, CancellationT
{
var builder = WebApplication.CreateBuilder();

builder.Services.AddSingleton<IRuntimeApiDataStore, RuntimeApiDataStore>();
builder.Services.AddSingleton<IRuntimeApiDataStoreManager, RuntimeApiDataStoreManager>();

// Add services to the container.
builder.Services.AddRazorComponents()
Expand Down Expand Up @@ -65,7 +65,7 @@ public static TestToolProcess Startup(RunCommandSettings settings, CancellationT
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();

_ = new LambdaRuntimeApi(app, app.Services.GetService<IRuntimeApiDataStore>()!);
LambdaRuntimeApi.SetupLambdaRuntimeApiEndpoints(app);

var runTask = app.RunAsync(cancellationToken);

Expand Down
Loading

0 comments on commit 9403f85

Please sign in to comment.