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

Enable to playback track 1 session record for track 2 mgmt sdk test cases #11535

Merged
merged 3 commits into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ public void Intercept(IInvocation invocation)
{
Type declaringType = invocation.Method.DeclaringType;
var ns = declaringType.Namespace;
var expectedName = declaringType.Name + "." + methodName.Substring(0, methodName.Length - 5);
var methodNameNoAysnc = methodName.Substring(0, methodName.Length - 5);
var expectedName = declaringType.Name + "." + methodNameNoAysnc;
string expectedNameNoStart = null;
//Fix scenario: StartCreateOrUpdateAsync -> CreateOrUpdate
if (methodNameNoAysnc.StartsWith("Start"))
{
expectedNameNoStart = $"{declaringType.Name}.{methodNameNoAysnc.Substring(5)}";
}
using ClientDiagnosticListener diagnosticListener = new ClientDiagnosticListener(s => s.StartsWith("Azure."));
invocation.Proceed();

Expand Down Expand Up @@ -71,6 +78,10 @@ public void Intercept(IInvocation invocation)
if (strict)
{
ClientDiagnosticListener.ProducedDiagnosticScope e = diagnosticListener.Scopes.FirstOrDefault(e => e.Name == expectedName);
if (e == default && !string.IsNullOrEmpty(expectedNameNoStart))
{
e = diagnosticListener.Scopes.FirstOrDefault(e => e.Name == expectedNameNoStart);
}

if (e == default)
{
Expand Down Expand Up @@ -103,4 +114,4 @@ public void Intercept(IInvocation invocation)
}
}
}
}
}
8 changes: 8 additions & 0 deletions sdk/core/Azure.Core/tests/TestFramework/RecordEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ public class RecordEntry

public string RequestUri { get; set; }

//Used only for deserializing track 1 session record files
public string EncodedRequestUri { get; set; }
Copy link
Contributor

@pakrym pakrym Apr 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have an explicit bool IsTrack1Recording property.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good suggestion.


public RequestMethod RequestMethod { get; set; }

public int StatusCode { get; set; }
Expand All @@ -35,6 +38,11 @@ public static RecordEntry Deserialize(JsonElement element)
record.RequestUri = property.GetString();
}

if (element.TryGetProperty(nameof(EncodedRequestUri), out property))
{
record.EncodedRequestUri = property.GetString();
}

if (element.TryGetProperty("RequestHeaders", out property))
{
DeserializeHeaders(record.Request.Headers, property);
Expand Down
20 changes: 19 additions & 1 deletion sdk/core/Azure.Core/tests/TestFramework/RecordMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,25 @@ public virtual RecordEntry FindMatch(Request request, IList<RecordEntry> entries
int bestScore = int.MaxValue;
RecordEntry bestScoreEntry = null;

bool isTrack1Record = entries.Any(item => !string.IsNullOrEmpty(item.EncodedRequestUri));

foreach (RecordEntry entry in entries)
{
int score = 0;

if (!AreUrisSame(entry.RequestUri, uri))
var recordRequestUri = entry.RequestUri;
if (isTrack1Record)
{
//there's no domain name for request uri in track 1 record, so add it from reqeust uri
int len = 8; //length of "https://"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we positive that schema is always https?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the len we used as start index for searching "/" to get end index of domain name, so 8 is good here even for http://

int domainEndingIndex = uri.IndexOf('/', len);
if (domainEndingIndex > 0)
{
recordRequestUri = uri.Substring(0, domainEndingIndex) + recordRequestUri;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this logic into RecordEntry.Deserialize this would allow us to drop the additional RequestUri property.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no domain name for request uri in track 1 record, so I get domain name from real request uri and add domain name to RequestUri of track 1 for comparison, the problem is we don't know real request uri during de-serializing. Please let me know if I have some misunderstanding.

The real request uri: https://xxx.com/subscriptions/xxxx
RequestUri in track 1: /subscriptions/xxxxx
RequestUri in track 2: https://xxx.com/subscriptions/xxxx

}
}

if (!AreUrisSame(recordRequestUri, uri))
{
score++;
}
Expand All @@ -84,7 +98,11 @@ public virtual RecordEntry FindMatch(Request request, IList<RecordEntry> entries
score++;
}

//we only check Uri + RequestMethod for track1 record
if (!isTrack1Record)
{
score += CompareHeaderDictionaries(headers, entry.Request.Headers, ExcludeHeaders);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes recordings way less useful, validating neither body nor headers.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This compromise is not ideal, this is best I could figure out, please let me know if any other good suggestion.

}

if (score == 0)
{
Expand Down
16 changes: 16 additions & 0 deletions sdk/core/Azure.Core/tests/TestFramework/RecordSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public class RecordSession

public SortedDictionary<string, string> Variables { get; } = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);

//Used only for deserializing track 1 session record files
public Dictionary<string, Queue<string>> Names { get; set; } = new Dictionary<string, Queue<string>>();

public void Serialize(Utf8JsonWriter jsonWriter)
{
jsonWriter.WriteStartObject();
Expand Down Expand Up @@ -52,6 +55,19 @@ public static RecordSession Deserialize(JsonElement element)
session.Variables[item.Name] = item.Value.GetString();
}
}

if (element.TryGetProperty(nameof(Names), out property))
{
foreach (JsonProperty item in property.EnumerateObject())
{
var queue = new Queue<string>();
foreach (JsonElement subItem in item.Value.EnumerateArray())
{
queue.Enqueue(subItem.GetString());
}
session.Names[item.Name] = queue;
}
}
return session;
}

Expand Down
29 changes: 28 additions & 1 deletion sdk/core/Azure.Core/tests/TestFramework/TestRecording.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text.Json;
using System.Threading;
Expand Down Expand Up @@ -90,7 +92,15 @@ public TestRandom Random
_random = new TestRandom(Mode, seed);
break;
case RecordedTestMode.Playback:
_random = new TestRandom(Mode, int.Parse(_session.Variables[RandomSeedVariableKey]));
if (IsTrack1SessionRecord())
{
//random is not really used for track 1 playback, so randomly pick one as seed
_random = new TestRandom(Mode, (int)DateTime.UtcNow.Ticks);
}
else
{
_random = new TestRandom(Mode, int.Parse(_session.Variables[RandomSeedVariableKey]));
}
break;
default:
throw new ArgumentOutOfRangeException();
Expand Down Expand Up @@ -201,6 +211,23 @@ public string GenerateId()
return Random.Next().ToString();
}

public string GenerateAssetName(string prefix, [CallerMemberName]string callerMethodName = "testframework_failed")
{
if (Mode == RecordedTestMode.Playback && IsTrack1SessionRecord())
{
return _session.Names[callerMethodName].Dequeue();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who adds items to _session.Names when test is re-recorded?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for re-record, the record file will be in track 2 format and Names is obsolete.

}
else
{
return prefix + Random.Next(9999);
}
}

public bool IsTrack1SessionRecord()
{
return _session.Entries.Any(item => !string.IsNullOrEmpty(item.EncodedRequestUri));
}

public string GetVariable(string variableName, string defaultValue)
{
switch (Mode)
Expand Down