Skip to content

Commit

Permalink
SNOW-1444876: Support for TOML connections (#995)
Browse files Browse the repository at this point in the history
Co-authored-by: Krzysztof Nozderko <[email protected]>
  • Loading branch information
1 parent 4392447 commit f27eb2a
Show file tree
Hide file tree
Showing 18 changed files with 1,602 additions and 363 deletions.
633 changes: 319 additions & 314 deletions .gitignore

Large diffs are not rendered by default.

23 changes: 11 additions & 12 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
* Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
*/

using System;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
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;

namespace Snowflake.Data.Tests.IntegrationTests
{
using NUnit.Framework;
using Snowflake.Data.Client;
using System.Data;
using System;
using Snowflake.Data.Core;
using System.Threading.Tasks;
using System.Threading;
using Snowflake.Data.Log;
using System.Diagnostics;
using Snowflake.Data.Tests.Mock;
using System.Runtime.InteropServices;
using System.Net.Http;

[TestFixture]
class SFConnectionIT : SFBaseTest
Expand Down
143 changes: 143 additions & 0 deletions Snowflake.Data.Tests/IntegrationTests/SFConnectionWithTomlIT.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Copyright (c) 2024 Snowflake Computing Inc. All rights reserved.
*/

using System;
using System.Data;
using System.IO;
using System.Runtime.InteropServices;
using Mono.Unix.Native;
using NUnit.Framework;
using Snowflake.Data.Client;
using Snowflake.Data.Core;
using Snowflake.Data.Log;
using Tomlyn;
using Tomlyn.Model;

namespace Snowflake.Data.Tests.IntegrationTests
{

[TestFixture, NonParallelizable]
class SFConnectionWithTomlIT : SFBaseTest
{
private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger<SFConnectionIT>();

private static string s_workingDirectory;


[SetUp]
public new void BeforeTest()
{
s_workingDirectory ??= Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../..", "toml_config_folder");
if (!Directory.Exists(s_workingDirectory))
{
Directory.CreateDirectory(s_workingDirectory);
}
CreateTomlConfigBaseOnConnectionString(ConnectionString);
}

[TearDown]
public new void AfterTest()
{
Directory.Delete(s_workingDirectory, true);
}

[Test]
public void TestLocalDefaultConnectStringReadFromToml()
{
var snowflakeHome = Environment.GetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome);
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome, s_workingDirectory);
try
{
using (var conn = new SnowflakeDbConnection())
{
conn.Open();
Assert.AreEqual(ConnectionState.Open, conn.State);
}
}
finally
{
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome, snowflakeHome);
}
}

[Test]
public void TestThrowExceptionIfTomlNotFoundWithOtherConnectionString()
{
var snowflakeHome = Environment.GetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome);
var connectionName = Environment.GetEnvironmentVariable(TomlConnectionBuilder.SnowflakeDefaultConnectionName);
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome, s_workingDirectory);
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeDefaultConnectionName, "notfoundconnection");
try
{
using (var conn = new SnowflakeDbConnection())
{
Assert.Throws<SnowflakeDbException>(() => conn.Open(), "Unable to connect. Specified connection name does not exist in connections.toml");
}
}
finally
{
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome, snowflakeHome);
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeDefaultConnectionName, connectionName);
}
}

[Test]
public void TestThrowExceptionIfTomlFromNotFoundFromDbConnection()
{
var snowflakeHome = Environment.GetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome);
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome, Path.Combine(s_workingDirectory, "InvalidFolder"));
try
{
using (var conn = new SnowflakeDbConnection())
{
Assert.Throws<SnowflakeDbException>(() => conn.Open(), "Error: Required property ACCOUNT is not provided");
}
}
finally
{
Environment.SetEnvironmentVariable(TomlConnectionBuilder.SnowflakeHome, snowflakeHome);
}
}

private static void CreateTomlConfigBaseOnConnectionString(string connectionString)
{
var tomlModel = new TomlTable();
var properties = SFSessionProperties.ParseConnectionString(connectionString, null);

var defaultTomlTable = new TomlTable();
tomlModel.Add("default", defaultTomlTable);

foreach (var property in properties)
{
defaultTomlTable.Add(property.Key.ToString(), property.Value);
}

var filePath = Path.Combine(s_workingDirectory, "connections.toml");

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
using (var writer = File.CreateText(filePath))
{
writer.Write(Toml.FromModel(tomlModel));
}
}
else
{
using (var writer = File.CreateText(filePath))
{
writer.Write(string.Empty);
}
Syscall.chmod(filePath, FilePermissions.S_IRUSR | FilePermissions.S_IWUSR);
using (var writer = File.CreateText(filePath))
{
writer.Write(Toml.FromModel(tomlModel));
}
Syscall.chmod(filePath, FilePermissions.S_IRUSR | FilePermissions.S_IWUSR);
}
}
}

}


15 changes: 13 additions & 2 deletions Snowflake.Data.Tests/SFBaseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,14 @@ public class IgnoreOnEnvIsAttribute : Attribute, ITestAction
private readonly string _key;

private readonly string[] _values;
public IgnoreOnEnvIsAttribute(string key, string[] values)

private readonly string _reason;

public IgnoreOnEnvIsAttribute(string key, string[] values, string reason = null)
{
_key = key;
_values = values;
_reason = reason;
}

public void BeforeTest(ITest test)
Expand All @@ -433,7 +437,7 @@ public void BeforeTest(ITest test)
{
if (Environment.GetEnvironmentVariable(_key) == value)
{
Assert.Ignore("Test is ignored when environment variable {0} is {1} ", _key, value);
Assert.Ignore("Test is ignored when environment variable {0} is {1}. {2}", _key, value, _reason);
}
}
}
Expand Down Expand Up @@ -468,4 +472,11 @@ public void AfterTest(ITest test)

public ActionTargets Targets => ActionTargets.Test | ActionTargets.Suite;
}

public class IgnoreOnCI : IgnoreOnEnvIsAttribute
{
public IgnoreOnCI(string reason = null) : base("CI", new[] { "true" }, reason)
{
}
}
}
1 change: 1 addition & 0 deletions Snowflake.Data.Tests/Snowflake.Data.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<PackageReference Include="RichardSzalay.MockHttp" Version="6.0.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="Tomlyn.Signed" Version="0.17.0" />
<ProjectReference Include="..\Snowflake.Data\Snowflake.Data.csproj" />
</ItemGroup>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ public void Setup()
MockHomeDirectory();
MockExecutionDirectory();
}

[Test]
public void TestThatTakesFilePathFromTheInput()
{
// arrange
MockFileFromEnvironmentalVariable();
MockFileOnDriverPath();
MockFileOnHomePath();

// act
var filePath = t_finder.FindConfigFilePath(InputConfigFilePath);

// assert
Assert.AreEqual(InputConfigFilePath, filePath);
t_fileOperations.VerifyNoOtherCalls();
Expand All @@ -71,14 +71,14 @@ public void TestThatTakesFilePathFromEnvironmentVariableIfInputNotPresent(
MockFileFromEnvironmentalVariable();
MockFileOnDriverPath();
MockFileOnHomePath();

// act
var filePath = t_finder.FindConfigFilePath(inputFilePath);

// assert
Assert.AreEqual(EnvironmentalConfigFilePath, filePath);
}

[Test]
public void TestThatTakesFilePathFromDriverLocationWhenNoInputParameterNorEnvironmentVariable()
{
Expand All @@ -88,20 +88,20 @@ public void TestThatTakesFilePathFromDriverLocationWhenNoInputParameterNorEnviro

// act
var filePath = t_finder.FindConfigFilePath(null);

// assert
Assert.AreEqual(s_driverConfigFilePath, filePath);
}

[Test]
public void TestThatTakesFilePathFromHomeLocationWhenNoInputParamEnvironmentVarNorDriverLocation()
{
// arrange
MockFileOnHomePath();

// act
var filePath = t_finder.FindConfigFilePath(null);

// assert
Assert.AreEqual(s_homeConfigFilePath, filePath);
}
Expand Down Expand Up @@ -138,13 +138,13 @@ public void TestThatConfigFileIsNotUsedIfOthersCanModifyTheConfigFile()
Assert.IsNotNull(thrown);
Assert.AreEqual(thrown.Message, $"Error due to other users having permission to modify the config file: {s_homeConfigFilePath}");
}

