Add typed high-level ruleset and set API
This commit is contained in:
99
tests/LibNftables.Tests/NftRulesetRendererTests.cs
Normal file
99
tests/LibNftables.Tests/NftRulesetRendererTests.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
namespace LibNftables.Tests;
|
||||
|
||||
public sealed class NftRulesetRendererTests
|
||||
{
|
||||
[Fact]
|
||||
public void Render_WithTypedSet_RendersExpectedCommands()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Family = NftFamily.Inet,
|
||||
Name = "filter",
|
||||
};
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "blocked_ipv4",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
};
|
||||
set.Elements.Add("10.0.0.1");
|
||||
set.Elements.Add("10.0.0.2");
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
string rendered = NftRulesetRenderer.Render(ruleset);
|
||||
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
rendered);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithCustomTypeExpression_UsesCustomKeyword()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Family = NftFamily.Ip,
|
||||
Name = "custom",
|
||||
};
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "ports",
|
||||
CustomTypeExpression = "inet_service",
|
||||
};
|
||||
set.Elements.Add("80");
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
string rendered = NftRulesetRenderer.Render(ruleset);
|
||||
|
||||
Assert.Contains("type inet_service;", rendered, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithNoTables_ThrowsValidationException()
|
||||
{
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(new NftRuleset()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithConflictingSetTypeSources_ThrowsValidationException()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Name = "filter",
|
||||
};
|
||||
table.Sets.Add(new NftSet
|
||||
{
|
||||
Name = "conflict",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
CustomTypeExpression = "ipv4_addr",
|
||||
});
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_WithInvalidElement_ThrowsValidationException()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Name = "filter",
|
||||
};
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "bad",
|
||||
Type = NftSetType.Mark,
|
||||
};
|
||||
set.Elements.Add("1; drop");
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
Assert.Throws<NftValidationException>(() => NftRulesetRenderer.Render(ruleset));
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,36 @@ public sealed class NftablesClientIntegrationTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateRuleset_WithTypedSetDefinition_ReturnsValidResult()
|
||||
{
|
||||
if (!CanCreateClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var client = new NftablesClient();
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Family = NftFamily.Inet,
|
||||
Name = "typed_validation",
|
||||
};
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "blocked_ipv4",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
};
|
||||
set.Elements.Add("10.0.0.1");
|
||||
set.Elements.Add("10.0.0.2");
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
|
||||
NftValidationResult result = client.ValidateRuleset(ruleset);
|
||||
|
||||
Assert.True(result.IsValid);
|
||||
}
|
||||
|
||||
private static bool CanCreateClient()
|
||||
{
|
||||
try
|
||||
|
||||
@@ -64,6 +64,55 @@ public sealed class NftablesClientUnitTests
|
||||
Assert.Equal("ok", result.Output);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ValidateRuleset_RendersTypedRulesetAndUsesDryRun()
|
||||
{
|
||||
var context = new FakeContext
|
||||
{
|
||||
OutputBuffer = "ok",
|
||||
ErrorBuffer = string.Empty,
|
||||
};
|
||||
var client = CreateClient(() => context);
|
||||
|
||||
NftValidationResult result = client.ValidateRuleset(CreateTypedRuleset());
|
||||
|
||||
Assert.True(result.IsValid);
|
||||
Assert.True(context.DryRun);
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
context.LastCommandText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ApplyRuleset_RendersTypedRulesetAndExecutesCommand()
|
||||
{
|
||||
var context = new FakeContext();
|
||||
var client = CreateClient(() => context);
|
||||
|
||||
client.ApplyRuleset(CreateTypedRuleset());
|
||||
|
||||
Assert.False(context.DryRun);
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
context.LastCommandText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApplyRulesetAsync_UsesTypedRulesetText()
|
||||
{
|
||||
var context = new FakeContext();
|
||||
var client = CreateClient(() => context);
|
||||
|
||||
await client.ApplyRulesetAsync(CreateTypedRuleset());
|
||||
|
||||
Assert.Equal(
|
||||
"add table inet filter" + Environment.NewLine +
|
||||
"add set inet filter blocked_ipv4 { type ipv4_addr; elements = { 10.0.0.1, 10.0.0.2 }; }" + Environment.NewLine,
|
||||
context.LastCommandText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Apply_WithFileRequest_UsesFileExecutionPath()
|
||||
{
|
||||
@@ -191,6 +240,26 @@ public sealed class NftablesClientUnitTests
|
||||
NftablesClientOptions? options = null)
|
||||
=> new(options, contextFactory ?? (() => new FakeContext()), skipRuntimeGuard: true);
|
||||
|
||||
private static NftRuleset CreateTypedRuleset()
|
||||
{
|
||||
var ruleset = new NftRuleset();
|
||||
var table = new NftTable
|
||||
{
|
||||
Family = NftFamily.Inet,
|
||||
Name = "filter",
|
||||
};
|
||||
var set = new NftSet
|
||||
{
|
||||
Name = "blocked_ipv4",
|
||||
Type = NftSetType.Ipv4Address,
|
||||
};
|
||||
set.Elements.Add("10.0.0.1");
|
||||
set.Elements.Add("10.0.0.2");
|
||||
table.Sets.Add(set);
|
||||
ruleset.Tables.Add(table);
|
||||
return ruleset;
|
||||
}
|
||||
|
||||
private sealed class FakeContext : INftContextHandle
|
||||
{
|
||||
public bool DryRun { get; set; }
|
||||
|
||||
Reference in New Issue
Block a user