src/server/plugins/postgresql/pgtest.c

changeset 385
a1f4cb076d2f
parent 374
77506ec632a4
child 403
0f678595d497
equal deleted inserted replaced
210:21274e5950af 385:a1f4cb076d2f
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2022 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <inttypes.h>
31
32 #include "../../util/util.h"
33 #include "../../test/testutils.h"
34 #include "../../test/webdav.h"
35 #include "../../public/nsapi.h"
36 #include "../../public/webdav.h"
37 #include "../../webdav/webdav.h"
38
39 #include <ucx/string.h>
40 #include <ucx/utils.h>
41 #include <ucx/buffer.h>
42
43 #include "pgtest.h"
44 #include "vfs.h"
45 #include "webdav.h"
46
47 #include <libpq-fe.h>
48
49 #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
50
51 static char *pg_connstr = "postgresql://localhost/test1";
52 static int abort_pg_tests = 0;
53 static PGconn *test_connection;
54 static ResourceData resdata;
55 static PgRepository test_repo;
56
57 void debug_print_resources(void) {
58 PGresult *result = PQexec(test_connection, "select * from Resource;");
59 int n = PQntuples(result);
60 printf("\nntuples: %d\n-----------------------------------------------\n", n);
61 printf("%10s %10s %s\n", "resource_id", "parent_id", "nodename");
62 for(int i=0;i<n;i++) {
63 char *res_id = PQgetvalue(result, i, 0);
64 char *parent_id = PQgetvalue(result, i, 1);
65 char *nodename = PQgetvalue(result, i, 2);
66 printf("%10s %10s %s\n", res_id, parent_id, nodename);
67 }
68 printf("\n");
69 }
70
71 static void test_root_lookup(void) {
72 memset(&test_repo, 0, sizeof(PgRepository));
73
74 int64_t root_id = -1;
75 int err = pg_lookup_root(&resdata, "root", &root_id);
76 test_repo.root_resource_id = root_id;
77
78 if(err || root_id < 0) {
79 abort_pg_tests = 1;
80 }
81 }
82
83 void register_pg_tests(int argc, char **argv, UcxTestSuite *suite) {
84
85 test_connection = PQconnectdb(pg_connstr);
86 if(!test_connection) {
87 abort_pg_tests = 1;
88 }
89
90 if(PQstatus(test_connection) != CONNECTION_OK) {
91 abort_pg_tests = 1;
92 }
93
94 resdata.data = test_connection;
95 test_root_lookup();
96
97 ucx_test_register(suite, test_pg_conn);
98 if(!abort_pg_tests) {
99 ucx_test_register(suite, test_pg_lookup_root);
100
101 ucx_test_register(suite, test_pg_vfs_open);
102 ucx_test_register(suite, test_pg_vfs_io);
103 ucx_test_register(suite, test_pg_vfs_stat);
104 ucx_test_register(suite, test_pg_vfs_mkdir);
105 ucx_test_register(suite, test_pg_vfs_unlink);
106 ucx_test_register(suite, test_pg_vfs_rmdir);
107
108 ucx_test_register(suite, test_pg_webdav_create_from_resdata);
109 ucx_test_register(suite, test_pg_prepare_tests);
110 ucx_test_register(suite, test_pg_webdav_propfind);
111 ucx_test_register(suite, test_pg_webdav_propfind_allprop);
112 ucx_test_register(suite, test_pg_webdav_proppatch_set);
113
114 PGresult *result = PQexec(test_connection, "BEGIN");
115 PQclear(result);
116 }
117 }
118
119 static void parse_response_tag(TestMultistatus *ms, xmlNode *node) {
120 // thanks to dav for some of this code
121 UcxAllocator *a = ms->mp->allocator;
122 node = node->children;
123
124 sstr_t href = {NULL, 0};
125 UcxMap *properties = ucx_map_new_a(ms->mp->allocator, 16);
126
127 while(node) {
128 if(node->type == XML_ELEMENT_NODE) {
129 if(xstreq(node->name, "href")) {
130 xmlNode *href_node = node->children;
131 if(href_node->type != XML_TEXT_NODE) {
132 return;
133 }
134 href = sstrdup_a(ms->mp->allocator, scstr((const char*)href_node->content));
135 } else if(xstreq(node->name, "propstat")) {
136 xmlNode *n = node->children;
137 xmlNode *prop_node = NULL;
138 int status_code = 0;
139 while(n) {
140 if(n->type == XML_ELEMENT_NODE) {
141 if(xstreq(n->name, "prop")) {
142 prop_node = n;
143 } else if(xstreq(n->name, "status")) {
144 xmlNode *status_node = n->children;
145 if(status_node->type != XML_TEXT_NODE) {
146 return;
147 }
148 sstr_t status_str = sstr((char*)status_node->content);
149 if(status_str.length < 13) {
150 return;
151 }
152 status_str = sstrsubsl(status_str, 9, 3);
153 sstr_t status_s = sstrdup(status_str);
154 status_code = atoi(status_s.ptr);
155 free(status_s.ptr);
156 }
157 }
158 n = n->next;
159 }
160
161 n = prop_node->children;
162 while(n) {
163 if(n->type == XML_ELEMENT_NODE) {
164 TestProperty *property = ucx_mempool_calloc(ms->mp, 1, sizeof(TestProperty));
165 if(n->ns) {
166 property->prefix = n->ns->prefix ? sstrdup_a(a, scstr((const char*)n->ns->prefix)).ptr : NULL;
167 property->namespace = n->ns->href ? sstrdup_a(a, scstr((const char*)n->ns->href)).ptr : NULL;
168 }
169 property->name = sstrdup_a(a, scstr((const char*)n->name)).ptr;
170 property->node = n;
171 property->status = status_code;
172 xmlNode *value = n->children;
173 if(value && value->type == XML_TEXT_NODE) {
174 property->value = sstrdup_a(a, scstr((const char*)value->content)).ptr;
175 }
176 sstr_t pname = sstrcat(2, sstr(property->namespace), sstr(property->name));
177 ucx_map_sstr_put(properties, pname, property);
178 free(pname.ptr);
179 }
180 n = n->next;
181 }
182 }
183 }
184 node = node->next;
185 }
186
187 TestResponse *resp =almalloc(a, sizeof(TestResponse));
188 resp->href = href.ptr;
189 resp->properties = properties;
190
191 ucx_map_sstr_put(ms->responses, href, resp);
192 }
193
194 TestMultistatus* test_parse_multistatus(const char *space, size_t size) {
195 xmlDoc *doc = xmlReadMemory(space, size, NULL, NULL, 0);
196 if(!doc) {
197 return NULL;
198 }
199
200 UcxMempool *mp = ucx_mempool_new(64);
201 TestMultistatus *ms = ucx_mempool_malloc(mp, sizeof(TestMultistatus));
202 ms->doc = doc;
203 ms->mp = mp;
204 ms->responses = ucx_map_new_a(mp->allocator, 8);
205
206 // parse response
207 xmlNode *xml_root = xmlDocGetRootElement(doc);
208 xmlNode *node = xml_root->children;
209 while(node) {
210 if(node->type == XML_ELEMENT_NODE) {
211 if(xstreq(node->name, "response")) {
212 parse_response_tag(ms, node);
213 }
214 }
215 node = node->next;
216 }
217
218 return ms;
219 }
220
221
222 void test_multistatus_destroy(TestMultistatus *ms) {
223 if(!ms) return;
224 xmlFreeDoc(ms->doc);
225 ucx_mempool_destroy(ms->mp);
226 }
227
228
229 UCX_TEST(test_pg_conn) {
230 char *msg = test_connection ? PQerrorMessage(test_connection) : "no connection";
231
232 UCX_TEST_BEGIN;
233
234 if(abort_pg_tests) {
235 int msglen = strlen(msg);
236 if(msglen > 0 && msg[msglen-1] == '\n') {
237 msglen--;
238 }
239 fprintf(stdout, "%.*s: ", msglen, msg);
240 UCX_TEST_ASSERT(1 == 0, "skip pg tests");
241 } else {
242 UCX_TEST_ASSERT(1 == 1, "ok");
243 }
244
245 UCX_TEST_END;
246 }
247
248 UCX_TEST(test_pg_lookup_root) {
249 UCX_TEST_BEGIN;
250
251 // test already done in test_root_lookup()
252 UCX_TEST_ASSERT(!abort_pg_tests, "Lookup failed");
253
254 UCX_TEST_END;
255 }
256
257
258 static VFS* create_test_pgvfs(Session *sn, Request *rq) {
259 return pg_vfs_create_from_resourcedata(sn, rq, &test_repo, &resdata);
260 }
261
262
263 UCX_TEST(test_pg_vfs_open) {
264 Session *sn = testutil_session();
265 Request *rq = testutil_request(sn->pool, "PUT", "/");
266 rq->vfs = create_test_pgvfs(sn, rq);
267 VFSContext *vfs = vfs_request_context(sn, rq);
268 SYS_FILE file;
269
270 UCX_TEST_BEGIN;
271
272 file = vfs_open(vfs, "/test_notfound1", O_RDONLY);
273 UCX_TEST_ASSERT(!file, "/test_notfound should not exist");
274
275 file = vfs_open(vfs, "/test_file1", O_RDWR | O_CREAT);
276 UCX_TEST_ASSERT(file, "cannot create file 1");
277
278 vfs_close(file);
279
280 UCX_TEST_END;
281
282 testutil_destroy_session(sn);
283 }
284
285 UCX_TEST(test_pg_vfs_io) {
286 Session *sn = testutil_session();
287 Request *rq = testutil_request(sn->pool, "PUT", "/");
288 rq->vfs = create_test_pgvfs(sn, rq);
289 VFSContext *vfs = vfs_request_context(sn, rq);
290 SYS_FILE file;
291 SYS_FILE file2;
292
293 UCX_TEST_BEGIN;
294
295 file = vfs_open(vfs, "/test_f1", O_WRONLY | O_CREAT);
296 UCX_TEST_ASSERT(file, "cannot open file1");
297
298 int w = system_fwrite(file, "test1\n", 6);
299 UCX_TEST_ASSERT(w == 6, "fwrite ret (1)");
300 w = system_fwrite(file, "2", 1);
301 UCX_TEST_ASSERT(w == 1, "fwrite ret (2)");
302
303 vfs_close(file);
304
305 file = vfs_open(vfs, "/test_f1", O_RDONLY);
306 file2 = vfs_open(vfs, "/test_f2", O_WRONLY | O_CREAT);
307 UCX_TEST_ASSERT(file, "cannot open file1");
308 UCX_TEST_ASSERT(file2, "cannot open file2");
309
310 char buf[128];
311 int r = system_fread(file, buf, 128);
312 UCX_TEST_ASSERT(r == 7, "cannot read from file1");
313
314 w = system_fwrite(file2, buf, r);
315 UCX_TEST_ASSERT(w == 7, "cannot write to file2");
316
317 vfs_close(file);
318 vfs_close(file2);
319
320 file2 = vfs_open(vfs, "/test_f2", O_RDONLY);
321
322 r = system_fread(file, buf, 128);
323 UCX_TEST_ASSERT(r == 7, "fread ret");
324 UCX_TEST_ASSERT(!memcmp(buf, "test1\n2", 7), "wrong buffer content after read");
325
326 vfs_close(file2);
327
328
329 UCX_TEST_END;
330
331 testutil_destroy_session(sn);
332 }
333
334 UCX_TEST(test_pg_vfs_stat) {
335 Session *sn = testutil_session();
336 Request *rq = testutil_request(sn->pool, "PUT", "/");
337 rq->vfs = create_test_pgvfs(sn, rq);
338 VFSContext *vfs = vfs_request_context(sn, rq);
339
340 UCX_TEST_BEGIN;
341
342 // testdata, content doesn't matter
343 char test1[512];
344 memset(test1, 'x', 512);
345 const int test_len1 = 200;
346 const int test_len2 = 432;
347
348 SYS_FILE f1 = vfs_open(vfs, "/test_s1", O_WRONLY|O_CREAT);
349 UCX_TEST_ASSERT(f1, "cannot open test_s1");
350 system_fwrite(f1, test1, test_len1);
351 vfs_close(f1);
352
353 SYS_FILE f2 = vfs_open(vfs, "/test_s2", O_RDWR|O_CREAT);
354 UCX_TEST_ASSERT(f2, "cannot open test_s2");
355 system_fwrite(f2, test1, test_len2);
356 vfs_close(f2);
357
358 struct stat st1, st2;
359 int r1 = vfs_stat(vfs, "/test_s1", &st1);
360 int r2 = vfs_stat(vfs, "/test_s2", &st2);
361
362 UCX_TEST_ASSERT(r1 == 0, "stat1 failed");
363 UCX_TEST_ASSERT(r2 == 0, "stat2 failed");
364
365 UCX_TEST_ASSERT(st1.st_size == test_len1, "s1 wrong length");
366 UCX_TEST_ASSERT(st2.st_size == test_len2, "s2 wrong length");
367
368 int testfail = vfs_stat(vfs, "/test_stat_fail", &st1);
369 UCX_TEST_ASSERT(testfail != 0, "stat 3 should fail");
370
371 UCX_TEST_END;
372
373 testutil_destroy_session(sn);
374 }
375
376 UCX_TEST(test_pg_vfs_mkdir) {
377 Session *sn = testutil_session();
378 Request *rq = testutil_request(sn->pool, "PUT", "/");
379 rq->vfs = create_test_pgvfs(sn, rq);
380 VFSContext *vfs = vfs_request_context(sn, rq);
381
382 UCX_TEST_BEGIN;
383
384 struct stat s;
385
386 SYS_FILE f1 = vfs_open(vfs, "/test_mkdir/file", O_WRONLY|O_CREAT);
387 UCX_TEST_ASSERT(f1 == NULL, "open should fail");
388
389 int r = vfs_mkdir(vfs, "/test_mkdir");
390 UCX_TEST_ASSERT(r == 0, "mkdir failed");
391
392 r = vfs_stat(vfs, "/test_mkdir", &s);
393 UCX_TEST_ASSERT(r == 0, "stat (1) failed");
394
395 UCX_TEST_ASSERT(S_ISDIR(s.st_mode), "/test_mkdir is not a directory");
396
397 f1 = vfs_open(vfs, "/test_mkdir/file", O_WRONLY|O_CREAT);
398 vfs_close(f1);
399 UCX_TEST_ASSERT(f1, "open failed");
400
401 r = vfs_stat(vfs, "/test_mkdir/file", &s);
402 UCX_TEST_ASSERT(r == 0, "stat (2) failed");
403
404 r = vfs_mkdir(vfs, "/test_mkdir/test_sub");
405 UCX_TEST_ASSERT(r == 0, "mkdir failed (2)");
406
407 r = vfs_stat(vfs, "/test_mkdir/test_sub", &s);
408 UCX_TEST_ASSERT(r == 0, "stat (3) failed");
409 UCX_TEST_ASSERT(S_ISDIR(s.st_mode), "/test_mkdir/test_sub is not a directory");
410
411 r = vfs_mkdir(vfs, "/test_mkdir/test_sub/test_sub2/");
412 UCX_TEST_ASSERT(r == 0, "mkdir failed (4)");
413
414 r = vfs_stat(vfs, "/test_mkdir/test_sub/test_sub2/", &s);
415 UCX_TEST_ASSERT(r == 0, "stat (4) failed");
416 UCX_TEST_ASSERT(S_ISDIR(s.st_mode), "/test_mkdir/test_sub/test_sub2/ is not a directory");
417
418 UCX_TEST_END;
419
420 testutil_destroy_session(sn);
421 }
422
423 UCX_TEST(test_pg_vfs_unlink) {
424 Session *sn = testutil_session();
425 Request *rq = testutil_request(sn->pool, "PUT", "/");
426 rq->vfs = create_test_pgvfs(sn, rq);
427 VFSContext *vfs = vfs_request_context(sn, rq);
428
429 UCX_TEST_BEGIN;
430
431 SYS_FILE f1 = vfs_open(vfs, "/test_unlink1", O_WRONLY|O_CREAT);
432 UCX_TEST_ASSERT(f1, "cannot create test file");
433 system_fwrite(f1, "test", 4);
434
435 PgFile *pgfile = f1->data;
436 Oid oid = pgfile->oid;
437
438 vfs_close(f1);
439
440 int r = vfs_unlink(vfs, "/test_unlink1");
441 UCX_TEST_ASSERT(r == 0, "unlink failed");
442
443 f1 = vfs_open(vfs, "/test_unlink1", O_RDONLY);
444 UCX_TEST_ASSERT(f1 == NULL, "test file not deleted");
445
446 PGresult *result = PQexec(test_connection, "savepoint sp;");
447 PQclear(result);
448 int pgfd = lo_open(test_connection, oid, INV_READ);
449 UCX_TEST_ASSERT(pgfd < 0, "large object not deleted");
450 result = PQexec(test_connection, "rollback to savepoint sp;");
451 PQclear(result);
452
453 r = vfs_unlink(vfs, "/test_unlink1");
454 UCX_TEST_ASSERT(r, "unlink should fail");
455
456 UCX_TEST_END;
457
458 testutil_destroy_session(sn);
459 }
460
461 UCX_TEST(test_pg_vfs_rmdir) {
462 Session *sn = testutil_session();
463 Request *rq = testutil_request(sn->pool, "PUT", "/");
464 rq->vfs = create_test_pgvfs(sn, rq);
465 VFSContext *vfs = vfs_request_context(sn, rq);
466
467 PQexec(test_connection, "delete from Resource where parent_id is not null;");
468
469 UCX_TEST_BEGIN;
470
471 int r;
472 SYS_FILE f1;
473
474 // prepare some dirs/files
475 r = vfs_mkdir(vfs, "/rmdir_test");
476 UCX_TEST_ASSERT(r == 0, "mkdir failed (1)");
477 r = vfs_mkdir(vfs, "/rmdir_test/subdir1");
478 UCX_TEST_ASSERT(r == 0, "mkdir failed (2)");
479 r = vfs_mkdir(vfs, "/rmdir_test/subdir2");
480 UCX_TEST_ASSERT(r == 0, "mkdir failed (3)");
481
482 f1 = vfs_open(vfs, "/rmdir_test/subdir2/file", O_CREAT|O_WRONLY);
483 UCX_TEST_ASSERT(f1, "open failed");
484 vfs_close(f1);
485
486 // test rmdir
487 r = vfs_rmdir(vfs, "/rmdir_test/subdir1");
488 UCX_TEST_ASSERT(r == 0, "rmdir failed");;
489
490 r = vfs_rmdir(vfs, "/rmdir_test/subdir2");
491 UCX_TEST_ASSERT(r != 0, "rmdir should fail if the dir is not empty");
492
493 r = vfs_unlink(vfs, "/rmdir_test/subdir2/file");
494 UCX_TEST_ASSERT(r == 0, "unlink failed");
495
496 r = vfs_rmdir(vfs, "/rmdir_test/subdir2");
497 UCX_TEST_ASSERT(r == 0, "rmdir failed 2");
498
499 UCX_TEST_END;
500
501 testutil_destroy_session(sn);
502 }
503
504 /* ----------------------------- WebDAV tests ----------------------------- */
505
506
507 static WebdavBackend* create_test_pgdav(Session *sn, Request *rq) {
508 return pg_webdav_create_from_resdata(sn, rq, &test_repo, &resdata);
509 }
510
511 UCX_TEST(test_pg_webdav_create_from_resdata) {
512 Session *sn = testutil_session();
513 Request *rq = testutil_request(sn->pool, "PROPFIND", "/");
514
515 UCX_TEST_BEGIN;
516
517 WebdavBackend *dav = create_test_pgdav(sn, rq);
518 UCX_TEST_ASSERT(dav, "cannot create pg dav backend");
519
520 UCX_TEST_END;
521 }
522
523 UCX_TEST(test_pg_prepare_tests) {
524 Session *sn = testutil_session();
525 Request *rq = testutil_request(sn->pool, "PUT", "/");
526 rq->vfs = create_test_pgvfs(sn, rq);
527 VFSContext *vfs = vfs_request_context(sn, rq);
528
529 UCX_TEST_BEGIN;
530
531 vfs_mkdir(vfs, "/propfind");
532 vfs_mkdir(vfs, "/proppatch");
533 SYS_FILE f1;
534
535 int64_t res1_id, res2_id;
536
537 f1 = vfs_open(vfs, "/propfind/res1", O_WRONLY|O_CREAT);
538 UCX_TEST_ASSERT(f1, "res1 create failed");
539 res1_id = ((PgFile*)f1->data)->resource_id;
540 vfs_close(f1);
541
542 f1 = vfs_open(vfs, "/propfind/res2", O_WRONLY|O_CREAT);
543 UCX_TEST_ASSERT(f1, "res2 create failed");
544 res2_id = ((PgFile*)f1->data)->resource_id;
545 vfs_close(f1);
546
547 f1 = vfs_open(vfs, "/propfind/res3", O_WRONLY|O_CREAT);
548 UCX_TEST_ASSERT(f1, "res3 create failed");
549 vfs_close(f1);
550
551 int r = vfs_mkdir(vfs, "/propfind/sub");
552 UCX_TEST_ASSERT(r == 0, "sub create failed");
553
554 f1 = vfs_open(vfs, "/propfind/sub/res4", O_WRONLY|O_CREAT);
555 UCX_TEST_ASSERT(f1, "res4 create failed");
556 vfs_close(f1);
557
558 f1 = vfs_open(vfs, "/proppatch/pp1", O_WRONLY|O_CREAT);
559 UCX_TEST_ASSERT(f1, "pp1 create failed");
560 vfs_close(f1);
561
562 // 2 properties for res1
563 char idstr[32];
564 snprintf(idstr, 32, "%" PRId64, res1_id);
565 const char* params[1] = { idstr };
566 PGresult *result = PQexecParams(
567 test_connection,
568 "insert into Property(resource_id, prefix, xmlns, pname, pvalue) values ($1, 'x', 'http://example.com/', 'test', 'testvalue');",
569 1, // number of parameters
570 NULL,
571 params, // parameter value
572 NULL,
573 NULL,
574 0); // 0: result in text format
575
576 UCX_TEST_ASSERT(PQresultStatus(result) == PGRES_COMMAND_OK, "cannot create property 1");
577 PQclear(result);
578
579 result = PQexecParams(
580 test_connection,
581 "insert into Property(resource_id, prefix, xmlns, pname, pvalue) values ($1, 'x', 'http://example.com/', 'prop2', 'value2');",
582 1, // number of parameters
583 NULL,
584 params, // parameter value
585 NULL,
586 NULL,
587 0); // 0: result in text format
588
589 UCX_TEST_ASSERT(PQresultStatus(result) == PGRES_COMMAND_OK, "cannot create property 1");
590 PQclear(result);
591
592 // 1 property for res2
593 snprintf(idstr, 32, "%" PRId64, res2_id);
594 result = PQexecParams(
595 test_connection,
596 "insert into Property(resource_id, prefix, xmlns, pname, pvalue) values ($1, 'x', 'http://example.com/', 'test', 'res2test');",
597 1, // number of parameters
598 NULL,
599 params, // parameter value
600 NULL,
601 NULL,
602 0); // 0: result in text format
603
604 UCX_TEST_ASSERT(PQresultStatus(result) == PGRES_COMMAND_OK, "cannot create property 1");
605 PQclear(result);
606
607 UCX_TEST_END;
608
609 testutil_destroy_session(sn);
610 }
611
612 UCX_TEST(test_pg_webdav_propfind) {
613 Session *sn;
614 Request *rq;
615 TestIOStream *st;
616 pblock *pb;
617
618 UCX_TEST_BEGIN;
619
620 // test data:
621 //
622 // /propfind/
623 // /propfind/res1 (2 properties: test, prop2)
624 // /propfind/res2 (1 property: test)
625 // /propfind/res3
626 // /propfind/sub
627 // /propfind/sub/res4
628
629 int ret;
630 // Test 1
631 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind/", PG_TEST_PROPFIND1);
632 rq->davCollection = create_test_pgdav(sn, rq);
633 pblock_nvinsert("depth", "0", rq->headers);
634
635 ret = webdav_propfind(pb, sn, rq);
636
637 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (1) failed");
638
639 TestMultistatus *ms = test_parse_multistatus(st->buf->space, st->buf->size);
640 UCX_TEST_ASSERT(ms, "propfind1: response is not valid xml");
641
642 TestResponse *r1 = ucx_map_cstr_get(ms->responses, "/propfind/");
643 UCX_TEST_ASSERT(r1, "propfind1: missing /propfind/ response");
644
645 UCX_TEST_ASSERT(ms->responses->count == 1, "propfind1: wrong response count");
646
647 TestProperty *p = ucx_map_cstr_get(r1->properties, "DAV:resourcetype");
648 UCX_TEST_ASSERT(p, "propfind1: missing property 'resourcetype'");
649 UCX_TEST_ASSERT(p->status == 200, "propfind1: wrong status code for property 'resourcetype'");
650
651 p = ucx_map_cstr_get(r1->properties, "DAV:getlastmodified");
652 UCX_TEST_ASSERT(p, "propfind1: missing property 'getlastmodified'");
653 UCX_TEST_ASSERT(p->status == 200, "propfind1: wrong status code for property 'getlastmodified'");
654
655 testutil_destroy_session(sn);
656 test_multistatus_destroy(ms);
657 testutil_iostream_destroy(st);
658
659
660 // Test 2
661 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind/", PG_TEST_PROPFIND2);
662 rq->davCollection = create_test_pgdav(sn, rq);
663 pblock_nvinsert("depth", "1", rq->headers);
664
665 ret = webdav_propfind(pb, sn, rq);
666
667 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
668
669 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (2) failed");
670
671 ms = test_parse_multistatus(st->buf->space, st->buf->size);
672 UCX_TEST_ASSERT(ms, "propfind2: response is not valid xml");
673
674 r1 = ucx_map_cstr_get(ms->responses, "/propfind/");
675 UCX_TEST_ASSERT(r1, "propfind2: missing /propfind/ response");
676
677 UCX_TEST_ASSERT(ms->responses->count == 5, "propfind2: wrong response count");
678
679 r1 = ucx_map_cstr_get(ms->responses, "/propfind/res2");
680 UCX_TEST_ASSERT(r1, "propfind2: missing /propfind/res2 response");
681
682 p = ucx_map_cstr_get(r1->properties, "http://example.com/test");
683 UCX_TEST_ASSERT(p, "propfind2: missing property 'test'");
684 UCX_TEST_ASSERT(p->status == 200, "propfind2: wrong status code for property 'test'");
685 UCX_TEST_ASSERT(!strcmp(p->value, "res2test"), "propfind2: wrong property value");
686
687
688 testutil_destroy_session(sn);
689 test_multistatus_destroy(ms);
690 testutil_iostream_destroy(st);
691
692
693
694 // Test 3
695 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind/", PG_TEST_PROPFIND2);
696 rq->davCollection = create_test_pgdav(sn, rq);
697 pblock_nvinsert("depth", "infinity", rq->headers);
698
699 ret = webdav_propfind(pb, sn, rq);
700
701 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
702
703 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (3) failed");
704
705 ms = test_parse_multistatus(st->buf->space, st->buf->size);
706 UCX_TEST_ASSERT(ms, "propfind3: response is not valid xml");
707
708 r1 = ucx_map_cstr_get(ms->responses, "/propfind/");
709 UCX_TEST_ASSERT(r1, "propfind3: missing /propfind/ response");
710
711 UCX_TEST_ASSERT(ms->responses->count == 6, "propfind3: wrong response count");
712
713
714 r1 = ucx_map_cstr_get(ms->responses, "/propfind/res1");
715 UCX_TEST_ASSERT(r1, "propfind3: missing /propfind/sub/res1 response");
716
717 p = ucx_map_cstr_get(r1->properties, "http://example.com/test");
718 UCX_TEST_ASSERT(p, "propfind3: missing property 'test'");
719 UCX_TEST_ASSERT(p->status == 200, "propfind3: wrong status code for property 'test'");
720 UCX_TEST_ASSERT(!strcmp(p->value, "testvalue"), "propfind3: wrong property value");
721
722 p = ucx_map_cstr_get(r1->properties, "http://example.com/prop2");
723 UCX_TEST_ASSERT(p, "propfind3: missing property 'prop2'");
724 UCX_TEST_ASSERT(p->status == 200, "propfind3: wrong status code for property 'prop2'");
725 UCX_TEST_ASSERT(!strcmp(p->value, "value2"), "propfind3: wrong property value");
726
727
728 r1 = ucx_map_cstr_get(ms->responses, "/propfind/sub/res4");
729 UCX_TEST_ASSERT(r1, "propfind3: missing /propfind/sub/res4 response");
730
731 testutil_destroy_session(sn);
732 test_multistatus_destroy(ms);
733 testutil_iostream_destroy(st);
734
735 UCX_TEST_END;
736 }
737
738
739 UCX_TEST(test_pg_webdav_propfind_allprop) {
740 Session *sn;
741 Request *rq;
742 TestIOStream *st;
743 pblock *pb;
744
745 UCX_TEST_BEGIN;
746
747 // test data:
748 //
749 // /propfind/
750 // /propfind/res1 (2 properties: test, prop2)
751 // /propfind/res2 (1 property: test)
752 // /propfind/res3
753 // /propfind/sub
754 // /propfind/sub/res4
755
756 int ret;
757 TestResponse *r1;
758 TestProperty *p;
759 // Test 1
760 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind/", PG_TEST_ALLPROP);
761 rq->davCollection = create_test_pgdav(sn, rq);
762 pblock_nvinsert("depth", "0", rq->headers);
763
764 ret = webdav_propfind(pb, sn, rq);
765
766 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (1) failed");
767
768 TestMultistatus *ms = test_parse_multistatus(st->buf->space, st->buf->size);
769 UCX_TEST_ASSERT(ms, "propfind1: response is not valid xml");
770
771 r1 = ucx_map_cstr_get(ms->responses, "/propfind/");
772 UCX_TEST_ASSERT(r1, "propfind1: missing /propfind/ response");
773 UCX_TEST_ASSERT(ms->responses->count == 1, "propfind1: wrong response count");
774
775 p = ucx_map_cstr_get(r1->properties, "DAV:resourcetype");
776 UCX_TEST_ASSERT(r1, "propfind1: missing resourcetype property");
777
778 testutil_destroy_session(sn);
779 test_multistatus_destroy(ms);
780 testutil_iostream_destroy(st);
781
782 // Test 2
783 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind/", PG_TEST_ALLPROP);
784 rq->davCollection = create_test_pgdav(sn, rq);
785 pblock_nvinsert("depth", "1", rq->headers);
786
787 ret = webdav_propfind(pb, sn, rq);
788
789 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
790
791 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (2) failed");
792
793 ms = test_parse_multistatus(st->buf->space, st->buf->size);
794 UCX_TEST_ASSERT(ms, "propfind2: response is not valid xml");
795
796 r1 = ucx_map_cstr_get(ms->responses, "/propfind/");
797 UCX_TEST_ASSERT(r1, "propfind2: missing /propfind/ response");
798 UCX_TEST_ASSERT(ms->responses->count == 5, "propfind2: wrong response count");
799
800 r1 = ucx_map_cstr_get(ms->responses, "/propfind/res1");
801 UCX_TEST_ASSERT(r1, "propfind2: missing /propfind/res1 response");
802
803 p = ucx_map_cstr_get(r1->properties, "DAV:resourcetype");
804 UCX_TEST_ASSERT(r1, "propfind2: missing resourcetype property");
805 p = ucx_map_cstr_get(r1->properties, "http://example.com/test");
806 UCX_TEST_ASSERT(r1, "propfind2: missing test property");
807 p = ucx_map_cstr_get(r1->properties, "http://example.com/prop2");
808 UCX_TEST_ASSERT(r1, "propfind2: missing prop2 property");
809
810 UCX_TEST_ASSERT(ucx_map_cstr_get(ms->responses, "/propfind/res2"), "propfind2: missing /propfind/res2 response");
811 UCX_TEST_ASSERT(ucx_map_cstr_get(ms->responses, "/propfind/res3"), "propfind2: missing /propfind/res3 response");
812 UCX_TEST_ASSERT(ucx_map_cstr_get(ms->responses, "/propfind/sub/"), "propfind2: missing /propfind/sub response");
813
814 testutil_destroy_session(sn);
815 test_multistatus_destroy(ms);
816 testutil_iostream_destroy(st);
817
818 // Test 3
819 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPFIND", "/propfind/", PG_TEST_ALLPROP);
820 rq->davCollection = create_test_pgdav(sn, rq);
821 pblock_nvinsert("depth", "infinity", rq->headers);
822
823 ret = webdav_propfind(pb, sn, rq);
824
825 UCX_TEST_ASSERT(ret == REQ_PROCEED, "webdav_propfind (2) failed");
826
827 ms = test_parse_multistatus(st->buf->space, st->buf->size);
828 UCX_TEST_ASSERT(ms, "propfind3: response is not valid xml");
829
830 r1 = ucx_map_cstr_get(ms->responses, "/propfind/");
831 UCX_TEST_ASSERT(r1, "propfind3: missing /propfind/ response");
832 UCX_TEST_ASSERT(ms->responses->count == 6, "propfind3: wrong response count");
833
834 r1 = ucx_map_cstr_get(ms->responses, "/propfind/res1");
835 UCX_TEST_ASSERT(r1, "propfind3: missing /propfind/res1 response");
836
837 p = ucx_map_cstr_get(r1->properties, "DAV:resourcetype");
838 UCX_TEST_ASSERT(r1, "propfind3: missing resourcetype property");
839 p = ucx_map_cstr_get(r1->properties, "http://example.com/test");
840 UCX_TEST_ASSERT(r1, "propfind3: missing test property");
841 p = ucx_map_cstr_get(r1->properties, "http://example.com/prop2");
842 UCX_TEST_ASSERT(r1, "propfind3: missing prop2 property");
843
844 UCX_TEST_ASSERT(ucx_map_cstr_get(ms->responses, "/propfind/res2"), "propfind3: missing /propfind/res2 response");
845 UCX_TEST_ASSERT(ucx_map_cstr_get(ms->responses, "/propfind/res3"), "propfind3: missing /propfind/res3 response");
846 UCX_TEST_ASSERT(ucx_map_cstr_get(ms->responses, "/propfind/sub/"), "propfind3: missing /propfind/sub response");
847 UCX_TEST_ASSERT(ucx_map_cstr_get(ms->responses, "/propfind/sub/res4"), "propfind3: missing /propfind/sub/res4 response");
848
849 testutil_destroy_session(sn);
850 test_multistatus_destroy(ms);
851 testutil_iostream_destroy(st);
852
853
854 UCX_TEST_END;
855 }
856
857 UCX_TEST(test_pg_webdav_proppatch_set) {
858 Session *sn;
859 Request *rq;
860 TestIOStream *st;
861 pblock *pb;
862
863 UCX_TEST_BEGIN;
864
865 // test data:
866 //
867 // /propfind/
868 // /propfind/res1 (2 properties: test, prop2)
869 // /propfind/res2 (1 property: test)
870 // /propfind/res3
871 // /propfind/sub
872 // /propfind/sub/res4
873
874 int ret;
875 TestResponse *r1;
876 TestProperty *p;
877 // Test 1
878 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPPATCH", "/proppatch/pp1", PG_TEST_PROPPATCH1);
879 rq->davCollection = create_test_pgdav(sn, rq);
880
881 ret = webdav_proppatch(pb, sn, rq);
882 UCX_TEST_ASSERT(ret == REQ_PROCEED, "proppatch1 failed");
883
884 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
885
886 TestMultistatus *ms = test_parse_multistatus(st->buf->space, st->buf->size);
887 UCX_TEST_ASSERT(ms, "proppatch1 response is not valid xml");
888
889 testutil_destroy_session(sn);
890 test_multistatus_destroy(ms);
891 testutil_iostream_destroy(st);
892
893 // Test 2: xml property value
894 init_test_webdav_method(&sn, &rq, &st, &pb, "PROPPATCH", "/proppatch/pp1", PG_TEST_PROPPATCH2);
895 rq->davCollection = create_test_pgdav(sn, rq);
896
897 ret = webdav_proppatch(pb, sn, rq);
898 UCX_TEST_ASSERT(ret == REQ_PROCEED, "proppatch2 failed");
899
900 //printf("\n\n%.*s\n", (int)st->buf->size, st->buf->space);
901
902 ms = test_parse_multistatus(st->buf->space, st->buf->size);
903 UCX_TEST_ASSERT(ms, "proppatch2 response is not valid xml");
904
905 testutil_destroy_session(sn);
906 test_multistatus_destroy(ms);
907 testutil_iostream_destroy(st);
908
909
910 UCX_TEST_END;
911 }

mercurial