this repo has no description
at master 148 lines 4.0 kB view raw
1defmodule TrinityTest do 2 use ExUnit.Case 3 4 alias Trinity.{Sim, SimProcess, SimPersistentTerm, SimLogger, Scheduler} 5 import Trinity.Scheduler, only: [receive_yield: 1] 6 require SimLogger 7 8 defmodule Counter do 9 use GenServer 10 alias Trinity.{SimServer, SimFile} 11 12 def start_link(id, initial_count) do 13 SimServer.start_link(__MODULE__, %{id: id, initial_count: initial_count}) 14 end 15 16 def add(server, amount) do 17 SimServer.call(server, {:add, amount}) 18 end 19 20 def init(%{id: id, initial_count: initial_count}) do 21 assert SimFile.exists?("/counters/#{id}/") == false 22 :ok = SimFile.mkdir_p("/counters/#{id}/") 23 assert SimFile.exists?("/counters/#{id}") == true 24 assert SimFile.exists?("/counters/#{id}/") == true 25 26 {:ok, fd} = SimFile.open("/counters/#{id}/#{id}.count", [:read, :write]) 27 assert SimFile.ls("/counters/#{id}/") == {:ok, ["#{id}.count"]} 28 29 SimLogger.debug "Init (id=#{id}, fd=#{fd}, initial_count=#{initial_count})" 30 31 state = %{ 32 fd: fd, 33 size: nil, 34 } 35 state = write_value(state, initial_count) 36 SimLogger.debug "Initial state (id=#{id}): #{inspect(state)}" 37 38 :ok = SimPersistentTerm.put("counter-#{id}", initial_count) 39 term = SimPersistentTerm.get("counter-#{id}", nil) 40 SimLogger.debug "Persistent term: #{term}" 41 42 # Note: this intentionally tests a log message with no variables 43 SimLogger.debug "Init complete" 44 {:ok, state} 45 end 46 47 def handle_call({:add, amount}, _from, state) do 48 value = read_value(state) 49 value = value + amount 50 state = write_value(state, value) 51 {:reply, value, state} 52 end 53 54 defp read_value(%{fd: fd, size: size}) do 55 {:ok, data} = SimFile.pread(fd, 3, size) 56 "The current value of the counter is: " <> value_str = data 57 String.to_integer(value_str) 58 end 59 60 defp write_value(%{fd: fd} = state, value) do 61 data = "The current value of the counter is: " <> Integer.to_string(value) 62 SimFile.pwrite(fd, 3, data) 63 %{state | size: byte_size(data)} 64 end 65 end 66 67 defmodule CounterSupervisor do 68 use GenServer 69 alias Trinity.SimServer 70 71 def start_link(children, opts), do: SimServer.start_link(__MODULE__, children, opts) 72 def get_children(server), do: SimServer.call(server, :get_children) 73 74 def init(children) do 75 pids = Enum.map(children, fn {m, f, a} -> 76 {:ok, pid} = apply(m, f, a) 77 pid 78 end) 79 {:ok, pids} 80 end 81 82 def handle_call(:get_children, _from, pids) do 83 {:reply, pids, pids} 84 end 85 end 86 87 test "scheduler" do 88 message = Sim.run_simulation(fn -> 89 nodes = [:n1, :n2, :n3] 90 91 names = Enum.map(nodes, fn node -> 92 name = String.to_atom(Atom.to_string(node) <> "_proc") 93 94 children = Enum.map(1..10, fn i -> 95 {TrinityTest.Counter, :start_link, [i, i]} 96 end) 97 98 node_mfa = { 99 TrinityTest.CounterSupervisor, 100 :start_link, 101 [children, [name: name]], 102 } 103 Sim.create_node(node, node_mfa) 104 Sim.start_node(node) 105 {name, node} 106 end) 107 108 # Wait for nodes to start/register 109 SimProcess.sleep(100) 110 111 pids = 112 names 113 |> Enum.map(fn name -> 114 CounterSupervisor.get_children(name) 115 |> Enum.with_index(1) 116 end) 117 |> Enum.concat() 118 119 Enum.each(pids, fn {pid, id} -> 120 result = Counter.add(pid, 10) 121 assert result == (id + 10) 122 end) 123 124 SimProcess.send_after self(), :finish, 1000 125 receive_yield do 126 :finish -> :noop 127 end 128 129 Scheduler.yield(1000) 130 #dbg Scheduler.dump(), limit: :infinity 131 :success 132 133 hash = SimLogger.get_hash() 134 tail = SimLogger.log_tail(10) 135 """ 136 Simulation complete. 137 138 Hash: #{hash} 139 140 Log tail: 141 #{Enum.join(tail, "\n")} 142 """ 143 end, seed: 101) 144 145 require Logger 146 Logger.info(message) 147 end 148end