Skip to content

Commit

Permalink
Merge branch 'pool/SNOW-860872-connection-pool' into pool/SNOW-937188…
Browse files Browse the repository at this point in the history
…-changed-session-behavior

# Conflicts:
#	Snowflake.Data/Core/Session/SessionPool.cs
  • Loading branch information
sfc-gh-mhofman committed May 7, 2024
2 parents fdc027f + 5de53f9 commit 3ac0204
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 100 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
run: |
cd Snowflake.Data.Tests
dotnet restore
dotnet build -f ${{ matrix.dotnet }}
dotnet build -f ${{ matrix.dotnet }} '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:
- name: Build Driver
run: |
dotnet restore
dotnet build
dotnet build '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down Expand Up @@ -175,7 +175,7 @@ jobs:
- name: Build Driver
run: |
dotnet restore
dotnet build
dotnet build '-p:DefineAdditionalConstants=SF_PUBLIC_ENVIRONMENT'
- name: Run Tests
run: |
cd Snowflake.Data.Tests
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -7,6 +6,7 @@
using Snowflake.Data.Client;
using Snowflake.Data.Core;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Log;
using Snowflake.Data.Tests.Mock;
using Snowflake.Data.Tests.Util;

Expand All @@ -17,6 +17,7 @@ namespace Snowflake.Data.Tests.IntegrationTests
public class ConnectionMultiplePoolsAsyncIT: SFBaseTestAsync
{
private readonly PoolConfig _previousPoolConfig = new PoolConfig();
private readonly SFLogger logger = SFLoggerFactory.GetLogger<SFConnectionIT>();

[SetUp]
public new void BeforeTest()
Expand Down Expand Up @@ -65,6 +66,8 @@ public async Task TestDoNotAddToPoolInvalidConnectionAsync()

// assert
var pool = SnowflakeDbConnectionPool.GetPool(connection.ConnectionString);
var poolState = pool.GetCurrentState();

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Linux (net6.0, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Linux (net6.0, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Linux (net6.0, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Linux (net6.0, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on MAC (net6.0, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on MAC (net6.0, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on MAC (net6.0, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on MAC (net6.0, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on MAC (net6.0, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on MAC (net6.0, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Linux (net6.0, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Linux (net6.0, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net6.0, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net6.0, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net472, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AWS)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net6.0, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net6.0, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net471, GCP)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net6.0, AZURE)

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

Check failure on line 69 in Snowflake.Data.Tests/IntegrationTests/ConnectionMultiplePoolsAsyncIT.cs

View workflow job for this annotation

GitHub Actions / Tests on Windows (net6.0, AZURE)

'SnowflakeDbSessionPool' does not contain a definition for 'GetCurrentState' and no accessible extension method 'GetCurrentState' accepting a first argument of type 'SnowflakeDbSessionPool' could be found (are you missing a using directive or an assembly reference?)
logger.Warn($"Pool state: {poolState}");
Assert.Less(pool.GetCurrentPoolSize(), SFSessionHttpClientProperties.DefaultMinPoolSize); // for invalid connection string it is used default min pool size

// cleanup
Expand Down
80 changes: 73 additions & 7 deletions Snowflake.Data.Tests/UnitTests/Session/SessionPoolTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Net;
using System.Text.RegularExpressions;
using NUnit.Framework;
using Snowflake.Data.Core.Session;

Expand All @@ -17,32 +19,32 @@ public void TestPoolParametersAreNotOverriden()
// assert
Assert.IsFalse(pool.IsConfigOverridden());
}

[Test]
public void TestOverrideMaxPoolSize()
{
// arrange
var pool = SessionPool.CreateSessionPool(ConnectionString, null);
var newMaxPoolSize = 15;

// act
pool.SetMaxPoolSize(newMaxPoolSize);

// assert
Assert.AreEqual(newMaxPoolSize, pool.GetMaxPoolSize());
Assert.IsTrue(pool.IsConfigOverridden());
}

[Test]
public void TestOverrideExpirationTimeout()
{
// arrange
var pool = SessionPool.CreateSessionPool(ConnectionString, null);
var newExpirationTimeoutSeconds = 15;

// act
pool.SetTimeout(newExpirationTimeoutSeconds);

// assert
Assert.AreEqual(newExpirationTimeoutSeconds, pool.GetTimeout());
Assert.IsTrue(pool.IsConfigOverridden());
Expand All @@ -56,10 +58,74 @@ public void TestOverrideSetPooling()

// act
pool.SetPooling(false);

// assert
Assert.IsFalse(pool.GetPooling());
Assert.IsTrue(pool.IsConfigOverridden());
}

[Test]
[TestCase("account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443", "somePassword", " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
[TestCase("account=someAccount;db=someDb;host=someHost;password=somePassword;user=SomeUser;port=443", null, " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
[TestCase("account=someAccount;db=someDb;host=someHost;password=somePassword;user=SomeUser;private_key=SomePrivateKey;port=443", null, " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
[TestCase("account=someAccount;db=someDb;host=someHost;password=somePassword;user=SomeUser;token=someToken;port=443", null, " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
[TestCase("account=someAccount;db=someDb;host=someHost;password=somePassword;user=SomeUser;private_key_pwd=somePrivateKeyPwd;port=443", null, " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
[TestCase("account=someAccount;db=someDb;host=someHost;password=somePassword;user=SomeUser;proxyPassword=someProxyPassword;port=443", null, " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
[TestCase("ACCOUNT=someAccount;DB=someDb;HOST=someHost;PASSWORD=somePassword;USER=SomeUser;PORT=443", null, " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
[TestCase("ACCOUNT=\"someAccount\";DB=\"someDb\";HOST=\"someHost\";PASSWORD=\"somePassword\";USER=\"SomeUser\";PORT=\"443\"", null, " [pool: account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443;]")]
public void TestPoolIdentificationBasedOnConnectionString(string connectionString, string password, string expectedPoolIdentification)
{
// arrange
var securePassword = password == null ? null : new NetworkCredential("", password).SecurePassword;
var pool = SessionPool.CreateSessionPool(connectionString, securePassword);

// act
var poolIdentification = pool.PoolIdentificationBasedOnConnectionString;

// assert
Assert.AreEqual(expectedPoolIdentification, poolIdentification);
}

[Test]
public void TestPoolIdentificationForInvalidConnectionString()
{
// arrange
var invalidConnectionString = "account=someAccount;db=someDb;host=someHost;user=SomeUser;port=443"; // invalid because password is not provided
var pool = SessionPool.CreateSessionPool(invalidConnectionString, null);

// act
var poolIdentification = pool.PoolIdentificationBasedOnConnectionString;

// assert
Assert.AreEqual(" [pool: could not parse connection string]", poolIdentification);
}

[Test]
public void TestPoolIdentificationBasedOnInternalId()
{
// arrange
var connectionString = "account=someAccount;db=someDb;host=someHost;password=somePassword;user=SomeUser;port=443";
var pool = SessionPool.CreateSessionPool(connectionString, null);
var poolIdRegex = new Regex(@"^ \[pool: [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\]$");

// act
var poolIdentification = pool.PoolIdentificationBasedOnInternalId;

// assert
Assert.IsTrue(poolIdRegex.IsMatch(poolIdentification));
}

[Test]
public void TestPoolIdentificationForOldPool()
{
// arrange
var pool = SessionPool.CreateSessionCache();

// act
var poolIdentification = pool.PoolIdentification();

// assert
Assert.AreEqual("", poolIdentification);
}
}
}
4 changes: 2 additions & 2 deletions Snowflake.Data/Core/Session/ConnectionPoolManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ public Task<SFSession> GetSessionAsync(string connectionString, SecureString pas

public bool AddSession(SFSession session)
{
s_logger.Debug($"ConnectionPoolManager::AddSession for {session.ConnectionString}");
s_logger.Debug("ConnectionPoolManager::AddSession");
return GetPool(session.ConnectionString, session.Password).AddSession(session, true);
}

public void ReleaseBusySession(SFSession session)
{
s_logger.Debug($"ConnectionPoolManager::ReleaseBusySession for {session.ConnectionString}");
s_logger.Debug("ConnectionPoolManager::ReleaseBusySession");
GetPool(session.ConnectionString, session.Password).ReleaseBusySession(session);
}

Expand Down
2 changes: 2 additions & 0 deletions Snowflake.Data/Core/Session/IWaitingQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ internal interface IWaitingQueue

bool IsAnyoneWaiting();

int WaitingCount();

bool IsWaitingEnabled();
}
}
5 changes: 5 additions & 0 deletions Snowflake.Data/Core/Session/NonWaitingQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public bool IsAnyoneWaiting()
return false;
}

public int WaitingCount()
{
return 0;
}

public bool IsWaitingEnabled()
{
return false;
Expand Down
52 changes: 39 additions & 13 deletions Snowflake.Data/Core/Session/SFSessionProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Snowflake.Data.Core.Authenticator;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Snowflake.Data.Core
Expand All @@ -23,7 +24,7 @@ internal enum SFSessionProperty
DB,
[SFSessionPropertyAttr(required = false)]
HOST,
[SFSessionPropertyAttr(required = true)]
[SFSessionPropertyAttr(required = true, IsSecret = true)]
PASSWORD,
[SFSessionPropertyAttr(required = false, defaultValue = "443")]
PORT,
Expand All @@ -45,11 +46,11 @@ internal enum SFSessionProperty
VALIDATE_DEFAULT_PARAMETERS,
[SFSessionPropertyAttr(required = false)]
PRIVATE_KEY_FILE,
[SFSessionPropertyAttr(required = false)]
[SFSessionPropertyAttr(required = false, IsSecret = true)]
PRIVATE_KEY_PWD,
[SFSessionPropertyAttr(required = false)]
[SFSessionPropertyAttr(required = false, IsSecret = true)]
PRIVATE_KEY,
[SFSessionPropertyAttr(required = false)]
[SFSessionPropertyAttr(required = false, IsSecret = true)]
TOKEN,
[SFSessionPropertyAttr(required = false, defaultValue = "false")]
INSECUREMODE,
Expand All @@ -61,7 +62,7 @@ internal enum SFSessionProperty
PROXYPORT,
[SFSessionPropertyAttr(required = false)]
PROXYUSER,
[SFSessionPropertyAttr(required = false)]
[SFSessionPropertyAttr(required = false, IsSecret = true)]
PROXYPASSWORD,
[SFSessionPropertyAttr(required = false)]
NONPROXYHOSTS,
Expand Down Expand Up @@ -116,21 +117,22 @@ class SFSessionPropertyAttr : Attribute
public bool required { get; set; }

public string defaultValue { get; set; }

public bool IsSecret { get; set; } = false;
}

class SFSessionProperties : Dictionary<SFSessionProperty, String>
{
private static SFLogger logger = SFLoggerFactory.GetLogger<SFSessionProperties>();

internal string ConnectionStringWithoutSecrets { get; set; }

// Connection string properties to obfuscate in the log
private static List<SFSessionProperty> secretProps =
new List<SFSessionProperty>{
SFSessionProperty.PASSWORD,
SFSessionProperty.PRIVATE_KEY,
SFSessionProperty.TOKEN,
SFSessionProperty.PRIVATE_KEY_PWD,
SFSessionProperty.PROXYPASSWORD,
};
private static readonly List<string> s_secretProps = Enum.GetValues(typeof(SFSessionProperty))
.Cast<SFSessionProperty>()
.Where(p => p.GetAttribute<SFSessionPropertyAttr>().IsSecret)
.Select(p => p.ToString())
.ToList();

private static readonly List<string> s_accountRegexStrings = new List<string>
{
Expand Down Expand Up @@ -196,6 +198,8 @@ internal static SFSessionProperties ParseConnectionString(string connectionStrin
builder.Keys.CopyTo(keys, 0);
builder.Values.CopyTo(values,0);

properties.ConnectionStringWithoutSecrets = BuildConnectionStringWithoutSecrets(ref keys, ref values);

for(var i=0; i<keys.Length; i++)
{
try
Expand Down Expand Up @@ -279,6 +283,28 @@ internal static SFSessionProperties ParseConnectionString(string connectionStrin
return properties;
}

private static string BuildConnectionStringWithoutSecrets(ref string[] keys, ref string[] values)
{
var count = keys.Length;
var result = new StringBuilder();
for (var i = 0; i < count; i++ )
{
if (!IsSecretProperty(keys[i]))
{
result.Append(keys[i]);
result.Append("=");
result.Append(values[i]);
result.Append(";");
}
}
return result.ToString();
}

private static bool IsSecretProperty(string propertyName)
{
return s_secretProps.Contains(propertyName, StringComparer.OrdinalIgnoreCase);
}

private static void UpdatePropertiesForSpecialCases(SFSessionProperties properties, string connectionString)
{
var propertyEntry = connectionString.Split(';');
Expand Down
Loading

0 comments on commit 3ac0204

Please sign in to comment.