Skip to content
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
15 changes: 9 additions & 6 deletions Examples/MovieProject/MovieProject.Web/StartupStubbing.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@ public static IServiceCollection AddInterceptionAndStubs(this IServiceCollection
return serviceCollection.InterceptHttpCallsAfterSending(async (intercept) =>
{
bool IsHappyPath = false;

// we check content length because downstream returns a 200 for not found, we can tell by the size it's likely a bad response
if (intercept.Response?.IsSuccessStatusCode ?? false && intercept.Response.Content.Headers.ContentLength > 100)
{
IsHappyPath = true;
if (intercept.Request.RequestUri.ToString().Contains("omdb"))
{
var movieName = intercept.Request.GetQueryValue("t");
await intercept.SaveAsRecording("omdb/new/happy", movieName.Replace(" ", "_"), 1);
await intercept.SaveAsRecording("omdb/new/happy", movieName.Replace(" ", "_"), 1); // save only 1 happy response per movie name
}
else
{
var action = intercept.Request.GetSoapAction();
var action = intercept.Request.GetSoapAction(); // it's a SOAP method, so we grab the action to best describe it
action = action.Split("/").LastOrDefault();
await intercept.SaveAsRecording("math/new/happy", action, howManyFilesToKeep: 50);
await intercept.SaveAsRecording("math/new/happy", action, howManyFilesToKeep: 50); // save up to 50 happy responses for action
}
}

Expand All @@ -38,14 +39,13 @@ public static IServiceCollection AddInterceptionAndStubs(this IServiceCollection
}

if (IsHappyPath)
return intercept.KeepResultUnchanged();

await intercept.SaveAsRecording("new/unhappy");
return intercept.KeepResultUnchanged(); // the real downstream system returned a good response, no reason to replace with stubs

var message = intercept.Summarize();

logger.LogError(intercept.Exception, message);

// get the most recent recording (stub), so we can be sure to be testing against the latest if possible
var recentRecording = RecordingCollection.Recordings.FirstOrDefault(
recording => recording.File.Contains("new/happy")
&& recording.Request.RequestUri.PathAndQuery == intercept.Request.RequestUri.PathAndQuery
Expand All @@ -54,6 +54,8 @@ public static IServiceCollection AddInterceptionAndStubs(this IServiceCollection
if (recentRecording != null)
return intercept.ReturnRecording(recentRecording, message);

// fall back #1, return a recording from the pre-approved folder, stored in github and vouched by a developer; might not be the latest
// but returns a good response to unblock developers
var oldRecording = RecordingCollection.Recordings.FirstOrDefault(
recording => recording.File.Contains("pre-approved/happy")
&& recording.Request.RequestUri.PathAndQuery == intercept.Request.RequestUri.PathAndQuery
Expand All @@ -62,6 +64,7 @@ public static IServiceCollection AddInterceptionAndStubs(this IServiceCollection
if (oldRecording != null)
return intercept.ReturnRecording(oldRecording, message);

// fall back #2, we return a dummy response
var fallBackRecording = RecordingCollection.Recordings.FirstOrDefault(
recording => recording.File.Contains("last_fallback"));

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ services.AddSingleton<ICalculatorSoap, CalculatorSoapClient>(factory => {
return client;
});
```
[Real life example](/Examples/MovieProject/MovieProject.Web/Startup.cs#L99)
[Real life example](/Examples/MovieProject/MovieProject.Web/Startup.cs#L115)

And then you can stub WCF Http calls, example (and you can use the header filters to avoid crossed wires):
```C#
Expand Down Expand Up @@ -404,6 +404,9 @@ It can store (in the designated folder) user private data or other confidential

If that's a concern, make sure you only enable this function in non production environments; and leave the option to have a configuration to disable it in an emergency, just in case.

[Example](/Examples/MovieProject/MovieProject.Web/Startup.cs#L64)


## 2 -The recorder generated file format divider

The recorder function generates files which a comment section at the top, with metadata and request information, and the response (in Fiddler like format) at the bottom.
Expand Down
2 changes: 1 addition & 1 deletion Tool/SystemTestingTools.UnitTests/RecordingManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public async Task GetRecordings_Works()
var sut = new RecordingManager(folder);

// act
var recordings = sut.GetRecordings();
var recordings = sut.GetRecordings(folder);

// asserts
recordings.Count.Should().Be(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ public static IServiceCollection InterceptHttpCallsAfterSending(this IServiceCol
Constants.GlobalConfiguration = config;
Constants.GlobalRecordingManager = new RecordingManager(config.RootStubsFolder);

serviceCollection.Replace(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, InterceptionFilter>((_) => new InterceptionFilter(() => new HttpCallInterceptor(false))));
serviceCollection.Replace(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, InterceptionFilter>((_) => new InterceptionFilter(() => new HttpCallInterceptor(false))));

RecordingCollection.Recordings.AddRange(Constants.GlobalRecordingManager.GetRecordings());
RecordingCollection.LoadFrom(config.RootStubsFolder);

return serviceCollection;
}
Expand Down
10 changes: 5 additions & 5 deletions Tool/SystemTestingTools/Internal/RecordingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,28 +43,28 @@ public string Save(RequestResponse log, FolderRelativePath relativeFolder = null
return finalFileName;
}

public List<Recording> GetRecordings()
public List<Recording> GetRecordings(FolderAbsolutePath folder)
{
var list = new List<Recording>();

foreach (var fullFilePath in _fileSystem.GetTextFileNames(baseDirectory))
foreach (var fullFilePath in _fileSystem.GetTextFileNames(folder))
{
var content = _fileSystem.ReadContent(fullFilePath);
if (!RecordingFormatter.IsValid(content)) continue;
var recording = RecordingFormatter.Read(content);
if (recording == null) continue;
recording.File = StandardizeFileNameForDisplay(fullFilePath);
recording.File = StandardizeFileNameForDisplay(folder, fullFilePath);
list.Add(recording);
}
return list;
}

private string StandardizeFileNameForDisplay(string str)
private static string StandardizeFileNameForDisplay(FolderAbsolutePath folder, string str)
{
// we replace something like C:\Users\AlanPC\Documents\GitHub\SystemTestingTools\Tool\SystemTestingTools.UnitTests\files/recordings\200\TheMatrix.txt
// to happy/TheMatrix, so we can easily search by folder name

return str.Replace(baseDirectory, "").Replace(".txt", "").TrimStart('/', '\\').Replace("\\","/");
return str.Replace(folder, "").Replace(".txt", "").TrimStart('/', '\\').Replace("\\","/");
}

private FileName GetFinalFileName(string finalFolder, FileName fileName, int howManyFilesToKeep)
Expand Down
11 changes: 11 additions & 0 deletions Tool/SystemTestingTools/RecordingCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@

namespace SystemTestingTools
{
/// <summary>
/// Collection of recording files
/// </summary>
public static class RecordingCollection
{
/// <summary>
/// The list of recordings available for usage
/// </summary>
public static List<Recording> Recordings = new List<Recording>();

internal static void LoadFrom(FolderAbsolutePath folder)
{
Recordings.AddRange(Constants.GlobalRecordingManager.GetRecordings(folder));
}
}
}
10 changes: 10 additions & 0 deletions Tool/SystemTestingTools/SystemTestingTools.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.