diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..bb09258 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], + line_length: 120 +] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..cb87d8a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + test: + runs-on: ubuntu-latest + env: + MIX_ENV: test + steps: + - uses: actions/checkout@v5 + + # Elixir/Erlang versions are read from .tool-versions + - uses: erlef/setup-beam@v1 + with: + version-file: .tool-versions + version-type: strict + + - uses: actions/cache@v4 + with: + path: | + deps + _build + key: ${{ runner.os }}-mix-${{ hashFiles('.tool-versions', 'mix.lock') }} + restore-keys: ${{ runner.os }}-mix- + + - run: mix deps.get + + - run: mix compile --warnings-as-errors + + - run: mix test diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..9b616b7 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +elixir 1.20.2 +erlang 29.0 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2cf95d7..0000000 --- a/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: elixir -elixir: - - 1.6.6 - - 1.7.1 -otp_release: - - 20.2 - - 21.0 -script: MIX_ENV=test mix compile --warnings-as-errors && MIX_ENV=test mix test diff --git a/README.md b/README.md index 36c5c3e..b6d5fde 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # CompilerCache -[![Build Status](https://travis-ci.org/arjan/decorator.png?branch=master)](https://travis-ci.org/arjan/compiler_cache) +[![CI](https://github.com/arjan/compiler_cache/actions/workflows/ci.yml/badge.svg)](https://github.com/arjan/compiler_cache/actions/workflows/ci.yml) [![Hex pm](http://img.shields.io/hexpm/v/compiler_cache.svg?style=flat)](https://hex.pm/packages/compiler_cache) @@ -34,7 +34,7 @@ The `create_ast/2` function must return an `{ast, opts}` tuple. The opts are the This cache can then be called like this: ```elixir -{:ok, _} = MyExpressionCache.start_link() +{:ok, _} = MyExpressionCache.start_link([]) iex> MyExpressionCache.execute("1 + 1", nil) 2 iex> MyExpressionCache.execute("2 * input", 3) diff --git a/VERSION b/VERSION index cb174d5..227cea2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.1 \ No newline at end of file +2.0.0 diff --git a/config/config.exs b/config/config.exs index d2d855e..becde76 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1 +1 @@ -use Mix.Config +import Config diff --git a/lib/compiler_cache.ex b/lib/compiler_cache.ex index b666dd1..053c43a 100644 --- a/lib/compiler_cache.ex +++ b/lib/compiler_cache.ex @@ -57,7 +57,7 @@ defmodule CompilerCache do @doc """ Start the given compiler cache """ - @callback start_link() :: GenServer.on_start + @callback start_link([]) :: GenServer.on_start() @doc """ Create the Abstract Syntax Tree and the execution context for the given expression. @@ -65,7 +65,6 @@ defmodule CompilerCache do @callback create_ast(expression :: any) :: {ast :: term(), opts :: list(term())} use GenServer - require Logger @doc false def start_link(mod_def) do @@ -78,7 +77,8 @@ defmodule CompilerCache do # check if we have a ETS table hit case :ets.lookup(mod_def.cache_table, key) do - [] -> # insert the ETS row + # insert the ETS row + [] -> if increase_hit_count(mod_def, key) do # ping the module to compile it when we reach the compilation limit GenServer.cast(mod_def.module, {:compile, key, expression}) @@ -87,7 +87,7 @@ defmodule CompilerCache do try do eval_quoted(mod_def, expression, input) rescue - error -> mod_def.module.handle_error(error, System.stacktrace()) + error -> mod_def.module.handle_error(error, __STACKTRACE__) end [{^key, compiled_module, ttl}] -> @@ -95,7 +95,6 @@ defmodule CompilerCache do GenServer.cast(mod_def.module, {:cache_hit, key, compiled_module, ttl}) # return fn compiled_module.eval(input) - end end @@ -107,13 +106,15 @@ defmodule CompilerCache do case mod_def.cache_misses do :none -> false + cache_misses -> case :ets.lookup(mod_def.hit_ctr_table, key) do [] -> :ets.insert(mod_def.hit_ctr_table, {key, 1}) cache_misses < 1 + [{^key, ctr}] -> - :ets.update_element(mod_def.hit_ctr_table, key, {2, ctr+1}) + :ets.update_element(mod_def.hit_ctr_table, key, {2, ctr + 1}) cache_misses == ctr end end @@ -121,20 +122,47 @@ defmodule CompilerCache do defp eval_quoted(mod_def = %{module: module}, expression, input) do try do - {ast, meta} = module.create_ast(expression) - {result, _} = Code.eval_quoted(ast, [{mod_def.input_name, input}], meta) + {ast, context} = module.create_ast(expression) + {result, _} = Code.eval_quoted(context_block(context, ast), [{mod_def.input_name, input}], eval_opts(context)) result rescue e -> - module.handle_error(e, System.stacktrace()) + module.handle_error(e, __STACKTRACE__) end end + @context_keys [:functions, :macros, :requires] + + defp eval_opts(context), do: Enum.reject(context || [], fn {key, _} -> key in @context_keys end) + + defp context_block(context, ast) do + case context_prelude(context) do + [] -> ast + prelude -> quote do: (unquote_splicing(prelude ++ [ast])) + end + end + + defp context_prelude(context) do + context = context || [] + + requires = + for mod <- context[:requires] || [] do + quote do: require(unquote(mod)) + end + + imports = + for {mod, fns} <- context_sort(context) do + quote do: import(unquote(mod), only: unquote(fns)) + end + + requires ++ imports + end + ## defmodule State do @moduledoc false - defstruct def: nil, atom_table: nil, compiling: MapSet.new, waiters: [] + defstruct def: nil, atom_table: nil, compiling: MapSet.new(), waiters: [] end def init(mod_def) do @@ -146,20 +174,24 @@ defmodule CompilerCache do # Create an atom table and fill it atom_table = :ets.new(:compiler_cache_atom_table, []) + for n <- 1..mod_def.max_size do atom = Module.concat(mod_def.module, "Cache#{n}") :ets.insert(atom_table, {atom}) end + :timer.send_interval(1000, :ttl_check) {:ok, %State{def: mod_def, atom_table: atom_table}} end - def handle_cast({:cache_hit, key, mod_name, old_ttl}, state) do + def handle_cast({:cache_hit, key, mod_name, old_ttl}, %State{} = state) do case :ets.lookup(state.def.ttl_table, old_ttl) do - [] -> # ignore + # ignore + [] -> :ok + [{^old_ttl, _, _}] -> - ttl = :erlang.monotonic_time + ttl = :erlang.monotonic_time() # update TTL in cache table :ets.update_element(state.def.cache_table, key, {@ttl_pos, ttl}) @@ -170,38 +202,37 @@ defmodule CompilerCache do # add new entry in TTL table :ets.insert(state.def.ttl_table, {ttl, key, mod_name}) end + {:noreply, state} end - def handle_cast({:compile, key, expression}, state) do - if not Enum.member?(state.compiling, key) do - case get_atom(state) do - {:ok, mod_name} -> - parent = self() - spawn_link(fn -> - try do - mod_compile(mod_name, key, expression, state) - rescue - _ -> - # Errors are logged in the synchronous (eval_quoted) flow - :ok - after - send(parent, {:compile_done, key}) - end - end) - {:noreply, %State{state | compiling: MapSet.put(state.compiling, key)}} - {:error, :empty} -> - {:ok, _, _} = purge(state) - handle_cast({:compile, key, expression}, state) - end + def handle_cast({:compile, key, expression}, %State{} = state) do + with false <- Enum.member?(state.compiling, key), + {:ok, mod_name} <- get_atom(state) do + parent = self() + + spawn_link(fn -> + try do + mod_compile(mod_name, key, expression, state) + rescue + _ -> + # Errors are logged in the synchronous (eval_quoted) flow + :ok + after + send(parent, {:compile_done, key}) + end + end) + + {:noreply, %State{state | compiling: MapSet.put(state.compiling, key)}} else - # we are already compiling - {:noreply, state} + _ -> + # we are already compiling + {:noreply, state} end end # used in the tests to let the test process wait for the module to be compiled. - def handle_call(:wait_for_completion, from, state) do + def handle_call(:wait_for_completion, from, %State{} = state) do if Enum.count(state.compiling) > 0 do {:noreply, %{state | waiters: [from | state.waiters]}} else @@ -214,14 +245,16 @@ defmodule CompilerCache do oldest_ttl = :ets.first(state.def.ttl_table) purge_loop(oldest_ttl, state) end + {:noreply, state} end - def handle_info({:compile_done, key}, state) do + def handle_info({:compile_done, key}, %State{} = state) do state = %State{state | compiling: MapSet.delete(state.compiling, key)} + if Enum.count(state.compiling) == 0 and Enum.count(state.waiters) > 0 do stats = stats(state) - Enum.map(state.waiters, fn(f) -> GenServer.reply(f, stats) end) + Enum.map(state.waiters, fn f -> GenServer.reply(f, stats) end) {:noreply, %State{state | waiters: []}} else {:noreply, state} @@ -229,8 +262,10 @@ defmodule CompilerCache do end defp purge_loop(:"$end_of_table", _state), do: :ok + defp purge_loop(ttl, state) do - delta = div((:erlang.monotonic_time - ttl), 1_000_000) + delta = div(:erlang.monotonic_time() - ttl, 1_000_000) + if delta > state.def.max_ttl do {:ok, _mod_name, ttl} = purge(ttl, state) purge_loop(ttl, state) @@ -244,7 +279,7 @@ defmodule CompilerCache do ttl_size: :ets.info(state.def.ttl_table, :size), hit_ctr_size: :ets.info(state.def.hit_ctr_table, :size), oldest_ttl: :ets.first(state.def.ttl_table), - loaded_modules: Enum.count(:code.all_loaded) + loaded_modules: Enum.count(:code.all_loaded()) } end @@ -253,34 +288,31 @@ defmodule CompilerCache do end defp mod_compile(mod_name, key, expression, state) do - {expression_ast, context} = state.def.module.create_ast(expression) - imports = context - |> context_sort() - |> Enum.map(fn({mod, fns}) -> - quote do import unquote(mod), only: unquote(fns) end - end) + prelude = context_prelude(context) vars = Macro.var(state.def.input_name, nil) - code = quote do - unquote_splicing(imports) - def eval(unquote(vars)) do - _ = unquote(vars) # prevent compilation warning about unused variable 'input' - unquote(expression_ast) - end - end + code = + quote do + unquote_splicing(prelude) + def eval(unquote(vars)) do + # prevent compilation warning about unused variable 'input' + _ = unquote(vars) + unquote(expression_ast) + end + end - {:module, ^mod_name, _, _} = Module.create(mod_name, code, [file: "#{inspect(expression)}", line: 1]) + {:module, ^mod_name, _, _} = Module.create(mod_name, code, file: "#{inspect(expression)}", line: 1) # Remove from hit counter table if :ets.lookup(state.def.hit_ctr_table, key) != [] do :ets.delete(state.def.hit_ctr_table, key) end - ttl = :erlang.monotonic_time + ttl = :erlang.monotonic_time() # Put it in the cache table :ets.insert(state.def.cache_table, {key, mod_name, ttl}) # And in the TTL table @@ -291,10 +323,11 @@ defmodule CompilerCache do # Get a new atom from the atom table; if there is no room, purge a compiled module. defp get_atom(state) do - case :ets.select(state.atom_table,[{{:"$1"},[],[:"$1"]}],1) do + case :ets.select(state.atom_table, [{{:"$1"}, [], [:"$1"]}], 1) do {[mod_name], _} -> true = :ets.delete(state.atom_table, mod_name) {:ok, mod_name} + :"$end_of_table" -> {:ok, mod_name, _ttl} = purge(state) true = :ets.delete(state.atom_table, mod_name) @@ -321,16 +354,15 @@ defmodule CompilerCache do {:ok, mod_name, next_ttl} end - @default_input_name :input @default_max_size 10000 @default_cache_misses 1 @default_max_ttl 1000 defmacro __using__(opts) do - quote do alias CompilerCache + use GenServer @mod_def %{ module: __MODULE__, @@ -350,10 +382,14 @@ defmodule CompilerCache do Start your compiler_cache-backed compiler process. The cache process is registered under the name of the module. """ - def start_link() do + def start_link([]) do CompilerCache.start_link(@mod_def) end + def init(mod_def) do + {:ok, mod_def} + end + def execute(expression, input) do CompilerCache.execute(@mod_def, expression, input) end @@ -366,9 +402,7 @@ defmodule CompilerCache do reraise error, stacktrace end - defoverridable [handle_error: 2] - + defoverridable handle_error: 2 end end - end diff --git a/mix.exs b/mix.exs index cf665e1..bd5cf03 100644 --- a/mix.exs +++ b/mix.exs @@ -4,8 +4,8 @@ defmodule CompilerCache.Mixfile do def project do [ app: :compiler_cache, - version: File.read!("VERSION"), - elixir: "~> 1.3", + version: File.read!("VERSION") |> String.trim(), + elixir: "~> 1.16", description: description(), package: package(), source_url: "https://github.com/arjan/compiler_cache", @@ -30,7 +30,7 @@ defmodule CompilerCache.Mixfile do end def application do - [applications: [:logger]] + [extra_applications: [:logger, :crypto]] end defp deps do diff --git a/mix.lock b/mix.lock index 9744824..e7a111d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,2 +1,9 @@ -%{"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], []}, - "ex_doc": {:hex, :ex_doc, "0.14.4", "a0a79a6896075814f4bc6802b74ccbed6549f47cc5ab34c71eaee2303170b8ef", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]}} +%{ + "earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], [], "hexpm", "0fdcd651f9689e81cda24c8e5d06947c5aca69dbd8ce3d836b02bcd0c6004592"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.46", "67607a0532e810c6f630a515c548d0b24949643f168cc556303bee4cf96105c7", [:mix], [], "hexpm", "9c44636e8a1c68c62f526b2dcd85d941dbbcee7ab82cf64ba06ce28bef8e89f5"}, + "ex_doc": {:hex, :ex_doc, "0.40.3", "4a972ffe64bc07dc605af487e98fc19b72a4185f55ca031b94c0552d6071c1d9", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2756e357742fecd9749b489b85d67c9ce99c465f2e75728d9e6dc8d704b973de"}, + "makeup": {:hex, :makeup, "1.2.2", "882d46dc0905e9ff7abf2aab61a7e6b3dcc555533977d8a23b06019e6c89ac94", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "9a1a24e5b343b8ae16abea0822c10a6f75da27af7fa802ada5251f7579bfccfa"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.1.0", "835f7e60792e08824cda445639555d7bf1bbbddb1b60b306e33cb6f6db24dc74", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "1cd6780fb1dd1a03979abaed0fe82712b0625118fd5257d3ebbf73f960c73c3c"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"}, +} diff --git a/test/compiler_cache/bench_test.exs b/test/compiler_cache/bench_test.exs index 8af45c7..8dce039 100644 --- a/test/compiler_cache/bench_test.exs +++ b/test/compiler_cache/bench_test.exs @@ -1,7 +1,6 @@ defmodule Unit.CompilerCache.BenchTest do use ExUnit.Case - defmodule NeverCompiledCache do use CompilerCache, cache_misses: :none @@ -10,7 +9,6 @@ defmodule Unit.CompilerCache.BenchTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end defmodule CompiledCache do @@ -21,21 +19,19 @@ defmodule Unit.CompilerCache.BenchTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end - @n 10_000 @expr "1000 + input" test "benchmark " do - {:ok, _} = NeverCompiledCache.start_link() - {:ok, _} = CompiledCache.start_link() + {:ok, _} = NeverCompiledCache.start_link([]) + {:ok, _} = CompiledCache.start_link([]) # cache miss #1 {t1, _} = :timer.tc(fn -> - Enum.each(1..@n, fn(n) -> + Enum.each(1..@n, fn n -> NeverCompiledCache.execute(@expr, n) end) end) @@ -45,7 +41,7 @@ defmodule Unit.CompilerCache.BenchTest do {t2, _} = :timer.tc(fn -> - Enum.each(1..@n, fn(n) -> + Enum.each(1..@n, fn n -> CompiledCache.execute(@expr, n) end) end) @@ -56,7 +52,5 @@ defmodule Unit.CompilerCache.BenchTest do for n <- 1..1_000_000 do CompiledCache.execute(@expr, n) end - end - end diff --git a/test/compiler_cache/cache_misses_test.exs b/test/compiler_cache/cache_misses_test.exs index 6102b7c..f66a3ce 100644 --- a/test/compiler_cache/cache_misses_test.exs +++ b/test/compiler_cache/cache_misses_test.exs @@ -9,12 +9,10 @@ defmodule Unit.CompilerCache.CacheMissesTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end - test "compile an expression after 2 cache misses" do - {:ok, _} = ExpressionCache.start_link() + {:ok, _} = ExpressionCache.start_link([]) # cache miss #1 assert 2 = ExpressionCache.execute("1 + input", 1) @@ -40,7 +38,6 @@ defmodule Unit.CompilerCache.CacheMissesTest do assert 9 == info.slots_remaining assert 1 == info.cache_size assert 0 == info.hit_ctr_size - end defmodule DefaultExpressionCache do @@ -51,11 +48,10 @@ defmodule Unit.CompilerCache.CacheMissesTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end test "compile an expression after 1 cache miss" do - {:ok, _} = DefaultExpressionCache.start_link() + {:ok, _} = DefaultExpressionCache.start_link([]) # cache miss #1 assert 2 = DefaultExpressionCache.execute("1 + input", 1) @@ -71,7 +67,5 @@ defmodule Unit.CompilerCache.CacheMissesTest do assert 9999 == info.slots_remaining assert 1 == info.cache_size assert 0 == info.hit_ctr_size - end - end diff --git a/test/compiler_cache/context_test.exs b/test/compiler_cache/context_test.exs index 46b3b00..7dc3dc9 100644 --- a/test/compiler_cache/context_test.exs +++ b/test/compiler_cache/context_test.exs @@ -1,14 +1,13 @@ defmodule Unit.CompilerCache.ContextTest do use ExUnit.Case - defmodule Compiler do use CompilerCache, cache_misses: 0 # callback def create_ast(expr) do {:ok, ast} = Code.string_to_quoted(expr) - {ast, [functions: [ {__MODULE__, [square: 1]}]]} + {ast, [functions: [{__MODULE__, [square: 1]}]]} end def square(var) do @@ -16,13 +15,12 @@ defmodule Unit.CompilerCache.ContextTest do end def handle_error(e, _stacktrace) do - IO.inspect e + IO.inspect(e) end - end test "compiler context " do - {:ok, _} = Compiler.start_link() + {:ok, _} = Compiler.start_link([]) assert 4 = Compiler.execute("square(input)", 2) @@ -33,9 +31,7 @@ defmodule Unit.CompilerCache.ContextTest do assert 4 = Compiler.execute("square(input)", 2) assert 4 = Compiler.execute("square(input)", 2) - :timer.sleep 10 - #assert 25 = Compiler.execute("square(arg)", 5) - + :timer.sleep(10) + # assert 25 = Compiler.execute("square(arg)", 5) end - end diff --git a/test/compiler_cache/input_name_test.exs b/test/compiler_cache/input_name_test.exs index 004778a..d454787 100644 --- a/test/compiler_cache/input_name_test.exs +++ b/test/compiler_cache/input_name_test.exs @@ -9,15 +9,13 @@ defmodule Unit.CompilerCache.InputNameTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end test "compiler cache with 'context' as input name" do - {:ok, _} = ExpressionCache.start_link() + {:ok, _} = ExpressionCache.start_link([]) # cache miss assert 2 = ExpressionCache.execute("1 + context", 1) assert 5 = ExpressionCache.execute("1 + context", 4) end - end diff --git a/test/compiler_cache/randomizer_stress_test.exs b/test/compiler_cache/randomizer_stress_test.exs index d4b198c..4f253c0 100644 --- a/test/compiler_cache/randomizer_stress_test.exs +++ b/test/compiler_cache/randomizer_stress_test.exs @@ -1,7 +1,6 @@ defmodule Unit.CompilerCache.RandomizerStressTest do use ExUnit.Case - defmodule ExpressionCache do use CompilerCache @@ -10,17 +9,16 @@ defmodule Unit.CompilerCache.RandomizerStressTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end @n 100_000 @m 100 test "small stresstest" do - {:ok, _} = ExpressionCache.start_link() + {:ok, _} = ExpressionCache.start_link([]) 1..@m - |> Enum.map(fn(_) -> + |> Enum.map(fn _ -> Task.async(fn -> for _ <- 1..@n do a = random() @@ -29,12 +27,10 @@ defmodule Unit.CompilerCache.RandomizerStressTest do end end) end) - |> Task.yield_many - - stats = ExpressionCache.stats - IO.puts "stats: #{inspect stats}" - + |> Task.yield_many() + stats = ExpressionCache.stats() + IO.puts("stats: #{inspect(stats)}") end defp expression(num) do @@ -42,5 +38,4 @@ defmodule Unit.CompilerCache.RandomizerStressTest do end defp random, do: Enum.random(1..100) - end diff --git a/test/compiler_cache/ttl_test.exs b/test/compiler_cache/ttl_test.exs index 14b539d..3076307 100644 --- a/test/compiler_cache/ttl_test.exs +++ b/test/compiler_cache/ttl_test.exs @@ -9,14 +9,12 @@ defmodule Unit.CompilerCache.TTLTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end - test "immediately compile an expression" do - {:ok, _} = ExpressionCache.start_link() + {:ok, _} = ExpressionCache.start_link([]) - assert 0 == :ets.info(ExpressionCache.config.cache_table, :size) + assert 0 == :ets.info(ExpressionCache.config().cache_table, :size) # assert 0 == :ets.info(ExpressionCache.ttl_table, :size) # cache miss @@ -43,13 +41,12 @@ defmodule Unit.CompilerCache.TTLTest do assert 8 == info.slots_remaining assert 2 == info.cache_size assert 2 == info.ttl_size - end test "test expire oldest expressions" do - {:ok, _} = ExpressionCache.start_link() + {:ok, _} = ExpressionCache.start_link([]) - assert 0 == :ets.info(ExpressionCache.config.ttl_table, :size) + assert 0 == :ets.info(ExpressionCache.config().ttl_table, :size) # Create 10 expressions; filling the cache table for n <- 1..10 do @@ -81,7 +78,5 @@ defmodule Unit.CompilerCache.TTLTest do # there should have been some cleanup taken place assert info.loaded_modules < prev_loaded_modules - end - end diff --git a/test/compiler_cache_test.exs b/test/compiler_cache_test.exs index 755e35d..7dac010 100644 --- a/test/compiler_cache_test.exs +++ b/test/compiler_cache_test.exs @@ -9,14 +9,12 @@ defmodule Unit.CompilerCacheTest do {:ok, ast} = Code.string_to_quoted(expr) {ast, []} end - end - test "Generated config with defaults" do - assert 10_000 == ExpressionCache.config.max_size - assert 1 == ExpressionCache.config.cache_misses - assert 1000 == ExpressionCache.config.max_ttl + assert 10_000 == ExpressionCache.config().max_size + assert 1 == ExpressionCache.config().cache_misses + assert 1000 == ExpressionCache.config().max_ttl end test "Override cache options" do @@ -26,18 +24,16 @@ defmodule Unit.CompilerCacheTest do def create_ast(_expr), do: nil end - assert 66 == MyCache.config.max_size - assert 10 == MyCache.config.cache_misses - assert 123 == MyCache.config.max_ttl - + assert 66 == MyCache.config().max_size + assert 10 == MyCache.config().cache_misses + assert 123 == MyCache.config().max_ttl end test "compiler cache" do - {:ok, _} = ExpressionCache.start_link() + {:ok, _} = ExpressionCache.start_link([]) # cache miss assert 2 = ExpressionCache.execute("1 + input", 1) assert 5 = ExpressionCache.execute("1 + input", 4) end - end