file: Add an internal "mode"
[nbdkit.git] / tests / test_ocaml_plugin.ml
blob37b80c597ac776dd58de0d37d468de2fb46e1c4a
1 (* nbdkit
2 * Copyright (C) 2013-2021 Red Hat Inc.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 let sector_size = 512
34 let nr_sectors = 2048
36 let disk = Bytes.make (nr_sectors*sector_size) '\000' (* disk image *)
37 let sparse = Bytes.make nr_sectors '\000' (* sparseness bitmap *)
39 (* Test parse_* functions. *)
40 let () =
41 assert (NBDKit.parse_size "1M" = Int64.of_int (1024*1024));
42 assert (NBDKit.parse_bool "true" = true);
43 assert (NBDKit.parse_bool "0" = false)
45 (* Test the realpath function. *)
46 let () =
47 let isdir d = try Sys.is_directory d with Sys_error _ -> false in
48 let test_dir = "/usr/bin" in
49 if isdir test_dir then
50 (* We don't know what the answer will be, but it must surely
51 * be a directory.
53 assert (isdir (NBDKit.realpath test_dir))
55 let load () =
56 NBDKit.debug "test ocaml plugin loaded"
58 let unload () =
59 (* A good way to find memory bugs: *)
60 Gc.compact ();
61 NBDKit.debug "test ocaml plugin unloaded"
63 let params = ref []
65 let config k v =
66 params := (k, v) :: !params
68 let config_complete () =
69 let params = List.rev !params in
70 assert (params = [ "a", "1"; "b", "2"; "c", "3"; "d", "4" ])
72 let get_ready () =
73 (* We could allocate the disk here, but it's easier to allocate
74 * it statically above.
76 NBDKit.debug "test ocaml plugin getting ready"
78 let after_fork () =
79 NBDKit.debug "test ocaml plugin after fork"
81 let cleanup () =
82 NBDKit.debug "test ocaml plugin cleaning up"
84 (* Test the handle is received by callbacks. *)
85 type handle = {
86 h_id : int;
87 h_sentinel : string;
90 let id = ref 0
91 let open_connection readonly =
92 let export_name = NBDKit.export_name () in
93 NBDKit.debug "test ocaml plugin handle opened readonly=%b export=%S"
94 readonly export_name;
95 incr id;
96 { h_id = !id; h_sentinel = "TESTING" }
98 let close h =
99 NBDKit.debug "test ocaml plugin closing handle id=%d" h.h_id;
100 assert (h.h_id > 0);
101 assert (h.h_sentinel = "TESTING");
104 let list_exports _ _ =
105 [ { NBDKit.name = "name1"; description = Some "desc1" };
106 { name = "name2"; description = None } ]
108 let default_export _ _ = "name1"
110 let get_size h =
111 NBDKit.debug "test ocaml plugin get_size handle id=%d" h.h_id;
112 assert (h.h_id > 0);
113 assert (h.h_sentinel = "TESTING");
114 Int64.of_int (Bytes.length disk)
116 let block_size _ = (1, 4096, -1L)
118 let pread h count offset _ =
119 assert (h.h_id > 0);
120 assert (h.h_sentinel = "TESTING");
121 let buf = Bytes.create count in
122 Bytes.blit disk (Int64.to_int offset) buf 0 count;
123 Bytes.unsafe_to_string buf
125 let set_non_sparse offset len =
126 Bytes.fill sparse (offset/sector_size) ((len-1)/sector_size) '\001'
128 let pwrite h buf offset _ =
129 assert (h.h_id > 0);
130 assert (h.h_sentinel = "TESTING");
131 let len = String.length buf in
132 let offset = Int64.to_int offset in
133 String.blit buf 0 disk offset len;
134 set_non_sparse offset len
136 let extents _ count offset _ =
137 let extents = Array.init nr_sectors (
138 fun sector ->
139 { NBDKit.offset = Int64.of_int (sector*sector_size);
140 length = Int64.of_int sector_size;
141 is_hole = true; is_zero = false }
142 ) in
143 Bytes.iteri (
144 fun i c ->
145 if c = '\001' then (* not sparse *)
146 extents.(i) <- { extents.(i) with is_hole = false }
147 ) sparse;
148 Array.to_list extents
150 let thread_model () =
151 NBDKit.THREAD_MODEL_SERIALIZE_ALL_REQUESTS
153 let () =
154 NBDKit.register_plugin
155 ~name: "testocaml"
156 ~version: (NBDKit.version ())
158 ~load
159 ~get_ready
160 ~after_fork
161 ~cleanup
162 ~unload
164 ~config
165 ~config_complete
166 ~thread_model
167 ~magic_config_key: "d"
169 ~open_connection
170 ~close
171 ~get_size
172 ~block_size
173 ~pread
174 ~pwrite
175 ~extents
177 ~list_exports
178 ~default_export