1 /*
2 * pristine-store-test.c : test the pristine-store subsystem
3 *
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
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
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
20 * under the License.
21 * ====================================================================
22 */
23
24 #include <apr_pools.h>
25 #include <apr_general.h>
26
27 #include "svn_types.h"
28
29 /* Make sure SVN_DEPRECATED is defined as empty before including svn_io.h.
30 We don't want to trigger deprecation warnings. */
31 #ifdef SVN_DEPRECATED
32 #undef SVN_DEPRECATED
33 #endif
34 #define SVN_DEPRECATED
35 #include "svn_io.h"
36
37 #include "svn_dirent_uri.h"
38 #include "svn_pools.h"
39 #include "svn_repos.h"
40 #include "svn_wc.h"
41 #include "svn_client.h"
42
43 #include "utils.h"
44
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"
49
50 #include "private/svn_wc_private.h"
51
52 #include "../svn_test.h"
53
54
55 /* Create repos and WC, set *WC_ABSPATH to the WC path, and set *DB to a new
56 * DB context. */
57 static svn_error_t *
create_repos_and_wc(const char ** wc_abspath,svn_wc__db_t ** db,const char * test_name,const svn_test_opts_t * opts,apr_pool_t * pool)58 create_repos_and_wc(const char **wc_abspath,
59 svn_wc__db_t **db,
60 const char *test_name,
61 const svn_test_opts_t *opts,
62 apr_pool_t *pool)
63 {
64 svn_test__sandbox_t sandbox;
65
66 SVN_ERR(svn_test__sandbox_create(&sandbox, test_name, opts, pool));
67 *wc_abspath = sandbox.wc_abspath;
68 *db = sandbox.wc_ctx->db;
69
70 return SVN_NO_ERROR;
71 }
72
73 /* Exercise the pristine text API with a simple write and read. */
74 static svn_error_t *
pristine_write_read(const svn_test_opts_t * opts,apr_pool_t * pool)75 pristine_write_read(const svn_test_opts_t *opts,
76 apr_pool_t *pool)
77 {
78 svn_wc__db_t *db;
79 const char *wc_abspath;
80
81 svn_wc__db_install_data_t *install_data;
82 svn_stream_t *pristine_stream;
83 apr_size_t sz;
84
85 const char data[] = "Blah";
86 svn_string_t *data_string = svn_string_create(data, pool);
87 svn_checksum_t *data_sha1, *data_md5;
88
89 SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
90 "pristine_write_read", opts, pool));
91
92 /* Write DATA into a new temporary pristine file, set PRISTINE_TMP_ABSPATH
93 * to its path and set DATA_SHA1 and DATA_MD5 to its checksums. */
94 SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
95 &install_data,
96 &data_sha1, &data_md5,
97 db, wc_abspath,
98 pool, pool));
99
100 sz = strlen(data);
101 SVN_ERR(svn_stream_write(pristine_stream, data, &sz));
102 SVN_ERR(svn_stream_close(pristine_stream));
103
104 /* Ensure it's not already in the store. */
105 {
106 svn_boolean_t present;
107
108 SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
109 pool));
110 SVN_TEST_ASSERT(! present);
111 }
112
113 /* Install the new pristine file, referenced by its checksum. */
114 SVN_ERR(svn_wc__db_pristine_install(install_data,
115 data_sha1, data_md5, pool));
116
117 /* Ensure it is now found in the store. */
118 {
119 svn_boolean_t present;
120
121 SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
122 pool));
123 SVN_TEST_ASSERT(present);
124 }
125
126 /* Look up its MD-5 from its SHA-1, and check it's the same MD-5. */
127 {
128 const svn_checksum_t *looked_up_md5;
129
130 SVN_ERR(svn_wc__db_pristine_get_md5(&looked_up_md5, db, wc_abspath,
131 data_sha1, pool, pool));
132 SVN_TEST_ASSERT(looked_up_md5->kind == svn_checksum_md5);
133 SVN_TEST_ASSERT(svn_checksum_match(data_md5, looked_up_md5));
134 }
135
136 /* Read the pristine text back and verify it's the same content. */
137 {
138 svn_stream_t *data_stream = svn_stream_from_string(data_string, pool);
139 svn_stream_t *data_read_back;
140 svn_boolean_t same;
141
142 SVN_ERR(svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath,
143 data_sha1, pool, pool));
144 SVN_ERR(svn_stream_contents_same2(&same, data_read_back, data_stream,
145 pool));
146 SVN_TEST_ASSERT(same);
147 }
148
149 /* Trivially test the "remove if unreferenced" API: it's not referenced
150 so we should be able to remove it. */
151 {
152 svn_error_t *err;
153 svn_stream_t *data_read_back;
154
155 SVN_ERR(svn_wc__db_pristine_remove(db, wc_abspath, data_sha1, pool));
156 err = svn_wc__db_pristine_read(&data_read_back, NULL, db, wc_abspath,
157 data_sha1, pool, pool);
158 SVN_TEST_ASSERT_ERROR(err, SVN_ERR_WC_PATH_NOT_FOUND);
159 }
160
161 /* Ensure it's no longer found in the store. */
162 {
163 svn_boolean_t present;
164
165 SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
166 pool));
167 SVN_TEST_ASSERT(! present);
168 }
169
170 return SVN_NO_ERROR;
171 }
172
173 /* Test deleting a pristine text while it is open for reading. */
174 static svn_error_t *
pristine_delete_while_open(const svn_test_opts_t * opts,apr_pool_t * pool)175 pristine_delete_while_open(const svn_test_opts_t *opts,
176 apr_pool_t *pool)
177 {
178 svn_wc__db_t *db;
179 const char *wc_abspath;
180 svn_wc__db_install_data_t *install_data;
181 svn_stream_t *pristine_stream;
182 svn_stream_t *contents;
183 apr_size_t sz;
184
185 const char data[] = "Blah";
186 svn_checksum_t *data_sha1, *data_md5;
187
188 SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
189 "pristine_delete_while_open", opts, pool));
190
191 SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
192 &install_data,
193 &data_sha1, &data_md5,
194 db, wc_abspath,
195 pool, pool));
196
197 sz = strlen(data);
198 SVN_ERR(svn_stream_write(pristine_stream, data, &sz));
199 SVN_ERR(svn_stream_close(pristine_stream));
200 SVN_ERR(svn_wc__db_pristine_install(install_data,
201 data_sha1, data_md5, pool));
202
203 /* Open it for reading */
204 SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db, wc_abspath, data_sha1,
205 pool, pool));
206
207 /* Delete it */
208 SVN_ERR(svn_wc__db_pristine_remove(db, wc_abspath, data_sha1, pool));
209
210 /* Continue to read from it */
211 {
212 char buffer[4];
213 apr_size_t len = 4;
214
215 SVN_ERR(svn_stream_read_full(contents, buffer, &len));
216 SVN_TEST_ASSERT(len == 4);
217 SVN_TEST_ASSERT(memcmp(buffer, data, len) == 0);
218 }
219
220 /* Ensure it's no longer found in the store. (The file may still exist as
221 * an orphan, depending on the implementation.) */
222 {
223 svn_boolean_t present;
224
225 SVN_ERR(svn_wc__db_pristine_check(&present, db, wc_abspath, data_sha1,
226 pool));
227 SVN_TEST_ASSERT(! present);
228 }
229
230 /* Close the read stream */
231 SVN_ERR(svn_stream_close(contents));
232
233 return SVN_NO_ERROR;
234 }
235
236 /* Check that the store rejects an attempt to replace an existing pristine
237 * text with different text.
238 *
239 * White-box knowledge: The implementation compares the file sizes but
240 * doesn't compare the text itself, so in this test we ensure the second
241 * text is a different size. */
242 static svn_error_t *
reject_mismatching_text(const svn_test_opts_t * opts,apr_pool_t * pool)243 reject_mismatching_text(const svn_test_opts_t *opts,
244 apr_pool_t *pool)
245 {
246 #ifdef SVN_DEBUG /* The pristine store only checks this in debug mode. */
247 svn_wc__db_t *db;
248 const char *wc_abspath;
249
250 const char data[] = "Blah";
251 svn_checksum_t *data_sha1, *data_md5;
252
253 const char data2[] = "Baz";
254
255 SVN_ERR(create_repos_and_wc(&wc_abspath, &db,
256 "reject_mismatching_text", opts, pool));
257
258 /* Install a pristine text. */
259 {
260 svn_wc__db_install_data_t *install_data;
261 svn_stream_t *pristine_stream;
262 apr_size_t sz;
263
264 SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
265 &install_data,
266 &data_sha1, &data_md5,
267 db, wc_abspath,
268 pool, pool));
269
270 sz = strlen(data);
271 SVN_ERR(svn_stream_write(pristine_stream, data, &sz));
272 SVN_ERR(svn_stream_close(pristine_stream));
273
274 SVN_ERR(svn_wc__db_pristine_install(install_data,
275 data_sha1, data_md5,
276 pool));
277 }
278
279 /* Try to install the wrong pristine text against the same checksum.
280 * Should fail. */
281 {
282 svn_wc__db_install_data_t *install_data;
283 svn_stream_t *pristine_stream;
284 apr_size_t sz;
285
286 SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_stream,
287 &install_data,
288 &data_sha1, &data_md5,
289 db, wc_abspath,
290 pool, pool));
291
292 sz = strlen(data2);
293 SVN_ERR(svn_stream_write(pristine_stream, data2, &sz));
294 SVN_ERR(svn_stream_close(pristine_stream));
295
296 SVN_ERR(svn_wc__db_pristine_install(install_data,
297 data_sha1, data_md5,
298 pool));
299 }
300
301 return SVN_NO_ERROR;
302 #else
303 return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
304 "The consistency check to be tested is only "
305 "active in debug-mode builds");
306 #endif
307 }
308
309
310 static int max_threads = -1;
311
312 static struct svn_test_descriptor_t test_funcs[] =
313 {
314 SVN_TEST_NULL,
315 SVN_TEST_OPTS_PASS(pristine_write_read,
316 "pristine_write_read"),
317 SVN_TEST_OPTS_PASS(pristine_delete_while_open,
318 "pristine_delete_while_open"),
319 SVN_TEST_OPTS_PASS(reject_mismatching_text,
320 "reject_mismatching_text"),
321 SVN_TEST_NULL
322 };
323
324 SVN_TEST_MAIN
325