-
Notifications
You must be signed in to change notification settings - Fork 109
/
Copy pathtests.nix
482 lines (418 loc) · 15.6 KB
/
tests.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# Integration tests, can be run without internet access.
lib: nixBitcoinModule:
let
# Included in all scenarios
baseConfig = { config, pkgs, ... }: with lib; let
cfg = config.services;
inherit (config.nix-bitcoin.lib.test) mkIfTest;
in {
imports = [
./lib/test-lib.nix
nixBitcoinModule
{
# Features required by the Python test suite
nix-bitcoin.secretsDir = "/secrets";
nix-bitcoin.generateSecrets = true;
nix-bitcoin.operator.enable = true;
environment.systemPackages = with pkgs; [ jq ];
}
];
options.test.features = {
clightningPlugins = mkEnableOption "all clightning plugins";
};
config = mkMerge [{
environment.systemPackages = mkMerge (with pkgs; [
# Needed to test macaroon creation
(mkIfTest "btcpayserver" [ openssl xxd ])
# Needed to test certificate creation
(mkIfTest "lnd" [ openssl ])
]);
tests.bitcoind = cfg.bitcoind.enable;
services.bitcoind = {
enable = true;
extraConfig = mkIf config.test.noConnections "connect=0";
};
tests.clightning = cfg.clightning.enable;
test.data.clightning-replication = cfg.clightning.replication.enable;
tests.trustedcoin = cfg.clightning.plugins.trustedcoin.enable;
# TODO-EXTERNAL:
# When WAN is disabled, DNS bootstrapping slows down service startup by ~15 s.
services.clightning.extraConfig = ''
${optionalString config.test.noConnections "disable-dns"}
'';
test.data.clightning-plugins = let
plugins = config.services.clightning.plugins;
removed = [
# Only defined via `obsolete-options.nix`
"commando"
"helpme"
"prometheus"
"summary"
];
available = subtractLists removed (builtins.attrNames plugins);
enabled = builtins.filter (plugin: plugins.${plugin}.enable) available;
nbPkgs = config.nix-bitcoin.pkgs;
pluginPkgs = nbPkgs.clightning-plugins // {
clboss.path = "${plugins.clboss.package}/bin/clboss";
clnrest.path = "${plugins.clnrest.package}/bin/clnrest";
trustedcoin.path = "${plugins.trustedcoin.package}/bin/trustedcoin";
};
in map (plugin: pluginPkgs.${plugin}.path) enabled;
tests.clightning-rest = cfg.clightning-rest.enable;
tests.rtl = cfg.rtl.enable;
services.rtl = {
nodes = {
lnd = {
enable = mkDefault true;
loop = mkDefault true;
extraConfig.Settings.userPersona = "MERCHANT";
};
clightning.enable = mkDefault true;
};
extraCurrency = mkDefault "CHF";
};
# Use a simple, non-random password for manual web interface tests
nix-bitcoin.generateSecretsCmds.rtl = mkIf cfg.rtl.enable (mkForce ''
echo a > rtl-password
'');
tests.mempool = cfg.mempool.enable;
services.mempool.electrumServer = "fulcrum";
tests.lnd = cfg.lnd.enable;
services.lnd = {
port = 9736;
certificate = {
extraIPs = [ "10.0.0.1" "20.0.0.1" ];
extraDomains = [ "example.com" ];
};
};
nix-bitcoin.onionServices.lnd.public = true;
tests.lndconnect-onion-lnd = with cfg.lnd.lndconnect; enable && onion;
tests.lnconnect-onion-clnrest = with cfg.clightning.plugins.clnrest.lnconnect; enable && onion;
tests.lndconnect-onion-clightning = with cfg.clightning-rest.lndconnect; enable && onion;
tests.lightning-loop = cfg.lightning-loop.enable;
services.lightning-loop.certificate.extraIPs = [ "20.0.0.1" ];
tests.lightning-pool = cfg.lightning-pool.enable;
tests.charge-lnd = cfg.charge-lnd.enable;
tests.electrs = cfg.electrs.enable;
services.fulcrum.port = 50002;
tests.fulcrum = cfg.fulcrum.enable;
tests.liquidd = cfg.liquidd.enable;
services.liquidd.extraConfig = mkIf config.test.noConnections "connect=0";
tests.btcpayserver = cfg.btcpayserver.enable;
services.btcpayserver = {
lightningBackend = mkDefault "lnd";
lbtc = mkDefault true;
};
test.data.btcpayserver-lbtc = config.services.btcpayserver.lbtc;
tests.joinmarket = cfg.joinmarket.enable;
tests.joinmarket-yieldgenerator = cfg.joinmarket.yieldgenerator.enable;
tests.joinmarket-ob-watcher = cfg.joinmarket-ob-watcher.enable;
services.joinmarket.yieldgenerator = {
enable = config.services.joinmarket.enable;
# Test a smattering of custom parameters
ordertype = "absoffer";
cjfee_a = 300;
cjfee_r = 0.00003;
};
tests.nodeinfo = config.nix-bitcoin.nodeinfo.enable;
tests.backups = cfg.backups.enable;
# To test that unused secrets are made inaccessible by 'setup-secrets'
systemd.services.setup-secrets.preStart = mkIfTest "security" ''
install -D -o nobody -g nogroup -m777 <(:) /secrets/dummy
'';
# Avoid timeout failures on slow CI nodes
systemd.services.postgresql.serviceConfig.TimeoutStartSec = "5min";
}
(mkIf config.services.clightning.plugins.clboss.enable {
# Torified 'dig' subprocesses of clboss don't respond to SIGTERM and keep
# running for a long time when WAN is disabled, which prevents clightning units
# from stopping quickly.
# Set TimeoutStopSec for faster stopping.
systemd.services.clightning.serviceConfig.TimeoutStopSec = "500ms";
})
(mkIf config.test.features.clightningPlugins {
services.clightning.plugins = {
clboss.enable = true;
feeadjuster.enable = true;
monitor.enable = true;
rebalance.enable = true;
zmq = let tcpEndpoint = "tcp://127.0.0.1:5501"; in {
enable = true;
channel-opened = tcpEndpoint;
connect = tcpEndpoint;
disconnect = tcpEndpoint;
invoice-payment = tcpEndpoint;
warning = tcpEndpoint;
forward-event = tcpEndpoint;
sendpay-success = tcpEndpoint;
sendpay-failure = tcpEndpoint;
};
};
})
];
};
scenarios = with lib; {
# Included in all scenarios by ./lib/make-test.nix
base = baseConfig;
default = scenarios.secureNode;
# All available basic services and tests
full = {
tests.security = true;
services.clightning.enable = true;
services.clightning.replication = {
enable = true;
encrypt = true;
local.directory = "/var/backup/clightning";
};
services.clightning.plugins.clnrest = {
enable = true;
lnconnect = { enable = true; onion = true; };
};
test.features.clightningPlugins = true;
services.rtl.enable = true;
services.clightning-rest.enable = true;
services.clightning-rest.lndconnect = { enable = true; onion = true; };
services.lnd.enable = true;
services.lnd.lndconnect = { enable = true; onion = true; };
services.lightning-loop.enable = true;
services.lightning-pool.enable = true;
services.charge-lnd.enable = true;
services.mempool.enable = true;
services.electrs.enable = true;
services.fulcrum.enable = true;
services.liquidd.enable = true;
services.btcpayserver.enable = true;
services.joinmarket.enable = true;
services.joinmarket-ob-watcher.enable = true;
services.backups.enable = true;
nix-bitcoin.nodeinfo.enable = true;
services.hardware-wallets = {
trezor = true;
ledger = true;
};
};
secureNode = {
imports = [
scenarios.full
../modules/presets/secure-node.nix
];
tests.secure-node = true;
tests.restart-bitcoind = true;
nix-bitcoin.onionServices.mempool-frontend.enable = true;
# Stop electrs from spamming the test log with 'WARN - wait until IBD is over' messages
tests.stop-electrs = true;
};
netns = {
imports = with scenarios; [ netnsBase secureNode ];
# This test is rather slow and unaffected by netns settings
tests.backups = mkForce false;
};
# All regtest-enabled services
regtest = {
imports = [ scenarios.regtestBase ];
services.clightning.enable = true;
test.features.clightningPlugins = true;
services.clightning-rest.enable = true;
services.liquidd.enable = true;
services.rtl.enable = true;
services.mempool.enable = true;
services.lnd.enable = true;
services.lightning-loop.enable = true;
services.lightning-pool.enable = true;
services.charge-lnd.enable = true;
services.electrs.enable = true;
services.fulcrum.enable = true;
services.btcpayserver.enable = true;
services.joinmarket.enable = true;
};
# netns and regtest, without secure-node.nix
netnsRegtest = {
imports = with scenarios; [ netnsBase regtest ];
};
hardened = {
imports = [
scenarios.secureNode
../modules/presets/hardened-extended.nix
];
# Patch clightning to increase the plugin init timeout.
# Otherwise this test can fail on slower hardware.
nix-bitcoin.pkgOverlays = super: self: {
clightning = super.clightning.overrideAttrs (old: {
postPatch = old.postPatch + ''
substituteInPlace lightningd/plugin.c \
--replace-fail "#define PLUGIN_MANIFEST_TIMEOUT 60" "#define PLUGIN_MANIFEST_TIMEOUT 200"
'';
});
};
};
netnsBase = { config, pkgs, ... }: {
nix-bitcoin.netns-isolation.enable = true;
test.data.netns = config.nix-bitcoin.netns-isolation.netns;
tests.netns-isolation = true;
environment.systemPackages = [ pkgs.fping ];
};
regtestBase = { config, pkgs, ... }: {
tests.regtest = true;
test.data.num_blocks = 100;
services.bitcoind.regtest = true;
systemd.services.bitcoind.postStart = mkAfter ''
cli=${config.services.bitcoind.cli}/bin/bitcoin-cli
if ! $cli listwallets | ${pkgs.jq}/bin/jq -e 'index("test")'; then
"$cli" -named createwallet wallet_name=test load_on_startup=true
address=$($cli -rpcwallet=test getnewaddress)
"$cli" generatetoaddress ${toString config.test.data.num_blocks} "$address"
fi
'';
# lightning-loop contains no builtin swap server for regtest.
# Add a dummy definition.
services.lightning-loop.extraConfig = ''
server.host=127.0.0.1
'';
# lightning-pool contains no builtin auction server for regtest.
# Add a dummy definition
services.lightning-pool.extraConfig = ''
auctionserver=127.0.0.1
'';
# `validatepegin` is incompatible with regtest
services.liquidd.validatepegin = mkForce false;
# TODO-EXTERNAL:
# Reenable `btcpayserver.lbtc` in regtest (and add test in tests.py)
# when nbxplorer can parse liquidd regtest blocks.
#
# When `btcpayserver.lbtc` is enabled in regtest, nxbplorer tries to
# generate regtest blocks, which fails because no liquidd wallet exists.
# When blocks are pre-generated via `liquidd.postStart`, nbxplorer
# fails to parse the blocks:
# info: NBXplorer.Indexer.LBTC: Full node version detected: 210002
# info: NBXplorer.Indexer.LBTC: NBXplorer is correctly whitelisted by the node
# fail: NBXplorer.Indexer.LBTC: Unhandled exception in the indexer, retrying in 10 seconds
# System.IO.EndOfStreamException: No more byte to read
# at NBitcoin.BitcoinStream.ReadWriteBytes(Span`1 data)
services.btcpayserver.lbtc = mkForce false;
};
# Test the special bitcoin RPC setup that lnd uses when bitcoin is pruned
lndPruned = {
services.lnd.enable = true;
services.bitcoind.prune = 1000;
};
trustedcoin = {
imports = [ scenarios.regtestBase ];
services.clightning = {
enable = true;
plugins.trustedcoin.enable = true;
};
};
} // (import ../dev/dev-scenarios.nix {
inherit lib scenarios;
});
## Example scenarios that showcase extra features
exampleScenarios = with lib; {
# Run a selection of tests in scenario 'netns'
selectedTests = {
imports = [ scenarios.netns ];
tests = mkForce {
btcpayserver = true;
netns-isolation = true;
};
};
# Container-specific features
containerFeatures = {
# Container has WAN access and bitcoind connects to external nodes
test.container.enableWAN = true;
# See ./lib/test-lib.nix for a description
test.container.exposeLocalhost = true;
};
## Scenarios with a custom Python test
# Variant 1: Define testing code that always runs
customTestSimple = {
networking.hostName = "myhost";
# Variant 1: Define testing code that always runs
test.extraTestScript = ''
succeed("[[ $(hostname) == myhost ]]")
'';
};
# Variant 2: Define a test that can be enabled/disabled
# via the Nix module system.
customTestExtended = {
networking.hostName = "myhost";
tests.hostName = true;
test.extraTestScript = ''
@test("hostName")
def _():
succeed("[[ $(hostname) == myhost ]]")
'';
};
};
in {
inherit scenarios;
pkgs = flake: pkgs: rec {
# A basic test using the nix-bitcoin test framework
makeTestBasic = import ./lib/make-test.nix flake pkgs makeTestVM;
# Wraps `makeTest` in NixOS' testing-python.nix so that the drv includes the
# log output and the test driver
makeTestVM = import ./lib/make-test-vm.nix pkgs;
# A test using the nix-bitcoin test framework, with some helpful defaults
makeTest = { name ? "nix-bitcoin-test", config }:
makeTestBasic {
inherit name;
config = {
imports = [
scenarios.base
config
];
# Share the same pkgs instance among tests
# Set priority slightly higher (i.e. to a slightly lower number) than `mkDefault`,
# so that this module can be used with function `pkgs.nixos`, which already
# sets `nixpkgs.pkgs` with prio `mkDefault`.
nixpkgs.pkgs = lib.mkOverride 900 pkgs;
};
};
# A test using the nix-bitcoin test framework, with defaults specific to nix-bitcoin
makeTestNixBitcoin = { name, config }:
makeTest {
name = "nix-bitcoin-${name}";
config = {
imports = [ config ];
test.shellcheckServices.sourcePrefix = toString ./..;
};
};
makeTests = scenarios: let
mainTests = builtins.mapAttrs (name: config:
makeTestNixBitcoin { inherit name config; }
) scenarios;
in
{
clightning-replication = import ./clightning-replication.nix makeTestVM pkgs;
wireguard-lndconnect = import ./wireguard-lndconnect.nix makeTestVM pkgs;
} // mainTests;
tests = makeTests scenarios;
## Helper for ./run-tests.sh
getTest = { name, extraScenariosFile ? null }:
let
tests = makeTests (scenarios // (
lib.optionalAttrs (extraScenariosFile != null)
(import extraScenariosFile {
inherit scenarios lib pkgs;
nix-bitcoin = flake;
})
));
in
tests.${name} or (makeTestNixBitcoin {
inherit name;
config = {
services.${name}.enable = true;
};
});
instantiateTests = testNames:
let
testNames' = lib.splitString " " testNames;
in
map (name:
let
test = tests.${name};
in
builtins.seq (builtins.trace "Evaluating test '${name}'" test.outPath)
test
) testNames';
};
}