From 7c02323bf48c6071572ac8fd427854b7fc57be36 Mon Sep 17 00:00:00 2001 From: Jamey Greenwood Date: Mon, 19 Jan 2026 21:14:27 +0000 Subject: [PATCH] test: add CSSCache unit tests and benchmarks Tests cover: - get/0, put/1, invalidate/0, warm/0 functions - Performance benchmark comparing cache hit vs CSS generation - 100 cache hit consistency test Run with: mix test test/simpleshop_theme/theme/css_cache_test.exs --include benchmark Co-Authored-By: Claude Opus 4.5 --- .../simpleshop_theme/theme/css_cache_test.exs | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 test/simpleshop_theme/theme/css_cache_test.exs diff --git a/test/simpleshop_theme/theme/css_cache_test.exs b/test/simpleshop_theme/theme/css_cache_test.exs new file mode 100644 index 0000000..9e1a6d5 --- /dev/null +++ b/test/simpleshop_theme/theme/css_cache_test.exs @@ -0,0 +1,109 @@ +defmodule SimpleshopTheme.Theme.CSSCacheTest do + use SimpleshopTheme.DataCase + + alias SimpleshopTheme.Theme.CSSCache + alias SimpleshopTheme.Theme.CSSGenerator + alias SimpleshopTheme.Settings.ThemeSettings + + describe "get/0" do + test "returns cached CSS after warm" do + # Cache should be pre-warmed on startup + assert {:ok, css} = CSSCache.get() + assert is_binary(css) + assert css =~ ".themed {" + end + end + + describe "put/1 and get/0" do + test "stores and retrieves CSS" do + test_css = "/* test css */" + :ok = CSSCache.put(test_css) + + assert {:ok, ^test_css} = CSSCache.get() + + # Restore original cache + CSSCache.warm() + end + end + + describe "invalidate/0" do + test "clears cached CSS" do + # Ensure cache has something + CSSCache.warm() + assert {:ok, _} = CSSCache.get() + + # Invalidate + :ok = CSSCache.invalidate() + assert :miss = CSSCache.get() + + # Restore + CSSCache.warm() + end + end + + describe "warm/0" do + test "populates cache from current settings" do + CSSCache.invalidate() + assert :miss = CSSCache.get() + + :ok = CSSCache.warm() + assert {:ok, css} = CSSCache.get() + assert is_binary(css) + end + end + + describe "performance" do + @tag :benchmark + test "cache hit is faster than generation" do + # Ensure cache is warm + CSSCache.warm() + settings = %ThemeSettings{} + + # Benchmark cache hit (should be microseconds) + {cache_time, {:ok, _cached_css}} = + :timer.tc(fn -> + CSSCache.get() + end) + + # Benchmark CSS generation (should be milliseconds) + {gen_time, _generated_css} = + :timer.tc(fn -> + CSSGenerator.generate(settings) + end) + + # Log results for visibility + IO.puts("\n") + IO.puts(" Cache hit: #{cache_time} µs") + IO.puts(" CSS generate: #{gen_time} µs") + IO.puts(" Speedup: #{Float.round(gen_time / max(cache_time, 1), 1)}x faster") + + # Cache should be faster than generation + assert cache_time < gen_time, + "Cache (#{cache_time}µs) should be faster than generation (#{gen_time}µs)" + end + + @tag :benchmark + test "multiple cache hits are consistent" do + CSSCache.warm() + + times = + for _ <- 1..100 do + {time, {:ok, _}} = :timer.tc(fn -> CSSCache.get() end) + time + end + + avg = Enum.sum(times) / length(times) + max_time = Enum.max(times) + min_time = Enum.min(times) + + IO.puts("\n") + IO.puts(" 100 cache hits:") + IO.puts(" Avg: #{Float.round(avg, 1)} µs") + IO.puts(" Min: #{min_time} µs") + IO.puts(" Max: #{max_time} µs") + + # Average should be under 100 microseconds (ETS is fast) + assert avg < 100, "Average cache hit (#{avg}µs) should be under 100µs" + end + end +end