Skip to content

Commit

Permalink
SNOW-937188 pool mode where a session gets destroyed on pooling when …
Browse files Browse the repository at this point in the history
…some of its settings gets changed and no longer match the pool initial setup
  • Loading branch information
sfc-gh-mhofman committed Apr 29, 2024
1 parent 43d8fd4 commit e727d1a
Show file tree
Hide file tree
Showing 9 changed files with 619 additions and 404 deletions.
160 changes: 160 additions & 0 deletions Snowflake.Data.Tests/IntegrationTests/ConnectionChangedSessionIT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
using NUnit.Framework;
using Snowflake.Data.Client;
using Snowflake.Data.Core;
using Snowflake.Data.Core.Session;
using Snowflake.Data.Tests.Util;

namespace Snowflake.Data.Tests.IntegrationTests
{
[TestFixture]
[NonParallelizable]
public class ConnectionChangedSessionIT : SFBaseTest
{
private readonly QueryExecResponseData _queryExecResponseChangedRole = new()
{
finalDatabaseName = TestEnvironment.TestConfig.database,
finalSchemaName = TestEnvironment.TestConfig.schema,
finalRoleName = "role change",
finalWarehouseName = TestEnvironment.TestConfig.warehouse
};

private readonly QueryExecResponseData _queryExecResponseChangedDatabase = new()
{
finalDatabaseName = "database changed",
finalSchemaName = TestEnvironment.TestConfig.schema,
finalRoleName = TestEnvironment.TestConfig.role,
finalWarehouseName = TestEnvironment.TestConfig.warehouse
};

private readonly QueryExecResponseData _queryExecResponseChangedSchema = new()
{
finalDatabaseName = TestEnvironment.TestConfig.database,
finalSchemaName = "schema changed",
finalRoleName = TestEnvironment.TestConfig.role,
finalWarehouseName = TestEnvironment.TestConfig.warehouse
};

private readonly QueryExecResponseData _queryExecResponseChangedWarehouse = new()
{
finalDatabaseName = TestEnvironment.TestConfig.database,
finalSchemaName = TestEnvironment.TestConfig.schema,
finalRoleName = TestEnvironment.TestConfig.role,
finalWarehouseName = "warehouse changed"
};

private static PoolConfig s_previousPoolConfigRestorer;

[OneTimeSetUp]
public static void BeforeAllTests()
{
s_previousPoolConfigRestorer = new PoolConfig();
SnowflakeDbConnectionPool.SetConnectionPoolVersion(ConnectionPoolType.MultipleConnectionPool);
}

[SetUp]
public new void BeforeTest()
{
SnowflakeDbConnectionPool.ClearAllPools();
}

[TearDown]
public new void AfterTest()
{
SnowflakeDbConnectionPool.ClearAllPools();
}

[OneTimeTearDown]
public static void AfterAllTests()
{
s_previousPoolConfigRestorer.Reset();
}

[Test]
public void TestPoolDestroysConnectionWhenChangedSessionProperties()
{
var connectionString = ConnectionString + "application=Destroy;ChangedSession=Destroy;minPoolSize=0;maxPoolSize=3";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);

var connection = new SnowflakeDbConnection(connectionString);
connection.Open();
connection.SfSession.UpdateSessionProperties(_queryExecResponseChangedDatabase);
connection.Close();

Assert.AreEqual(0, pool.GetCurrentPoolSize());
}

[Test]
public void TestPoolingWhenSessionPropertiesUnchanged()
{
var connectionString = ConnectionString + "application=NoSessionChanges;ChangedSession=Destroy;minPoolSize=0;maxPoolSize=3";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);

var connection = new SnowflakeDbConnection(connectionString);
connection.Open();
connection.Close();

Assert.AreEqual(1, pool.GetCurrentPoolSize());
}

[Test]
public void TestPoolingWhenConnectionPropertiesChangedForOriginalPoolMode()
{
var connectionString = ConnectionString + "application=OriginalPoolMode;ChangedSession=OriginalPool;minPoolSize=0;maxPoolSize=3";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);

var connection = new SnowflakeDbConnection(connectionString);
connection.Open();
connection.SfSession.UpdateSessionProperties(_queryExecResponseChangedWarehouse);
var sessionId = connection.SfSession.sessionId;
connection.Close();

Assert.AreEqual(1, pool.GetCurrentPoolSize());
connection.Close();

var connection2 = new SnowflakeDbConnection(connectionString);
connection2.Open();
Assert.AreEqual(sessionId, connection2.SfSession.sessionId);
connection2.Close();
}

[Test]
public void TestPoolingWhenConnectionPropertiesChangedForDefaultPoolMode()
{
var connectionString = ConnectionString + "application=DefaultPoolMode;minPoolSize=0;maxPoolSize=3";
var pool = SnowflakeDbConnectionPool.GetPool(connectionString);

var connection = new SnowflakeDbConnection(connectionString);
connection.Open();
connection.SfSession.UpdateSessionProperties(_queryExecResponseChangedRole);
var sessionId = connection.SfSession.sessionId;
connection.Close();

Assert.AreEqual(1, pool.GetCurrentPoolSize());

var connection2 = new SnowflakeDbConnection(connectionString);
connection2.Open();
Assert.AreEqual(sessionId, connection2.SfSession.sessionId);
connection2.Close();
}

