17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2015 Intel Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg/* A collection of unit tests for cache.c */
257ec681f3Smrg
267ec681f3Smrg#include <stdio.h>
277ec681f3Smrg#include <stdlib.h>
287ec681f3Smrg#include <stdbool.h>
297ec681f3Smrg#include <string.h>
307ec681f3Smrg#include <ftw.h>
317ec681f3Smrg#include <errno.h>
327ec681f3Smrg#include <stdarg.h>
337ec681f3Smrg#include <inttypes.h>
347ec681f3Smrg#include <limits.h>
357ec681f3Smrg#include <time.h>
367ec681f3Smrg#include <unistd.h>
377ec681f3Smrg
387ec681f3Smrg#include "util/mesa-sha1.h"
397ec681f3Smrg#include "util/disk_cache.h"
407ec681f3Smrg
417ec681f3Smrgbool error = false;
427ec681f3Smrg
437ec681f3Smrg#ifdef ENABLE_SHADER_CACHE
447ec681f3Smrg
457ec681f3Smrgstatic void
467ec681f3Smrgexpect_true(bool result, const char *test)
477ec681f3Smrg{
487ec681f3Smrg   if (!result) {
497ec681f3Smrg      fprintf(stderr, "Error: Test '%s' failed: Expected=true"
507ec681f3Smrg              ", Actual=false\n", test);
517ec681f3Smrg      error = true;
527ec681f3Smrg   }
537ec681f3Smrg}
547ec681f3Smrgstatic void
557ec681f3Smrgexpect_false(bool result, const char *test)
567ec681f3Smrg{
577ec681f3Smrg   if (result) {
587ec681f3Smrg      fprintf(stderr, "Error: Test '%s' failed: Expected=false"
597ec681f3Smrg              ", Actual=true\n", test);
607ec681f3Smrg      error = true;
617ec681f3Smrg   }
627ec681f3Smrg}
637ec681f3Smrg
647ec681f3Smrgstatic void
657ec681f3Smrgexpect_equal(uint64_t actual, uint64_t expected, const char *test)
667ec681f3Smrg{
677ec681f3Smrg   if (actual != expected) {
687ec681f3Smrg      fprintf(stderr, "Error: Test '%s' failed: Expected=%" PRIu64
697ec681f3Smrg              ", Actual=%" PRIu64 "\n",
707ec681f3Smrg              test, expected, actual);
717ec681f3Smrg      error = true;
727ec681f3Smrg   }
737ec681f3Smrg}
747ec681f3Smrg
757ec681f3Smrgstatic void
767ec681f3Smrgexpect_null(void *ptr, const char *test)
777ec681f3Smrg{
787ec681f3Smrg   if (ptr != NULL) {
797ec681f3Smrg      fprintf(stderr, "Error: Test '%s' failed: Result=%p, but expected NULL.\n",
807ec681f3Smrg              test, ptr);
817ec681f3Smrg      error = true;
827ec681f3Smrg   }
837ec681f3Smrg}
847ec681f3Smrg
857ec681f3Smrgstatic void
867ec681f3Smrgexpect_non_null(void *ptr, const char *test)
877ec681f3Smrg{
887ec681f3Smrg   if (ptr == NULL) {
897ec681f3Smrg      fprintf(stderr, "Error: Test '%s' failed: Result=NULL, but expected something else.\n",
907ec681f3Smrg              test);
917ec681f3Smrg      error = true;
927ec681f3Smrg   }
937ec681f3Smrg}
947ec681f3Smrg
957ec681f3Smrgstatic void
967ec681f3Smrgexpect_equal_str(const char *actual, const char *expected, const char *test)
977ec681f3Smrg{
987ec681f3Smrg   if (strcmp(actual, expected)) {
997ec681f3Smrg      fprintf(stderr, "Error: Test '%s' failed:\n\t"
1007ec681f3Smrg              "Expected=\"%s\", Actual=\"%s\"\n",
1017ec681f3Smrg              test, expected, actual);
1027ec681f3Smrg      error = true;
1037ec681f3Smrg   }
1047ec681f3Smrg}
1057ec681f3Smrg
1067ec681f3Smrg/* Callback for nftw used in rmrf_local below.
1077ec681f3Smrg */
1087ec681f3Smrgstatic int
1097ec681f3Smrgremove_entry(const char *path,
1107ec681f3Smrg             const struct stat *sb,
1117ec681f3Smrg             int typeflag,
1127ec681f3Smrg             struct FTW *ftwbuf)
1137ec681f3Smrg{
1147ec681f3Smrg   int err = remove(path);
1157ec681f3Smrg
1167ec681f3Smrg   if (err)
1177ec681f3Smrg      fprintf(stderr, "Error removing %s: %s\n", path, strerror(errno));
1187ec681f3Smrg
1197ec681f3Smrg   return err;
1207ec681f3Smrg}
1217ec681f3Smrg
1227ec681f3Smrg/* Recursively remove a directory.
1237ec681f3Smrg *
1247ec681f3Smrg * This is equivalent to "rm -rf <dir>" with one bit of protection
1257ec681f3Smrg * that the directory name must begin with "." to ensure we don't
1267ec681f3Smrg * wander around deleting more than intended.
1277ec681f3Smrg *
1287ec681f3Smrg * Returns 0 on success, -1 on any error.
1297ec681f3Smrg */
1307ec681f3Smrgstatic int
1317ec681f3Smrgrmrf_local(const char *path)
1327ec681f3Smrg{
1337ec681f3Smrg   if (path == NULL || *path == '\0' || *path != '.')
1347ec681f3Smrg      return -1;
1357ec681f3Smrg
1367ec681f3Smrg   return nftw(path, remove_entry, 64, FTW_DEPTH | FTW_PHYS);
1377ec681f3Smrg}
1387ec681f3Smrg
1397ec681f3Smrgstatic void
1407ec681f3Smrgcheck_directories_created(const char *cache_dir)
1417ec681f3Smrg{
1427ec681f3Smrg   bool sub_dirs_created = false;
1437ec681f3Smrg
1447ec681f3Smrg   char buf[PATH_MAX];
1457ec681f3Smrg   if (getcwd(buf, PATH_MAX)) {
1467ec681f3Smrg      char *full_path = NULL;
1477ec681f3Smrg      if (asprintf(&full_path, "%s%s", buf, ++cache_dir) != -1 ) {
1487ec681f3Smrg         struct stat sb;
1497ec681f3Smrg         if (stat(full_path, &sb) != -1 && S_ISDIR(sb.st_mode))
1507ec681f3Smrg            sub_dirs_created = true;
1517ec681f3Smrg
1527ec681f3Smrg         free(full_path);
1537ec681f3Smrg      }
1547ec681f3Smrg   }
1557ec681f3Smrg
1567ec681f3Smrg   expect_true(sub_dirs_created, "create sub dirs");
1577ec681f3Smrg}
1587ec681f3Smrg
1597ec681f3Smrgstatic bool
1607ec681f3Smrgdoes_cache_contain(struct disk_cache *cache, const cache_key key)
1617ec681f3Smrg{
1627ec681f3Smrg   void *result;
1637ec681f3Smrg
1647ec681f3Smrg   result = disk_cache_get(cache, key, NULL);
1657ec681f3Smrg
1667ec681f3Smrg   if (result) {
1677ec681f3Smrg      free(result);
1687ec681f3Smrg      return true;
1697ec681f3Smrg   }
1707ec681f3Smrg
1717ec681f3Smrg   return false;
1727ec681f3Smrg}
1737ec681f3Smrg
1747ec681f3Smrgstatic bool
1757ec681f3Smrgcache_exists(struct disk_cache *cache)
1767ec681f3Smrg{
1777ec681f3Smrg   uint8_t key[20];
1787ec681f3Smrg   char data[] = "some test data";
1797ec681f3Smrg
1807ec681f3Smrg   if (!cache)
1817ec681f3Smrg      return NULL;
1827ec681f3Smrg
1837ec681f3Smrg   disk_cache_compute_key(cache, data, sizeof(data), key);
1847ec681f3Smrg   disk_cache_put(cache, key, data, sizeof(data), NULL);
1857ec681f3Smrg   disk_cache_wait_for_idle(cache);
1867ec681f3Smrg   void *result = disk_cache_get(cache, key, NULL);
1877ec681f3Smrg
1887ec681f3Smrg   free(result);
1897ec681f3Smrg   return result != NULL;
1907ec681f3Smrg}
1917ec681f3Smrg
1927ec681f3Smrg#define CACHE_TEST_TMP "./cache-test-tmp"
1937ec681f3Smrg
1947ec681f3Smrgstatic void
1957ec681f3Smrgtest_disk_cache_create(const char *cache_dir_name)
1967ec681f3Smrg{
1977ec681f3Smrg   struct disk_cache *cache;
1987ec681f3Smrg   int err;
1997ec681f3Smrg
2007ec681f3Smrg   /* Before doing anything else, ensure that with
2017ec681f3Smrg    * MESA_GLSL_CACHE_DISABLE set to true, that disk_cache_create returns NULL.
2027ec681f3Smrg    */
2037ec681f3Smrg   setenv("MESA_GLSL_CACHE_DISABLE", "true", 1);
2047ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
2057ec681f3Smrg   expect_null(cache, "disk_cache_create with MESA_GLSL_CACHE_DISABLE set");
2067ec681f3Smrg
2077ec681f3Smrg   unsetenv("MESA_GLSL_CACHE_DISABLE");
2087ec681f3Smrg
2097ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
2107ec681f3Smrg   /* With SHADER_CACHE_DISABLE_BY_DEFAULT, ensure that with
2117ec681f3Smrg    * MESA_GLSL_CACHE_DISABLE set to nothing, disk_cache_create returns NULL.
2127ec681f3Smrg    */
2137ec681f3Smrg   unsetenv("MESA_GLSL_CACHE_DISABLE");
2147ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
2157ec681f3Smrg   expect_null(cache, "disk_cache_create with MESA_GLSL_CACHE_DISABLE unset "
2167ec681f3Smrg               " and SHADER_CACHE_DISABLE_BY_DEFAULT build option");
2177ec681f3Smrg
2187ec681f3Smrg   /* For remaining tests, ensure that the cache is enabled. */
2197ec681f3Smrg   setenv("MESA_GLSL_CACHE_DISABLE", "false", 1);
2207ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
2217ec681f3Smrg
2227ec681f3Smrg   /* For the first real disk_cache_create() clear these environment
2237ec681f3Smrg    * variables to test creation of cache in home directory.
2247ec681f3Smrg    */
2257ec681f3Smrg   unsetenv("MESA_GLSL_CACHE_DIR");
2267ec681f3Smrg   unsetenv("XDG_CACHE_HOME");
2277ec681f3Smrg
2287ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
2297ec681f3Smrg   expect_non_null(cache, "disk_cache_create with no environment variables");
2307ec681f3Smrg
2317ec681f3Smrg   disk_cache_destroy(cache);
2327ec681f3Smrg
2337ec681f3Smrg#ifdef ANDROID
2347ec681f3Smrg   /* Android doesn't try writing to disk (just calls the cache callbacks), so
2357ec681f3Smrg    * the directory tests below don't apply.
2367ec681f3Smrg    */
2377ec681f3Smrg   exit(error ? 1 : 0);
2387ec681f3Smrg#endif
2397ec681f3Smrg
2407ec681f3Smrg   /* Test with XDG_CACHE_HOME set */
2417ec681f3Smrg   setenv("XDG_CACHE_HOME", CACHE_TEST_TMP "/xdg-cache-home", 1);
2427ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
2437ec681f3Smrg   expect_false(cache_exists(cache), "disk_cache_create with XDG_CACHE_HOME set "
2447ec681f3Smrg                "with a non-existing parent directory");
2457ec681f3Smrg
2467ec681f3Smrg   err = mkdir(CACHE_TEST_TMP, 0755);
2477ec681f3Smrg   if (err != 0) {
2487ec681f3Smrg      fprintf(stderr, "Error creating %s: %s\n", CACHE_TEST_TMP, strerror(errno));
2497ec681f3Smrg      error = true;
2507ec681f3Smrg      return;
2517ec681f3Smrg   }
2527ec681f3Smrg   disk_cache_destroy(cache);
2537ec681f3Smrg
2547ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
2557ec681f3Smrg   expect_true(cache_exists(cache), "disk_cache_create with XDG_CACHE_HOME "
2567ec681f3Smrg               "set");
2577ec681f3Smrg
2587ec681f3Smrg   char *path;
2597ec681f3Smrg   asprintf(&path, "%s%s", CACHE_TEST_TMP "/xdg-cache-home/", cache_dir_name);
2607ec681f3Smrg   check_directories_created(path);
2617ec681f3Smrg   free(path);
2627ec681f3Smrg
2637ec681f3Smrg   disk_cache_destroy(cache);
2647ec681f3Smrg
2657ec681f3Smrg   /* Test with MESA_GLSL_CACHE_DIR set */
2667ec681f3Smrg   err = rmrf_local(CACHE_TEST_TMP);
2677ec681f3Smrg   expect_equal(err, 0, "Removing " CACHE_TEST_TMP);
2687ec681f3Smrg
2697ec681f3Smrg   setenv("MESA_GLSL_CACHE_DIR", CACHE_TEST_TMP "/mesa-glsl-cache-dir", 1);
2707ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
2717ec681f3Smrg   expect_false(cache_exists(cache), "disk_cache_create with MESA_GLSL_CACHE_DIR"
2727ec681f3Smrg                " set with a non-existing parent directory");
2737ec681f3Smrg
2747ec681f3Smrg   err = mkdir(CACHE_TEST_TMP, 0755);
2757ec681f3Smrg   if (err != 0) {
2767ec681f3Smrg      fprintf(stderr, "Error creating %s: %s\n", CACHE_TEST_TMP, strerror(errno));
2777ec681f3Smrg      error = true;
2787ec681f3Smrg      return;
2797ec681f3Smrg   }
2807ec681f3Smrg   disk_cache_destroy(cache);
2817ec681f3Smrg
2827ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
2837ec681f3Smrg   expect_true(cache_exists(cache), "disk_cache_create with "
2847ec681f3Smrg               "MESA_GLSL_CACHE_DIR set");
2857ec681f3Smrg
2867ec681f3Smrg   asprintf(&path, "%s%s", CACHE_TEST_TMP "/mesa-glsl-cache-dir/",
2877ec681f3Smrg            cache_dir_name);
2887ec681f3Smrg   check_directories_created(path);
2897ec681f3Smrg   free(path);
2907ec681f3Smrg
2917ec681f3Smrg   disk_cache_destroy(cache);
2927ec681f3Smrg}
2937ec681f3Smrg
2947ec681f3Smrgstatic void
2957ec681f3Smrgtest_put_and_get(bool test_cache_size_limit)
2967ec681f3Smrg{
2977ec681f3Smrg   struct disk_cache *cache;
2987ec681f3Smrg   char blob[] = "This is a blob of thirty-seven bytes";
2997ec681f3Smrg   uint8_t blob_key[20];
3007ec681f3Smrg   char string[] = "While this string has thirty-four";
3017ec681f3Smrg   uint8_t string_key[20];
3027ec681f3Smrg   char *result;
3037ec681f3Smrg   size_t size;
3047ec681f3Smrg   uint8_t *one_KB, *one_MB;
3057ec681f3Smrg   uint8_t one_KB_key[20], one_MB_key[20];
3067ec681f3Smrg   int count;
3077ec681f3Smrg
3087ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
3097ec681f3Smrg   setenv("MESA_GLSL_CACHE_DISABLE", "false", 1);
3107ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
3117ec681f3Smrg
3127ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
3137ec681f3Smrg
3147ec681f3Smrg   disk_cache_compute_key(cache, blob, sizeof(blob), blob_key);
3157ec681f3Smrg
3167ec681f3Smrg   /* Ensure that disk_cache_get returns nothing before anything is added. */
3177ec681f3Smrg   result = disk_cache_get(cache, blob_key, &size);
3187ec681f3Smrg   expect_null(result, "disk_cache_get with non-existent item (pointer)");
3197ec681f3Smrg   expect_equal(size, 0, "disk_cache_get with non-existent item (size)");
3207ec681f3Smrg
3217ec681f3Smrg   /* Simple test of put and get. */
3227ec681f3Smrg   disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL);
3237ec681f3Smrg
3247ec681f3Smrg   /* disk_cache_put() hands things off to a thread so wait for it. */
3257ec681f3Smrg   disk_cache_wait_for_idle(cache);
3267ec681f3Smrg
3277ec681f3Smrg   result = disk_cache_get(cache, blob_key, &size);
3287ec681f3Smrg   expect_equal_str(blob, result, "disk_cache_get of existing item (pointer)");
3297ec681f3Smrg   expect_equal(size, sizeof(blob), "disk_cache_get of existing item (size)");
3307ec681f3Smrg
3317ec681f3Smrg   free(result);
3327ec681f3Smrg
3337ec681f3Smrg   /* Test put and get of a second item. */
3347ec681f3Smrg   disk_cache_compute_key(cache, string, sizeof(string), string_key);
3357ec681f3Smrg   disk_cache_put(cache, string_key, string, sizeof(string), NULL);
3367ec681f3Smrg
3377ec681f3Smrg   /* disk_cache_put() hands things off to a thread so wait for it. */
3387ec681f3Smrg   disk_cache_wait_for_idle(cache);
3397ec681f3Smrg
3407ec681f3Smrg   result = disk_cache_get(cache, string_key, &size);
3417ec681f3Smrg   expect_equal_str(result, string, "2nd disk_cache_get of existing item (pointer)");
3427ec681f3Smrg   expect_equal(size, sizeof(string), "2nd disk_cache_get of existing item (size)");
3437ec681f3Smrg
3447ec681f3Smrg   free(result);
3457ec681f3Smrg
3467ec681f3Smrg   /* Set the cache size to 1KB and add a 1KB item to force an eviction. */
3477ec681f3Smrg   disk_cache_destroy(cache);
3487ec681f3Smrg
3497ec681f3Smrg   if (!test_cache_size_limit)
3507ec681f3Smrg      return;
3517ec681f3Smrg
3527ec681f3Smrg   setenv("MESA_GLSL_CACHE_MAX_SIZE", "1K", 1);
3537ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
3547ec681f3Smrg
3557ec681f3Smrg   one_KB = calloc(1, 1024);
3567ec681f3Smrg
3577ec681f3Smrg   /* Obviously the SHA-1 hash of 1024 zero bytes isn't particularly
3587ec681f3Smrg    * interesting. But we do have want to take some special care with
3597ec681f3Smrg    * the hash we use here. The issue is that in this artificial case,
3607ec681f3Smrg    * (with only three files in the cache), the probability is good
3617ec681f3Smrg    * that each of the three files will end up in their own
3627ec681f3Smrg    * directory. Then, if the directory containing the .tmp file for
3637ec681f3Smrg    * the new item being added for disk_cache_put() is the chosen victim
3647ec681f3Smrg    * directory for eviction, then no suitable file will be found and
3657ec681f3Smrg    * nothing will be evicted.
3667ec681f3Smrg    *
3677ec681f3Smrg    * That's actually expected given how the eviction code is
3687ec681f3Smrg    * implemented, (which expects to only evict once things are more
3697ec681f3Smrg    * interestingly full than that).
3707ec681f3Smrg    *
3717ec681f3Smrg    * For this test, we force this signature to land in the same
3727ec681f3Smrg    * directory as the original blob first written to the cache.
3737ec681f3Smrg    */
3747ec681f3Smrg   disk_cache_compute_key(cache, one_KB, 1024, one_KB_key);
3757ec681f3Smrg   one_KB_key[0] = blob_key[0];
3767ec681f3Smrg
3777ec681f3Smrg   disk_cache_put(cache, one_KB_key, one_KB, 1024, NULL);
3787ec681f3Smrg
3797ec681f3Smrg   free(one_KB);
3807ec681f3Smrg
3817ec681f3Smrg   /* disk_cache_put() hands things off to a thread so wait for it. */
3827ec681f3Smrg   disk_cache_wait_for_idle(cache);
3837ec681f3Smrg
3847ec681f3Smrg   result = disk_cache_get(cache, one_KB_key, &size);
3857ec681f3Smrg   expect_non_null(result, "3rd disk_cache_get of existing item (pointer)");
3867ec681f3Smrg   expect_equal(size, 1024, "3rd disk_cache_get of existing item (size)");
3877ec681f3Smrg
3887ec681f3Smrg   free(result);
3897ec681f3Smrg
3907ec681f3Smrg   /* Ensure eviction happened by checking that both of the previous
3917ec681f3Smrg    * cache itesm were evicted.
3927ec681f3Smrg    */
3937ec681f3Smrg   bool contains_1KB_file = false;
3947ec681f3Smrg   count = 0;
3957ec681f3Smrg   if (does_cache_contain(cache, blob_key))
3967ec681f3Smrg       count++;
3977ec681f3Smrg
3987ec681f3Smrg   if (does_cache_contain(cache, string_key))
3997ec681f3Smrg       count++;
4007ec681f3Smrg
4017ec681f3Smrg   if (does_cache_contain(cache, one_KB_key)) {
4027ec681f3Smrg      count++;
4037ec681f3Smrg      contains_1KB_file = true;
4047ec681f3Smrg   }
4057ec681f3Smrg
4067ec681f3Smrg   expect_true(contains_1KB_file,
4077ec681f3Smrg               "disk_cache_put eviction last file == MAX_SIZE (1KB)");
4087ec681f3Smrg   expect_equal(count, 1, "disk_cache_put eviction with MAX_SIZE=1K");
4097ec681f3Smrg
4107ec681f3Smrg   /* Now increase the size to 1M, add back both items, and ensure all
4117ec681f3Smrg    * three that have been added are available via disk_cache_get.
4127ec681f3Smrg    */
4137ec681f3Smrg   disk_cache_destroy(cache);
4147ec681f3Smrg
4157ec681f3Smrg   setenv("MESA_GLSL_CACHE_MAX_SIZE", "1M", 1);
4167ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
4177ec681f3Smrg
4187ec681f3Smrg   disk_cache_put(cache, blob_key, blob, sizeof(blob), NULL);
4197ec681f3Smrg   disk_cache_put(cache, string_key, string, sizeof(string), NULL);
4207ec681f3Smrg
4217ec681f3Smrg   /* disk_cache_put() hands things off to a thread so wait for it. */
4227ec681f3Smrg   disk_cache_wait_for_idle(cache);
4237ec681f3Smrg
4247ec681f3Smrg   count = 0;
4257ec681f3Smrg   if (does_cache_contain(cache, blob_key))
4267ec681f3Smrg       count++;
4277ec681f3Smrg
4287ec681f3Smrg   if (does_cache_contain(cache, string_key))
4297ec681f3Smrg       count++;
4307ec681f3Smrg
4317ec681f3Smrg   if (does_cache_contain(cache, one_KB_key))
4327ec681f3Smrg       count++;
4337ec681f3Smrg
4347ec681f3Smrg   expect_equal(count, 3, "no eviction before overflow with MAX_SIZE=1M");
4357ec681f3Smrg
4367ec681f3Smrg   /* Finally, check eviction again after adding an object of size 1M. */
4377ec681f3Smrg   one_MB = calloc(1024, 1024);
4387ec681f3Smrg
4397ec681f3Smrg   disk_cache_compute_key(cache, one_MB, 1024 * 1024, one_MB_key);
4407ec681f3Smrg   one_MB_key[0] = blob_key[0];
4417ec681f3Smrg
4427ec681f3Smrg   disk_cache_put(cache, one_MB_key, one_MB, 1024 * 1024, NULL);
4437ec681f3Smrg
4447ec681f3Smrg   free(one_MB);
4457ec681f3Smrg
4467ec681f3Smrg   /* disk_cache_put() hands things off to a thread so wait for it. */
4477ec681f3Smrg   disk_cache_wait_for_idle(cache);
4487ec681f3Smrg
4497ec681f3Smrg   bool contains_1MB_file = false;
4507ec681f3Smrg   count = 0;
4517ec681f3Smrg   if (does_cache_contain(cache, blob_key))
4527ec681f3Smrg       count++;
4537ec681f3Smrg
4547ec681f3Smrg   if (does_cache_contain(cache, string_key))
4557ec681f3Smrg       count++;
4567ec681f3Smrg
4577ec681f3Smrg   if (does_cache_contain(cache, one_KB_key))
4587ec681f3Smrg       count++;
4597ec681f3Smrg
4607ec681f3Smrg   if (does_cache_contain(cache, one_MB_key)) {
4617ec681f3Smrg      count++;
4627ec681f3Smrg      contains_1MB_file = true;
4637ec681f3Smrg   }
4647ec681f3Smrg
4657ec681f3Smrg   expect_true(contains_1MB_file,
4667ec681f3Smrg               "disk_cache_put eviction last file == MAX_SIZE (1MB)");
4677ec681f3Smrg   expect_equal(count, 1, "eviction after overflow with MAX_SIZE=1M");
4687ec681f3Smrg
4697ec681f3Smrg   disk_cache_destroy(cache);
4707ec681f3Smrg}
4717ec681f3Smrg
4727ec681f3Smrgstatic void
4737ec681f3Smrgtest_put_key_and_get_key(void)
4747ec681f3Smrg{
4757ec681f3Smrg   struct disk_cache *cache;
4767ec681f3Smrg   bool result;
4777ec681f3Smrg
4787ec681f3Smrg   uint8_t key_a[20] = {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
4797ec681f3Smrg                         10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
4807ec681f3Smrg   uint8_t key_b[20] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
4817ec681f3Smrg                         30, 33, 32, 33, 34, 35, 36, 37, 38, 39};
4827ec681f3Smrg   uint8_t key_a_collide[20] =
4837ec681f3Smrg                        { 0,  1, 42, 43, 44, 45, 46, 47, 48, 49,
4847ec681f3Smrg                         50, 55, 52, 53, 54, 55, 56, 57, 58, 59};
4857ec681f3Smrg
4867ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
4877ec681f3Smrg   setenv("MESA_GLSL_CACHE_DISABLE", "false", 1);
4887ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
4897ec681f3Smrg
4907ec681f3Smrg   cache = disk_cache_create("test", "make_check", 0);
4917ec681f3Smrg
4927ec681f3Smrg   /* First test that disk_cache_has_key returns false before disk_cache_put_key */
4937ec681f3Smrg   result = disk_cache_has_key(cache, key_a);
4947ec681f3Smrg   expect_equal(result, 0, "disk_cache_has_key before key added");
4957ec681f3Smrg
4967ec681f3Smrg   /* Then a couple of tests of disk_cache_put_key followed by disk_cache_has_key */
4977ec681f3Smrg   disk_cache_put_key(cache, key_a);
4987ec681f3Smrg   result = disk_cache_has_key(cache, key_a);
4997ec681f3Smrg   expect_equal(result, 1, "disk_cache_has_key after key added");
5007ec681f3Smrg
5017ec681f3Smrg   disk_cache_put_key(cache, key_b);
5027ec681f3Smrg   result = disk_cache_has_key(cache, key_b);
5037ec681f3Smrg   expect_equal(result, 1, "2nd disk_cache_has_key after key added");
5047ec681f3Smrg
5057ec681f3Smrg   /* Test that a key with the same two bytes as an existing key
5067ec681f3Smrg    * forces an eviction.
5077ec681f3Smrg    */
5087ec681f3Smrg   disk_cache_put_key(cache, key_a_collide);
5097ec681f3Smrg   result = disk_cache_has_key(cache, key_a_collide);
5107ec681f3Smrg   expect_equal(result, 1, "put_key of a colliding key lands in the cache");
5117ec681f3Smrg
5127ec681f3Smrg   result = disk_cache_has_key(cache, key_a);
5137ec681f3Smrg   expect_equal(result, 0, "put_key of a colliding key evicts from the cache");
5147ec681f3Smrg
5157ec681f3Smrg   /* And finally test that we can re-add the original key to re-evict
5167ec681f3Smrg    * the colliding key.
5177ec681f3Smrg    */
5187ec681f3Smrg   disk_cache_put_key(cache, key_a);
5197ec681f3Smrg   result = disk_cache_has_key(cache, key_a);
5207ec681f3Smrg   expect_equal(result, 1, "put_key of original key lands again");
5217ec681f3Smrg
5227ec681f3Smrg   result = disk_cache_has_key(cache, key_a_collide);
5237ec681f3Smrg   expect_equal(result, 0, "put_key of orginal key evicts the colliding key");
5247ec681f3Smrg
5257ec681f3Smrg   disk_cache_destroy(cache);
5267ec681f3Smrg}
5277ec681f3Smrg
5287ec681f3Smrg/* To make sure we are not just using the inmemory cache index for the single
5297ec681f3Smrg * file cache we test adding and retriving cache items between two different
5307ec681f3Smrg * cache instances.
5317ec681f3Smrg */
5327ec681f3Smrgstatic void
5337ec681f3Smrgtest_put_and_get_between_instances()
5347ec681f3Smrg{
5357ec681f3Smrg   char blob[] = "This is a blob of thirty-seven bytes";
5367ec681f3Smrg   uint8_t blob_key[20];
5377ec681f3Smrg   char string[] = "While this string has thirty-four";
5387ec681f3Smrg   uint8_t string_key[20];
5397ec681f3Smrg   char *result;
5407ec681f3Smrg   size_t size;
5417ec681f3Smrg
5427ec681f3Smrg#ifdef SHADER_CACHE_DISABLE_BY_DEFAULT
5437ec681f3Smrg   setenv("MESA_GLSL_CACHE_DISABLE", "false", 1);
5447ec681f3Smrg#endif /* SHADER_CACHE_DISABLE_BY_DEFAULT */
5457ec681f3Smrg
5467ec681f3Smrg   struct disk_cache *cache1 = disk_cache_create("test_between_instances",
5477ec681f3Smrg                                                 "make_check", 0);
5487ec681f3Smrg   struct disk_cache *cache2 = disk_cache_create("test_between_instances",
5497ec681f3Smrg                                                 "make_check", 0);
5507ec681f3Smrg
5517ec681f3Smrg   disk_cache_compute_key(cache1, blob, sizeof(blob), blob_key);
5527ec681f3Smrg
5537ec681f3Smrg   /* Ensure that disk_cache_get returns nothing before anything is added. */
5547ec681f3Smrg   result = disk_cache_get(cache1, blob_key, &size);
5557ec681f3Smrg   expect_null(result, "disk_cache_get(cache1) with non-existent item (pointer)");
5567ec681f3Smrg   expect_equal(size, 0, "disk_cache_get(cach1) with non-existent item (size)");
5577ec681f3Smrg
5587ec681f3Smrg   result = disk_cache_get(cache2, blob_key, &size);
5597ec681f3Smrg   expect_null(result, "disk_cache_get(cache2) with non-existent item (pointer)");
5607ec681f3Smrg   expect_equal(size, 0, "disk_cache_get(cache2) with non-existent item (size)");
5617ec681f3Smrg
5627ec681f3Smrg   /* Simple test of put and get. */
5637ec681f3Smrg   disk_cache_put(cache1, blob_key, blob, sizeof(blob), NULL);
5647ec681f3Smrg
5657ec681f3Smrg   /* disk_cache_put() hands things off to a thread so wait for it. */
5667ec681f3Smrg   disk_cache_wait_for_idle(cache1);
5677ec681f3Smrg
5687ec681f3Smrg   result = disk_cache_get(cache2, blob_key, &size);
5697ec681f3Smrg   expect_equal_str(blob, result, "disk_cache_get(cache2) of existing item (pointer)");
5707ec681f3Smrg   expect_equal(size, sizeof(blob), "disk_cache_get of(cache2) existing item (size)");
5717ec681f3Smrg
5727ec681f3Smrg   free(result);
5737ec681f3Smrg
5747ec681f3Smrg   /* Test put and get of a second item, via the opposite instances */
5757ec681f3Smrg   disk_cache_compute_key(cache2, string, sizeof(string), string_key);
5767ec681f3Smrg   disk_cache_put(cache2, string_key, string, sizeof(string), NULL);
5777ec681f3Smrg
5787ec681f3Smrg   /* disk_cache_put() hands things off to a thread so wait for it. */
5797ec681f3Smrg   disk_cache_wait_for_idle(cache2);
5807ec681f3Smrg
5817ec681f3Smrg   result = disk_cache_get(cache1, string_key, &size);
5827ec681f3Smrg   expect_equal_str(result, string, "2nd disk_cache_get(cache1) of existing item (pointer)");
5837ec681f3Smrg   expect_equal(size, sizeof(string), "2nd disk_cache_get(cache1) of existing item (size)");
5847ec681f3Smrg
5857ec681f3Smrg   free(result);
5867ec681f3Smrg
5877ec681f3Smrg   disk_cache_destroy(cache1);
5887ec681f3Smrg   disk_cache_destroy(cache2);
5897ec681f3Smrg}
5907ec681f3Smrg#endif /* ENABLE_SHADER_CACHE */
5917ec681f3Smrg
5927ec681f3Smrgstatic void
5937ec681f3Smrgtest_multi_file_cache(void)
5947ec681f3Smrg{
5957ec681f3Smrg   int err;
5967ec681f3Smrg
5977ec681f3Smrg   printf("Test multi file disk cache - Start\n");
5987ec681f3Smrg
5997ec681f3Smrg   test_disk_cache_create(CACHE_DIR_NAME);
6007ec681f3Smrg
6017ec681f3Smrg   test_put_and_get(true);
6027ec681f3Smrg
6037ec681f3Smrg   test_put_key_and_get_key();
6047ec681f3Smrg
6057ec681f3Smrg   printf("Test multi file disk cache - End\n");
6067ec681f3Smrg
6077ec681f3Smrg   err = rmrf_local(CACHE_TEST_TMP);
6087ec681f3Smrg   expect_equal(err, 0, "Removing " CACHE_TEST_TMP " again");
6097ec681f3Smrg}
6107ec681f3Smrg
6117ec681f3Smrgstatic void
6127ec681f3Smrgtest_single_file_cache(void)
6137ec681f3Smrg{
6147ec681f3Smrg   int err;
6157ec681f3Smrg
6167ec681f3Smrg   printf("Test single file disk cache - Start\n");
6177ec681f3Smrg
6187ec681f3Smrg   setenv("MESA_DISK_CACHE_SINGLE_FILE", "true", 1);
6197ec681f3Smrg
6207ec681f3Smrg   test_disk_cache_create(CACHE_DIR_NAME_SF);
6217ec681f3Smrg
6227ec681f3Smrg   /* We skip testing cache size limit as the single file cache currently
6237ec681f3Smrg    * doesn't have any functionality to enforce cache size limits.
6247ec681f3Smrg    */
6257ec681f3Smrg   test_put_and_get(false);
6267ec681f3Smrg
6277ec681f3Smrg   test_put_key_and_get_key();
6287ec681f3Smrg
6297ec681f3Smrg   test_put_and_get_between_instances();
6307ec681f3Smrg
6317ec681f3Smrg   setenv("MESA_DISK_CACHE_SINGLE_FILE", "false", 1);
6327ec681f3Smrg
6337ec681f3Smrg   printf("Test single file disk cache - End\n");
6347ec681f3Smrg
6357ec681f3Smrg   err = rmrf_local(CACHE_TEST_TMP);
6367ec681f3Smrg   expect_equal(err, 0, "Removing " CACHE_TEST_TMP " again");
6377ec681f3Smrg}
6387ec681f3Smrg
6397ec681f3Smrgint
6407ec681f3Smrgmain(void)
6417ec681f3Smrg{
6427ec681f3Smrg#ifdef ENABLE_SHADER_CACHE
6437ec681f3Smrg
6447ec681f3Smrg   test_multi_file_cache();
6457ec681f3Smrg
6467ec681f3Smrg   test_single_file_cache();
6477ec681f3Smrg
6487ec681f3Smrg#endif /* ENABLE_SHADER_CACHE */
6497ec681f3Smrg
6507ec681f3Smrg   return error ? 1 : 0;
6517ec681f3Smrg}
652