1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2015 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg/* A collection of unit tests for cache.c */
25b8e80941Smrg
26b8e80941Smrg#include <stdio.h>
27b8e80941Smrg#include <stdlib.h>
28b8e80941Smrg#include <stdbool.h>
29b8e80941Smrg#include <string.h>
30b8e80941Smrg#include <ftw.h>
31b8e80941Smrg#include <errno.h>
32b8e80941Smrg#include <stdarg.h>
33b8e80941Smrg#include <inttypes.h>
34b8e80941Smrg#include <limits.h>
35b8e80941Smrg#include <time.h>
36b8e80941Smrg#include <unistd.h>
37b8e80941Smrg
38b8e80941Smrg#include "util/mesa-sha1.h"
39b8e80941Smrg#include "util/disk_cache.h"
40b8e80941Smrg
41b8e80941Smrgbool error = false;
42b8e80941Smrg
43b8e80941Smrg#ifdef ENABLE_SHADER_CACHE
44b8e80941Smrg
45b8e80941Smrgstatic void
46b8e80941Smrgexpect_true(bool result, const char *test)
47b8e80941Smrg{
48b8e80941Smrg   if (!result) {
49b8e80941Smrg      fprintf(stderr, "Error: Test '%s' failed: Expected=true"
50b8e80941Smrg              ", Actual=false\n", test);
51b8e80941Smrg      error = true;
52b8e80941Smrg   }
53b8e80941Smrg}
54b8e80941Smrg
55b8e80941Smrgstatic void
56b8e80941Smrgexpect_equal(uint64_t actual, uint64_t expected, const char *test)
57b8e80941Smrg{
58b8e80941Smrg   if (actual != expected) {
59b8e80941Smrg      fprintf(stderr, "Error: Test '%s' failed: Expected=%" PRIu64
60b8e80941Smrg              ", Actual=%" PRIu64 "\n",
61b8e80941Smrg              test, expected, actual);
62b8e80941Smrg      error = true;
63b8e80941Smrg   }
64b8e80941Smrg}
65b8e80941Smrg
66b8e80941Smrgstatic void
67b8e80941Smrgexpect_null(void *ptr, const char *test)
68b8e80941Smrg{
69b8e80941Smrg   if (ptr != NULL) {
70b8e80941Smrg      fprintf(stderr, "Error: Test '%s' failed: Result=%p, but expected NULL.\n",
71b8e80941Smrg              test, ptr);
72b8e80941Smrg      error = true;
73b8e80941Smrg   }
74b8e80941Smrg}
75b8e80941Smrg
76b8e80941Smrgstatic void
77b8e80941Smrgexpect_non_null(void *ptr, const char *test)
78b8e80941Smrg{
79b8e80941Smrg   if (ptr == NULL) {
80b8e80941Smrg      fprintf(stderr, "Error: Test '%s' failed: Result=NULL, but expected something else.\n",
81b8e80941Smrg              test);
82b8e80941Smrg      error = true;
83b8e80941Smrg   }
84b8e80941Smrg}
85b8e80941Smrg
86b8e80941Smrgstatic void
87b8e80941Smrgexpect_equal_str(const char *actual, const char *expected, const char *test)
88b8e80941Smrg{
89b8e80941Smrg   if (strcmp(actual, expected)) {
90b8e80941Smrg      fprintf(stderr, "Error: Test '%s' failed:\n\t"
91b8e80941Smrg              "Expected=\"%s\", Actual=\"%s\"\n",
92b8e80941Smrg              test, expected, actual);
93b8e80941Smrg      error = true;
94b8e80941Smrg   }
95b8e80941Smrg}
96b8e80941Smrg
97b8e80941Smrg/* Callback for nftw used in rmrf_local below.
98b8e80941Smrg */
99b8e80941Smrgstatic int
100b8e80941Smrgremove_entry(const char *path,
101b8e80941Smrg             const struct stat *sb,
102b8e80941Smrg             int typeflag,
103b8e80941Smrg             struct FTW *ftwbuf)
104b8e80941Smrg{
105b8e80941Smrg   int err = remove(path);
106b8e80941Smrg
107b8e80941Smrg   if (err)
108b8e80941Smrg      fprintf(stderr, "Error removing %s: %s\n", path, strerror(errno));
109b8e80941Smrg
110b8e80941Smrg   return err;
111b8e80941Smrg}
112b8e80941Smrg
113b8e80941Smrg/* Recursively remove a directory.
114b8e80941Smrg *
115b8e80941Smrg * This is equivalent to "rm -rf <dir>" with one bit of protection
116b8e80941Smrg * that the directory name must begin with "." to ensure we don't
117b8e80941Smrg * wander around deleting more than intended.
118b8e80941Smrg *
119b8e80941Smrg * Returns 0 on success, -1 on any error.
120b8e80941Smrg */
121b8e80941Smrgstatic int
122b8e80941Smrgrmrf_local(const char *path)
123b8e80941Smrg{
124b8e80941Smrg   if (path == NULL || *path == '\0' || *path != '.')
125b8e80941Smrg      return -1;
126b8e80941Smrg
127b8e80941Smrg   return nftw(path, remove_entry, 64, FTW_DEPTH | FTW_PHYS);
128b8e80941Smrg}
129b8e80941Smrg
130b8e80941Smrgstatic void
131b8e80941Smrgcheck_directories_created(const char *cache_dir)
132b8e80941Smrg{
133b8e80941Smrg   bool sub_dirs_created = false;
134b8e80941Smrg
135b8e80941Smrg   char buf[PATH_MAX];
136b8e80941Smrg   if (getcwd(buf, PATH_MAX)) {
137b8e80941Smrg      char *full_path = NULL;
138b8e80941Smrg      if (asprintf(&full_path, "%s%s", buf, ++cache_dir) != -1 ) {
139b8e80941Smrg         struct stat sb;
140b8e80941Smrg         if (stat(full_path, &sb) != -1 && S_ISDIR(sb.st_mode))
141b8e80941Smrg            sub_dirs_created = true;
142b8e80941Smrg
143b8e80941Smrg         free(full_path);
144b8e80941Smrg      }
145b8e80941Smrg   }
146b8e80941Smrg
147b8e80941Smrg   expect_true(sub_dirs_created, "create sub dirs");
148b8e80941Smrg}
149b8e80941Smrg
150b8e80941Smrgstatic bool
151b8e80941Smrgdoes_cache_contain(struct disk_cache *cache, const cache_key key)
152b8e80941Smrg{
153b8e80941Smrg   void *result;
154b8e80941Smrg
155b8e80941Smrg   result = disk_cache_get(cache, key, NULL);
156b8e80941Smrg
157b8e80941Smrg   if (result) {
158b8e80941Smrg      free(result);
159b8e80941Smrg      return true;
160b8e80941Smrg   }
161b8e80941Smrg
162b8e80941Smrg   return false;
163b8e80941Smrg}
164b8e80941Smrg
165b8e80941Smrgstatic void
166b8e80941Smrgwait_until_file_written(struct disk_cache *cache, const cache_key key)
167b8e80941Smrg{
168b8e80941Smrg   struct timespec req;
169b8e80941Smrg   struct timespec rem;
170b8e80941Smrg
171b8e80941Smrg   /* Set 100ms delay */
172b8e80941Smrg   req.tv_sec = 0;
173b8e80941Smrg   req.tv_nsec = 100000000;
174b8e80941Smrg
175b8e80941Smrg   unsigned retries = 0;
176b8e80941Smrg   while (retries++ < 20) {
177b8e80941Smrg      if (does_cache_contain(cache, key)) {
178b8e80941Smrg         break;
179b8e80941Smrg      }
180b8e80941Smrg
181b8e80941Smrg      nanosleep(&req, &rem);
182b8e80941Smrg   }
183b8e80941Smrg}
184b8e80941Smrg
185b8e80941Smrgstatic void *
186b8e80941Smrgcache_exists(struct disk_cache *cache)
187b8e80941Smrg{
188b8e80941Smrg   uint8_t dummy_key[20];
189b8e80941Smrg   char data[] = "some test data";
190b8e80941Smrg
191b8e80941Smrg   if (!cache)
192b8e80941Smrg      return NULL;
193b8e80941Smrg
194b8e80941Smrg   disk_cache_put(cache, dummy_key, data, sizeof(data), NULL);
195b8e80941Smrg   wait_until_file_written(cache, dummy_key);
196b8e80941Smrg   return disk_cache_get(cache, dummy_key, NULL);
197b8e80941Smrg}
198b8e80941Smrg
199b8e80941Smrg#define CACHE_TEST_TMP "./cache-test-tmp"
200b8e80941Smrg
201b8e80941Smrgstatic void
202b8e80941Smrgtest_disk_cache_create(void)
203b8e80941Smrg{
204b8e80941Smrg   struct disk_cache *cache;
205b8e80941Smrg   int err;
206b8e80941Smrg
207b8e80941Smrg   /* Before doing anything else, ensure that with
208b8e80941Smrg    * MESA_GLSL_CACHE_DISABLE set to true, that disk_cache_create returns NULL.
209b8e80941Smrg    */
210b8e80941Smrg   setenv("MESA_GLSL_CACHE_DISABLE", "true", 1);
211b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
212b8e80941Smrg   expect_null(cache, "disk_cache_create with MESA_GLSL_CACHE_DISABLE set");
213b8e80941Smrg
214b8e80941Smrg   unsetenv("MESA_GLSL_CACHE_DISABLE");
215b8e80941Smrg
216b8e80941Smrg   /* For the first real disk_cache_create() clear these environment
217b8e80941Smrg    * variables to test creation of cache in home directory.
218b8e80941Smrg    */
219b8e80941Smrg   unsetenv("MESA_GLSL_CACHE_DIR");
220b8e80941Smrg   unsetenv("XDG_CACHE_HOME");
221b8e80941Smrg
222b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
223b8e80941Smrg   expect_non_null(cache, "disk_cache_create with no environment variables");
224b8e80941Smrg
225b8e80941Smrg   disk_cache_destroy(cache);
226b8e80941Smrg
227b8e80941Smrg   /* Test with XDG_CACHE_HOME set */
228b8e80941Smrg   setenv("XDG_CACHE_HOME", CACHE_TEST_TMP "/xdg-cache-home", 1);
229b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
230b8e80941Smrg   expect_null(cache_exists(cache), "disk_cache_create with XDG_CACHE_HOME set "
231b8e80941Smrg               "with a non-existing parent directory");
232b8e80941Smrg
233b8e80941Smrg   mkdir(CACHE_TEST_TMP, 0755);
234b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
235b8e80941Smrg   expect_non_null(cache_exists(cache), "disk_cache_create with XDG_CACHE_HOME "
236b8e80941Smrg                   "set");
237b8e80941Smrg
238b8e80941Smrg   check_directories_created(CACHE_TEST_TMP "/xdg-cache-home/"
239b8e80941Smrg                             CACHE_DIR_NAME);
240b8e80941Smrg
241b8e80941Smrg   disk_cache_destroy(cache);
242b8e80941Smrg
243b8e80941Smrg   /* Test with MESA_GLSL_CACHE_DIR set */
244b8e80941Smrg   err = rmrf_local(CACHE_TEST_TMP);
245b8e80941Smrg   expect_equal(err, 0, "Removing " CACHE_TEST_TMP);
246b8e80941Smrg
247b8e80941Smrg   setenv("MESA_GLSL_CACHE_DIR", CACHE_TEST_TMP "/mesa-glsl-cache-dir", 1);
248b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
249b8e80941Smrg   expect_null(cache_exists(cache), "disk_cache_create with MESA_GLSL_CACHE_DIR"
250b8e80941Smrg               " set with a non-existing parent directory");
251b8e80941Smrg
252b8e80941Smrg   mkdir(CACHE_TEST_TMP, 0755);
253b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
254b8e80941Smrg   expect_non_null(cache_exists(cache), "disk_cache_create with "
255b8e80941Smrg                   "MESA_GLSL_CACHE_DIR set");
256b8e80941Smrg
257b8e80941Smrg   check_directories_created(CACHE_TEST_TMP "/mesa-glsl-cache-dir/"
258b8e80941Smrg                             CACHE_DIR_NAME);
259b8e80941Smrg
260b8e80941Smrg   disk_cache_destroy(cache);
261b8e80941Smrg}
262b8e80941Smrg
263b8e80941Smrgstatic void
264b8e80941Smrgtest_put_and_get(void)
265b8e80941Smrg{
266b8e80941Smrg   struct disk_cache *cache;
267b8e80941Smrg   char blob[] = "This is a blob of thirty-seven bytes";
268b8e80941Smrg   uint8_t blob_key[20];
269b8e80941Smrg   char string[] = "While this string has thirty-four";
270b8e80941Smrg   uint8_t string_key[20];
271b8e80941Smrg   char *result;
272b8e80941Smrg   size_t size;
273b8e80941Smrg   uint8_t *one_KB, *one_MB;
274b8e80941Smrg   uint8_t one_KB_key[20], one_MB_key[20];
275b8e80941Smrg   int count;
276b8e80941Smrg
277b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
278b8e80941Smrg
279b8e80941Smrg   disk_cache_compute_key(cache, blob, sizeof(blob), blob_key);
280b8e80941Smrg
281b8e80941Smrg   /* Ensure that disk_cache_get returns nothing before anything is added. */
282b8e80941Smrg   result = disk_cache_get(cache, blob_key, &size);
283b8e80941Smrg   expect_null(result, "disk_cache_get with non-existent item (pointer)");
284b8e80941Smrg   expect_equal(size, 0, "disk_cache_get with non-existent item (size)");
285b8e80941Smrg
286b8e80941Smrg   /* Simple test of put and get. */
287b8e80941Smrg   disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL);
288b8e80941Smrg
289b8e80941Smrg   /* disk_cache_put() hands things off to a thread give it some time to
290b8e80941Smrg    * finish.
291b8e80941Smrg    */
292b8e80941Smrg   wait_until_file_written(cache, blob_key);
293b8e80941Smrg
294b8e80941Smrg   result = disk_cache_get(cache, blob_key, &size);
295b8e80941Smrg   expect_equal_str(blob, result, "disk_cache_get of existing item (pointer)");
296b8e80941Smrg   expect_equal(size, sizeof(blob), "disk_cache_get of existing item (size)");
297b8e80941Smrg
298b8e80941Smrg   free(result);
299b8e80941Smrg
300b8e80941Smrg   /* Test put and get of a second item. */
301b8e80941Smrg   disk_cache_compute_key(cache, string, sizeof(string), string_key);
302b8e80941Smrg   disk_cache_put(cache, string_key, string, sizeof(string), NULL);
303b8e80941Smrg
304b8e80941Smrg   /* disk_cache_put() hands things off to a thread give it some time to
305b8e80941Smrg    * finish.
306b8e80941Smrg    */
307b8e80941Smrg   wait_until_file_written(cache, string_key);
308b8e80941Smrg
309b8e80941Smrg   result = disk_cache_get(cache, string_key, &size);
310b8e80941Smrg   expect_equal_str(result, string, "2nd disk_cache_get of existing item (pointer)");
311b8e80941Smrg   expect_equal(size, sizeof(string), "2nd disk_cache_get of existing item (size)");
312b8e80941Smrg
313b8e80941Smrg   free(result);
314b8e80941Smrg
315b8e80941Smrg   /* Set the cache size to 1KB and add a 1KB item to force an eviction. */
316b8e80941Smrg   disk_cache_destroy(cache);
317b8e80941Smrg
318b8e80941Smrg   setenv("MESA_GLSL_CACHE_MAX_SIZE", "1K", 1);
319b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
320b8e80941Smrg
321b8e80941Smrg   one_KB = calloc(1, 1024);
322b8e80941Smrg
323b8e80941Smrg   /* Obviously the SHA-1 hash of 1024 zero bytes isn't particularly
324b8e80941Smrg    * interesting. But we do have want to take some special care with
325b8e80941Smrg    * the hash we use here. The issue is that in this artificial case,
326b8e80941Smrg    * (with only three files in the cache), the probability is good
327b8e80941Smrg    * that each of the three files will end up in their own
328b8e80941Smrg    * directory. Then, if the directory containing the .tmp file for
329b8e80941Smrg    * the new item being added for disk_cache_put() is the chosen victim
330b8e80941Smrg    * directory for eviction, then no suitable file will be found and
331b8e80941Smrg    * nothing will be evicted.
332b8e80941Smrg    *
333b8e80941Smrg    * That's actually expected given how the eviction code is
334b8e80941Smrg    * implemented, (which expects to only evict once things are more
335b8e80941Smrg    * interestingly full than that).
336b8e80941Smrg    *
337b8e80941Smrg    * For this test, we force this signature to land in the same
338b8e80941Smrg    * directory as the original blob first written to the cache.
339b8e80941Smrg    */
340b8e80941Smrg   disk_cache_compute_key(cache, one_KB, 1024, one_KB_key);
341b8e80941Smrg   one_KB_key[0] = blob_key[0];
342b8e80941Smrg
343b8e80941Smrg   disk_cache_put(cache, one_KB_key, one_KB, 1024, NULL);
344b8e80941Smrg
345b8e80941Smrg   free(one_KB);
346b8e80941Smrg
347b8e80941Smrg   /* disk_cache_put() hands things off to a thread give it some time to
348b8e80941Smrg    * finish.
349b8e80941Smrg    */
350b8e80941Smrg   wait_until_file_written(cache, one_KB_key);
351b8e80941Smrg
352b8e80941Smrg   result = disk_cache_get(cache, one_KB_key, &size);
353b8e80941Smrg   expect_non_null(result, "3rd disk_cache_get of existing item (pointer)");
354b8e80941Smrg   expect_equal(size, 1024, "3rd disk_cache_get of existing item (size)");
355b8e80941Smrg
356b8e80941Smrg   free(result);
357b8e80941Smrg
358b8e80941Smrg   /* Ensure eviction happened by checking that both of the previous
359b8e80941Smrg    * cache itesm were evicted.
360b8e80941Smrg    */
361b8e80941Smrg   bool contains_1KB_file = false;
362b8e80941Smrg   count = 0;
363b8e80941Smrg   if (does_cache_contain(cache, blob_key))
364b8e80941Smrg       count++;
365b8e80941Smrg
366b8e80941Smrg   if (does_cache_contain(cache, string_key))
367b8e80941Smrg       count++;
368b8e80941Smrg
369b8e80941Smrg   if (does_cache_contain(cache, one_KB_key)) {
370b8e80941Smrg      count++;
371b8e80941Smrg      contains_1KB_file = true;
372b8e80941Smrg   }
373b8e80941Smrg
374b8e80941Smrg   expect_true(contains_1KB_file,
375b8e80941Smrg               "disk_cache_put eviction last file == MAX_SIZE (1KB)");
376b8e80941Smrg   expect_equal(count, 1, "disk_cache_put eviction with MAX_SIZE=1K");
377b8e80941Smrg
378b8e80941Smrg   /* Now increase the size to 1M, add back both items, and ensure all
379b8e80941Smrg    * three that have been added are available via disk_cache_get.
380b8e80941Smrg    */
381b8e80941Smrg   disk_cache_destroy(cache);
382b8e80941Smrg
383b8e80941Smrg   setenv("MESA_GLSL_CACHE_MAX_SIZE", "1M", 1);
384b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
385b8e80941Smrg
386b8e80941Smrg   disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL);
387b8e80941Smrg   disk_cache_put(cache, string_key, string, sizeof(string), NULL);
388b8e80941Smrg
389b8e80941Smrg   /* disk_cache_put() hands things off to a thread give it some time to
390b8e80941Smrg    * finish.
391b8e80941Smrg    */
392b8e80941Smrg   wait_until_file_written(cache, blob_key);
393b8e80941Smrg   wait_until_file_written(cache, string_key);
394b8e80941Smrg
395b8e80941Smrg   count = 0;
396b8e80941Smrg   if (does_cache_contain(cache, blob_key))
397b8e80941Smrg       count++;
398b8e80941Smrg
399b8e80941Smrg   if (does_cache_contain(cache, string_key))
400b8e80941Smrg       count++;
401b8e80941Smrg
402b8e80941Smrg   if (does_cache_contain(cache, one_KB_key))
403b8e80941Smrg       count++;
404b8e80941Smrg
405b8e80941Smrg   expect_equal(count, 3, "no eviction before overflow with MAX_SIZE=1M");
406b8e80941Smrg
407b8e80941Smrg   /* Finally, check eviction again after adding an object of size 1M. */
408b8e80941Smrg   one_MB = calloc(1024, 1024);
409b8e80941Smrg
410b8e80941Smrg   disk_cache_compute_key(cache, one_MB, 1024 * 1024, one_MB_key);
411b8e80941Smrg   one_MB_key[0] = blob_key[0];
412b8e80941Smrg
413b8e80941Smrg   disk_cache_put(cache, one_MB_key, one_MB, 1024 * 1024, NULL);
414b8e80941Smrg
415b8e80941Smrg   free(one_MB);
416b8e80941Smrg
417b8e80941Smrg   /* disk_cache_put() hands things off to a thread give it some time to
418b8e80941Smrg    * finish.
419b8e80941Smrg    */
420b8e80941Smrg   wait_until_file_written(cache, one_MB_key);
421b8e80941Smrg
422b8e80941Smrg   bool contains_1MB_file = false;
423b8e80941Smrg   count = 0;
424b8e80941Smrg   if (does_cache_contain(cache, blob_key))
425b8e80941Smrg       count++;
426b8e80941Smrg
427b8e80941Smrg   if (does_cache_contain(cache, string_key))
428b8e80941Smrg       count++;
429b8e80941Smrg
430b8e80941Smrg   if (does_cache_contain(cache, one_KB_key))
431b8e80941Smrg       count++;
432b8e80941Smrg
433b8e80941Smrg   if (does_cache_contain(cache, one_MB_key)) {
434b8e80941Smrg      count++;
435b8e80941Smrg      contains_1MB_file = true;
436b8e80941Smrg   }
437b8e80941Smrg
438b8e80941Smrg   expect_true(contains_1MB_file,
439b8e80941Smrg               "disk_cache_put eviction last file == MAX_SIZE (1MB)");
440b8e80941Smrg   expect_equal(count, 1, "eviction after overflow with MAX_SIZE=1M");
441b8e80941Smrg
442b8e80941Smrg   disk_cache_destroy(cache);
443b8e80941Smrg}
444b8e80941Smrg
445b8e80941Smrgstatic void
446b8e80941Smrgtest_put_key_and_get_key(void)
447b8e80941Smrg{
448b8e80941Smrg   struct disk_cache *cache;
449b8e80941Smrg   bool result;
450b8e80941Smrg
451b8e80941Smrg   uint8_t key_a[20] = {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
452b8e80941Smrg                         10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
453b8e80941Smrg   uint8_t key_b[20] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
454b8e80941Smrg                         30, 33, 32, 33, 34, 35, 36, 37, 38, 39};
455b8e80941Smrg   uint8_t key_a_collide[20] =
456b8e80941Smrg                        { 0,  1, 42, 43, 44, 45, 46, 47, 48, 49,
457b8e80941Smrg                         50, 55, 52, 53, 54, 55, 56, 57, 58, 59};
458b8e80941Smrg
459b8e80941Smrg   cache = disk_cache_create("test", "make_check", 0);
460b8e80941Smrg
461b8e80941Smrg   /* First test that disk_cache_has_key returns false before disk_cache_put_key */
462b8e80941Smrg   result = disk_cache_has_key(cache, key_a);
463b8e80941Smrg   expect_equal(result, 0, "disk_cache_has_key before key added");
464b8e80941Smrg
465b8e80941Smrg   /* Then a couple of tests of disk_cache_put_key followed by disk_cache_has_key */
466b8e80941Smrg   disk_cache_put_key(cache, key_a);
467b8e80941Smrg   result = disk_cache_has_key(cache, key_a);
468b8e80941Smrg   expect_equal(result, 1, "disk_cache_has_key after key added");
469b8e80941Smrg
470b8e80941Smrg   disk_cache_put_key(cache, key_b);
471b8e80941Smrg   result = disk_cache_has_key(cache, key_b);
472b8e80941Smrg   expect_equal(result, 1, "2nd disk_cache_has_key after key added");
473b8e80941Smrg
474b8e80941Smrg   /* Test that a key with the same two bytes as an existing key
475b8e80941Smrg    * forces an eviction.
476b8e80941Smrg    */
477b8e80941Smrg   disk_cache_put_key(cache, key_a_collide);
478b8e80941Smrg   result = disk_cache_has_key(cache, key_a_collide);
479b8e80941Smrg   expect_equal(result, 1, "put_key of a colliding key lands in the cache");
480b8e80941Smrg
481b8e80941Smrg   result = disk_cache_has_key(cache, key_a);
482b8e80941Smrg   expect_equal(result, 0, "put_key of a colliding key evicts from the cache");
483b8e80941Smrg
484b8e80941Smrg   /* And finally test that we can re-add the original key to re-evict
485b8e80941Smrg    * the colliding key.
486b8e80941Smrg    */
487b8e80941Smrg   disk_cache_put_key(cache, key_a);
488b8e80941Smrg   result = disk_cache_has_key(cache, key_a);
489b8e80941Smrg   expect_equal(result, 1, "put_key of original key lands again");
490b8e80941Smrg
491b8e80941Smrg   result = disk_cache_has_key(cache, key_a_collide);
492b8e80941Smrg   expect_equal(result, 0, "put_key of orginal key evicts the colliding key");
493b8e80941Smrg
494b8e80941Smrg   disk_cache_destroy(cache);
495b8e80941Smrg}
496b8e80941Smrg#endif /* ENABLE_SHADER_CACHE */
497b8e80941Smrg
498b8e80941Smrgint
499b8e80941Smrgmain(void)
500b8e80941Smrg{
501b8e80941Smrg#ifdef ENABLE_SHADER_CACHE
502b8e80941Smrg   int err;
503b8e80941Smrg
504b8e80941Smrg   test_disk_cache_create();
505b8e80941Smrg
506b8e80941Smrg   test_put_and_get();
507b8e80941Smrg
508b8e80941Smrg   test_put_key_and_get_key();
509b8e80941Smrg
510b8e80941Smrg   err = rmrf_local(CACHE_TEST_TMP);
511b8e80941Smrg   expect_equal(err, 0, "Removing " CACHE_TEST_TMP " again");
512b8e80941Smrg#endif /* ENABLE_SHADER_CACHE */
513b8e80941Smrg
514b8e80941Smrg   return error ? 1 : 0;
515b8e80941Smrg}
516