[Test]
public void TestPoolDestroysAndRecreatesConnection()
{
var connectionString = ConnectionString + "application=DestroyRecreateSession;ChangedSession=Destroy;minPoolSize=1;maxPoolSize=3";

var connection = new SnowflakeDbConnection(connectionString);
connection.Open();
var sessionId = connection.SfSession.sessionId;
connection.SfSession.UpdateSessionProperties(_queryExecResponseChangedSchema);
connection.Close();

var pool = SnowflakeDbConnectionPool.GetPool(connectionString);
Assert.AreEqual(1, pool.GetCurrentPoolSize());

var connection2 = new SnowflakeDbConnection(connectionString);
connection2.Open();
Assert.AreNotEqual(sessionId, connection2.SfSession.sessionId);
connection2.Close();
}
}
}
58 changes: 45 additions & 13 deletions Snowflake.Data.Tests/UnitTests/SFSessionTest.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
/*
* Copyright (c) 2012-2019 Snowflake Computing Inc. All rights reserved.
* Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved.
*/

using Snowflake.Data.Configuration;
using Snowflake.Data.Log;
using Snowflake.Data.Core;
using NUnit.Framework;

namespace Snowflake.Data.Tests.UnitTests
{
using Snowflake.Data.Core;
using NUnit.Framework;

[TestFixture]
class SFSessionTest
{
Expand All @@ -20,26 +17,61 @@ public void TestSessionGoneWhenClose()
Mock.MockCloseSessionGone restRequester = new Mock.MockCloseSessionGone();
SFSession sfSession = new SFSession("account=test;user=test;password=test", null, restRequester);
sfSession.Open();
sfSession.close(); // no exception is raised.
Assert.DoesNotThrow(() => sfSession.close());
}

[Test]
public void TestUpdateDatabaseAndSchema()
public void TestUpdateSessionProperties()
{
// arrange
string databaseName = "DB_TEST";
string schemaName = "SC_TEST";

string warehouseName = "WH_TEST";
string roleName = "ROLE_TEST";
QueryExecResponseData queryExecResponseData = new QueryExecResponseData
{
finalSchemaName = schemaName,
finalDatabaseName = databaseName,
finalRoleName = roleName,
finalWarehouseName = warehouseName
};

// act
SFSession sfSession = new SFSession("account=test;user=test;password=test", null);
sfSession.UpdateDatabaseAndSchema(databaseName, schemaName);
sfSession.UpdateSessionProperties(queryExecResponseData);

// assert
Assert.AreEqual(databaseName, sfSession.database);
Assert.AreEqual(schemaName, sfSession.schema);
Assert.AreEqual(warehouseName, sfSession.warehouse);
Assert.AreEqual(roleName, sfSession.role);
}

[Test]
public void TestSkipUpdateSessionPropertiesWhenPropertiesMissing()
{
// arrange
string databaseName = "DB_TEST";
string schemaName = "SC_TEST";
string warehouseName = "WH_TEST";
string roleName = "ROLE_TEST";
SFSession sfSession = new SFSession("account=test;user=test;password=test", null);
sfSession.database = databaseName;
sfSession.warehouse = warehouseName;
sfSession.role = roleName;
sfSession.schema = schemaName;

// act
QueryExecResponseData queryExecResponseWithoutData = new QueryExecResponseData();
sfSession.UpdateSessionProperties(queryExecResponseWithoutData);

// assert
// when database or schema name is missing in the response,
// the cached value should keep unchanged
sfSession.UpdateDatabaseAndSchema(null, null);
Assert.AreEqual(databaseName, sfSession.database);
Assert.AreEqual(schemaName, sfSession.schema);
Assert.AreEqual(warehouseName, sfSession.warehouse);
Assert.AreEqual(roleName, sfSession.role);
}

[Test]
Expand All @@ -54,10 +86,10 @@ public void TestThatConfiguresEasyLogging(string configPath)
var connectionString = configPath == null
? simpleConnectionString
: $"{simpleConnectionString}client_config_file={configPath};";

// act
new SFSession(connectionString, null, easyLoggingStarter.Object);

// assert
easyLoggingStarter.Verify(starter => starter.Init(configPath));
}
Expand Down
4 changes: 2 additions & 2 deletions Snowflake.Data/Core/ArrowResultSet.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
* Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved.
*/

using System;
Expand Down Expand Up @@ -398,7 +398,7 @@ internal override string GetString(int ordinal)
private void UpdateSessionStatus(QueryExecResponseData responseData)
{
SFSession session = this.sfStatement.SfSession;
session.UpdateDatabaseAndSchema(responseData.finalDatabaseName, responseData.finalSchemaName);
session.UpdateSessionProperties(responseData);
session.UpdateSessionParameterMap(responseData.parameters);
}

Expand Down
2 changes: 1 addition & 1 deletion Snowflake.Data/Core/SFMultiStatementsResultSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ internal override bool Rewind()
private void updateSessionStatus(QueryExecResponseData responseData)
{
SFSession session = this.sfStatement.SfSession;
session.UpdateDatabaseAndSchema(responseData.finalDatabaseName, responseData.finalSchemaName);
session.UpdateSessionProperties(responseData);
session.UpdateSessionParameterMap(responseData.parameters);
session.UpdateQueryContextCache(responseData.QueryContext);
}
Expand Down
Loading

0 comments on commit e727d1a

Please sign in to comment.