Skip to content

Commit 3cb8b48

Browse files
authored
Merge branch 'main' into copilot/add-metrics-table-to-graph
2 parents a85254c + 78b1136 commit 3cb8b48

File tree

3 files changed

+253
-1
lines changed

3 files changed

+253
-1
lines changed

Src/BlueDotBrigade.Weevil.Core/Configuration/Sidecar/SidecarManager.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Collections.Immutable;
6+
using System.IO;
67
using Data;
78
using Diagnostics;
89
using IO;
@@ -20,7 +21,27 @@ public SidecarManager(string logFilePath)
2021
_sidecarFilePath = string.IsNullOrEmpty(logFilePath)
2122
? throw new ArgumentNullException(nameof(logFilePath))
2223
: $"{logFilePath}.{MetadataFileExtension}";
23-
_file = new File();
24+
_file = new IO.File();
25+
}
26+
27+
/// <summary>
28+
/// Determines if the sidecar file path is in a temporary directory.
29+
/// </summary>
30+
private bool IsInTemporaryDirectory()
31+
{
32+
try
33+
{
34+
var tempPath = Path.GetTempPath();
35+
var sidecarDirectory = Path.GetDirectoryName(_sidecarFilePath);
36+
37+
// Check if the sidecar path starts with the temp path
38+
return sidecarDirectory?.StartsWith(tempPath, StringComparison.OrdinalIgnoreCase) ?? false;
39+
}
40+
catch
41+
{
42+
// If we can't determine, assume it's not in temp directory
43+
return false;
44+
}
2445
}
2546

