t_storage.ml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. (*
  2. * _ _ ____ _
  3. * _| || |_/ ___| ___ _ __ _ __ ___ | |
  4. * |_ .. _\___ \ / _ \ '_ \| '_ \ / _ \| |
  5. * |_ _|___) | __/ |_) | |_) | (_) |_|
  6. * |_||_| |____/ \___| .__/| .__/ \___/(_)
  7. * |_| |_|
  8. *
  9. * Personal Social Web.
  10. *
  11. * Copyright (C) The #Seppo contributors. All rights reserved.
  12. *
  13. * This program is free software: you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation, either version 3 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  25. *)
  26. open Seppo_lib
  27. open Storage
  28. open Alcotest
  29. let equals_string = Assrt.equals_string
  30. let equals_int = Assrt.equals_int
  31. module Fifo = struct
  32. type t = string * int
  33. let make size fn : t =
  34. (fn,size)
  35. let push (fn,size) byt =
  36. let sep = '\n' in
  37. let len = byt |> Bytes.length in
  38. let keep = size - len |> pred in
  39. if keep < try (Unix.stat fn).st_size with _ -> 0
  40. then (* make space and add *)
  41. let ret = len |> Bytes.create in
  42. let buf = keep |> Bytes.create in
  43. fn |> File.in_channel (fun ic ->
  44. really_input ic ret 0 len;
  45. let _ = input_char ic in
  46. really_input ic buf 0 keep );
  47. let mode = [ Open_creat; Open_binary; Open_excl; Open_trunc; Open_wronly ] in
  48. fn |> File.out_channel_replace ~mode (fun oc ->
  49. output_bytes oc buf;
  50. output_bytes oc byt;
  51. output_char oc sep
  52. );
  53. Some ret
  54. else (* just add *)
  55. let mode = [ Open_append; Open_binary; Open_excl; Open_wronly ] in
  56. (fn |> File.out_channel_append ~mode (fun oc ->
  57. output_bytes oc byt;
  58. output_char oc sep
  59. );
  60. None)
  61. end
  62. let set_up () =
  63. Mirage_crypto_rng_lwt.initialize (module Mirage_crypto_rng.Fortuna);
  64. Unix.chdir "../../../test/"
  65. let _tc_fifo () =
  66. let bu = Fifo.make 12 "buffer.fifo" in
  67. let by = Bytes.make 2 '_' in
  68. let _ = Fifo.push bu by in
  69. ()
  70. let tc_dir_of_ix () =
  71. let a,b = "app/var/db/o/p/23.s" |> Page.of_fn |> Option.get in
  72. a |> equals_string __LOC__ "o/p";
  73. b |> equals_int __LOC__ 23;
  74. let a,_ = "app/var/db/o/t/foo/23.s" |> Page.of_fn |> Option.get in
  75. a |> equals_string __LOC__ "o/t/foo";
  76. ()
  77. let tc_tuple () =
  78. (23,42) |> TwoPad10.to_string |> equals_string __LOC__ "(10:0x0000001710:0x0000002a)";
  79. (0x3fff_ffff,42) |> TwoPad10.to_string |> equals_string __LOC__ "(10:0x3fffffff10:0x0000002a)";
  80. let (a,b) = "(10:000000002310:0000000042)"
  81. |> Csexp.parse_string_many
  82. |> Result.value ~default:[]
  83. |> TwoPad10.decode_many
  84. |> List.hd in
  85. a |> equals_int __LOC__ 23;
  86. b |> equals_int __LOC__ 42;
  87. assert true
  88. (*
  89. let tc_json () =
  90. let minify = false in
  91. let base = Uri.of_string "https://example.com/su/" in
  92. let item = Rfc4287_test.mk_sample () in
  93. item |> As2.Note.mk_note_json ~base
  94. |> As2.Note.mk_create_json ~base item
  95. |> Ezjsonm.to_string ~minify
  96. |> eq_s __LOC__ {|{
  97. "type": "Create",
  98. "id": "https://example.com/su/o/p-12/#23/Create",
  99. "actor": "https://example.com/su/activitypub/",
  100. "published": "2023-02-11T11:07:23+01:00",
  101. "to": [
  102. "https://www.w3.org/ns/activitystreams#Public"
  103. ],
  104. "cc": [
  105. "https://example.com/su/activitypub/followers/"
  106. ],
  107. "object": {
  108. "type": "Note",
  109. "id": "o/p-12/#23",
  110. "actor": "activitypub/",
  111. "to": [
  112. "https://www.w3.org/ns/activitystreams#Public"
  113. ],
  114. "cc": [
  115. "activitypub/followers/"
  116. ],
  117. "mediaType": "text/plain; charset=utf8",
  118. "content": "I am happy to announce the premiere release of #Seppo!, Personal #Social #Media under funding of NLnet.nl.\n\nFind it at https://Seppo.Social/downloads/\n\nIt has no notable user facing #ActivityPub features so far, but\n\n- easy setup of instance & account,\n- #webfinger discoverability (from e.g. mastodon search),\n- a welcoming, long-term reliable website.\n\nI made this embarrassingly limited release to build awareness for low-barrier-entry internet services in general and especially in the field of personal communication as well as letting the #fediverse and #permacomputing communities know.\n\nYour comments are very much appreciated.",
  119. "sensitive": false,
  120. "summary": "#Announce Seppo.Social v0.1 and Request for Comments.",
  121. "published": "2023-02-11T10:07:23Z",
  122. "tags": [
  123. {
  124. "type": "Hashtag",
  125. "href": "o/t/webfinger/",
  126. "name": "#webfinger"
  127. },
  128. {
  129. "type": "Hashtag",
  130. "href": "o/t/Social/",
  131. "name": "#Social"
  132. },
  133. {
  134. "type": "Hashtag",
  135. "href": "o/t/Seppo/",
  136. "name": "#Seppo"
  137. },
  138. {
  139. "type": "Hashtag",
  140. "href": "o/t/permacomputing/",
  141. "name": "#permacomputing"
  142. },
  143. {
  144. "type": "Hashtag",
  145. "href": "o/t/Media/",
  146. "name": "#Media"
  147. },
  148. {
  149. "type": "Hashtag",
  150. "href": "o/t/Fediverse/",
  151. "name": "#Fediverse"
  152. },
  153. {
  154. "type": "Hashtag",
  155. "href": "o/t/Announce/",
  156. "name": "#Announce"
  157. },
  158. {
  159. "type": "Hashtag",
  160. "href": "o/t/ActivityPub/",
  161. "name": "#ActivityPub"
  162. }
  163. ]
  164. }
  165. }|}
  166. *)
  167. let tc_strut () =
  168. let strut' (p0,p1 as s) =
  169. let r = s |> TwoPad10.strut |> Csexp.to_string in
  170. Logr.info (fun m -> m "%s.%s %d %s" "" "" (p1-p0) r);
  171. r
  172. in
  173. (0,6) |> strut' |> equals_string __LOC__ "(0:0:)";
  174. (0,7) |> strut' |> equals_string __LOC__ "(0:1:x)";
  175. (0,8) |> strut' |> equals_string __LOC__ "(0:2:xx)";
  176. (0,9) |> strut' |> equals_string __LOC__ "(0:3:xxx)";
  177. (0,14) |> strut' |> equals_string __LOC__ "(0:8:xxxxxxxx)";
  178. (0,15) |> strut' |> equals_string __LOC__ "(0:9:xxxxxxxxx)";
  179. (0,16) |> strut' |> equals_string __LOC__ "(1:x9:xxxxxxxxx)";
  180. (0,17) |> strut' |> equals_string __LOC__ "(0:10:xxxxxxxxxx)";
  181. (0,18) |> strut' |> equals_string __LOC__ "(0:11:xxxxxxxxxxx)";
  182. (0,106) |> strut' |> equals_string __LOC__ "(0:99:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  183. (0,107) |> strut' |> equals_string __LOC__ "(1:x99:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  184. (0,108) |> strut' |> equals_string __LOC__ "(0:100:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  185. (0,1007) |> strut' |> equals_string __LOC__ "(0:999:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  186. (0,1008) |> strut' |> equals_string __LOC__ "(1:x999:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  187. (0,1009) |> strut' |> equals_string __LOC__ "(0:1000:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)";
  188. assert true
  189. module Page = struct
  190. let tc_jig () =
  191. let j = "%-%/index.xml" |> Make.Jig.make in
  192. let v = "o/p-42/index.xml" |> Make.Jig.cut j |> Option.value ~default:[] in
  193. (match v with
  194. | [dir;idx] ->
  195. dir |> equals_string __LOC__ "o/p";
  196. idx |> equals_string __LOC__ "42"
  197. | _ -> failwith __LOC__);
  198. let dir,idx = "app/var/db/o/p/42.s" |> Storage.Page.of_fn |> Option.get in
  199. dir |> equals_string __LOC__ "o/p";
  200. idx |> equals_int __LOC__ 42
  201. let tc_pred_succ () =
  202. let v = "app/var/db/o/p/42.s" |> Storage.Page.of_fn |> Option.get in
  203. let dir,idx = v |> Storage.Page.pred in
  204. dir |> equals_string __LOC__ "o/p";
  205. idx |> equals_int __LOC__ 41;
  206. let dir,idx = v |> Storage.Page.succ in
  207. dir |> equals_string __LOC__ "o/p";
  208. idx |> equals_int __LOC__ 43
  209. let tc_other_feeds () =
  210. let _e = match
  211. Rfc4287.Entry.from_text_plain
  212. ~published:(Rfc3339.T "1970-01-01T00:00:00Z")
  213. ~author:Rfc4287.Person.empty
  214. ~lang:(Rfc4287.Rfc4646 "nl")
  215. ~uri:Uri.empty
  216. "title" "content" with
  217. | Ok o -> o
  218. | Error e -> failwith e
  219. in
  220. let s,i = match _e |> Storage.Page.other_feeds with
  221. | [x] -> x
  222. | _ -> failwith "ouch" in
  223. s |> Assrt.equals_string __LOC__ "o/d/1970-01-01";
  224. i |> Assrt.equals_int __LOC__ (-3)
  225. end
  226. module TwoPad10 = struct
  227. let tc_id_to_page_i () =
  228. (match "o/p-12/#35" |> Uri.of_string |> Storage.Id.to_page_i with
  229. | Ok ((f,j),i) ->
  230. f |> Assrt.equals_string __LOC__ "o/p";
  231. j |> Assrt.equals_int __LOC__ 12;
  232. i |> Assrt.equals_int __LOC__ 35;
  233. | _ -> failwith __LOC__);
  234. (* match "https://example.com/sub/o/p-12/#35" |> Uri.of_string |> Storage.TwoPad10.id_to_page_i with
  235. | Ok ((f,j),i) ->
  236. f |> Assrt.equals_string __LOC__ "o/p";
  237. j |> Assrt.equals_int __LOC__ 12;
  238. i |> Assrt.equals_int __LOC__ 35;
  239. | _ -> failwith __LOC__ *)
  240. ()
  241. let _tc_from_id' () =
  242. let _a,_b = "o/p-12/#35"
  243. |> Uri.of_string
  244. |> Storage.TwoPad10.from_id ~prefix:"data/"
  245. |> Result.get_ok in
  246. ()
  247. end
  248. let () =
  249. run
  250. "seppo_suite" [
  251. __FILE__ , [
  252. "set_up", `Quick, set_up ;
  253. (* "tc_fifo", `Quick, tc_fifo ; *)
  254. "tc_dir_of_ix", `Quick, tc_dir_of_ix ;
  255. "tc_tuple", `Quick, tc_tuple ;
  256. "tc_strut", `Quick, tc_strut ;
  257. (* "tc_json ()", `Quick, tc_json () ; *)
  258. "Page.tc_jig", `Quick, Page.tc_jig ;
  259. "Page.tc_pred_succ", `Quick, Page.tc_pred_succ ;
  260. "Page.tc_other_feeds", `Quick, Page.tc_other_feeds ;
  261. (*
  262. TwoPad10.tc_id_to_page_i ();
  263. TwoPad10.tc_from_id' ();
  264. *)
  265. "TwoPad10.tc_id_to_page_i", `Quick, TwoPad10.tc_id_to_page_i ;
  266. ]
  267. ]