Public Access
Let a host carry pinned folders, merged path by path
This commit is contained in:
@@ -58,6 +58,7 @@ public sealed class HostSecretMergeTests
|
||||
SshKeyId = DeployKey,
|
||||
GroupId = Production,
|
||||
TagIds = TagSet.Create([Pci]),
|
||||
PinnedPaths = PinnedPathList.Create(["/var/www/app"]),
|
||||
};
|
||||
|
||||
var result = HostSecretMerge.Merge(ancestor, local, ancestor);
|
||||
@@ -160,6 +161,102 @@ public sealed class HostSecretMergeTests
|
||||
|
||||
private static Guid[] Wearing(bool tagged) => tagged ? [Pci] : [];
|
||||
|
||||
[Fact]
|
||||
public void TwoPeoplePinningDifferentPathsToOneHost_BothKeepTheirs()
|
||||
{
|
||||
// The same reason TagIds merges per tag rather than as a whole value: a whole-value merge would
|
||||
// take one side's list entire and drop the other's.
|
||||
var ancestor = Host();
|
||||
|
||||
var result = HostSecretMerge.Merge(
|
||||
ancestor,
|
||||
ancestor with { PinnedPaths = PinnedPathList.Create(["/var/www/app"]) },
|
||||
ancestor with { PinnedPaths = PinnedPathList.Create(["/var/log"]) });
|
||||
|
||||
result.Merged.PinnedPaths.ShouldBe(PinnedPathList.Create(["/var/www/app", "/var/log"]));
|
||||
result.HasConflicts.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PinnedPathAdditions_ComeOutInBaseOrderThenLocalThenRemote()
|
||||
{
|
||||
// The order guarantee this merge exists to keep: unlike a tag chip, a pinned path's position is
|
||||
// part of what the user set, so the merge must produce a deterministic order rather than whatever
|
||||
// a set union happens to yield.
|
||||
var ancestor = Host(pinnedPaths: ["/base/one", "/base/two"]);
|
||||
|
||||
var result = HostSecretMerge.Merge(
|
||||
ancestor,
|
||||
ancestor with
|
||||
{
|
||||
PinnedPaths = PinnedPathList.Create(["/base/one", "/base/two", "/local/added"]),
|
||||
},
|
||||
ancestor with
|
||||
{
|
||||
PinnedPaths = PinnedPathList.Create(["/base/one", "/base/two", "/remote/added"]),
|
||||
});
|
||||
|
||||
result.Merged.PinnedPaths.ShouldBe(
|
||||
PinnedPathList.Create(["/base/one", "/base/two", "/local/added", "/remote/added"]));
|
||||
result.HasConflicts.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OneSideRemovingAPinnedPathWhileTheOtherAddsAnother_KeepsBothDecisions()
|
||||
{
|
||||
// Each path is resolved on its own, so a removal on one side and an addition on the other are two
|
||||
// independent answers rather than two versions of one. A whole-value merge would have to pick.
|
||||
var ancestor = Host(pinnedPaths: ["/var/www/app"]);
|
||||
|
||||
var result = HostSecretMerge.Merge(
|
||||
ancestor,
|
||||
ancestor with { PinnedPaths = PinnedPathList.Empty },
|
||||
ancestor with
|
||||
{
|
||||
PinnedPaths = PinnedPathList.Create(["/var/www/app", "/var/log"]),
|
||||
});
|
||||
|
||||
result.Merged.PinnedPaths.ShouldBe(PinnedPathList.Create(["/var/log"]));
|
||||
result.HasConflicts.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void APinnedPathRemovedOnBothSides_IsNotResurrected()
|
||||
{
|
||||
var ancestor = Host(pinnedPaths: ["/var/www/app", "/var/log"]);
|
||||
var withoutApp = ancestor with { PinnedPaths = PinnedPathList.Create(["/var/log"]) };
|
||||
|
||||
var result = HostSecretMerge.Merge(ancestor, withoutApp, withoutApp);
|
||||
|
||||
result.Merged.PinnedPaths.ShouldBe(PinnedPathList.Create(["/var/log"]));
|
||||
result.HasConflicts.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="NoArrangementOfOneTag_ProducesAConflict" />
|
||||
[Theory]
|
||||
[InlineData(true, true, true)]
|
||||
[InlineData(true, true, false)]
|
||||
[InlineData(true, false, true)]
|
||||
[InlineData(true, false, false)]
|
||||
[InlineData(false, true, true)]
|
||||
[InlineData(false, true, false)]
|
||||
[InlineData(false, false, true)]
|
||||
[InlineData(false, false, false)]
|
||||
public void NoArrangementOfOnePinnedPath_ProducesAConflict(bool inAncestor, bool inLocal, bool inRemote)
|
||||
{
|
||||
var result = HostSecretMerge.Merge(
|
||||
Host(pinnedPaths: Pinning(inAncestor)),
|
||||
Host(pinnedPaths: Pinning(inLocal)),
|
||||
Host(pinnedPaths: Pinning(inRemote)));
|
||||
|
||||
result.HasConflicts.ShouldBeFalse();
|
||||
|
||||
result.Merged.PinnedPaths.Contains("/var/www/app")
|
||||
.ShouldBe(inAncestor ? inLocal && inRemote : inLocal || inRemote);
|
||||
}
|
||||
|
||||
private static string[] Pinning(bool pinned) => pinned ? ["/var/www/app"] : [];
|
||||
|
||||
[Fact]
|
||||
public void TwoSidesTakingDifferentPorts_NamesTheInheritedOneInTheConflict()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user