networking.scm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017 Thomas Danckaert <post@thomasdanckaert.be>
  3. ;;; Copyright © 2017, 2020 Marius Bakke <marius@gnu.org>
  4. ;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
  5. ;;; Copyright © 2018 Arun Isaac <arunisaac@systemreboot.net>
  6. ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
  7. ;;; Copyright © 2021 Ludovic Courtès <ludo@gnu.org>
  8. ;;;
  9. ;;; This file is part of GNU Guix.
  10. ;;;
  11. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  12. ;;; under the terms of the GNU General Public License as published by
  13. ;;; the Free Software Foundation; either version 3 of the License, or (at
  14. ;;; your option) any later version.
  15. ;;;
  16. ;;; GNU Guix is distributed in the hope that it will be useful, but
  17. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  18. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. ;;; GNU General Public License for more details.
  20. ;;;
  21. ;;; You should have received a copy of the GNU General Public License
  22. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  23. (define-module (gnu tests networking)
  24. #:use-module (gnu tests)
  25. #:use-module (gnu system)
  26. #:use-module (gnu system vm)
  27. #:use-module (gnu services)
  28. #:use-module (gnu services base)
  29. #:use-module (gnu services networking)
  30. #:use-module (guix gexp)
  31. #:use-module (guix store)
  32. #:use-module (guix monads)
  33. #:use-module (guix modules)
  34. #:use-module (gnu packages bash)
  35. #:use-module (gnu packages linux)
  36. #:use-module (gnu packages networking)
  37. #:use-module (gnu packages guile)
  38. #:use-module (gnu services shepherd)
  39. #:use-module (ice-9 match)
  40. #:export (%test-static-networking
  41. %test-inetd
  42. %test-openvswitch
  43. %test-dhcpd
  44. %test-tor
  45. %test-iptables
  46. %test-ipfs))
  47. ;;;
  48. ;;; Static networking.
  49. ;;;
  50. (define (run-static-networking-test vm)
  51. (define test
  52. (with-imported-modules '((gnu build marionette)
  53. (guix build syscalls))
  54. #~(begin
  55. (use-modules (gnu build marionette)
  56. (guix build syscalls)
  57. (srfi srfi-64))
  58. (define marionette
  59. (make-marionette
  60. '(#$vm "-nic" "user,model=virtio-net-pci")))
  61. (test-runner-current (system-test-runner #$output))
  62. (test-begin "static-networking")
  63. (test-assert "service is up"
  64. (marionette-eval
  65. '(begin
  66. (use-modules (gnu services herd))
  67. (start-service 'networking))
  68. marionette))
  69. (test-assert "network interfaces"
  70. (marionette-eval
  71. '(begin
  72. (use-modules (guix build syscalls))
  73. (network-interface-names))
  74. marionette))
  75. (test-equal "address of eth0"
  76. "10.0.2.15"
  77. (marionette-eval
  78. '(let* ((sock (socket AF_INET SOCK_STREAM 0))
  79. (addr (network-interface-address sock "eth0")))
  80. (close-port sock)
  81. (inet-ntop (sockaddr:fam addr) (sockaddr:addr addr)))
  82. marionette))
  83. (test-equal "netmask of eth0"
  84. "255.255.255.0"
  85. (marionette-eval
  86. '(let* ((sock (socket AF_INET SOCK_STREAM 0))
  87. (mask (network-interface-netmask sock "eth0")))
  88. (close-port sock)
  89. (inet-ntop (sockaddr:fam mask) (sockaddr:addr mask)))
  90. marionette))
  91. (test-equal "eth0 is up"
  92. IFF_UP
  93. (marionette-eval
  94. '(let* ((sock (socket AF_INET SOCK_STREAM 0))
  95. (flags (network-interface-flags sock "eth0")))
  96. (logand flags IFF_UP))
  97. marionette))
  98. (test-end))))
  99. (gexp->derivation "static-networking" test))
  100. (define %test-static-networking
  101. (system-test
  102. (name "static-networking")
  103. (description "Test the 'static-networking' service.")
  104. (value
  105. (let ((os (marionette-operating-system
  106. (simple-operating-system
  107. (service static-networking-service-type
  108. (list %qemu-static-networking)))
  109. #:imported-modules '((gnu services herd)
  110. (guix combinators)))))
  111. (run-static-networking-test (virtual-machine os))))))
  112. ;;;
  113. ;;; Inetd.
  114. ;;;
  115. (define %inetd-os
  116. ;; Operating system with 2 inetd services.
  117. (simple-operating-system
  118. (service dhcp-client-service-type)
  119. (service inetd-service-type
  120. (inetd-configuration
  121. (entries (list
  122. (inetd-entry
  123. (name "echo")
  124. (socket-type 'stream)
  125. (protocol "tcp")
  126. (wait? #f)
  127. (user "root"))
  128. (inetd-entry
  129. (name "dict")
  130. (socket-type 'stream)
  131. (protocol "tcp")
  132. (wait? #f)
  133. (user "root")
  134. (program (file-append bash
  135. "/bin/bash"))
  136. (arguments
  137. (list "bash" (plain-file "my-dict.sh" "\
  138. while read line
  139. do
  140. if [[ $line =~ ^DEFINE\\ (.*)$ ]]
  141. then
  142. case ${BASH_REMATCH[1]} in
  143. Guix)
  144. echo GNU Guix is a package management tool for the GNU system.
  145. ;;
  146. G-expression)
  147. echo Like an S-expression but with a G.
  148. ;;
  149. *)
  150. echo NO DEFINITION FOUND
  151. ;;
  152. esac
  153. else
  154. echo ERROR
  155. fi
  156. done" ))))))))))
  157. (define* (run-inetd-test)
  158. "Run tests in %INETD-OS, where the inetd service provides an echo service on
  159. port 7, and a dict service on port 2628."
  160. (define os
  161. (marionette-operating-system %inetd-os))
  162. (define vm
  163. (virtual-machine
  164. (operating-system os)
  165. (port-forwardings `((8007 . 7)
  166. (8628 . 2628)))))
  167. (define test
  168. (with-imported-modules '((gnu build marionette))
  169. #~(begin
  170. (use-modules (ice-9 rdelim)
  171. (srfi srfi-64)
  172. (gnu build marionette))
  173. (define marionette
  174. (make-marionette (list #$vm)))
  175. (test-runner-current (system-test-runner #$output))
  176. (test-begin "inetd")
  177. ;; Make sure the PID file is created.
  178. (test-assert "PID file"
  179. (marionette-eval
  180. '(file-exists? "/var/run/inetd.pid")
  181. marionette))
  182. ;; Test the echo service.
  183. (test-equal "echo response"
  184. "Hello, Guix!"
  185. (let ((echo (socket PF_INET SOCK_STREAM 0))
  186. (addr (make-socket-address AF_INET INADDR_LOOPBACK 8007)))
  187. (connect echo addr)
  188. (display "Hello, Guix!\n" echo)
  189. (let ((response (read-line echo)))
  190. (close echo)
  191. response)))
  192. ;; Test the dict service
  193. (test-equal "dict response"
  194. "GNU Guix is a package management tool for the GNU system."
  195. (let ((dict (socket PF_INET SOCK_STREAM 0))
  196. (addr (make-socket-address AF_INET INADDR_LOOPBACK 8628)))
  197. (connect dict addr)
  198. (display "DEFINE Guix\n" dict)
  199. (let ((response (read-line dict)))
  200. (close dict)
  201. response)))
  202. (test-end))))
  203. (gexp->derivation "inetd-test" test))
  204. (define %test-inetd
  205. (system-test
  206. (name "inetd")
  207. (description "Connect to a host with an INETD server.")
  208. (value (run-inetd-test))))
  209. ;;;
  210. ;;; Open vSwitch
  211. ;;;
  212. (define setup-openvswitch
  213. #~(let ((ovs-vsctl (lambda (str)
  214. (zero? (apply system*
  215. #$(file-append openvswitch "/bin/ovs-vsctl")
  216. (string-tokenize str)))))
  217. (add-native-port (lambda (if)
  218. (string-append "--may-exist add-port br0 " if
  219. " vlan_mode=native-untagged"
  220. " -- set Interface " if
  221. " type=internal"))))
  222. (and (ovs-vsctl "--may-exist add-br br0")
  223. ;; Connect eth0 as an "untagged" port (no VLANs).
  224. (ovs-vsctl "--may-exist add-port br0 eth0 vlan_mode=native-untagged")
  225. (ovs-vsctl (add-native-port "ovs0")))))
  226. (define openvswitch-configuration-service
  227. (simple-service 'openvswitch-configuration shepherd-root-service-type
  228. (list (shepherd-service
  229. (provision '(openvswitch-configuration))
  230. (requirement '(vswitchd))
  231. (start #~(lambda ()
  232. #$setup-openvswitch))
  233. (respawn? #f)))))
  234. (define %openvswitch-os
  235. (operating-system
  236. (inherit (simple-operating-system
  237. (simple-service 'openswitch-networking
  238. static-networking-service-type
  239. (list (static-networking
  240. (addresses (list (network-address
  241. (value "10.1.1.1/24")
  242. (device "ovs0"))))
  243. (requirement '(openvswitch-configuration)))))
  244. (service openvswitch-service-type)
  245. openvswitch-configuration-service))
  246. ;; Ensure the interface name does not change depending on the driver.
  247. (kernel-arguments (cons "net.ifnames=0" %default-kernel-arguments))))
  248. (define (run-openvswitch-test)
  249. (define os
  250. (marionette-operating-system %openvswitch-os
  251. #:imported-modules '((gnu services herd)
  252. (guix build syscalls))))
  253. (define test
  254. (with-imported-modules '((gnu build marionette)
  255. (guix build syscalls))
  256. #~(begin
  257. (use-modules (gnu build marionette)
  258. (guix build syscalls)
  259. (ice-9 popen)
  260. (ice-9 rdelim)
  261. (srfi srfi-64))
  262. (define marionette
  263. (make-marionette (list #$(virtual-machine os))))
  264. (test-runner-current (system-test-runner #$output))
  265. (test-begin "openvswitch")
  266. ;; Make sure the bridge is created.
  267. (test-assert "br0 exists"
  268. (marionette-eval
  269. '(zero? (system* #$(file-append openvswitch "/bin/ovs-vsctl")
  270. "br-exists" "br0"))
  271. marionette))
  272. ;; Make sure eth0 is connected to the bridge.
  273. (test-equal "eth0 is connected to br0"
  274. "br0"
  275. (marionette-eval
  276. '(begin
  277. (use-modules (ice-9 popen) (ice-9 rdelim))
  278. (let* ((port (open-pipe*
  279. OPEN_READ
  280. (string-append #$openvswitch "/bin/ovs-vsctl")
  281. "port-to-br" "eth0"))
  282. (output (read-line port)))
  283. (close-pipe port)
  284. output))
  285. marionette))
  286. ;; Make sure the virtual interface got a static IP.
  287. (test-assert "networking has started on ovs0"
  288. (marionette-eval
  289. '(begin
  290. (use-modules (gnu services herd)
  291. (srfi srfi-1))
  292. (live-service-running
  293. (find (lambda (live)
  294. (memq 'networking
  295. (live-service-provision live)))
  296. (current-services))))
  297. marionette))
  298. (test-equal "ovs0 is up"
  299. IFF_UP
  300. (marionette-eval
  301. '(begin
  302. (use-modules (guix build syscalls))
  303. (let* ((sock (socket AF_INET SOCK_STREAM 0))
  304. (flags (network-interface-flags sock "ovs0")))
  305. (close-port sock)
  306. (logand flags IFF_UP)))
  307. marionette))
  308. (test-end))))
  309. (gexp->derivation "openvswitch-test" test))
  310. (define %test-openvswitch
  311. (system-test
  312. (name "openvswitch")
  313. (description "Test a running OpenvSwitch configuration.")
  314. (value (run-openvswitch-test))))
  315. ;;;
  316. ;;; DHCP Daemon
  317. ;;;
  318. (define minimal-dhcpd-v4-config-file
  319. (plain-file "dhcpd.conf"
  320. "\
  321. default-lease-time 600;
  322. max-lease-time 7200;
  323. subnet 192.168.1.0 netmask 255.255.255.0 {
  324. range 192.168.1.100 192.168.1.200;
  325. option routers 192.168.1.1;
  326. option domain-name-servers 192.168.1.2, 192.168.1.3;
  327. option domain-name \"dummy.domain.name.abc123xyz\";
  328. }
  329. "))
  330. (define dhcpd-v4-configuration
  331. (dhcpd-configuration
  332. (config-file minimal-dhcpd-v4-config-file)
  333. (version "4")
  334. (interfaces '("ens3"))))
  335. (define %dhcpd-os
  336. (simple-operating-system
  337. (service static-networking-service-type
  338. (list (static-networking
  339. (addresses (list (network-address
  340. (value "192.168.1.4/24")
  341. (device "ens3"))))
  342. (routes (list (network-route
  343. (destination "default")
  344. (gateway "192.168.1.1"))))
  345. (name-servers '("192.168.1.2" "192.168.1.3")))))
  346. (service dhcpd-service-type dhcpd-v4-configuration)))
  347. (define (run-dhcpd-test)
  348. (define os
  349. (marionette-operating-system %dhcpd-os
  350. #:imported-modules '((gnu services herd))))
  351. (define test
  352. (with-imported-modules '((gnu build marionette))
  353. #~(begin
  354. (use-modules (gnu build marionette)
  355. (ice-9 popen)
  356. (ice-9 rdelim)
  357. (srfi srfi-64))
  358. (define marionette
  359. (make-marionette (list #$(virtual-machine os))))
  360. (test-runner-current (system-test-runner #$output))
  361. (test-begin "dhcpd")
  362. (test-assert "pid file exists"
  363. (marionette-eval
  364. '(file-exists?
  365. #$(dhcpd-configuration-pid-file dhcpd-v4-configuration))
  366. marionette))
  367. (test-assert "lease file exists"
  368. (marionette-eval
  369. '(file-exists?
  370. #$(dhcpd-configuration-lease-file dhcpd-v4-configuration))
  371. marionette))
  372. (test-assert "run directory exists"
  373. (marionette-eval
  374. '(file-exists?
  375. #$(dhcpd-configuration-run-directory dhcpd-v4-configuration))
  376. marionette))
  377. (test-assert "dhcpd is alive"
  378. (marionette-eval
  379. '(begin
  380. (use-modules (gnu services herd)
  381. (srfi srfi-1))
  382. (live-service-running
  383. (find (lambda (live)
  384. (memq 'dhcpv4-daemon
  385. (live-service-provision live)))
  386. (current-services))))
  387. marionette))
  388. (test-end))))
  389. (gexp->derivation "dhcpd-test" test))
  390. (define %test-dhcpd
  391. (system-test
  392. (name "dhcpd")
  393. (description "Test a running DHCP daemon configuration.")
  394. (value (run-dhcpd-test))))
  395. ;;;
  396. ;;; Services related to Tor
  397. ;;;
  398. (define %tor-os
  399. (simple-operating-system
  400. (service tor-service-type)))
  401. (define %tor-os/unix-socks-socket
  402. (simple-operating-system
  403. (service tor-service-type
  404. (tor-configuration
  405. (socks-socket-type 'unix)))))
  406. (define (run-tor-test)
  407. (define os
  408. (marionette-operating-system %tor-os
  409. #:imported-modules '((gnu services herd))
  410. #:requirements '(tor)))
  411. (define os/unix-socks-socket
  412. (marionette-operating-system %tor-os/unix-socks-socket
  413. #:imported-modules '((gnu services herd))
  414. #:requirements '(tor)))
  415. (define test
  416. (with-imported-modules '((gnu build marionette))
  417. #~(begin
  418. (use-modules (gnu build marionette)
  419. (ice-9 popen)
  420. (ice-9 rdelim)
  421. (srfi srfi-64))
  422. (define marionette
  423. (make-marionette (list #$(virtual-machine os))))
  424. (define (tor-is-alive? marionette)
  425. (marionette-eval
  426. '(begin
  427. (use-modules (gnu services herd)
  428. (srfi srfi-1))
  429. (live-service-running
  430. (find (lambda (live)
  431. (memq 'tor
  432. (live-service-provision live)))
  433. (current-services))))
  434. marionette))
  435. (test-runner-current (system-test-runner #$output))
  436. (test-begin "tor")
  437. ;; Test the usual Tor service.
  438. (test-assert "tor is alive"
  439. (tor-is-alive? marionette))
  440. (test-assert "tor is listening"
  441. (let ((default-port 9050))
  442. (wait-for-tcp-port default-port marionette)))
  443. ;; Don't run two VMs at once.
  444. (marionette-control "quit" marionette)
  445. ;; Test the Tor service using a SOCKS socket.
  446. (let* ((socket-directory "/tmp/more-sockets")
  447. (_ (mkdir socket-directory))
  448. (marionette/unix-socks-socket
  449. (make-marionette
  450. (list #$(virtual-machine os/unix-socks-socket))
  451. ;; We can't use the same socket directory as the first
  452. ;; marionette.
  453. #:socket-directory socket-directory)))
  454. (test-assert "tor is alive, even when using a SOCKS socket"
  455. (tor-is-alive? marionette/unix-socks-socket))
  456. (test-assert "tor is listening, even when using a SOCKS socket"
  457. (wait-for-unix-socket "/var/run/tor/socks-sock"
  458. marionette/unix-socks-socket)))
  459. (test-end))))
  460. (gexp->derivation "tor-test" test))
  461. (define %test-tor
  462. (system-test
  463. (name "tor")
  464. (description "Test a running Tor daemon configuration.")
  465. (value (run-tor-test))))
  466. (define* (run-iptables-test)
  467. "Run tests of 'iptables-service-type'."
  468. (define iptables-rules
  469. "*filter
  470. :INPUT ACCEPT
  471. :FORWARD ACCEPT
  472. :OUTPUT ACCEPT
  473. -A INPUT -p tcp -m tcp --dport 7 -j REJECT --reject-with icmp-port-unreachable
  474. COMMIT
  475. ")
  476. (define ip6tables-rules
  477. "*filter
  478. :INPUT ACCEPT
  479. :FORWARD ACCEPT
  480. :OUTPUT ACCEPT
  481. -A INPUT -p tcp -m tcp --dport 7 -j REJECT --reject-with icmp6-port-unreachable
  482. COMMIT
  483. ")
  484. (define inetd-echo-port 7)
  485. (define os
  486. (marionette-operating-system
  487. (simple-operating-system
  488. (service dhcp-client-service-type)
  489. (service inetd-service-type
  490. (inetd-configuration
  491. (entries (list
  492. (inetd-entry
  493. (name "echo")
  494. (socket-type 'stream)
  495. (protocol "tcp")
  496. (wait? #f)
  497. (user "root"))))))
  498. (service iptables-service-type
  499. (iptables-configuration
  500. (ipv4-rules (plain-file "iptables.rules" iptables-rules))
  501. (ipv6-rules (plain-file "ip6tables.rules" ip6tables-rules)))))
  502. #:imported-modules '((gnu services herd))
  503. #:requirements '(inetd iptables)))
  504. (define test
  505. (with-imported-modules '((gnu build marionette))
  506. #~(begin
  507. (use-modules (srfi srfi-64)
  508. (gnu build marionette))
  509. (define marionette
  510. (make-marionette (list #$(virtual-machine os))))
  511. (define (dump-iptables iptables-save marionette)
  512. (marionette-eval
  513. `(begin
  514. (use-modules (ice-9 popen)
  515. (ice-9 rdelim)
  516. (ice-9 regex))
  517. (call-with-output-string
  518. (lambda (out)
  519. (call-with-port
  520. (open-pipe* OPEN_READ ,iptables-save)
  521. (lambda (in)
  522. (let loop ((line (read-line in)))
  523. ;; iptables-save does not output rules in the exact
  524. ;; same format we loaded using iptables-restore. It
  525. ;; adds comments, packet counters, etc. We remove
  526. ;; these additions.
  527. (unless (eof-object? line)
  528. (cond
  529. ;; Remove comments
  530. ((string-match "^#" line) #t)
  531. ;; Remove packet counters
  532. ((string-match "^:([A-Z]*) ([A-Z]*) .*" line)
  533. => (lambda (match-record)
  534. (format out ":~a ~a~%"
  535. (match:substring match-record 1)
  536. (match:substring match-record 2))))
  537. ;; Pass other lines without modification
  538. (else (display line out)
  539. (newline out)))
  540. (loop (read-line in)))))))))
  541. marionette))
  542. (test-runner-current (system-test-runner #$output))
  543. (test-begin "iptables")
  544. (test-equal "iptables-save dumps the same rules that were loaded"
  545. (dump-iptables #$(file-append iptables "/sbin/iptables-save")
  546. marionette)
  547. #$iptables-rules)
  548. (test-equal "ip6tables-save dumps the same rules that were loaded"
  549. (dump-iptables #$(file-append iptables "/sbin/ip6tables-save")
  550. marionette)
  551. #$ip6tables-rules)
  552. (test-error "iptables firewall blocks access to inetd echo service"
  553. 'misc-error
  554. (wait-for-tcp-port inetd-echo-port marionette #:timeout 5))
  555. ;; TODO: This test freezes up at the login prompt without any
  556. ;; relevant messages on the console. Perhaps it is waiting for some
  557. ;; timeout. Find and fix this issue.
  558. ;; (test-assert "inetd echo service is accessible after iptables firewall is stopped"
  559. ;; (begin
  560. ;; (marionette-eval
  561. ;; '(begin
  562. ;; (use-modules (gnu services herd))
  563. ;; (stop-service 'iptables))
  564. ;; marionette)
  565. ;; (wait-for-tcp-port inetd-echo-port marionette #:timeout 5)))
  566. (test-end))))
  567. (gexp->derivation "iptables" test))
  568. (define %test-iptables
  569. (system-test
  570. (name "iptables")
  571. (description "Test a running iptables daemon.")
  572. (value (run-iptables-test))))
  573. ;;;
  574. ;;; IPFS service
  575. ;;;
  576. (define %ipfs-os
  577. (simple-operating-system
  578. (service ipfs-service-type)))
  579. (define (run-ipfs-test)
  580. (define os
  581. (marionette-operating-system %ipfs-os
  582. #:imported-modules (source-module-closure
  583. '((gnu services herd)
  584. (guix ipfs)))
  585. #:extensions (list guile-json-4)
  586. #:requirements '(ipfs)))
  587. (define test
  588. (with-imported-modules '((gnu build marionette))
  589. #~(begin
  590. (use-modules (gnu build marionette)
  591. (rnrs bytevectors)
  592. (srfi srfi-64)
  593. (ice-9 binary-ports))
  594. (define marionette
  595. (make-marionette (list #$(virtual-machine os))))
  596. (define (ipfs-is-alive?)
  597. (marionette-eval
  598. '(begin
  599. (use-modules (gnu services herd)
  600. (srfi srfi-1))
  601. (live-service-running
  602. (find (lambda (live)
  603. (memq 'ipfs
  604. (live-service-provision live)))
  605. (current-services))))
  606. marionette))
  607. ;; The default API endpoint port 5001 is used,
  608. ;; so there is no need to parameterize %ipfs-base-url.
  609. (define (add-data data)
  610. (marionette-eval `(content-name (add-data ,data)) marionette))
  611. (define (read-contents object)
  612. (marionette-eval
  613. `(let* ((input (read-contents ,object))
  614. (all-input (get-bytevector-all input)))
  615. (close-port input)
  616. all-input)
  617. marionette))
  618. (marionette-eval '(use-modules (guix ipfs)) marionette)
  619. (test-runner-current (system-test-runner #$output))
  620. (test-begin "ipfs")
  621. ;; Test the IPFS service.
  622. (test-assert "ipfs is alive" (ipfs-is-alive?))
  623. (test-assert "ipfs is listening on the gateway"
  624. (let ((default-port 8082))
  625. (wait-for-tcp-port default-port marionette)))
  626. (test-assert "ipfs is listening on the API endpoint"
  627. (let ((default-port 5001))
  628. (wait-for-tcp-port default-port marionette)))
  629. (define test-bv (string->utf8 "hello ipfs!"))
  630. (test-equal "can upload and download a file to/from ipfs"
  631. test-bv
  632. (read-contents (add-data test-bv)))
  633. (test-end))))
  634. (gexp->derivation "ipfs-test" test))
  635. (define %test-ipfs
  636. (system-test
  637. (name "ipfs")
  638. (description "Test a running IPFS daemon configuration.")
  639. (value (run-ipfs-test))))