Skip to content

Commit

Permalink
SNOW-990111 easy logging driver directory + Mono.Unix (#868)
Browse files Browse the repository at this point in the history
### Description
Easy Logging: get driver directory from executable path and use Mono.Unix

### Checklist
- [x] Code compiles correctly
- [x] Code is formatted according to [Coding
Conventions](../CodingConventions.md)
- [x] Created tests which fail without the change (if possible)
- [x] All tests passing (`dotnet test`)
- [x] Extended the README / documentation, if necessary
- [x] Provide JIRA issue id (if possible) or GitHub issue id in PR name
  • Loading branch information
sfc-gh-knozderko authored Feb 22, 2024
1 parent 22871b5 commit a868910
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 6 deletions.
25 changes: 25 additions & 0 deletions Snowflake.Data.Tests/IntegrationTests/EasyLoggingIT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,30 @@ public void TestFailToEnableEasyLoggingWhenConfigHasWrongPermissions()
Assert.IsFalse(EasyLoggerManager.HasEasyLoggingAppender());
}
}

[Test]
public void TestFailToEnableEasyLoggingWhenLogDirectoryNotAccessible()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Assert.Ignore("skip test on Windows");
}

// arrange
var configFilePath = CreateConfigTempFile(s_workingDirectory, Config("WARN", "/"));
using (IDbConnection conn = new SnowflakeDbConnection())
{
conn.ConnectionString = ConnectionString + $"CLIENT_CONFIG_FILE={configFilePath}";

// act
var thrown = Assert.Throws<SnowflakeDbException>(() => conn.Open());

// assert
Assert.That(thrown.Message, Does.Contain("Connection string is invalid: Unable to connect"));
Assert.That(thrown.InnerException.Message, Does.Contain("Failed to create logs directory"));
Assert.IsFalse(EasyLoggerManager.HasEasyLoggingAppender());
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public void Setup()
t_environmentOperations = new Mock<EnvironmentOperations>();
t_finder = new EasyLoggingConfigFinder(t_fileOperations.Object, t_unixOperations.Object, t_environmentOperations.Object);
MockHomeDirectory();
MockExecutionDirectory();
}

[Test]
Expand Down Expand Up @@ -213,6 +214,13 @@ private static void MockHomeDirectoryFails()
.Throws(() => new Exception("No home directory"));
}

private static void MockExecutionDirectory()
{
t_environmentOperations
.Setup(e => e.GetExecutionDirectory())
.Returns(DriverDirectory);
}

private static void MockFileOnHomePathDoesNotExist()
{
t_fileOperations
Expand Down
23 changes: 23 additions & 0 deletions Snowflake.Data.Tests/UnitTests/Session/EasyLoggingStarterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,29 @@ public void TestThatDoesNotFailWhenLogDirectoryPermissionIsNot700()
FilePermissions.S_IRUSR | FilePermissions.S_IWUSR | FilePermissions.S_IXUSR), Times.Never);
}

[Test]
public void TestFailIfDirectoryCreationFails()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Assert.Ignore("skip test on Windows");
}

// arrange
t_easyLoggingProvider
.Setup(provider => provider.ProvideConfig(ConfigPath))
.Returns(s_configWithErrorLevel);
t_unixOperations
.Setup(u => u.CreateDirectoryWithPermissions(s_expectedLogPath, FilePermissions.S_IRUSR | FilePermissions.S_IWUSR | FilePermissions.S_IXUSR))
.Returns((int)Errno.EPERM);

// act
var thrown = Assert.Throws<Exception>(() => t_easyLoggerStarter.Init(ConfigPath));

// assert
Assert.That(thrown.Message, Does.Contain("Failed to create logs directory"));
}

[Test]
public void TestThatConfiguresEasyLoggingOnlyOnceWhenInitializedWithConfigPath()
{
Expand Down
4 changes: 2 additions & 2 deletions Snowflake.Data/Configuration/EasyLoggingConfigFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ private string GetFilePathFromInputParameter(string filePath, string inputDescri

private string GetHomeDirectory() => HomeDirectoryProvider.HomeDirectory(_environmentOperations);

private string GetFilePathFromDriverLocation() => SearchForConfigInDirectory(() => ".", "driver");

private string GetFilePathFromDriverLocation() => SearchForConfigInDirectory(() => _environmentOperations.GetExecutionDirectory(), "driver");
private string SearchForConfigInDirectory(Func<string> directoryProvider, string directoryDescription)
{
try
Expand Down
7 changes: 6 additions & 1 deletion Snowflake.Data/Core/Session/EasyLoggingStarter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,13 @@ private string GetLogPath(string logPath)
{
Directory.CreateDirectory(logPathOrDefault);
}
_unixOperations.CreateDirectoryWithPermissions(pathWithDotnetSubdirectory,
var createDirResult = _unixOperations.CreateDirectoryWithPermissions(pathWithDotnetSubdirectory,
FilePermissions.S_IRUSR | FilePermissions.S_IWUSR | FilePermissions.S_IXUSR);
if (createDirResult != 0)
{
s_logger.Error($"Failed to create logs directory: {pathWithDotnetSubdirectory}");
throw new Exception("Failed to create logs directory");
}
}
}
CheckDirPermissionsOnlyAllowUser(pathWithDotnetSubdirectory);
Expand Down
15 changes: 15 additions & 0 deletions Snowflake.Data/Core/Tools/EnvironmentOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
*/

using System;
using System.IO;
using Snowflake.Data.Log;

namespace Snowflake.Data.Core.Tools
{
internal class EnvironmentOperations
{
public static readonly EnvironmentOperations Instance = new EnvironmentOperations();
private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger<EnvironmentOperations>();

public virtual string GetEnvironmentVariable(string variable)
{
Expand All @@ -19,5 +22,17 @@ public virtual string GetFolderPath(Environment.SpecialFolder folder)
{
return Environment.GetFolderPath(folder);
}

public virtual string GetExecutionDirectory()
{
var executablePath = Environment.GetCommandLineArgs()[0];
var directoryName = string.IsNullOrEmpty(executablePath) ? null : Path.GetDirectoryName(executablePath);
if (string.IsNullOrEmpty(directoryName))
{
s_logger.Warn("Unable to determine execution directory");
return null;
}
return directoryName;
}
}
}
4 changes: 2 additions & 2 deletions Snowflake.Data/Core/Tools/UnixOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ internal class UnixOperations
{
public static readonly UnixOperations Instance = new UnixOperations();

public virtual void CreateDirectoryWithPermissions(string path, FilePermissions permissions)
public virtual int CreateDirectoryWithPermissions(string path, FilePermissions permissions)
{
Syscall.mkdir(path, permissions);
return Syscall.mkdir(path, permissions);
}

public virtual FileAccessPermissions GetDirPermissions(string path)
Expand Down
2 changes: 1 addition & 1 deletion Snowflake.Data/Snowflake.Data.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<PackageReference Include="Google.Cloud.Storage.V1" Version="4.6.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.13.0" />
<PackageReference Include="Azure.Storage.Common" Version="12.12.0" />
<PackageReference Include="Mono.Posix" Version="7.1.0-final.1.21458.1" />
<PackageReference Include="Mono.Unix" Version="7.1.0-final.1.21458.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="log4net" Version="2.0.12" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
Expand Down

0 comments on commit a868910

Please sign in to comment.