2
* pristine-store-test.c : test the pristine-store subsystem
4
* ====================================================================
5
* Licensed to the Apache Software Foundation (ASF) under one
6
* or more contributor license agreements. See the NOTICE file
7
* distributed with this work for additional information
8
* regarding copyright ownership. The ASF licenses this file
9
* to you under the Apache License, Version 2.0 (the
10
* "License"); you may not use this file except in compliance
11
* with the License. You may obtain a copy of the License at
13
* http://www.apache.org/licenses/LICENSE-2.0
15
* Unless required by applicable law or agreed to in writing,
16
* software distributed under the License is distributed on an
17
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18
* KIND, either express or implied. See the License for the
19
* specific language governing permissions and limitations
21
* ====================================================================
24
#include <apr_pools.h>
25
#include <apr_general.h>
27
#include "svn_types.h"
29
/* Make sure SVN_DEPRECATED is defined as empty before including svn_io.h.
30
We don't want to trigger deprecation warnings. */
34
#define SVN_DEPRECATED
37
#include "svn_dirent_uri.h"
38
#include "svn_pools.h"
39
#include "svn_repos.h"
41
#include "svn_client.h"
45
#include "../../libsvn_wc/wc.h"
46
#include "../../libsvn_wc/wc_db.h"
47
#include "../../libsvn_wc/wc-queries.h"
48
#include "../../libsvn_wc/workqueue.h"
50
#include "private/svn_wc_private.h"
52
#include "../svn_test.h"
55
/* Create repos and WC, set *WC_ABSPATH to the WC path, and set *DB to a new
58
create_repos_and_wc(const char **wc_abspath,
60
const char *test_name,
61
const svn_test_opts_t *opts,
64
svn_test__sandbox_t sandbox;
66
SVN_ERR(svn_test__sandbox_create(&sandbox, test_name, opts, pool));
67
*wc_abspath = sandbox.wc_abspath;
68
*db = sandbox.wc_ctx->db;
74
/* Write the string DATA into a new unique-named file in the directory
75
* DIR_ABSPATH. Set *FILE_ABSPATH to its absolute path and *CHECKSUM_SHA1
76
* and *CHECKSUM_MD5 to its SHA-1 and MD-5 checksums.
78
* CHECKSUM_SHA1 and/or CHECKSUM_MD5 may be null if not required. */
80
write_and_checksum_temp_file(const char **file_abspath,
81
svn_checksum_t **sha1_checksum,
82
svn_checksum_t **md5_checksum,
84
const char *dir_abspath,
89
SVN_ERR(svn_io_open_unique_file3(&file, file_abspath,
90
dir_abspath, svn_io_file_del_none,
93
SVN_ERR(svn_io_file_write_full(file, data, strlen(data), NULL, pool));
94
SVN_ERR(svn_io_file_close(file, pool));
97
SVN_ERR(svn_io_file_checksum2(sha1_checksum, *file_abspath,
98
svn_checksum_sha1, pool));
100
SVN_ERR(svn_io_file_checksum2(md5_checksum, *file_abspath,
101
svn_checksum_md5, pool));
107
/* Exercise the pristine text API with a simple write and read. */
109
pristine_write_read(const svn_test_opts_t *opts,
113
const char *wc_abspath;
115
const char *pristine_tmp_abspath;
117
const char data[] = "Blah";
118
svn_string_t *data_string = svn_string_create(data, pool);
119
svn_checksum_t *data_sha1, *data_md5;
121
SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
122
"pristine_write_read", opts, pool));
124
/* Write DATA into a new temporary pristine file, set PRISTINE_TMP_ABSPATH
125
* to its path and set DATA_SHA1 and DATA_MD5 to its checksums. */
127
const char *pristine_tmp_dir;
129
SVN_ERR(svn_wc__db_pristine_get_tempdir(&pristine_tmp_dir, db,
130
wc_abspath, pool, pool));
131
SVN_ERR(write_and_checksum_temp_file(&pristine_tmp_abspath,
132
&data_sha1, &data_md5,
133
data, pristine_tmp_dir, pool));
136
/* Ensure it's not already in the store. */
138
svn_boolean_t present;
140
SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
142
SVN_TEST_ASSERT(! present);
145
/* Install the new pristine file, referenced by its checksum. */
146
SVN_ERR(svn_wc__db_pristine_install(db, pristine_tmp_abspath,
147
data_sha1, data_md5, pool));
149
/* Ensure it is now found in the store. */
151
svn_boolean_t present;
153
SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
155
SVN_TEST_ASSERT(present);
158
/* Look up its MD-5 from its SHA-1, and check it's the same MD-5. */
160
const svn_checksum_t *looked_up_md5;
162
SVN_ERR(svn_wc__db_pristine_get_md5(&looked_up_md5, db, wc_abspath,
163
data_sha1, pool, pool));
164
SVN_TEST_ASSERT(looked_up_md5->kind == svn_checksum_md5);
165
SVN_TEST_ASSERT(svn_checksum_match(data_md5, looked_up_md5));
168
/* Read the pristine text back and verify it's the same content. */
170
svn_stream_t *data_stream = svn_stream_from_string(data_string, pool);
171
svn_stream_t *data_read_back;
174
SVN_ERR(svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath,
175
data_sha1, pool, pool));
176
SVN_ERR(svn_stream_contents_same2(&same, data_read_back, data_stream,
178
SVN_TEST_ASSERT(same);
181
/* Trivially test the "remove if unreferenced" API: it's not referenced
182
so we should be able to remove it. */
185
svn_stream_t *data_read_back;
187
SVN_ERR(svn_wc__db_pristine_remove(db, wc_abspath, data_sha1, pool));
188
err = svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath,
189
data_sha1, pool, pool);
190
SVN_TEST_ASSERT(err != NULL);
191
svn_error_clear(err);
194
/* Ensure it's no longer found in the store. */
196
svn_boolean_t present;
198
SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
200
SVN_TEST_ASSERT(! present);
206
/* Test deleting a pristine text while it is open for reading. */
208
pristine_delete_while_open(const svn_test_opts_t *opts,
212
const char *wc_abspath;
213
const char *pristine_tmp_dir;
214
svn_stream_t *contents;
216
const char data[] = "Blah";
217
svn_checksum_t *data_sha1, *data_md5;
219
SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
220
"pristine_delete_while_open", opts, pool));
222
SVN_ERR(svn_wc__db_pristine_get_tempdir(&pristine_tmp_dir, db,
223
wc_abspath, pool, pool));
225
/* Install a pristine text. */
229
SVN_ERR(write_and_checksum_temp_file(&path, &data_sha1, &data_md5,
230
data, pristine_tmp_dir, pool));
231
SVN_ERR(svn_wc__db_pristine_install(db, path, data_sha1, data_md5, pool));
234
/* Open it for reading */
235
SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db, wc_abspath, data_sha1,
239
SVN_ERR(svn_wc__db_pristine_remove(db, wc_abspath, data_sha1, pool));
241
/* Continue to read from it */
246
SVN_ERR(svn_stream_read(contents, buffer, &len));
247
SVN_TEST_ASSERT(len == 4);
248
SVN_TEST_ASSERT(memcmp(buffer, data, len) == 0);
251
/* Ensure it's no longer found in the store. (The file may still exist as
252
* an orphan, depending on the implementation.) */
254
svn_boolean_t present;
256
SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
258
SVN_TEST_ASSERT(! present);
261
/* Close the read stream */
262
SVN_ERR(svn_stream_close(contents));
267
/* Check that the store rejects an attempt to replace an existing pristine
268
* text with different text.
270
* White-box knowledge: The implementation compares the file sizes but
271
* doesn't compare the text itself, so in this test we ensure the second
272
* text is a different size. */
274
reject_mismatching_text(const svn_test_opts_t *opts,
277
#ifdef SVN_DEBUG /* The pristine store only checks this in debug mode. */
279
const char *wc_abspath;
280
const char *pristine_tmp_dir;
282
const char data[] = "Blah";
283
svn_checksum_t *data_sha1, *data_md5;
285
const char data2[] = "Baz";
287
SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
288
"reject_mismatching_text", opts, pool));
290
SVN_ERR(svn_wc__db_pristine_get_tempdir(&pristine_tmp_dir, db,
291
wc_abspath, pool, pool));
293
/* Install a pristine text. */
297
SVN_ERR(write_and_checksum_temp_file(&path, &data_sha1, &data_md5,
298
data, pristine_tmp_dir, pool));
299
SVN_ERR(svn_wc__db_pristine_install(db, path, data_sha1, data_md5, pool));
302
/* Try to install the wrong pristine text against the same checksum.
308
SVN_ERR(write_and_checksum_temp_file(&path, NULL, NULL,
309
data2, pristine_tmp_dir, pool));
310
err = svn_wc__db_pristine_install(db, path, data_sha1, data_md5, pool);
311
SVN_TEST_ASSERT(err != NULL);
312
SVN_TEST_ASSERT(err->apr_err == SVN_ERR_WC_CORRUPT_TEXT_BASE);
313
svn_error_clear(err);
318
return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
319
"The consistency check to be tested is only "
320
"active in debug-mode builds");
325
struct svn_test_descriptor_t test_funcs[] =
328
SVN_TEST_OPTS_PASS(pristine_write_read,
329
"pristine_write_read"),
330
SVN_TEST_OPTS_PASS(pristine_delete_while_open,
331
"pristine_delete_while_open"),
332
SVN_TEST_OPTS_PASS(reject_mismatching_text,
333
"reject_mismatching_text"),