1 | #include <Common/Config/ConfigProcessor.h> |
2 | #include <Interpreters/UsersManager.h> |
3 | #include <filesystem> |
4 | #include <vector> |
5 | #include <string> |
6 | #include <tuple> |
7 | #include <iostream> |
8 | #include <fstream> |
9 | #include <sstream> |
10 | #include <stdexcept> |
11 | #include <cstdlib> |
12 | #include <port/unistd.h> |
13 | |
14 | namespace |
15 | { |
16 | |
17 | namespace fs = std::filesystem; |
18 | |
19 | struct TestEntry |
20 | { |
21 | std::string user_name; |
22 | std::string database_name; |
23 | bool is_allowed; |
24 | }; |
25 | |
26 | using TestEntries = std::vector<TestEntry>; |
27 | |
28 | struct TestDescriptor |
29 | { |
30 | const char * config_content; |
31 | TestEntries entries; |
32 | }; |
33 | |
34 | using TestSet = std::vector<TestDescriptor>; |
35 | |
36 | /// Tests description. |
37 | |
38 | TestSet test_set = |
39 | { |
40 | { |
41 | "<?xml version=\"1.0\"?><yandex>" |
42 | " <profiles><default></default></profiles>" |
43 | " <users>" |
44 | " <default>" |
45 | " <password></password><profile>default</profile><quota>default</quota>" |
46 | " <allow_databases>" |
47 | " <database>default</database>" |
48 | " <database>test</database>" |
49 | " </allow_databases>" |
50 | " </default>" |
51 | " <web>" |
52 | " <password></password><profile>default</profile><quota>default</quota>" |
53 | " </web>" |
54 | " </users>" |
55 | " <quotas><default></default></quotas>" |
56 | "</yandex>" , |
57 | |
58 | { |
59 | { "default" , "default" , true }, |
60 | { "default" , "test" , true }, |
61 | { "default" , "stats" , false }, |
62 | { "web" , "default" , true }, |
63 | { "web" , "test" , true }, |
64 | { "web" , "stats" , true }, |
65 | { "analytics" , "default" , false }, |
66 | { "analytics" , "test" , false }, |
67 | { "analytics" , "stats" , false } |
68 | } |
69 | }, |
70 | |
71 | { |
72 | "<?xml version=\"1.0\"?><yandex>" |
73 | " <profiles><default></default></profiles>" |
74 | " <users>" |
75 | " <default>" |
76 | " <password></password><profile>default</profile><quota>default</quota>" |
77 | " <allow_databases>" |
78 | " <database>default</database>" |
79 | " </allow_databases>" |
80 | " </default>" |
81 | " <web>" |
82 | " <password></password><profile>default</profile><quota>default</quota>" |
83 | " </web>" |
84 | " </users>" |
85 | " <quotas><default></default></quotas>" |
86 | "</yandex>" , |
87 | |
88 | { |
89 | { "default" , "default" , true }, |
90 | { "default" , "test" , false }, |
91 | { "default" , "stats" , false }, |
92 | { "web" , "default" , true }, |
93 | { "web" , "test" , true }, |
94 | { "web" , "stats" , true }, |
95 | { "analytics" , "default" , false }, |
96 | { "analytics" , "test" , false }, |
97 | { "analytics" , "stats" , false } |
98 | } |
99 | }, |
100 | |
101 | { |
102 | "<?xml version=\"1.0\"?><yandex>" |
103 | " <profiles><default></default></profiles>" |
104 | " <users>" |
105 | " <default>" |
106 | " <password></password><profile>default</profile><quota>default</quota>" |
107 | " <allow_databases>" |
108 | " </allow_databases>" |
109 | " </default>" |
110 | " <web>" |
111 | " <password></password><profile>default</profile><quota>default</quota>" |
112 | " </web>" |
113 | " </users>" |
114 | " <quotas><default></default></quotas>" |
115 | "</yandex>" , |
116 | |
117 | { |
118 | { "default" , "default" , true }, |
119 | { "default" , "test" , true }, |
120 | { "default" , "stats" , true }, |
121 | { "web" , "default" , true }, |
122 | { "web" , "test" , true }, |
123 | { "web" , "stats" , true }, |
124 | { "analytics" , "default" , false }, |
125 | { "analytics" , "test" , false }, |
126 | { "analytics" , "stats" , false } |
127 | } |
128 | }, |
129 | |
130 | { |
131 | "<?xml version=\"1.0\"?><yandex>" |
132 | " <profiles><default></default></profiles>" |
133 | " <users>" |
134 | " <default>" |
135 | " <password></password><profile>default</profile><quota>default</quota>" |
136 | " <allow_databases>" |
137 | " <database>default</database>" |
138 | " </allow_databases>" |
139 | " </default>" |
140 | " <web>" |
141 | " <password></password><profile>default</profile><quota>default</quota>" |
142 | " <allow_databases>" |
143 | " <database>test</database>" |
144 | " </allow_databases>" |
145 | " </web>" |
146 | " </users>" |
147 | " <quotas><default></default></quotas>" |
148 | "</yandex>" , |
149 | |
150 | { |
151 | { "default" , "default" , true }, |
152 | { "default" , "test" , false }, |
153 | { "default" , "stats" , false }, |
154 | { "web" , "default" , false }, |
155 | { "web" , "test" , true }, |
156 | { "web" , "stats" , false }, |
157 | { "analytics" , "default" , false }, |
158 | { "analytics" , "test" , false }, |
159 | { "analytics" , "stats" , false } |
160 | } |
161 | } |
162 | }; |
163 | |
164 | std::string createTmpPath(const std::string & filename) |
165 | { |
166 | char pattern[] = "/tmp/fileXXXXXX" ; |
167 | char * dir = mkdtemp(pattern); |
168 | if (dir == nullptr) |
169 | throw std::runtime_error("Could not create directory" ); |
170 | |
171 | return std::string(dir) + "/" + filename; |
172 | } |
173 | |
174 | void createFile(const std::string & filename, const char * data) |
175 | { |
176 | std::ofstream ofs(filename.c_str()); |
177 | if (!ofs.is_open()) |
178 | throw std::runtime_error("Could not open file " + filename); |
179 | ofs << data; |
180 | } |
181 | |
182 | void runOneTest(const TestDescriptor & test_descriptor) |
183 | { |
184 | const auto path_name = createTmpPath("users.xml" ); |
185 | createFile(path_name, test_descriptor.config_content); |
186 | |
187 | DB::ConfigurationPtr config; |
188 | |
189 | try |
190 | { |
191 | config = DB::ConfigProcessor(path_name).loadConfig().configuration; |
192 | } |
193 | catch (const Poco::Exception & ex) |
194 | { |
195 | std::ostringstream os; |
196 | os << "Error: " << ex.what() << ": " << ex.displayText(); |
197 | throw std::runtime_error(os.str()); |
198 | } |
199 | |
200 | DB::UsersManager users_manager; |
201 | |
202 | try |
203 | { |
204 | users_manager.loadFromConfig(*config); |
205 | } |
206 | catch (const Poco::Exception & ex) |
207 | { |
208 | std::ostringstream os; |
209 | os << "Error: " << ex.what() << ": " << ex.displayText(); |
210 | throw std::runtime_error(os.str()); |
211 | } |
212 | |
213 | for (const auto & entry : test_descriptor.entries) |
214 | { |
215 | bool res; |
216 | |
217 | try |
218 | { |
219 | res = users_manager.hasAccessToDatabase(entry.user_name, entry.database_name); |
220 | } |
221 | catch (const Poco::Exception &) |
222 | { |
223 | res = false; |
224 | } |
225 | |
226 | if (res != entry.is_allowed) |
227 | { |
228 | auto to_string = [](bool access){ return (access ? "'granted'" : "'denied'" ); }; |
229 | std::ostringstream os; |
230 | os << "(user=" << entry.user_name << ", database=" << entry.database_name << "): " ; |
231 | os << "Expected " << to_string(entry.is_allowed) << " but got " << to_string(res); |
232 | throw std::runtime_error(os.str()); |
233 | } |
234 | } |
235 | |
236 | fs::remove_all(fs::path(path_name).parent_path().string()); |
237 | } |
238 | |
239 | auto runTestSet() |
240 | { |
241 | size_t test_num = 1; |
242 | size_t failure_count = 0; |
243 | |
244 | for (const auto & test_descriptor : test_set) |
245 | { |
246 | try |
247 | { |
248 | runOneTest(test_descriptor); |
249 | std::cout << "Test " << test_num << " passed\n" ; |
250 | } |
251 | catch (const std::runtime_error & ex) |
252 | { |
253 | std::cerr << "Test " << test_num << " failed with reason: " << ex.what() << "\n" ; |
254 | ++failure_count; |
255 | } |
256 | catch (...) |
257 | { |
258 | std::cerr << "Test " << test_num << " failed with unknown reason\n" ; |
259 | ++failure_count; |
260 | } |
261 | |
262 | ++test_num; |
263 | } |
264 | |
265 | return std::make_tuple(test_set.size(), failure_count); |
266 | } |
267 | |
268 | } |
269 | |
270 | int main() |
271 | { |
272 | size_t test_count; |
273 | size_t failure_count; |
274 | |
275 | std::tie(test_count, failure_count) = runTestSet(); |
276 | |
277 | std::cout << (test_count - failure_count) << " test(s) passed out of " << test_count << "\n" ; |
278 | |
279 | return (failure_count == 0) ? 0 : EXIT_FAILURE; |
280 | } |
281 | |