Skip to content

Commit

Permalink
SNOW-950923 fix flaky test for login retries for 404 error
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-mhofman committed Feb 21, 2024
1 parent 3d90e7f commit 32cc219
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 11 deletions.
36 changes: 25 additions & 11 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

using System.Data.Common;
using System.Net;
using Snowflake.Data.Tests.Util;

namespace Snowflake.Data.Tests.IntegrationTests
Expand Down Expand Up @@ -520,12 +521,12 @@ public void TestDefaultLoginTimeout()
}

[Test]
public void TestConnectionFailFast()
public void TestConnectionFailFastForNonRetried404OnLogin()
{
using (var conn = new SnowflakeDbConnection())
{
// Just a way to get a 404 on the login request and make sure there are no retry
string invalidConnectionString = "host=learn.microsoft.com;"
string invalidConnectionString = "host=google.com/404;"
+ "connection_timeout=0;account=testFailFast;user=testFailFast;password=testFailFast;";

conn.ConnectionString = invalidConnectionString;
Expand All @@ -538,20 +539,24 @@ public void TestConnectionFailFast()
}
catch (SnowflakeDbException e)
{
Assert.AreEqual(SFError.INTERNAL_ERROR.GetAttribute<SFErrorAttr>().errorCode,
e.ErrorCode);
SnowflakeDbExceptionAssert.HasHttpErrorCodeInExceptionChain(e, HttpStatusCode.NotFound);
SnowflakeDbExceptionAssert.HasMessageInExceptionChain(e, "404 (Not Found)");
}
catch (Exception unexpected)
{
Assert.Fail($"Unexpected {unexpected.GetType()} exception occurred");
}

Assert.AreEqual(ConnectionState.Closed, conn.State);
}
}

[Test]
public void TestEnableRetry()
public void TestEnableLoginRetryOn404()
{
using (var conn = new SnowflakeDbConnection())
{
string invalidConnectionString = "host=learn.microsoft.com;"
string invalidConnectionString = "host=google.com/404;"
+ "connection_timeout=0;account=testFailFast;user=testFailFast;password=testFailFast;disableretry=true;forceretryon404=true";
conn.ConnectionString = invalidConnectionString;

Expand All @@ -563,8 +568,12 @@ public void TestEnableRetry()
}
catch (SnowflakeDbException e)
{
Assert.AreEqual(SFError.INTERNAL_ERROR.GetAttribute<SFErrorAttr>().errorCode,
e.ErrorCode);
SnowflakeDbExceptionAssert.HasErrorCode(e, SFError.INTERNAL_ERROR);
SnowflakeDbExceptionAssert.HasHttpErrorCodeInExceptionChain(e, HttpStatusCode.NotFound);
}
catch (Exception unexpected)
{
Assert.Fail($"Unexpected {unexpected.GetType()} exception occurred");
}

Assert.AreEqual(ConnectionState.Closed, conn.State);
Expand Down Expand Up @@ -1947,12 +1956,12 @@ public void TestAsyncDefaultLoginTimeout()
}

[Test]
public void TestAsyncConnectionFailFast()
public void TestAsyncConnectionFailFastForNonRetried404OnLogin()
{
using (var conn = new SnowflakeDbConnection())
{
// Just a way to get a 404 on the login request and make sure there are no retry
string invalidConnectionString = "host=learn.microsoft.com;"
string invalidConnectionString = "host=google.com/404;"
+ "connection_timeout=0;account=testFailFast;user=testFailFast;password=testFailFast;";

conn.ConnectionString = invalidConnectionString;
Expand All @@ -1967,7 +1976,12 @@ public void TestAsyncConnectionFailFast()
}
catch (AggregateException e)
{
SnowflakeDbExceptionAssert.HasErrorCode((SnowflakeDbException)e.InnerException, SFError.INTERNAL_ERROR);
SnowflakeDbExceptionAssert.HasHttpErrorCodeInExceptionChain(e, HttpStatusCode.NotFound);
SnowflakeDbExceptionAssert.HasMessageInExceptionChain(e, "404 (Not Found)");
}
catch (Exception unexpected)
{
Assert.Fail($"Unexpected {unexpected.GetType()} exception occurred");
}

Assert.AreEqual(ConnectionState.Closed, conn.State);
Expand Down
69 changes: 69 additions & 0 deletions Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using Snowflake.Data.Core;
using Snowflake.Data.Client;
using NUnit.Framework;
Expand All @@ -10,5 +15,69 @@ public static void HasErrorCode(SnowflakeDbException exception, SFError sfError)
{
Assert.AreEqual(exception.ErrorCode, sfError.GetAttribute<SFErrorAttr>().errorCode);
}

public static void HasErrorCode(Exception exception, SFError sfError)
{
Assert.NotNull(exception);
switch (exception)
{
case SnowflakeDbException snowflakeDbException:
Assert.AreEqual(snowflakeDbException.ErrorCode, sfError.GetAttribute<SFErrorAttr>().errorCode);
break;
default:
Assert.Fail(exception.GetType() + " type is not " + typeof(SnowflakeDbException));
break;
}
}

public static void HasHttpErrorCodeInExceptionChain(Exception exception, HttpStatusCode expected)
{
var exceptions = CollectExceptions(exception);
Assert.AreEqual(true,
exceptions.Any(e =>
{
switch (e)
{
case SnowflakeDbException se:
return se.ErrorCode == (int)expected;
case HttpRequestException he:
return he.StatusCode == expected;

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AWS)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AWS)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, GCP)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, GCP)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AWS)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AWS)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, GCP)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, GCP)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AZURE)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AZURE)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AZURE)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)

Check failure on line 44 in Snowflake.Data.Tests/Util/SnowflakeDbExceptionAssert.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AZURE)

'HttpRequestException' does not contain a definition for 'StatusCode' and no accessible extension method 'StatusCode' accepting a first argument of type 'HttpRequestException' could be found (are you missing a using directive or an assembly reference?)
default:
return false;
}
}),
$"Any of exceptions in the chain should have HTTP Status: {expected}");
}

public static void HasMessageInExceptionChain(Exception exception, string expected)
{
var exceptions = CollectExceptions(exception);
Assert.AreEqual(true,
exceptions.Any(e => e.Message.Contains(expected)),
$"Any of exceptions in the chain should contain message: {expected}");
}

private static List<Exception> CollectExceptions(Exception exception)
{
var collected = new List<Exception>();
if (exception is null)
return collected;
switch (exception)
{
case AggregateException aggregate:
var inner = aggregate.Flatten().InnerExceptions;
// collected.AddRange(inner.OfType<SnowflakeDbException>());
collected.AddRange(inner);
collected.AddRange(inner
.Where(e => e.InnerException != null)
.SelectMany(e => CollectExceptions(e.InnerException)));
break;
case Exception general:
collected.AddRange(CollectExceptions(general.InnerException));
collected.Add(general);
break;
}
return collected;
}
}
}

0 comments on commit 32cc219

Please sign in to comment.