testbuckets.c revision 251876
1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "abts.h" 18#include "testutil.h" 19#include "apr_buckets.h" 20#include "apr_strings.h" 21 22static void test_create(abts_case *tc, void *data) 23{ 24 apr_bucket_alloc_t *ba; 25 apr_bucket_brigade *bb; 26 27 ba = apr_bucket_alloc_create(p); 28 bb = apr_brigade_create(p, ba); 29 30 ABTS_ASSERT(tc, "new brigade not NULL", bb != NULL); 31 ABTS_ASSERT(tc, "new brigade is empty", APR_BRIGADE_EMPTY(bb)); 32 33 apr_brigade_destroy(bb); 34 apr_bucket_alloc_destroy(ba); 35} 36 37static void test_simple(abts_case *tc, void *data) 38{ 39 apr_bucket_alloc_t *ba; 40 apr_bucket_brigade *bb; 41 apr_bucket *fb, *tb; 42 43 ba = apr_bucket_alloc_create(p); 44 bb = apr_brigade_create(p, ba); 45 46 fb = APR_BRIGADE_FIRST(bb); 47 ABTS_ASSERT(tc, "first bucket of empty brigade is sentinel", 48 fb == APR_BRIGADE_SENTINEL(bb)); 49 50 fb = apr_bucket_flush_create(ba); 51 APR_BRIGADE_INSERT_HEAD(bb, fb); 52 53 ABTS_ASSERT(tc, "first bucket of brigade is flush", 54 APR_BRIGADE_FIRST(bb) == fb); 55 56 ABTS_ASSERT(tc, "bucket after flush is sentinel", 57 APR_BUCKET_NEXT(fb) == APR_BRIGADE_SENTINEL(bb)); 58 59 tb = apr_bucket_transient_create("aaa", 3, ba); 60 APR_BUCKET_INSERT_BEFORE(fb, tb); 61 62 ABTS_ASSERT(tc, "bucket before flush now transient", 63 APR_BUCKET_PREV(fb) == tb); 64 ABTS_ASSERT(tc, "bucket after transient is flush", 65 APR_BUCKET_NEXT(tb) == fb); 66 ABTS_ASSERT(tc, "bucket before transient is sentinel", 67 APR_BUCKET_PREV(tb) == APR_BRIGADE_SENTINEL(bb)); 68 69 apr_brigade_cleanup(bb); 70 71 ABTS_ASSERT(tc, "cleaned up brigade was empty", APR_BRIGADE_EMPTY(bb)); 72 73 apr_brigade_destroy(bb); 74 apr_bucket_alloc_destroy(ba); 75} 76 77static apr_bucket_brigade *make_simple_brigade(apr_bucket_alloc_t *ba, 78 const char *first, 79 const char *second) 80{ 81 apr_bucket_brigade *bb = apr_brigade_create(p, ba); 82 apr_bucket *e; 83 84 e = apr_bucket_transient_create(first, strlen(first), ba); 85 APR_BRIGADE_INSERT_TAIL(bb, e); 86 87 e = apr_bucket_transient_create(second, strlen(second), ba); 88 APR_BRIGADE_INSERT_TAIL(bb, e); 89 90 return bb; 91} 92 93/* tests that 'bb' flattens to string 'expect'. */ 94static void flatten_match(abts_case *tc, const char *ctx, 95 apr_bucket_brigade *bb, 96 const char *expect) 97{ 98 apr_size_t elen = strlen(expect); 99 char *buf = malloc(elen); 100 apr_size_t len = elen; 101 char msg[200]; 102 103 sprintf(msg, "%s: flatten brigade", ctx); 104 apr_assert_success(tc, msg, apr_brigade_flatten(bb, buf, &len)); 105 sprintf(msg, "%s: length match (%ld not %ld)", ctx, 106 (long)len, (long)elen); 107 ABTS_ASSERT(tc, msg, len == elen); 108 sprintf(msg, "%s: result match", msg); 109 ABTS_STR_NEQUAL(tc, expect, buf, len); 110 free(buf); 111} 112 113static void test_flatten(abts_case *tc, void *data) 114{ 115 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 116 apr_bucket_brigade *bb; 117 118 bb = make_simple_brigade(ba, "hello, ", "world"); 119 120 flatten_match(tc, "flatten brigade", bb, "hello, world"); 121 122 apr_brigade_destroy(bb); 123 apr_bucket_alloc_destroy(ba); 124} 125 126static int count_buckets(apr_bucket_brigade *bb) 127{ 128 apr_bucket *e; 129 int count = 0; 130 131 for (e = APR_BRIGADE_FIRST(bb); 132 e != APR_BRIGADE_SENTINEL(bb); 133 e = APR_BUCKET_NEXT(e)) { 134 count++; 135 } 136 137 return count; 138} 139 140static void test_split(abts_case *tc, void *data) 141{ 142 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 143 apr_bucket_brigade *bb, *bb2; 144 apr_bucket *e; 145 146 bb = make_simple_brigade(ba, "hello, ", "world"); 147 148 /* split at the "world" bucket */ 149 e = APR_BRIGADE_LAST(bb); 150 bb2 = apr_brigade_split(bb, e); 151 152 ABTS_ASSERT(tc, "split brigade contains one bucket", 153 count_buckets(bb2) == 1); 154 ABTS_ASSERT(tc, "original brigade contains one bucket", 155 count_buckets(bb) == 1); 156 157 flatten_match(tc, "match original brigade", bb, "hello, "); 158 flatten_match(tc, "match split brigade", bb2, "world"); 159 160 apr_brigade_destroy(bb2); 161 apr_brigade_destroy(bb); 162 apr_bucket_alloc_destroy(ba); 163} 164 165#define COUNT 3000 166#define THESTR "hello" 167 168static void test_bwrite(abts_case *tc, void *data) 169{ 170 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 171 apr_bucket_brigade *bb = apr_brigade_create(p, ba); 172 apr_off_t length; 173 int n; 174 175 for (n = 0; n < COUNT; n++) { 176 apr_assert_success(tc, "brigade_write", 177 apr_brigade_write(bb, NULL, NULL, 178 THESTR, sizeof THESTR)); 179 } 180 181 apr_assert_success(tc, "determine brigade length", 182 apr_brigade_length(bb, 1, &length)); 183 184 ABTS_ASSERT(tc, "brigade has correct length", 185 length == (COUNT * sizeof THESTR)); 186 187 apr_brigade_destroy(bb); 188 apr_bucket_alloc_destroy(ba); 189} 190 191static void test_splitline(abts_case *tc, void *data) 192{ 193 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 194 apr_bucket_brigade *bin, *bout; 195 196 bin = make_simple_brigade(ba, "blah blah blah-", 197 "end of line.\nfoo foo foo"); 198 bout = apr_brigade_create(p, ba); 199 200 apr_assert_success(tc, "split line", 201 apr_brigade_split_line(bout, bin, 202 APR_BLOCK_READ, 100)); 203 204 flatten_match(tc, "split line", bout, "blah blah blah-end of line.\n"); 205 flatten_match(tc, "remainder", bin, "foo foo foo"); 206 207 apr_brigade_destroy(bout); 208 apr_brigade_destroy(bin); 209 apr_bucket_alloc_destroy(ba); 210} 211 212/* Test that bucket E has content EDATA of length ELEN. */ 213static void test_bucket_content(abts_case *tc, 214 apr_bucket *e, 215 const char *edata, 216 apr_size_t elen) 217{ 218 const char *adata; 219 apr_size_t alen; 220 221 apr_assert_success(tc, "read from bucket", 222 apr_bucket_read(e, &adata, &alen, 223 APR_BLOCK_READ)); 224 225 ABTS_ASSERT(tc, "read expected length", alen == elen); 226 ABTS_STR_NEQUAL(tc, edata, adata, elen); 227} 228 229static void test_splits(abts_case *tc, void *ctx) 230{ 231 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 232 apr_bucket_brigade *bb; 233 apr_bucket *e; 234 char *str = "alphabeta"; 235 int n; 236 237 bb = apr_brigade_create(p, ba); 238 239 APR_BRIGADE_INSERT_TAIL(bb, 240 apr_bucket_immortal_create(str, 9, ba)); 241 APR_BRIGADE_INSERT_TAIL(bb, 242 apr_bucket_transient_create(str, 9, ba)); 243 APR_BRIGADE_INSERT_TAIL(bb, 244 apr_bucket_heap_create(strdup(str), 9, free, ba)); 245 APR_BRIGADE_INSERT_TAIL(bb, 246 apr_bucket_pool_create(apr_pstrdup(p, str), 9, p, 247 ba)); 248 249 ABTS_ASSERT(tc, "four buckets inserted", count_buckets(bb) == 4); 250 251 /* now split each of the buckets after byte 5 */ 252 for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { 253 ABTS_ASSERT(tc, "reached end of brigade", 254 e != APR_BRIGADE_SENTINEL(bb)); 255 ABTS_ASSERT(tc, "split bucket OK", 256 apr_bucket_split(e, 5) == APR_SUCCESS); 257 e = APR_BUCKET_NEXT(e); 258 ABTS_ASSERT(tc, "split OK", e != APR_BRIGADE_SENTINEL(bb)); 259 e = APR_BUCKET_NEXT(e); 260 } 261 262 ABTS_ASSERT(tc, "four buckets split into eight", 263 count_buckets(bb) == 8); 264 265 for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { 266 const char *data; 267 apr_size_t len; 268 269 apr_assert_success(tc, "read alpha from bucket", 270 apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); 271 ABTS_ASSERT(tc, "read 5 bytes", len == 5); 272 ABTS_STR_NEQUAL(tc, "alpha", data, 5); 273 274 e = APR_BUCKET_NEXT(e); 275 276 apr_assert_success(tc, "read beta from bucket", 277 apr_bucket_read(e, &data, &len, APR_BLOCK_READ)); 278 ABTS_ASSERT(tc, "read 4 bytes", len == 4); 279 ABTS_STR_NEQUAL(tc, "beta", data, 5); 280 281 e = APR_BUCKET_NEXT(e); 282 } 283 284 /* now delete the "alpha" buckets */ 285 for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) { 286 apr_bucket *f; 287 288 ABTS_ASSERT(tc, "reached end of brigade", 289 e != APR_BRIGADE_SENTINEL(bb)); 290 f = APR_BUCKET_NEXT(e); 291 apr_bucket_delete(e); 292 e = APR_BUCKET_NEXT(f); 293 } 294 295 ABTS_ASSERT(tc, "eight buckets reduced to four", 296 count_buckets(bb) == 4); 297 298 flatten_match(tc, "flatten beta brigade", bb, 299 "beta" "beta" "beta" "beta"); 300 301 apr_brigade_destroy(bb); 302 apr_bucket_alloc_destroy(ba); 303} 304 305#define TIF_FNAME "testfile.txt" 306 307static void test_insertfile(abts_case *tc, void *ctx) 308{ 309 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 310 apr_bucket_brigade *bb; 311 const apr_off_t bignum = (APR_INT64_C(2) << 32) + 424242; 312 apr_off_t count; 313 apr_file_t *f; 314 apr_bucket *e; 315 316 ABTS_ASSERT(tc, "open test file", 317 apr_file_open(&f, TIF_FNAME, 318 APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE 319 | APR_FOPEN_CREATE | APR_FOPEN_SPARSE, 320 APR_OS_DEFAULT, p) == APR_SUCCESS); 321 322 if (apr_file_trunc(f, bignum)) { 323 apr_file_close(f); 324 apr_file_remove(TIF_FNAME, p); 325 ABTS_NOT_IMPL(tc, "Skipped: could not create large file"); 326 return; 327 } 328 329 bb = apr_brigade_create(p, ba); 330 331 e = apr_brigade_insert_file(bb, f, 0, bignum, p); 332 333 ABTS_ASSERT(tc, "inserted file was not at end of brigade", 334 e == APR_BRIGADE_LAST(bb)); 335 336 /* check that the total size of inserted buckets is equal to the 337 * total size of the file. */ 338 count = 0; 339 340 for (e = APR_BRIGADE_FIRST(bb); 341 e != APR_BRIGADE_SENTINEL(bb); 342 e = APR_BUCKET_NEXT(e)) { 343 ABTS_ASSERT(tc, "bucket size sane", e->length != (apr_size_t)-1); 344 count += e->length; 345 } 346 347 ABTS_ASSERT(tc, "total size of buckets incorrect", count == bignum); 348 349 apr_brigade_destroy(bb); 350 351 /* Truncate the file to zero size before close() so that we don't 352 * actually write out the large file if we are on a non-sparse file 353 * system - like Mac OS X's HFS. Otherwise, pity the poor user who 354 * has to wait for the 8GB file to be written to disk. 355 */ 356 apr_file_trunc(f, 0); 357 358 apr_file_close(f); 359 apr_bucket_alloc_destroy(ba); 360 apr_file_remove(TIF_FNAME, p); 361} 362 363/* Make a test file named FNAME, and write CONTENTS to it. */ 364static apr_file_t *make_test_file(abts_case *tc, const char *fname, 365 const char *contents) 366{ 367 apr_file_t *f; 368 369 ABTS_ASSERT(tc, "create test file", 370 apr_file_open(&f, fname, 371 APR_FOPEN_READ|APR_FOPEN_WRITE|APR_FOPEN_TRUNCATE|APR_FOPEN_CREATE, 372 APR_OS_DEFAULT, p) == APR_SUCCESS); 373 374 ABTS_ASSERT(tc, "write test file contents", 375 apr_file_puts(contents, f) == APR_SUCCESS); 376 377 return f; 378} 379 380static void test_manyfile(abts_case *tc, void *data) 381{ 382 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 383 apr_bucket_brigade *bb = apr_brigade_create(p, ba); 384 apr_file_t *f; 385 386 f = make_test_file(tc, "manyfile.bin", 387 "world" "hello" "brave" " ,\n"); 388 389 apr_brigade_insert_file(bb, f, 5, 5, p); 390 apr_brigade_insert_file(bb, f, 16, 1, p); 391 apr_brigade_insert_file(bb, f, 15, 1, p); 392 apr_brigade_insert_file(bb, f, 10, 5, p); 393 apr_brigade_insert_file(bb, f, 15, 1, p); 394 apr_brigade_insert_file(bb, f, 0, 5, p); 395 apr_brigade_insert_file(bb, f, 17, 1, p); 396 397 /* can you tell what it is yet? */ 398 flatten_match(tc, "file seek test", bb, 399 "hello, brave world\n"); 400 401 apr_file_close(f); 402 apr_brigade_destroy(bb); 403 apr_bucket_alloc_destroy(ba); 404} 405 406/* Regression test for PR 34708, where a file bucket will keep 407 * duplicating itself on being read() when EOF is reached 408 * prematurely. */ 409static void test_truncfile(abts_case *tc, void *data) 410{ 411 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 412 apr_bucket_brigade *bb = apr_brigade_create(p, ba); 413 apr_file_t *f = make_test_file(tc, "testfile.txt", "hello"); 414 apr_bucket *e; 415 const char *buf; 416 apr_size_t len; 417 418 apr_brigade_insert_file(bb, f, 0, 5, p); 419 420 apr_file_trunc(f, 0); 421 422 e = APR_BRIGADE_FIRST(bb); 423 424 ABTS_ASSERT(tc, "single bucket in brigade", 425 APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb)); 426 427 apr_bucket_file_enable_mmap(e, 0); 428 429 ABTS_ASSERT(tc, "read gave APR_EOF", 430 apr_bucket_read(e, &buf, &len, APR_BLOCK_READ) == APR_EOF); 431 432 ABTS_ASSERT(tc, "read length 0", len == 0); 433 434 ABTS_ASSERT(tc, "still a single bucket in brigade", 435 APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb)); 436 437 apr_file_close(f); 438 apr_brigade_destroy(bb); 439 apr_bucket_alloc_destroy(ba); 440} 441 442static const char hello[] = "hello, world"; 443 444static void test_partition(abts_case *tc, void *data) 445{ 446 apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p); 447 apr_bucket_brigade *bb = apr_brigade_create(p, ba); 448 apr_bucket *e; 449 450 e = apr_bucket_immortal_create(hello, strlen(hello), ba); 451 APR_BRIGADE_INSERT_HEAD(bb, e); 452 453 apr_assert_success(tc, "partition brigade", 454 apr_brigade_partition(bb, 5, &e)); 455 456 test_bucket_content(tc, APR_BRIGADE_FIRST(bb), 457 "hello", 5); 458 459 test_bucket_content(tc, APR_BRIGADE_LAST(bb), 460 ", world", 7); 461 462 ABTS_ASSERT(tc, "partition returns APR_INCOMPLETE", 463 apr_brigade_partition(bb, 8192, &e)); 464 465 ABTS_ASSERT(tc, "APR_INCOMPLETE partition returned sentinel", 466 e == APR_BRIGADE_SENTINEL(bb)); 467 468 apr_brigade_destroy(bb); 469 apr_bucket_alloc_destroy(ba); 470} 471 472abts_suite *testbuckets(abts_suite *suite) 473{ 474 suite = ADD_SUITE(suite); 475 476 abts_run_test(suite, test_create, NULL); 477 abts_run_test(suite, test_simple, NULL); 478 abts_run_test(suite, test_flatten, NULL); 479 abts_run_test(suite, test_split, NULL); 480 abts_run_test(suite, test_bwrite, NULL); 481 abts_run_test(suite, test_splitline, NULL); 482 abts_run_test(suite, test_splits, NULL); 483 abts_run_test(suite, test_insertfile, NULL); 484 abts_run_test(suite, test_manyfile, NULL); 485 abts_run_test(suite, test_truncfile, NULL); 486 abts_run_test(suite, test_partition, NULL); 487 488 return suite; 489} 490 491 492