Add initial control protocol test.
[oweals/dinit.git] / src / tests / test-bpsys.cc
1 #include <vector>
2 #include <utility>
3 #include <algorithm>
4 #include <map>
5
6 #include <cstdlib>
7
8 #include "baseproc-sys.h"
9
10 namespace {
11
12 std::vector<bool> usedfds = {true, true, true};
13
14 struct read_result
15 {
16         read_result(int errcode_p) : errcode(errcode_p) {}
17
18         read_result(std::vector<char> &data_p) : errcode(0), data(data_p) {}
19         read_result(std::vector<char> &&data_p) : errcode(0), data(std::move(data_p)) {}
20
21         int errcode; // errno return
22         std::vector<char> data;  // data (if errcode == 0)
23 };
24
25 // map of fd to read results to supply for reads of that fd
26 std::map<int,std::vector<read_result>> read_data;
27
28 // map of data written to each fd
29 std::map<int,std::vector<char>> written_data;
30
31 } // anon namespace
32
33 namespace bp_sys {
34
35 int last_sig_sent = -1; // last signal number sent, accessible for tests.
36 pid_t last_forked_pid = 1;  // last forked process id (incremented each 'fork')
37
38 // Test helper methods:
39
40 // Allocate a file descriptor
41 int allocfd()
42 {
43     auto f = std::find(usedfds.begin(), usedfds.end(), false);
44     if (f == usedfds.end()) {
45         int r = usedfds.size();
46         usedfds.push_back(true);
47         return r;
48     }
49
50     *f = true;
51     return f - usedfds.begin();
52 }
53
54 // Supply data to be returned by read()
55 void supply_read_data(int fd, std::vector<char> &data)
56 {
57         read_data[fd].emplace_back(data);
58 }
59
60 void supply_read_data(int fd, std::vector<char> &&data)
61 {
62         read_data[fd].emplace_back(std::move(data));
63 }
64
65 // retrieve data written via write()
66 void extract_written_data(int fd, std::vector<char> &data)
67 {
68         data = std::move(written_data[fd]);
69 }
70
71
72 // Mock implementations of system calls:
73
74 int pipe2(int fds[2], int flags)
75 {
76     fds[0] = allocfd();
77     fds[1] = allocfd();
78     return 0;
79 }
80
81 int close(int fd)
82 {
83     if (size_t(fd) >= usedfds.size()) abort();
84
85     usedfds[fd] = false;
86     return 0;
87 }
88
89 int kill(pid_t pid, int sig)
90 {
91     last_sig_sent = sig;
92     return 0;
93 }
94
95 ssize_t read(int fd, void *buf, size_t count)
96 {
97         std::vector<read_result> rrs = read_data[fd];
98         if (rrs.empty()) {
99                 return 0;
100         }
101
102         read_result &rr = rrs.front();
103         if (rr.errcode != 0) {
104                 errno = rr.errcode;
105                 // Remove the result record:
106                 auto i = rrs.begin();
107                 i++;
108                 rrs.erase(rrs.begin(), i);
109                 return -1;
110         }
111
112         auto dsize = rr.data.size();
113         if (dsize <= count) {
114                 // Consume entire result:
115                 std::copy_n(rr.data.begin(), dsize, (char *)buf);
116                 // Remove the result record:
117                 auto i = rrs.begin();
118                 i++;
119                 rrs.erase(rrs.begin(), i);
120                 return dsize;
121         }
122
123         // Consume partial result:
124         std::copy_n(rr.data.begin(), count, (char *)buf);
125         rr.data.erase(rr.data.begin(), rr.data.begin() + count);
126         return count;
127 }
128
129 ssize_t write(int fd, const void *buf, size_t count)
130 {
131         std::vector<char> &wd = written_data[fd];
132         wd.insert(wd.end(), (char *)buf, (char *)buf + count);
133         return count;
134 }
135
136 }