Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions src/Grok.Net.PowerShell/OutputHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ public static string GetJsonOutput(List<Dictionary<string, object>> records, boo

public static string GetCsvOutput(List<Dictionary<string, object>> records, string delimiter)
{
if (records.Count == 0)
{
return string.Empty;
}

Dictionary<string, object>[] notNullRecords = records.Where(r => r != null).ToArray();
if (!notNullRecords.Any())
{
Expand Down
6 changes: 5 additions & 1 deletion src/Grok.Net.Tests/Grok.Net.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@
</ItemGroup>

<ItemGroup>
<None Update="Patterns\grok-custom-patterns">

<None Update="Resources\grok-custom-patterns">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Resources\example-log-file">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
273 changes: 269 additions & 4 deletions src/Grok.Net.Tests/PowerShellUnitTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using CsvHelper;
using GrokNet;
using GrokNet.PowerShell;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;

namespace GrokNetTests
Expand Down Expand Up @@ -106,14 +113,112 @@ public void StringInput_FormattedTableOutputWithEmptyRow_ValidOutput()
public void StringInput_FormattedTableOutput_NoMatchingFeedback()
{
// Arrange
var intendedColumns = new[] {"client", "method", "request", "bytes", "duration"};

var input = "Hello world!";
var pattern = "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}";

var cmdlet = new GrokCmdlet {Input = input, GrokPattern = pattern};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.NotNull(result);
Assert.NotEmpty(result);
Assert.Equal("No matching elements found", result);
}

[Fact]
public void StringInput_JsonOutput_ValidOutput()
{
// Arrange
var data = new Dictionary<string, string>()
{
{"client", "55.3.244.1"},
{"method", "GET"},
{"request", "/index.html"},
{"bytes", "15824"},
{"duration", "0.043"}
};

var input = string.Format("{0} {1} {2} {3} {4}", data.Values.ToArray());
var pattern =
string.Format("%{{IP:{0}}} %{{WORD:{1}}} %{{URIPATHPARAM:{2}}} %{{NUMBER:{3}}} %{{NUMBER:{4}}}",
intendedColumns);
data.Keys.ToArray());

var cmdlet = new GrokCmdlet {Input = input, GrokPattern = pattern};
var cmdlet = new GrokCmdlet {Input = input, GrokPattern = pattern, OutputFormat = "json"};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.NotNull(result);
var json = JsonConvert.DeserializeObject<JArray>(result);

Assert.NotNull(json);
Assert.Single(json);

var element = json.First();

foreach (var (key, value) in data)
{
Assert.NotNull(element[key]);
Assert.Equal(value, element[key]);
}
}

[Fact]
public void StringInput_JsonOutput_EmptyArray()
{
// Arrange
var cmdlet = new GrokCmdlet
{
Input = string.Empty,
GrokPattern = "%{NUMBER:duration} %{IP:client}",
OutputFormat = "json",
IgnoreEmptyLines = true
};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.Equal("[]", result);
}

[Fact]
public void StringInput_JsonOutputWithNullElement_ValidOutput()
{
// Arrange
var input = @"55.3.244.1 GET /index.html 15824 0.043

127.0.0.1 POST /contact.html 123123 1212.5";
var pattern = "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}";

var cmdlet = new GrokCmdlet {Input = input, GrokPattern = pattern, OutputFormat = "json"};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.NotNull(result);

var json = JsonConvert.DeserializeObject<JArray>(result);

Assert.NotNull(json);
Assert.True(json.Count == 3);

var emptyElement = json[1] as JValue;
Assert.Null(emptyElement?.Value);
}

[Fact]
public void StringInput_CsvOutput_NoMatchingFeedback()
{
// Arrange
var input = "Hello world!";
var pattern = "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}";

var cmdlet = new GrokCmdlet {Input = input, GrokPattern = pattern, OutputFormat = "csv"};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();
Expand All @@ -123,5 +228,165 @@ public void StringInput_FormattedTableOutput_NoMatchingFeedback()
Assert.NotEmpty(result);
Assert.Equal("No matching elements found", result);
}

[Fact]
public void StringInput_CsvOutput_ValidOutput()
{
// Arrange
var data = new Dictionary<string, string>()
{
{"client", "55.3.244.1"},
{"method", "GET"},
{"request", "/index.html"},
{"bytes", "15824"},
{"duration", "0.043"}
};

var input = string.Format("{0} {1} {2} {3} {4}", data.Values.ToArray());
var pattern =
string.Format("%{{IP:{0}}} %{{WORD:{1}}} %{{URIPATHPARAM:{2}}} %{{NUMBER:{3}}} %{{NUMBER:{4}}}",
data.Keys.ToArray());

var cmdlet = new GrokCmdlet {Input = input, GrokPattern = pattern, OutputFormat = "csv"};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.NotNull(result);

using var reader = new StringReader(result);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
var records = csv.GetRecords<dynamic>().ToArray();

Assert.Single(records);

var element = records.First() as IDictionary<string, object>;

Assert.NotNull(element);

foreach (var (key, value) in data)
{
Assert.True(element.ContainsKey(key));
Assert.Equal(value, element[key]);
}
}

[Fact]
public void StringInput_CsvOutputWithNullElement_ValidOutput()
{
// Arrange
var input = @"55.3.244.1 GET /index.html 15824 0.043

127.0.0.1 POST /contact.html 123123 1212.5";
var pattern = "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}";

var cmdlet = new GrokCmdlet {Input = input, GrokPattern = pattern, OutputFormat = "csv"};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.NotNull(result);

using var reader = new StringReader(result);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
csv.GetRecords<dynamic>();

var lines = result.Split(Environment.NewLine);
Assert.True(lines.Length >= 4); // 3 elements + header
Assert.True(string.IsNullOrWhiteSpace(lines[2]));
}

[Fact]
public void FileInput_JsonOutput_ValidOutput()
{
// Arrange
var expectedData = new Dictionary<string, string>()
{
{"client", "55.3.244.1"},
{"method", "GET"},
{"request", "/index.html"},
{"bytes", "15824"},
{"duration", "0.043"}
};

var path = "./Resources/example-log-file";
var pattern =
string.Format("%{{IP:{0}}} %{{WORD:{1}}} %{{URIPATHPARAM:{2}}} %{{NUMBER:{3}}} %{{NUMBER:{4}}}",
expectedData.Keys.ToArray());

var cmdlet = new GrokCmdlet {Path = path, GrokPattern = pattern, OutputFormat = "json"};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.NotNull(result);

var json = JsonConvert.DeserializeObject<JArray>(result);

Assert.NotNull(json);
Assert.Single(json);

var element = json.First();

foreach (var (key, value) in expectedData)
{
Assert.NotNull(element[key]);
Assert.Equal(value, element[key]);
}
}

[Fact]
public void CustomPatternsFile_ValidOutput()
{
// Arrange
var path = "./Resources/grok-custom-patterns";
var expectedData = new Dictionary<string, string>()
{
{"zipcode", "122001"}, {"email", "[email protected]"}
};
var input = string.Format("{0} {1}", expectedData.Values.ToArray());
var pattern = string.Format("%{{ZIPCODE:{0}}} %{{EMAILADDRESS:{1}}}", expectedData.Keys.ToArray());

var cmdlet = new GrokCmdlet
{
Input = input, GrokPattern = pattern, CustomPatterns = path, OutputFormat = "json"
};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
Assert.NotNull(result);

var json = JsonConvert.DeserializeObject<JArray>(result);

Assert.NotNull(json);
Assert.Single(json);

var element = json.First();

foreach (var (key, value) in expectedData)
{
Assert.NotNull(element[key]);
Assert.Equal(value, element[key]);
}
}

[Fact]
public void Version_GrokNetVersion()
{
// Arrange
var cmdlet = new GrokCmdlet {Version = true};

// Act
var result = cmdlet.Invoke().OfType<string>().FirstOrDefault();

// Assert
var version = typeof(Grok).Assembly.GetName().Version?.ToString();
Assert.Equal($"Grok.Net {version}", result);
}
}
}
1 change: 1 addition & 0 deletions src/Grok.Net.Tests/Resources/example-log-file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
55.3.244.1 GET /index.html 15824 0.043
2 changes: 1 addition & 1 deletion src/Grok.Net.Tests/UnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace GrokNetTests
public class UnitTests
{
private static Stream ReadCustomFile() =>
File.OpenRead($"Patterns{Path.DirectorySeparatorChar}grok-custom-patterns");
File.OpenRead($"Resources{Path.DirectorySeparatorChar}grok-custom-patterns");

[Fact]
public void Parse_Empty_Logs_Not_Throws()
Expand Down