2647
public void Load(
@@ -109,6 +130,15 @@ public void Load(
109130

110131
public void Save(SidecarData data, bool deleteBackup)
111132
{
133+
// Skip save operation if the file is from a compressed archive (in temp directory)
134+
if (IsInTemporaryDirectory())
135+
{
136+
Log.Default.Write(
137+
LogSeverityType.Information,
138+
$"Skipping sidecar save for file from compressed archive. File={_sidecarFilePath}");
139+
return;
140+
}
141+
112142
var backupFilePath = $"{_sidecarFilePath}~";
113143

114144
Log.Default.Write(LogSeverityType.Debug, $"Sidecar data is being saved... File={_sidecarFilePath}");
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
namespace BlueDotBrigade.Weevil.Integration
2+
{
3+
using System;
4+
using System.IO;
5+
using System.IO.Compression;
6+
using BlueDotBrigade.Weevil;
7+
using Microsoft.VisualStudio.TestTools.UnitTesting;
8+
9+
/// <summary>
10+
/// Integration test to verify that opening a log from a zip file and saving metadata
11+
/// does not throw an exception when the temporary directory is deleted.
12+
/// </summary>
13+
[TestClass]
14+
public class CompressedFileIntegrationTests
15+
{
16+
[TestMethod]
17+
public void OpenLogFromZip_SaveMetadata_SkipsSaveInTempDirectory()
18+
{
19+
// Arrange - Create a test log file in a zip
20+
var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
21+
Directory.CreateDirectory(tempDir);
22+
23+
var logDir = Path.Combine(tempDir, "logs");
24+
Directory.CreateDirectory(logDir);
25+
26+
var logFilePath = Path.Combine(logDir, "test.log");
27+
System.IO.File.WriteAllLines(logFilePath, new[]
28+
{
29+
"2024-01-01 10:00:00 [INFO] Test log entry 1",
30+
"2024-01-01 10:00:01 [INFO] Test log entry 2",
31+
"2024-01-01 10:00:02 [ERROR] Test error entry 3",
32+
"2024-01-01 10:00:03 [INFO] Test log entry 4",
33+
"2024-01-01 10:00:04 [INFO] Test log entry 5"
34+
});
35+
36+
var zipFilePath = Path.Combine(tempDir, "test.zip");
37+
ZipFile.CreateFromDirectory(logDir, zipFilePath, CompressionLevel.Optimal, false);
38+
39+
// Simulate extracting to a temp directory (like Weevil does)
40+
var extractDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
41+
ZipFile.ExtractToDirectory(zipFilePath, extractDir);
42+
var extractedLogPath = Path.Combine(extractDir, "test.log");
43+
44+
try
45+
{
46+
// Act - Open the log file and add a comment
47+
var engine = Engine
48+
.UsingPath(extractedLogPath)
49+
.Open();
50+
51+
// Add a comment to the first record
52+
engine.Records[0].Metadata.Comment = "Test comment added";
53+
54+
// Try to save - this should NOT throw an exception
55+
// and should skip the save since it's in a temp directory
56+
engine.Save();
57+
58+
// Assert - no sidecar should be created in temp directory
59+
var sidecarPath = $"{extractedLogPath}.xml";
60+
Assert.IsFalse(System.IO.File.Exists(sidecarPath), "Sidecar should not be created in temp directory");
61+
}
62+
finally
63+
{
64+
// Cleanup
65+
try
66+
{
67+
if (Directory.Exists(tempDir))
68+
{
69+
Directory.Delete(tempDir, true);
70+
}
71+
if (Directory.Exists(extractDir))
72+
{
73+
Directory.Delete(extractDir, true);
74+
}
75+
}
76+
catch
77+
{
78+
// Ignore cleanup errors
79+
}
80+
}
81+
}
82+
83+
[TestMethod]
84+
public void OpenLogFromNonTempDirectory_SuccessfulSave_CreatesMetadata()
85+
{
86+
// Arrange - Create a test log file in current directory (not temp)
87+
var currentDir = Directory.GetCurrentDirectory();
88+
var testDir = Path.Combine(currentDir, $"test_{Guid.NewGuid()}");
89+
Directory.CreateDirectory(testDir);
90+
91+
var logFilePath = Path.Combine(testDir, "test.log");
92+
System.IO.File.WriteAllLines(logFilePath, new[]
93+
{
94+
"2024-01-01 10:00:00 [INFO] Test log entry 1",
95+
"2024-01-01 10:00:01 [INFO] Test log entry 2",
96+
"2024-01-01 10:00:02 [ERROR] Test error entry 3"
97+
});
98+
99+
try
100+
{
101+
// Act - Open the log file and add a comment
102+
var engine = Engine
103+
.UsingPath(logFilePath)
104+
.Open();
105+
106+
// Add a comment to the first record
107+
engine.Records[0].Metadata.Comment = "Test comment";
108+
109+
// Save - this should succeed since it's not in temp directory
110+
engine.Save();
111+
112+
// Assert
113+
var sidecarPath = $"{logFilePath}.xml";
114+
Assert.IsTrue(System.IO.File.Exists(sidecarPath), "Sidecar file should be created in non-temp directory");
115+
116+
// Verify the comment was saved
117+
var engine2 = Engine
118+
.UsingPath(logFilePath)
119+
.Open();
120+
121+
Assert.AreEqual("Test comment", engine2.Records[0].Metadata.Comment, "Comment should be loaded from sidecar");
122+
}
123+
finally
124+
{
125+
// Cleanup
126+
try
127+
{
128+
if (Directory.Exists(testDir))
129+
{
130+
Directory.Delete(testDir, true);
131+
}
132+
}
133+
catch
134+
{
135+
// Ignore cleanup errors
136+
}
137+
}
138+
}
139+
}
140+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
namespace BlueDotBrigade.Weevil.Configuration.Sidecar
2+
{
3+
using System;
4+
using System.Collections.Immutable;
5+
using System.IO;
6+
using BlueDotBrigade.Weevil.Data;
7+
using BlueDotBrigade.Weevil.Navigation;
8+
using Microsoft.VisualStudio.TestTools.UnitTesting;
9+
10+
[TestClass]
11+
public class SidecarManagerTests
12+
{
13+
[TestMethod]
14+
public void Save_WhenInTemporaryDirectory_SkipsSaveOperation()
15+
{
16+
// Arrange - Use temp directory (from compressed archive scenario)
17+
var tempPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString(), "test.log");
18+
var sidecarManager = new SidecarManager(tempPath);
19+
var sidecarData = new SidecarData
20+
{
21+
Records = ImmutableArray<IRecord>.Empty,
22+
Context = new ContextDictionary(),
23+
FilterTraits = null,
24+
SourceFileRemarks = string.Empty,
25+
TableOfContents = null,
26+
Regions = ImmutableArray<Region>.Empty,
27+
Bookmarks = ImmutableArray<Bookmark>.Empty
28+
};
29+
30+
// Act - should skip save and not throw exception
31+
sidecarManager.Save(sidecarData, false);
32+
33+
// Assert - test passes if no exception is thrown and no file is created
34+
Assert.IsFalse(System.IO.File.Exists($"{tempPath}.xml"), "Sidecar should not be created in temp directory");
35+
}
36+
37+
[TestMethod]
38+
public void Save_WhenNotInTemporaryDirectory_SavesMetadata()
39+
{
40+
// Arrange - Use a non-temp directory
41+
var currentDir = Directory.GetCurrentDirectory();
42+
var tempFile = Path.Combine(currentDir, $"test_{Guid.NewGuid()}.log");
43+
System.IO.File.WriteAllText(tempFile, "test content");
44+
45+
try
46+
{
47+
var sidecarManager = new SidecarManager(tempFile);
48+
var sidecarData = new SidecarData
49+
{
50+
Records = ImmutableArray<IRecord>.Empty,
51+
Context = new ContextDictionary(),
52+
FilterTraits = null,
53+
SourceFileRemarks = "Test remarks",
54+
TableOfContents = null,
55+
Regions = ImmutableArray<Region>.Empty,
56+
Bookmarks = ImmutableArray<Bookmark>.Empty
57+
};
58+
59+
// Act
60+
sidecarManager.Save(sidecarData, true);
61+
62+
// Assert
63+
var sidecarPath = $"{tempFile}.xml";
64+
Assert.IsTrue(System.IO.File.Exists(sidecarPath), "Sidecar file should be created in non-temp directory");
65+
}
66+
finally
67+
{
68+
// Cleanup
69+
try
70+
{
71+
System.IO.File.Delete(tempFile);
72+
System.IO.File.Delete($"{tempFile}.xml");
73+
System.IO.File.Delete($"{tempFile}.xml~");
74+
}
75+
catch
76+
{
77+
// Ignore cleanup errors
78+
}
79+
}
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)