databases.scm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
  3. ;;; Copyright © 2020 Marius Bakke <marius@gnu.org>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (gnu tests databases)
  20. #:use-module (gnu tests)
  21. #:use-module (gnu system)
  22. #:use-module (gnu system file-systems)
  23. #:use-module (gnu system shadow)
  24. #:use-module (gnu system vm)
  25. #:use-module (gnu services)
  26. #:use-module (gnu services databases)
  27. #:use-module (gnu services networking)
  28. #:use-module (gnu packages databases)
  29. #:use-module (guix gexp)
  30. #:use-module (guix store)
  31. #:export (%test-memcached
  32. %test-mongodb
  33. %test-postgresql
  34. %test-mysql))
  35. (define %memcached-os
  36. (simple-operating-system
  37. (service dhcp-client-service-type)
  38. (service memcached-service-type)))
  39. (define* (run-memcached-test #:optional (port 11211))
  40. "Run tests in %MEMCACHED-OS, forwarding PORT."
  41. (define os
  42. (marionette-operating-system
  43. %memcached-os
  44. #:imported-modules '((gnu services herd)
  45. (guix combinators))))
  46. (define vm
  47. (virtual-machine
  48. (operating-system os)
  49. (port-forwardings `((11211 . ,port)))))
  50. (define test
  51. (with-imported-modules '((gnu build marionette))
  52. #~(begin
  53. (use-modules (srfi srfi-11) (srfi srfi-64)
  54. (gnu build marionette)
  55. (ice-9 rdelim))
  56. (define marionette
  57. (make-marionette (list #$vm)))
  58. (mkdir #$output)
  59. (chdir #$output)
  60. (test-begin "memcached")
  61. ;; Wait for memcached to be up and running.
  62. (test-assert "service running"
  63. (marionette-eval
  64. '(begin
  65. (use-modules (gnu services herd))
  66. (match (start-service 'memcached)
  67. (#f #f)
  68. (('service response-parts ...)
  69. (match (assq-ref response-parts 'running)
  70. ((pid) (number? pid))))))
  71. marionette))
  72. (let* ((ai (car (getaddrinfo "localhost"
  73. #$(number->string port))))
  74. (s (socket (addrinfo:fam ai)
  75. (addrinfo:socktype ai)
  76. (addrinfo:protocol ai)))
  77. (key "testkey")
  78. (value "guix"))
  79. (connect s (addrinfo:addr ai))
  80. (test-equal "set"
  81. "STORED\r"
  82. (begin
  83. (simple-format s "set ~A 0 60 ~A\r\n~A\r\n"
  84. key
  85. (string-length value)
  86. value)
  87. (read-line s)))
  88. (test-equal "get"
  89. (simple-format #f "VALUE ~A 0 ~A\r~A\r"
  90. key
  91. (string-length value)
  92. value)
  93. (begin
  94. (simple-format s "get ~A\r\n" key)
  95. (string-append
  96. (read-line s)
  97. (read-line s))))
  98. (close-port s))
  99. ;; There should be a log file in here.
  100. (test-assert "log file"
  101. (marionette-eval
  102. '(file-exists? "/var/log/memcached")
  103. marionette))
  104. (test-end)
  105. (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
  106. (gexp->derivation "memcached-test" test))
  107. (define %test-memcached
  108. (system-test
  109. (name "memcached")
  110. (description "Connect to a running MEMCACHED server.")
  111. (value (run-memcached-test))))
  112. (define %mongodb-os
  113. (operating-system
  114. (inherit
  115. (simple-operating-system
  116. (service dhcp-client-service-type)
  117. (service mongodb-service-type)))
  118. (packages (cons* mongodb
  119. %base-packages))))
  120. (define* (run-mongodb-test #:optional (port 27017))
  121. "Run tests in %MONGODB-OS, forwarding PORT."
  122. (define os
  123. (marionette-operating-system
  124. %mongodb-os
  125. #:imported-modules '((gnu services herd)
  126. (guix combinators))))
  127. (define vm
  128. (virtual-machine
  129. (operating-system os)
  130. (memory-size 1024)
  131. (disk-image-size (* 1024 (expt 2 20)))
  132. (port-forwardings `((27017 . ,port)))))
  133. (define test
  134. (with-imported-modules '((gnu build marionette))
  135. #~(begin
  136. (use-modules (srfi srfi-11) (srfi srfi-64)
  137. (gnu build marionette)
  138. (ice-9 popen)
  139. (ice-9 rdelim))
  140. (define marionette
  141. (make-marionette (list #$vm)))
  142. (mkdir #$output)
  143. (chdir #$output)
  144. (test-begin "mongodb")
  145. (test-assert "service running"
  146. (marionette-eval
  147. '(begin
  148. (use-modules (gnu services herd))
  149. (match (start-service 'mongodb)
  150. (#f #f)
  151. (('service response-parts ...)
  152. (match (assq-ref response-parts 'running)
  153. ((pid) (number? pid))))))
  154. marionette))
  155. (test-eq "test insert"
  156. 0
  157. (system* (string-append #$mongodb "/bin/mongo")
  158. "test"
  159. "--eval"
  160. "db.testCollection.insert({data: 'test-data'})"))
  161. (test-equal "test find"
  162. "test-data"
  163. (let* ((port (open-pipe*
  164. OPEN_READ
  165. (string-append #$mongodb "/bin/mongo")
  166. "test"
  167. "--quiet"
  168. "--eval"
  169. "db.testCollection.findOne().data"))
  170. (output (read-line port))
  171. (status (close-pipe port)))
  172. output))
  173. (test-end)
  174. (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
  175. (gexp->derivation "mongodb-test" test))
  176. (define %test-mongodb
  177. (system-test
  178. (name "mongodb")
  179. (description "Connect to a running MONGODB server.")
  180. (value (run-mongodb-test))))
  181. ;;;
  182. ;;; The PostgreSQL service.
  183. ;;;
  184. (define %postgresql-log-directory
  185. "/var/log/postgresql")
  186. (define %role-log-file
  187. "/var/log/postgresql_roles.log")
  188. (define %postgresql-os
  189. (simple-operating-system
  190. (service postgresql-service-type
  191. (postgresql-configuration
  192. (postgresql postgresql-10)
  193. (config-file
  194. (postgresql-config-file
  195. (extra-config
  196. '(("session_preload_libraries" "auto_explain")
  197. ("random_page_cost" 2)
  198. ("auto_explain.log_min_duration" "100 ms")
  199. ("work_mem" "500 MB")
  200. ("debug_print_plan" #t)))))))
  201. (service postgresql-role-service-type
  202. (postgresql-role-configuration
  203. (roles
  204. (list (postgresql-role
  205. (name "root")
  206. (create-database? #t))))))))
  207. (define (run-postgresql-test)
  208. "Run tests in %POSTGRESQL-OS."
  209. (define os
  210. (marionette-operating-system
  211. %postgresql-os
  212. #:imported-modules '((gnu services herd)
  213. (guix combinators))))
  214. (define vm
  215. (virtual-machine
  216. (operating-system os)
  217. (memory-size 512)))
  218. (define test
  219. (with-imported-modules '((gnu build marionette))
  220. #~(begin
  221. (use-modules (srfi srfi-64)
  222. (gnu build marionette))
  223. (define marionette
  224. (make-marionette (list #$vm)))
  225. (mkdir #$output)
  226. (chdir #$output)
  227. (test-begin "postgresql")
  228. (test-assert "service running"
  229. (marionette-eval
  230. '(begin
  231. (use-modules (gnu services herd))
  232. (start-service 'postgres))
  233. marionette))
  234. (test-assert "log-file"
  235. (marionette-eval
  236. '(begin
  237. (use-modules (ice-9 ftw)
  238. (ice-9 match))
  239. (current-output-port
  240. (open-file "/dev/console" "w0"))
  241. (let ((server-log-file
  242. (string-append #$%postgresql-log-directory
  243. "/pg_ctl.log")))
  244. (and (file-exists? server-log-file)
  245. (display
  246. (call-with-input-file server-log-file
  247. get-string-all)))
  248. #t))
  249. marionette))
  250. (test-assert "database ready"
  251. (begin
  252. (marionette-eval
  253. '(begin
  254. (let loop ((i 10))
  255. (unless (or (zero? i)
  256. (and (file-exists? #$%role-log-file)
  257. (string-contains
  258. (call-with-input-file #$%role-log-file
  259. get-string-all)
  260. ";\nCREATE DATABASE")))
  261. (sleep 1)
  262. (loop (- i 1)))))
  263. marionette)))
  264. (test-assert "database creation"
  265. (marionette-eval
  266. '(begin
  267. (use-modules (gnu services herd)
  268. (ice-9 popen))
  269. (current-output-port
  270. (open-file "/dev/console" "w0"))
  271. (let* ((port (open-pipe*
  272. OPEN_READ
  273. #$(file-append postgresql "/bin/psql")
  274. "-tAh" "/var/run/postgresql"
  275. "-c" "SELECT 1 FROM pg_database WHERE
  276. datname='root'"))
  277. (output (get-string-all port)))
  278. (close-pipe port)
  279. (string-contains output "1")))
  280. marionette))
  281. (test-end)
  282. (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
  283. (gexp->derivation "postgresql-test" test))
  284. (define %test-postgresql
  285. (system-test
  286. (name "postgresql")
  287. (description "Start the PostgreSQL service.")
  288. (value (run-postgresql-test))))
  289. ;;;
  290. ;;; The MySQL service.
  291. ;;;
  292. (define %mysql-os
  293. (simple-operating-system
  294. (service mysql-service-type)))
  295. (define* (run-mysql-test)
  296. "Run tests in %MYSQL-OS."
  297. (define os
  298. (marionette-operating-system
  299. %mysql-os
  300. #:imported-modules '((gnu services herd)
  301. (guix combinators))))
  302. (define vm
  303. (virtual-machine
  304. (operating-system os)
  305. (memory-size 512)))
  306. (define test
  307. (with-imported-modules '((gnu build marionette))
  308. #~(begin
  309. (use-modules (srfi srfi-11) (srfi srfi-64)
  310. (gnu build marionette))
  311. (define marionette
  312. (make-marionette (list #$vm)))
  313. (mkdir #$output)
  314. (chdir #$output)
  315. (test-begin "mysql")
  316. (test-assert "service running"
  317. (marionette-eval
  318. '(begin
  319. (use-modules (gnu services herd))
  320. (match (start-service 'mysql)
  321. (#f #f)
  322. (('service response-parts ...)
  323. (match (assq-ref response-parts 'running)
  324. ((pid) (number? pid))))))
  325. marionette))
  326. (test-assert "mysql_upgrade completed"
  327. (wait-for-file "/var/lib/mysql/mysql_upgrade_info" marionette))
  328. (test-eq "create database"
  329. 0
  330. (marionette-eval
  331. '(begin
  332. (system* #$(file-append mariadb "/bin/mysql")
  333. "-e" "CREATE DATABASE guix;"))
  334. marionette))
  335. (test-eq "create table"
  336. 0
  337. (marionette-eval
  338. '(begin
  339. (system*
  340. #$(file-append mariadb "/bin/mysql") "guix"
  341. "-e" "CREATE TABLE facts (id INT, data VARCHAR(12));"))
  342. marionette))
  343. (test-eq "insert data"
  344. 0
  345. (marionette-eval
  346. '(begin
  347. (system* #$(file-append mariadb "/bin/mysql") "guix"
  348. "-e" "INSERT INTO facts VALUES (1, 'awesome')"))
  349. marionette))
  350. (test-equal "retrieve data"
  351. "awesome\n"
  352. (marionette-eval
  353. '(begin
  354. (use-modules (ice-9 popen))
  355. (let* ((port (open-pipe*
  356. OPEN_READ
  357. #$(file-append mariadb "/bin/mysql") "guix"
  358. "-NB" "-e" "SELECT data FROM facts WHERE id=1;"))
  359. (output (get-string-all port)))
  360. (close-pipe port)
  361. output))
  362. marionette))
  363. (test-end)
  364. (exit (= (test-runner-fail-count (test-runner-current)) 0)))))
  365. (gexp->derivation "mysql-test" test))
  366. (define %test-mysql
  367. (system-test
  368. (name "mysql")
  369. (description "Start the MySQL service.")
  370. (value (run-mysql-test))))