2024-04-20 19:24:10 +02:00
|
|
|
(local { : view } (require :fennel))
|
2024-04-20 18:45:40 +02:00
|
|
|
(import-macros { : expect= } :anoia.assert)
|
|
|
|
|
2024-04-20 19:24:10 +02:00
|
|
|
(fn parse-uevent [s]
|
2024-04-20 23:20:43 +02:00
|
|
|
(let [at (string.find s "@" 1 true)
|
|
|
|
(nl nxt) (string.find s "\0" 1 true)]
|
2024-04-20 19:24:10 +02:00
|
|
|
(doto
|
|
|
|
(collect [k v (string.gmatch
|
|
|
|
(string.sub s (+ 1 nxt))
|
|
|
|
"(%g-)=(%g+)")]
|
|
|
|
(k:lower) v)
|
2024-04-20 23:20:43 +02:00
|
|
|
(tset :path (string.sub s (+ at 1) (- nl 1))))))
|
2024-04-20 18:45:40 +02:00
|
|
|
|
2024-04-20 19:42:42 +02:00
|
|
|
(fn event-matches? [e terms]
|
|
|
|
(accumulate [match? true
|
|
|
|
name value (pairs terms)]
|
|
|
|
(and match? (= value (. e name)))))
|
|
|
|
|
|
|
|
(fn find-in-database [db terms]
|
|
|
|
(accumulate [found []
|
|
|
|
_ e (pairs db)]
|
|
|
|
(if (event-matches? e terms)
|
|
|
|
(doto found (table.insert e))
|
|
|
|
found)))
|
|
|
|
|
2024-04-20 18:45:40 +02:00
|
|
|
(fn database []
|
2024-04-20 19:24:10 +02:00
|
|
|
(let [db {}]
|
|
|
|
{
|
2024-04-20 19:42:42 +02:00
|
|
|
:find (fn [_ terms] (find-in-database db terms))
|
2024-04-20 19:24:10 +02:00
|
|
|
:add (fn [_ event-string]
|
|
|
|
(let [e (parse-uevent event-string)]
|
|
|
|
(tset db e.path e)))
|
2024-04-20 23:20:43 +02:00
|
|
|
:at-path (fn [_ path] (. db path))
|
2024-04-20 19:24:10 +02:00
|
|
|
}))
|
2024-04-20 18:45:40 +02:00
|
|
|
|
2024-04-20 22:46:37 +02:00
|
|
|
(var failed false)
|
|
|
|
(fn fail [d msg] (set failed true) (print :FAIL d (.. "\n" msg)))
|
|
|
|
|
2024-04-20 18:45:40 +02:00
|
|
|
(macro example [description & body]
|
2024-04-20 22:46:37 +02:00
|
|
|
`(let [(ok?# err#) (xpcall (fn [] ,body) debug.traceback)]
|
|
|
|
(if ok?#
|
|
|
|
(print :PASS ,description)
|
|
|
|
(fail ,description err#))))
|
2024-04-20 18:45:40 +02:00
|
|
|
|
|
|
|
(example
|
2024-04-20 19:42:42 +02:00
|
|
|
"given an empty database, searching it finds no entries"
|
2024-04-20 18:45:40 +02:00
|
|
|
(let [db (database)]
|
|
|
|
(expect= (db:find {:partname "boot"}) [])))
|
|
|
|
|
2024-04-20 19:42:42 +02:00
|
|
|
(local sda-uevent
|
|
|
|
"add@/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda\0ACTION=add
|
2024-04-20 19:24:10 +02:00
|
|
|
DEVPATH=/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda
|
|
|
|
SUBSYSTEM=block
|
|
|
|
MAJOR=8
|
|
|
|
MINOR=0
|
|
|
|
DEVNAME=sda
|
|
|
|
DEVTYPE=disk
|
|
|
|
DISKSEQ=2
|
|
|
|
SEQNUM=1527")
|
2024-04-20 19:42:42 +02:00
|
|
|
|
|
|
|
(example
|
|
|
|
"when I add a device, I can find it"
|
|
|
|
(let [db (database)]
|
|
|
|
(db:add sda-uevent)
|
|
|
|
(let [[m & more] (db:find {:devname "sda"})]
|
2024-04-20 19:24:10 +02:00
|
|
|
(expect= m.devname "sda")
|
|
|
|
(expect= m.major "8")
|
|
|
|
(expect= more []))))
|
|
|
|
|
2024-04-20 19:42:42 +02:00
|
|
|
(example
|
|
|
|
"when I add a device, I cannot find it with wrong terms"
|
|
|
|
(let [db (database)]
|
|
|
|
(db:add sda-uevent)
|
|
|
|
(expect= (db:find {:devname "sdb"}) [])))
|
|
|
|
|
2024-04-20 23:20:43 +02:00
|
|
|
(example
|
|
|
|
"when I add a device, I can retrieve it by path"
|
|
|
|
(let [db (database)]
|
|
|
|
(db:add sda-uevent)
|
|
|
|
(let [m (db:at-path "/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda")]
|
|
|
|
(expect= m.devname "sda")
|
|
|
|
(expect= m.major "8"))))
|
|
|
|
|
|
|
|
|
2024-04-20 19:42:42 +02:00
|
|
|
(example
|
|
|
|
"when I search on multiple terms it uses all of them"
|
|
|
|
(let [db (database)]
|
|
|
|
(db:add sda-uevent)
|
|
|
|
(expect= (# (db:find {:devname "sda" :devtype "disk"})) 1)
|
|
|
|
(expect= (# (db:find {:devname "sda" :devtype "dosk"})) 0)))
|
|
|
|
|
|
|
|
|
2024-04-20 18:45:40 +02:00
|
|
|
|
2024-04-20 22:46:37 +02:00
|
|
|
(if failed (os.exit 1) (print "OK"))
|