[Test]
public void TestThatReturnsNullIfNoWayOfGettingTheFile()
{
// act
var filePath = t_finder.FindConfigFilePath(null);

// assert
Assert.IsNull(filePath);
}
Expand All @@ -157,7 +157,7 @@ public void TestThatDoesNotFailWhenSearchForOneOfDirectoriesFails()

// act
var filePath = t_finder.FindConfigFilePath(null);

// assert
Assert.IsNull(filePath);
t_environmentOperations.Verify(e => e.GetFolderPath(Environment.SpecialFolder.UserProfile), Times.Once);
Expand Down Expand Up @@ -186,7 +186,7 @@ public void TestThatDoesNotFailWhenHomeDirectoryDoesNotExist()

// act
var filePath = t_finder.FindConfigFilePath(null);

// assert
Assert.IsNull(filePath);
t_environmentOperations.Verify(e => e.GetFolderPath(Environment.SpecialFolder.UserProfile), Times.Once);
Expand Down Expand Up @@ -220,7 +220,7 @@ private static void MockExecutionDirectory()
.Setup(e => e.GetExecutionDirectory())
.Returns(DriverDirectory);
}

private static void MockFileOnHomePathDoesNotExist()
{
t_fileOperations
Expand Down
61 changes: 61 additions & 0 deletions Snowflake.Data.Tests/UnitTests/SnowflakeDbConnectionTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@


using System;
using System.IO;
using Mono.Unix;

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

public class SnowflakeDbConnectionTest
{
[Test]
public void TestFillConnectionStringFromTomlConfig()
{
// Arrange
var mockFileOperations = new Mock<FileOperations>();
var mockEnvironmentOperations = new Mock<EnvironmentOperations>();
mockEnvironmentOperations.Setup(e => e.GetFolderPath(Environment.SpecialFolder.UserProfile))
.Returns($"{Path.DirectorySeparatorChar}home");
mockFileOperations.Setup(f => f.Exists(It.IsAny<string>())).Returns(true);
mockFileOperations.Setup(f => f.ReadAllText(It.IsAny<string>(), It.IsAny<Action<UnixStream>>()))
.Returns("[default]\naccount=\"testaccount\"\nuser=\"testuser\"\npassword=\"testpassword\"\n");
var tomlConnectionBuilder = new TomlConnectionBuilder(mockFileOperations.Object, mockEnvironmentOperations.Object);

// Act
using (var conn = new SnowflakeDbConnection(tomlConnectionBuilder))
{
conn.FillConnectionStringFromTomlConfigIfNotSet();
// Assert
Assert.AreEqual("account=testaccount;user=testuser;password=testpassword;", conn.ConnectionString);
}
}

[Test]
public void TestTomlConfigurationDoesNotOverrideExistingConnectionString()
{
// Arrange
var connectionTest = "account=user1account;user=user1;password=user1password;";
var mockFileOperations = new Mock<FileOperations>();
var mockEnvironmentOperations = new Mock<EnvironmentOperations>();
mockFileOperations.Setup(f => f.Exists(It.IsAny<string>())).Returns(true);
mockFileOperations.Setup(f => f.ReadAllText(It.IsAny<string>()))
.Returns("[default]\naccount=\"testaccount\"\nuser=\"testuser\"\npassword=\"testpassword\"\n");
var tomlConnectionBuilder = new TomlConnectionBuilder(mockFileOperations.Object, mockEnvironmentOperations.Object);

// Act
using (var conn = new SnowflakeDbConnection(tomlConnectionBuilder))
{
conn.ConnectionString = connectionTest;
conn.FillConnectionStringFromTomlConfigIfNotSet();
// Assert
Assert.AreEqual(connectionTest, conn.ConnectionString);
}
}
}
}
Loading

0 comments on commit f27eb2a

Please sign in to comment.