-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
320 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,224 @@ | ||
using System.Net; | ||
using System.Net.Sockets; | ||
using Docker.DotNet; | ||
using Docker.DotNet.Models; | ||
using LNUnit.Setup; | ||
using Npgsql; | ||
using ServiceStack; | ||
using Xunit; | ||
using Assert = NUnit.Framework.Assert; | ||
using HostConfig = Docker.DotNet.Models.HostConfig; | ||
|
||
namespace LNUnit.Fixtures; | ||
|
||
// ReSharper disable once ClassNeverInstantiated.Global | ||
public class PostgresLightningFixture : IDisposable | ||
{ | ||
public string DbContainerName { get; set; }= "postgres"; | ||
private readonly DockerClient _client = new DockerClientConfiguration().CreateClient(); | ||
private string _containerId; | ||
private string _ip; | ||
|
||
public PostgresLightningFixture() | ||
{ | ||
StartPostgres().Wait(); | ||
AddDb("alice"); | ||
AddDb("bob"); | ||
AddDb("carol"); | ||
SetupNetwork().Wait(); | ||
} | ||
|
||
private void AddDb(string dbName) | ||
{ | ||
using (NpgsqlConnection connection = new(DbConnectionString)) | ||
{ | ||
connection.Open(); | ||
using var checkIfExistsCommand = new NpgsqlCommand($"SELECT 1 FROM pg_catalog.pg_database WHERE datname = '{dbName}'", connection); | ||
var result = checkIfExistsCommand.ExecuteScalar(); | ||
|
||
if (result == null) | ||
{ | ||
|
||
using var command = new NpgsqlCommand($"CREATE DATABASE \"{dbName}\"", connection); | ||
command.ExecuteNonQuery(); | ||
} | ||
} | ||
LNDConnectionStrings.Add(dbName, | ||
$"postgresql://superuser:superuser@{_ip}:5432/{dbName}?sslmode=disable"); | ||
} | ||
|
||
public string DbConnectionStringLND { get; private set; } | ||
public string DbConnectionString { get; private set; } | ||
|
||
public Dictionary<string, string> LNDConnectionStrings = new(); | ||
public void Dispose() | ||
{ | ||
GC.SuppressFinalize(this); | ||
|
||
// Remove containers | ||
RemoveContainer(DbContainerName).Wait(); | ||
RemoveContainer("miner").Wait(); | ||
RemoveContainer("alice").Wait(); | ||
RemoveContainer("bob").Wait(); | ||
RemoveContainer("carol").Wait(); | ||
|
||
Builder?.Destroy(); | ||
_client.Dispose(); | ||
} | ||
|
||
public LNUnitBuilder? Builder { get; private set; } | ||
|
||
|
||
public async Task SetupNetwork() | ||
{ | ||
await RemoveContainer("miner"); | ||
await RemoveContainer("alice"); | ||
await RemoveContainer("bob"); | ||
await RemoveContainer("carol"); | ||
|
||
await _client.CreateDockerImageFromPath("../../../../Docker/lnd", ["custom_lnd", "custom_lnd:latest"]); | ||
Builder = new LNUnitBuilder(); | ||
|
||
Builder.AddBitcoinCoreNode(); | ||
|
||
Builder.AddPolarLNDNode("alice", | ||
[ | ||
new() | ||
{ | ||
ChannelSize = 10_000_000, //10MSat | ||
RemoteName = "bob" | ||
} | ||
], imageName: "custom_lnd", tagName: "latest", pullImage: false,postgresDSN: LNDConnectionStrings["alice"]); | ||
|
||
Builder.AddPolarLNDNode("bob", | ||
[ | ||
new() | ||
{ | ||
ChannelSize = 10_000_000, //10MSat | ||
RemotePushOnStart = 1_000_000, // 1MSat | ||
RemoteName = "alice" | ||
} | ||
], imageName: "custom_lnd", tagName: "latest", pullImage: false,postgresDSN: LNDConnectionStrings["bob"]); | ||
|
||
Builder.AddPolarLNDNode("carol", | ||
[ | ||
new() | ||
{ | ||
ChannelSize = 10_000_000, //10MSat | ||
RemotePushOnStart = 1_000_000, // 1MSat | ||
RemoteName = "alice" | ||
}, | ||
new() | ||
{ | ||
ChannelSize = 10_000_000, //10MSat | ||
RemotePushOnStart = 1_000_000, // 1MSat | ||
RemoteName = "bob" | ||
} | ||
], imageName: "custom_lnd", tagName: "latest", pullImage: false,postgresDSN: LNDConnectionStrings["carol"]); | ||
|
||
await Builder.Build(); | ||
} | ||
|
||
public async Task StartPostgres() | ||
{ | ||
await _client.PullImageAndWaitForCompleted("postgres", "16.2-alpine"); | ||
await RemoveContainer(DbContainerName); | ||
var nodeContainer = await _client.Containers.CreateContainerAsync(new CreateContainerParameters | ||
{ | ||
Image = "postgres:16.2-alpine", | ||
HostConfig = new HostConfig | ||
{ | ||
NetworkMode = "bridge" | ||
}, | ||
Name = $"{DbContainerName}", | ||
Hostname = $"{DbContainerName}", | ||
Env = | ||
[ | ||
"POSTGRES_PASSWORD=superuser", | ||
"POSTGRES_USER=superuser", | ||
"POSTGRES_DB=postgres" | ||
] | ||
}); | ||
Assert.NotNull(nodeContainer); | ||
_containerId = nodeContainer.ID; | ||
var started = await _client.Containers.StartContainerAsync(_containerId, new ContainerStartParameters()); | ||
|
||
//Build connection string | ||
var ipAddressReady = false; | ||
while (!ipAddressReady) | ||
{ | ||
var listContainers = await _client.Containers.ListContainersAsync(new ContainersListParameters()); | ||
|
||
var db = listContainers.FirstOrDefault(x => x.ID == nodeContainer.ID); | ||
if (db != null) | ||
{ | ||
_ip = db.NetworkSettings.Networks.First().Value.IPAddress; | ||
DbConnectionString = $"Host={_ip};Database=postgres;Username=superuser;Password=superuser"; | ||
ipAddressReady = true; | ||
} | ||
else | ||
{ | ||
await Task.Delay(100); | ||
} | ||
|
||
} | ||
//wait for TCP socket to open | ||
var tcpConnectable = false; | ||
while (!tcpConnectable) | ||
{ | ||
try | ||
{ | ||
TcpClient c = new() | ||
{ | ||
ReceiveTimeout = 1, | ||
SendTimeout = 1 | ||
}; | ||
await c.ConnectAsync(new IPEndPoint(IPAddress.Parse(_ip), 5432)); | ||
if (c.Connected) | ||
{ | ||
tcpConnectable = true; | ||
} | ||
} | ||
catch (Exception e) | ||
{ | ||
await Task.Delay(50); | ||
} | ||
} | ||
} | ||
|
||
private async Task RemoveContainer(string name) | ||
{ | ||
try | ||
{ | ||
await _client.Containers.RemoveContainerAsync(name, | ||
new ContainerRemoveParameters { Force = true, RemoveVolumes = true }); | ||
} | ||
catch | ||
{ | ||
// ignored | ||
} | ||
} | ||
|
||
public async Task<bool> IsRunning() | ||
{ | ||
try | ||
{ | ||
var inspect = await _client.Containers.InspectContainerAsync(DbContainerName); | ||
return inspect.State.Running; | ||
} | ||
catch | ||
{ | ||
// ignored | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
|
||
[CollectionDefinition("postgres")] | ||
public class PostgresLightningFixtureCollection : ICollectionFixture<PostgresLightningFixture> | ||
{ | ||
// This class has no code, and is never created. Its purpose is simply | ||
// to be the place to apply [CollectionDefinition] and all the | ||
// ICollectionFixture<> interfaces. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System.Collections.Immutable; | ||
using System.Diagnostics; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
using Lnrpc; | ||
using LNUnit.Fixtures; | ||
using ServiceStack; | ||
using ServiceStack.Text; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
using Assert = NUnit.Framework.Assert; | ||
|
||
namespace NLightning.Bolts.Tests.Docker; | ||
|
||
#pragma warning disable xUnit1033 // Test classes decorated with 'Xunit.IClassFixture<TFixture>' or 'Xunit.ICollectionFixture<TFixture>' should add a constructor argument of type TFixture | ||
[Collection("postgres")] | ||
public class PostgresXUnitTest | ||
{ | ||
private readonly PostgresLightningFixture _lightningRegtestNetworkFixture; | ||
|
||
public PostgresXUnitTest(PostgresLightningFixture fixture, ITestOutputHelper output) | ||
{ | ||
_lightningRegtestNetworkFixture = fixture; | ||
Console.SetOut(new TestOutputWriter(output)); | ||
} | ||
|
||
|
||
|
||
[Fact] | ||
public async Task Verify_Alice_Bob_Carol_Setup() | ||
{ | ||
var readyNodes = _lightningRegtestNetworkFixture.Builder!.LNDNodePool!.ReadyNodes.ToImmutableList(); | ||
var nodeCount = readyNodes.Count; | ||
Assert.AreEqual(3, nodeCount); | ||
$"LND Nodes in Ready State: {nodeCount}".Print(); | ||
foreach (var node in readyNodes) | ||
{ | ||
var walletBalanceResponse = await node.LightningClient.WalletBalanceAsync(new WalletBalanceRequest()); | ||
var channels = await node.LightningClient.ListChannelsAsync(new ListChannelsRequest()); | ||
$"Node {node.LocalAlias} ({node.LocalNodePubKey})".Print(); | ||
walletBalanceResponse.PrintDump(); | ||
channels.PrintDump(); | ||
} | ||
$"Bitcoin Node Balance: {(await _lightningRegtestNetworkFixture.Builder!.BitcoinRpcClient!.GetBalanceAsync()).Satoshi / 1e8}".Print(); | ||
} | ||
|
||
// [Fact] | ||
// public async Task KeepRunning5Min() | ||
// { | ||
// await Task.Delay(5 * 60 * 1000); | ||
// } | ||
} | ||
#pragma warning restore xUnit1033 // Test classes decorated with 'Xunit.IClassFixture<TFixture>' or 'Xunit.ICollectionFixture<TFixture>' should add a constructor argument of type TFixture |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.Text; | ||
using Xunit.Abstractions; | ||
|
||
namespace NLightning.Bolts.Tests.Docker; | ||
|
||
public class TestOutputWriter : TextWriter | ||
{ | ||
private readonly ITestOutputHelper _output; | ||
|
||
public TestOutputWriter(ITestOutputHelper output) | ||
{ | ||
_output = output; | ||
} | ||
|
||
public override Encoding Encoding => Encoding.UTF8; | ||
|
||
public override void Write(char[] buffer, int index, int count) | ||
{ | ||
_output.WriteLine(new string(buffer, index, count)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters