]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/fs/fuse/mockfs.hh
fuse(4): add tests for CREATE, OPEN, READLINK, SETATTR and SYMLINK
[FreeBSD/FreeBSD.git] / tests / sys / fs / fuse / mockfs.hh
1 /*-
2  * Copyright (c) 2019 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by BFF Storage Systems, LLC under sponsorship
6  * from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 extern "C" {
31 #include <sys/types.h>
32
33 #include <pthread.h>
34
35 #include "fuse_kernel.h"
36 }
37
38 #include <gmock/gmock.h>
39
40 #define SET_OUT_HEADER_LEN(out, variant) { \
41         (out)->header.len = (sizeof((out)->header) + \
42                              sizeof((out)->body.variant)); \
43 }
44
45 extern int verbosity;
46
47 /* This struct isn't defined by fuse_kernel.h or libfuse, but it should be */
48 struct fuse_create_out {
49         struct fuse_entry_out   entry;
50         struct fuse_open_out    open;
51 };
52
53 union fuse_payloads_in {
54         /* value is from fuse_kern_chan.c in fusefs-libs */
55         uint8_t         bytes[0x21000 - sizeof(struct fuse_in_header)];
56         fuse_forget_in  forget;
57         fuse_init_in    init;
58         char            lookup[0];
59         fuse_open_in    open;
60         fuse_setattr_in setattr;
61 };
62
63 struct mockfs_buf_in {
64         fuse_in_header          header;
65         union fuse_payloads_in  body;
66 };
67
68 union fuse_payloads_out {
69         fuse_attr_out           attr;
70         fuse_create_out         create;
71         fuse_entry_out          entry;
72         fuse_init_out           init;
73         fuse_open_out           open;
74         /*
75          * The protocol places no limits on the length of the string.  This is
76          * merely convenient for testing.
77          */
78         char                    str[80];
79 };
80
81 struct mockfs_buf_out {
82         fuse_out_header         header;
83         union fuse_payloads_out body;
84 };
85
86 /*
87  * Fake FUSE filesystem
88  *
89  * "Mounts" a filesystem to a temporary directory and services requests
90  * according to the programmed expectations.
91  *
92  * Operates directly on the fuse(4) kernel API, not the libfuse(3) user api.
93  */
94 class MockFS {
95         public:
96         /* thread id of the fuse daemon thread */
97         pthread_t m_daemon_id;
98
99         private:
100         /* file descriptor of /dev/fuse control device */
101         int m_fuse_fd;
102         
103         /* pid of the test process */
104         pid_t m_pid;
105
106         /* 
107          * Thread that's running the mockfs daemon.
108          *
109          * It must run in a separate thread so it doesn't deadlock with the
110          * client test code.
111          */
112         pthread_t m_thr;
113
114         /* Initialize a session after mounting */
115         void init();
116
117         /* Default request handler */
118         void process_default(const mockfs_buf_in*, mockfs_buf_out*);
119
120         /* Entry point for the daemon thread */
121         static void* service(void*);
122
123         /* Read, but do not process, a single request from the kernel */
124         void read_request(mockfs_buf_in*);
125
126         public:
127         /* Create a new mockfs and mount it to a tempdir */
128         MockFS();
129         virtual ~MockFS();
130
131         /* Process FUSE requests endlessly */
132         void loop();
133
134         /* 
135          * Request handler
136          *
137          * This method is expected to provide the response to each FUSE
138          * operation.  Responses must be immediate (so this method can't be used
139          * for testing a daemon with queue depth > 1).  Test cases must define
140          * each response using Googlemock expectations
141          */
142         MOCK_METHOD2(process, void(const mockfs_buf_in*, mockfs_buf_out*));
143
144         /* Gracefully unmount */
145         void unmount();
146 };