Land #331: Extract Explorer.Indexer to Indexer

pull/347/head
Luke Imhoff 7 years ago committed by GitHub
commit 2066427b29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      README.md
  2. 6
      apps/ethereum_jsonrpc/mix.exs
  3. 3
      apps/ethereum_jsonrpc/test/test_helper.exs
  4. 4
      apps/explorer/config/config.exs
  5. 1
      apps/explorer/lib/explorer/application.ex
  6. 26
      apps/explorer/lib/explorer/indexer/supervisor.ex
  7. 4
      apps/explorer/mix.exs
  8. 3
      apps/explorer/test/test_helper.exs
  9. 8
      apps/explorer_web/mix.exs
  10. 7
      apps/explorer_web/test/test_helper.exs
  11. 4
      apps/indexer/.formatter.exs
  12. 24
      apps/indexer/.gitignore
  13. 21
      apps/indexer/README.md
  14. 9
      apps/indexer/config/config.exs
  15. 22
      apps/indexer/lib/indexer.ex
  16. 8
      apps/indexer/lib/indexer/address_balance_fetcher.ex
  17. 14
      apps/indexer/lib/indexer/address_extraction.ex
  18. 24
      apps/indexer/lib/indexer/application.ex
  19. 14
      apps/indexer/lib/indexer/block_fetcher.ex
  20. 4
      apps/indexer/lib/indexer/buffered_task.ex
  21. 8
      apps/indexer/lib/indexer/internal_transaction_fetcher.ex
  22. 10
      apps/indexer/lib/indexer/pending_transaction_fetcher.ex
  23. 2
      apps/indexer/lib/indexer/sequence.ex
  24. 49
      apps/indexer/mix.exs
  25. 6
      apps/indexer/test/indexer/address_balance_fetcher_test.exs
  26. 16
      apps/indexer/test/indexer/address_extraction_test.exs
  27. 16
      apps/indexer/test/indexer/block_fetcher_test.exs
  28. 4
      apps/indexer/test/indexer/buffered_task_test.exs
  29. 12
      apps/indexer/test/indexer/internal_transaction_fetcher_test.exs
  30. 6
      apps/indexer/test/indexer/pending_transaction_fetcher_test.exs
  31. 4
      apps/indexer/test/indexer/sequence_test.exs
  32. 4
      apps/indexer/test/indexer_test.exs
  33. 4
      apps/indexer/test/support/indexer/address_balance_fetcher_case.ex
  34. 4
      apps/indexer/test/support/indexer/internal_transaction_fetcher_case.ex
  35. 20
      apps/indexer/test/test_helper.exs
  36. 2
      coveralls.json
  37. 12
      mix.exs

@ -33,6 +33,19 @@ Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.
You can also run IEx (Interactive Elixir): `iex -S mix phx.server`
#### Umbrella Project Organization
This repository is an [umbrella project](https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-projects.html): each directory under `apps/` is a separate [Mix](https://hexdocs.pm/mix/Mix.html) project and [OTP application](https://hexdocs.pm/elixir/Application.html), but the projects can use each other as a dependency in their `mix.exs`.
Each OTP application has a restricted domain
| Directory | OTP Application | Namespace | Purpose |
|:------------------------|:--------------------|:------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `apps/ethereum_jsonrpc` | `:ethereum_jsonrpc` | `EthereumJSONRPC` | Ethereum JSONRPC client. It is allowed to know `Explorer`'s param format, but it cannot directly depend on `:explorer` |
| `apps/explorer` | `:explorer` | `Explorer` | Storage for the indexed chain. Can read and write to the backing storage. MUST be able to boot in a read-only mode when run independently from `:indexer`, so cannot depend on `:indexer` as that would start `:indexer` indexing. |
| `apps/explorer_web` | `:explorer_web` | `ExplorerWeb` | Phoenix interface to `:explorer`. The minimum interface to allow web access should go in `:explorer_web`. Any business rules or interface that is not tied directly to `Phoenix` or `Plug` should go in `:explorer`. MUST be able to boot in a read-only mode when run independently from `:indexer`, so cannot depend on `:indexer` as that would start `:indexer` indexing. |
| `apps/indexer` | `:indexer` | `Indexer` | Uses `:ethereum_jsonrpc` to index chain and batch import data into `:explorer`. Any process, `Task`, or `GenServer` that automatically reads from the chain and writes to `:explorer` should be in `:indexer`, so that automatic writes are restricted to `:indexer` and read-only mode can be achieved by not running `:indexer`. |
### CircleCI Updates
Configure your local CCMenu with the following url: [`https://circleci.com/gh/poanetwork/poa-explorer.cc.xml?circle-token=f8823a3d0090407c11f87028c73015a331dbf604`](https://circleci.com/gh/poanetwork/poa-explorer.cc.xml?circle-token=f8823a3d0090407c11f87028c73015a331dbf604)

@ -38,7 +38,11 @@ defmodule EthereumJsonrpc.MixProject do
end
defp aliases(env) do
env_aliases(env)
[
# to match behavior of `mix test` from project root, which needs to not start applications for `indexer` to
# prevent its supervision tree from starting, which is undesirable in test
test: "test --no-start"
] ++ env_aliases(env)
end
defp env_aliases(:dev), do: []

@ -3,5 +3,8 @@ junit_folder = Mix.Project.build_path() <> "/junit/#{Mix.Project.config()[:app]}
File.mkdir_p!(junit_folder)
:ok = Application.put_env(:junit_formatter, :report_dir, junit_folder)
# Counter `test --no-start`. `--no-start` is needed for `:indexer` compatibility
{:ok, _} = Application.ensure_all_started(:ethereum_jsonrpc)
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start()

@ -7,10 +7,6 @@ use Mix.Config
config :ecto, json_library: Jason
config :explorer, :indexer,
block_rate: 5_000,
debug_logs: !!System.get_env("DEBUG_INDEXER")
# General application configuration
config :explorer,
ecto_repos: [Explorer.Repo],

@ -25,7 +25,6 @@ defmodule Explorer.Application do
[
configure(Explorer.Chain.Statistics.Server),
configure(Explorer.ExchangeRates),
configure(Explorer.Indexer.Supervisor),
configure(Explorer.Market.History.Cataloger)
]
|> List.flatten()

@ -1,26 +0,0 @@
defmodule Explorer.Indexer.Supervisor do
@moduledoc """
Supervising the fetchers for the `Explorer.Indexer`
"""
use Supervisor
alias Explorer.Indexer.{AddressBalanceFetcher, BlockFetcher, InternalTransactionFetcher, PendingTransactionFetcher}
def start_link(opts) do
Supervisor.start_link(__MODULE__, opts, name: __MODULE__)
end
@impl Supervisor
def init(_opts) do
children = [
{Task.Supervisor, name: Explorer.Indexer.TaskSupervisor},
{AddressBalanceFetcher, name: AddressBalanceFetcher},
{PendingTransactionFetcher, name: PendingTransactionFetcher},
{InternalTransactionFetcher, name: InternalTransactionFetcher},
{BlockFetcher, []}
]
Supervisor.init(children, strategy: :one_for_one)
end
end

@ -75,8 +75,6 @@ defmodule Explorer.Mixfile do
# Code coverage
{:excoveralls, "~> 0.8.1", only: [:test]},
{:exvcr, "~> 0.10", only: :test},
# JSONRPC access to Parity for `Explorer.Indexer`
{:ethereum_jsonrpc, in_umbrella: true},
{:httpoison, "~> 1.0", override: true},
{:jason, "~> 1.0"},
{:junit_formatter, ">= 0.0.0", only: [:test], runtime: false},
@ -100,7 +98,7 @@ defmodule Explorer.Mixfile do
[
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate", "test"]
test: ["ecto.create --quiet", "ecto.migrate", "test --no-start"]
] ++ env_aliases(env)
end

@ -3,6 +3,9 @@ junit_folder = Mix.Project.build_path() <> "/junit/#{Mix.Project.config()[:app]}
File.mkdir_p!(junit_folder)
:ok = Application.put_env(:junit_formatter, :report_dir, junit_folder)
# Counter `test --no-start`. `--no-start` is needed for `:indexer` compatibility
{:ok, _} = Application.ensure_all_started(:explorer)
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start()

@ -112,7 +112,13 @@ defmodule ExplorerWeb.Mixfile do
compile: "compile --warnings-as-errors",
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate", "test"]
test: [
"ecto.create --quiet",
"ecto.migrate",
# to match behavior of `mix test` from project root, which needs to not start applications for `indexer` to
# prevent its supervision tree from starting, which is undesirable in test
"test --no-start"
]
]
end

@ -3,12 +3,15 @@ junit_folder = Mix.Project.build_path() <> "/junit/#{Mix.Project.config()[:app]}
File.mkdir_p!(junit_folder)
:ok = Application.put_env(:junit_formatter, :report_dir, junit_folder)
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start()
# Counter `test --no-start`. `--no-start` is needed for `:indexer` compatibility
{:ok, _} = Application.ensure_all_started(:explorer_web)
{:ok, _} = Application.ensure_all_started(:wallaby)
Application.put_env(:wallaby, :base_url, ExplorerWeb.Endpoint.url())
{:ok, _} = Application.ensure_all_started(:ex_machina)
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, :manual)

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where 3rd-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
indexer-*.tar

@ -0,0 +1,21 @@
# Indexer
**TODO: Add description**
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `indexer` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:indexer, "~> 0.1.0"}
]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/indexer](https://hexdocs.pm/indexer).

@ -0,0 +1,9 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config
config :indexer,
block_rate: 5_000,
debug_logs: !!System.get_env("DEBUG_INDEXER")
config :indexer, ecto_repos: [Explorer.Repo]

@ -1,10 +1,10 @@
defmodule Explorer.Indexer do
defmodule Indexer do
@moduledoc """
Indexes an Ethereum-based chain using JSONRPC.
"""
require Logger
alias Explorer.{Chain, Indexer}
alias Explorer.Chain
@doc """
The maximum `t:Explorer.Chain.Block.t/0` `number` that was indexed
@ -13,12 +13,12 @@ defmodule Explorer.Indexer do
iex> insert(:block, number: 2)
iex> insert(:block, number: 1)
iex> Explorer.Indexer.max_block_number()
iex> Indexer.max_block_number()
2
If there are no blocks, `0` is returned to indicate to index from genesis block.
iex> Explorer.Indexer.max_block_number()
iex> Indexer.max_block_number()
0
"""
@ -34,16 +34,16 @@ defmodule Explorer.Indexer do
When there are no blocks the next block is the 0th block
iex> Explorer.Indexer.max_block_number()
iex> Indexer.max_block_number()
0
iex> Explorer.Indexer.next_block_number()
iex> Indexer.next_block_number()
0
When there is a block, it is the successive block number
iex> insert(:block, number: 2)
iex> insert(:block, number: 1)
iex> Explorer.Indexer.next_block_number()
iex> Indexer.next_block_number()
3
"""
@ -69,14 +69,14 @@ defmodule Explorer.Indexer do
Enables debug logs for indexing system.
"""
def enable_debug_logs do
Application.put_env(:explorer, :indexer, Keyword.put(config(), :debug_logs, true))
Application.put_env(:indexer, :debug_logs, true)
end
@doc """
Disables debug logs for indexing system.
"""
def disable_debug_logs do
Application.put_env(:explorer, :indexer, Keyword.put(config(), :debug_logs, false))
Application.put_env(:indexer, :debug_logs, false)
end
@doc """
@ -90,8 +90,6 @@ defmodule Explorer.Indexer do
end
defp debug_logs_enabled? do
Keyword.fetch!(config(), :debug_logs)
Application.fetch_env!(:indexer, :debug_logs)
end
defp config, do: Application.fetch_env!(:explorer, :indexer)
end

@ -1,13 +1,13 @@
defmodule Explorer.Indexer.AddressBalanceFetcher do
defmodule Indexer.AddressBalanceFetcher do
@moduledoc """
Fetches `t:Explorer.Chain.Address.t/0` `fetched_balance`.
"""
import EthereumJSONRPC, only: [integer_to_quantity: 1]
alias Explorer.{BufferedTask, Chain}
alias Explorer.Chain
alias Explorer.Chain.{Block, Hash}
alias Explorer.Indexer
alias Indexer.BufferedTask
@behaviour BufferedTask
@ -16,7 +16,7 @@ defmodule Explorer.Indexer.AddressBalanceFetcher do
max_batch_size: 500,
max_concurrency: 4,
init_chunk_size: 1000,
task_supervisor: Explorer.Indexer.TaskSupervisor
task_supervisor: Indexer.TaskSupervisor
]
@doc """

@ -1,4 +1,4 @@
defmodule Explorer.Indexer.AddressExtraction do
defmodule Indexer.AddressExtraction do
@moduledoc """
Extract Addresses from data fetched from the Blockchain and structured as Blocks, InternalTransactions,
Transactions and Logs.
@ -104,7 +104,7 @@ defmodule Explorer.Indexer.AddressExtraction do
Blocks have their `miner_hash` extracted.
iex> Explorer.Indexer.AddressExtraction.extract_addresses(
iex> Indexer.AddressExtraction.extract_addresses(
...> %{
...> blocks: [
...> %{
@ -124,7 +124,7 @@ defmodule Explorer.Indexer.AddressExtraction do
Internal transactions can have their `from_address_hash`, `to_address_hash` and/or `created_contract_address_hash`
extracted.
iex> Explorer.Indexer.AddressExtraction.extract_addresses(
iex> Indexer.AddressExtraction.extract_addresses(
...> %{
...> internal_transactions: [
...> %{
@ -161,7 +161,7 @@ defmodule Explorer.Indexer.AddressExtraction do
Transactions can have their `from_address_hash` and/or `to_address_hash` extracted.
iex> Explorer.Indexer.AddressExtraction.extract_addresses(
iex> Indexer.AddressExtraction.extract_addresses(
...> %{
...> transactions: [
...> %{
@ -193,7 +193,7 @@ defmodule Explorer.Indexer.AddressExtraction do
Logs can have their `address_hash` extracted.
iex> Explorer.Indexer.AddressExtraction.extract_addresses(
iex> Indexer.AddressExtraction.extract_addresses(
...> %{
...> logs: [
...> %{
@ -212,7 +212,7 @@ defmodule Explorer.Indexer.AddressExtraction do
When the same address is mentioned multiple times, the greatest `block_number` is used
iex> Explorer.Indexer.AddressExtraction.extract_addresses(
iex> Indexer.AddressExtraction.extract_addresses(
...> %{
...> blocks: [
...> %{
@ -262,7 +262,7 @@ defmodule Explorer.Indexer.AddressExtraction do
When a contract is created and then used in internal transactions and transaction in the same fetched data, the
`created_contract_code` is merged with the greatest `block_number`
iex> Explorer.Indexer.AddressExtraction.extract_addresses(
iex> Indexer.AddressExtraction.extract_addresses(
...> %{
...> internal_transactions: [
...> %{

@ -0,0 +1,24 @@
defmodule Indexer.Application do
@moduledoc """
This is the `Application` module for `Indexer`.
"""
use Application
alias Indexer.{AddressBalanceFetcher, BlockFetcher, InternalTransactionFetcher, PendingTransactionFetcher}
@impl Application
def start(_type, _args) do
children = [
{Task.Supervisor, name: Indexer.TaskSupervisor},
{AddressBalanceFetcher, name: AddressBalanceFetcher},
{PendingTransactionFetcher, name: PendingTransactionFetcher},
{InternalTransactionFetcher, name: InternalTransactionFetcher},
{BlockFetcher, []}
]
opts = [strategy: :one_for_one, name: Indexer.Supervisor]
Supervisor.start_link(children, opts)
end
end

@ -1,4 +1,4 @@
defmodule Explorer.Indexer.BlockFetcher do
defmodule Indexer.BlockFetcher do
@moduledoc """
Fetches and indexes block ranges from gensis to realtime.
"""
@ -7,12 +7,12 @@ defmodule Explorer.Indexer.BlockFetcher do
require Logger
import Explorer.Indexer, only: [debug: 1]
import Indexer, only: [debug: 1]
alias EthereumJSONRPC
alias EthereumJSONRPC.Transactions
alias Explorer.{BufferedTask, Chain, Indexer}
alias Explorer.Indexer.{AddressBalanceFetcher, AddressExtraction, InternalTransactionFetcher, Sequence}
alias Explorer.Chain
alias Indexer.{AddressBalanceFetcher, AddressExtraction, BufferedTask, InternalTransactionFetcher, Sequence}
# dialyzer thinks that Logger.debug functions always have no_local_return
@dialyzer {:nowarn_function, import_range: 3}
@ -63,7 +63,11 @@ defmodule Explorer.Indexer.BlockFetcher do
@impl GenServer
def init(opts) do
opts = Keyword.merge(Application.fetch_env!(:explorer, :indexer), opts)
opts =
:indexer
|> Application.get_all_env()
|> Keyword.merge(opts)
:timer.send_interval(15_000, self(), :debug_count)
state = %{

@ -1,4 +1,4 @@
defmodule Explorer.BufferedTask do
defmodule Indexer.BufferedTask do
@moduledoc """
Provides a behaviour for batched task running with retries.
@ -166,7 +166,7 @@ defmodule Explorer.BufferedTask do
]}
) :: {:ok, pid()} | {:error, {:already_started, pid()}}
def start_link({module, base_opts}) do
default_opts = Application.fetch_env!(:explorer, :indexer)
default_opts = Application.get_all_env(:indexer)
opts = Keyword.merge(default_opts, base_opts)
GenServer.start_link(__MODULE__, {module, opts}, name: opts[:name])

@ -1,4 +1,4 @@
defmodule Explorer.Indexer.InternalTransactionFetcher do
defmodule Indexer.InternalTransactionFetcher do
@moduledoc """
Fetches and indexes `t:Explorer.Chain.InternalTransaction.t/0`.
@ -7,8 +7,8 @@ defmodule Explorer.Indexer.InternalTransactionFetcher do
require Logger
alias Explorer.{BufferedTask, Chain, Indexer}
alias Explorer.Indexer.{AddressBalanceFetcher, AddressExtraction}
alias Explorer.Chain
alias Indexer.{AddressBalanceFetcher, AddressExtraction, BufferedTask}
alias Explorer.Chain.{Block, Hash}
@behaviour BufferedTask
@ -20,7 +20,7 @@ defmodule Explorer.Indexer.InternalTransactionFetcher do
max_concurrency: @max_concurrency,
max_batch_size: @max_batch_size,
init_chunk_size: 5000,
task_supervisor: Explorer.Indexer.TaskSupervisor
task_supervisor: Indexer.TaskSupervisor
]
@doc """

@ -1,4 +1,4 @@
defmodule Explorer.Indexer.PendingTransactionFetcher do
defmodule Indexer.PendingTransactionFetcher do
@moduledoc """
Fetches pending transactions and imports them.
@ -11,8 +11,8 @@ defmodule Explorer.Indexer.PendingTransactionFetcher do
import EthereumJSONRPC.Parity, only: [fetch_pending_transactions: 0]
alias Explorer.{Chain, Indexer}
alias Explorer.Indexer.{AddressExtraction, PendingTransactionFetcher}
alias Explorer.Chain
alias Indexer.{AddressExtraction, PendingTransactionFetcher}
# milliseconds
@default_interval 1_000
@ -46,8 +46,8 @@ defmodule Explorer.Indexer.PendingTransactionFetcher do
@impl GenServer
def init(opts) do
opts =
:explorer
|> Application.fetch_env!(:indexer)
:indexer
|> Application.get_all_env()
|> Keyword.merge(opts)
state =

@ -1,4 +1,4 @@
defmodule Explorer.Indexer.Sequence do
defmodule Indexer.Sequence do
@moduledoc false
use Agent

@ -0,0 +1,49 @@
defmodule Indexer.MixProject do
use Mix.Project
def project do
[
aliases: aliases(),
app: :indexer,
version: "0.1.0",
build_path: "../../_build",
config_path: "../../config/config.exs",
deps_path: "../../deps",
lockfile: "../../mix.lock",
elixir: "~> 1.6",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger],
mod: {Indexer.Application, []}
]
end
defp aliases do
[
# so that the supervision tree does not start, which would begin indexing, and so that the various fetchers can
# be started with `ExUnit`'s `start_supervised` for unit testing.
test: "test --no-start"
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
# JSONRPC access to Parity for `Explorer.Indexer`
{:ethereum_jsonrpc, in_umbrella: true},
# Importing to database
{:explorer, in_umbrella: true}
]
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["test/support" | elixirc_paths(:dev)]
defp elixirc_paths(_), do: ["lib"]
end

@ -1,10 +1,10 @@
defmodule Explorer.Indexer.AddressBalanceFetcherTest do
defmodule Indexer.AddressBalanceFetcherTest do
# MUST be `async: false` so that {:shared, pid} is set for connection to allow AddressBalanceFetcher's self-send to have
# connection allowed immediately.
use Explorer.DataCase, async: false
alias Explorer.Chain.{Address, Hash, Wei}
alias Explorer.Indexer.{AddressBalanceFetcher, AddressBalanceFetcherCase}
alias Indexer.{AddressBalanceFetcher, AddressBalanceFetcherCase}
@block_number 2_932_838
@hash %Explorer.Chain.Hash{
@ -13,7 +13,7 @@ defmodule Explorer.Indexer.AddressBalanceFetcherTest do
}
setup do
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
:ok
end

@ -1,13 +1,13 @@
defmodule Explorer.Indexer.AddressExtractionTest do
defmodule Indexer.AddressExtractionTest do
use Explorer.DataCase, async: true
alias Explorer.Indexer.AddressExtraction
alias Indexer.AddressExtraction
doctest AddressExtraction
describe "extract_addresses/1" do
test "blocks without a `miner_hash` aren't extracted" do
assert Explorer.Indexer.AddressExtraction.extract_addresses(%{
assert Indexer.AddressExtraction.extract_addresses(%{
blocks: [
%{
number: 34
@ -17,7 +17,7 @@ defmodule Explorer.Indexer.AddressExtractionTest do
end
test "blocks without a `number` aren't extracted" do
assert Explorer.Indexer.AddressExtraction.extract_addresses(%{
assert Indexer.AddressExtraction.extract_addresses(%{
blocks: [
%{
miner_hash: "0xe8ddc5c7a2d2f0d7a9798459c0104fdf5e987aca"
@ -27,7 +27,7 @@ defmodule Explorer.Indexer.AddressExtractionTest do
end
test "internal_transactions with a `from_address_hash` without a `block_number` aren't extracted" do
assert Explorer.Indexer.AddressExtraction.extract_addresses(%{
assert Indexer.AddressExtraction.extract_addresses(%{
internal_transactions: [
%{
from_address_hash: "0x0000000000000000000000000000000000000001"
@ -37,7 +37,7 @@ defmodule Explorer.Indexer.AddressExtractionTest do
end
test "internal_transactions with a `to_address_hash` without a `block_number` aren't extracted" do
assert Explorer.Indexer.AddressExtraction.extract_addresses(%{
assert Indexer.AddressExtraction.extract_addresses(%{
internal_transactions: [
%{
to_address_hash: "0x0000000000000000000000000000000000000002"
@ -48,7 +48,7 @@ defmodule Explorer.Indexer.AddressExtractionTest do
test "internal_transactions with a `created_contract_address_hash` and `created_contract_code` " <>
"without a `block_number` aren't extracted" do
assert Explorer.Indexer.AddressExtraction.extract_addresses(%{
assert Indexer.AddressExtraction.extract_addresses(%{
internal_transactions: [
%{
created_contract_address_hash: "0x0000000000000000000000000000000000000003",
@ -59,7 +59,7 @@ defmodule Explorer.Indexer.AddressExtractionTest do
end
test "differing contract code is ignored" do
assert Explorer.Indexer.AddressExtraction.extract_addresses(%{
assert Indexer.AddressExtraction.extract_addresses(%{
internal_transactions: [
%{
block_number: 1,

@ -1,16 +1,16 @@
defmodule Explorer.Indexer.BlockFetcherTest do
defmodule Indexer.BlockFetcherTest do
# `async: false` due to use of named GenServer
use Explorer.DataCase, async: false
import ExUnit.CaptureLog
alias Explorer.Chain.{Address, Block, Log, Transaction, Wei}
alias Explorer.Indexer
alias Explorer.Indexer.{
alias Indexer.{
AddressBalanceFetcher,
AddressBalanceFetcherCase,
BlockFetcher,
BufferedTask,
InternalTransactionFetcher,
InternalTransactionFetcherCase,
Sequence
@ -46,7 +46,7 @@ defmodule Explorer.Indexer.BlockFetcherTest do
assert Repo.aggregate(Block, :count, :hash) == 0
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
AddressBalanceFetcherCase.start_supervised!()
InternalTransactionFetcherCase.start_supervised!()
start_supervised!(BlockFetcher)
@ -89,7 +89,7 @@ defmodule Explorer.Indexer.BlockFetcherTest do
@tag :capture_log
@heading "persisted counts"
test "without debug_logs", %{state: state} do
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
AddressBalanceFetcherCase.start_supervised!()
InternalTransactionFetcherCase.start_supervised!()
@ -104,7 +104,7 @@ defmodule Explorer.Indexer.BlockFetcherTest do
@tag :capture_log
test "with debug_logs", %{state: state} do
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
AddressBalanceFetcherCase.start_supervised!()
InternalTransactionFetcherCase.start_supervised!()
@ -129,7 +129,7 @@ defmodule Explorer.Indexer.BlockFetcherTest do
setup :state
setup do
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
AddressBalanceFetcherCase.start_supervised!()
InternalTransactionFetcherCase.start_supervised!()
{:ok, state} = BlockFetcher.init([])
@ -293,7 +293,7 @@ defmodule Explorer.Indexer.BlockFetcherTest do
defp wait_for_tasks(buffered_task) do
wait_until(5000, fn ->
counts = Explorer.BufferedTask.debug_count(buffered_task)
counts = BufferedTask.debug_count(buffered_task)
counts.buffer == 0 and counts.tasks == 0
end)
end

@ -1,7 +1,7 @@
defmodule Explorer.BufferedTaskTest do
defmodule Indexer.BufferedTaskTest do
use ExUnit.Case, async: true
alias Explorer.BufferedTask
alias Indexer.BufferedTask
@max_batch_size 2

@ -1,15 +1,15 @@
defmodule Explorer.Indexer.InternalTransactionFetcherTest do
defmodule Indexer.InternalTransactionFetcherTest do
use Explorer.DataCase, async: false
import ExUnit.CaptureLog
alias Explorer.Chain.Transaction
alias Explorer.Indexer.{AddressBalanceFetcherCase, InternalTransactionFetcher, PendingTransactionFetcher}
alias Indexer.{AddressBalanceFetcherCase, InternalTransactionFetcher, PendingTransactionFetcher}
@moduletag :capture_log
test "does not try to fetch pending transactions from Explorer.Indexer.PendingTransactionFetcher" do
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
test "does not try to fetch pending transactions from Indexer.PendingTransactionFetcher" do
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
AddressBalanceFetcherCase.start_supervised!()
start_supervised!(PendingTransactionFetcher)
@ -57,7 +57,7 @@ defmodule Explorer.Indexer.InternalTransactionFetcherTest do
describe "run/2" do
test "duplicate transaction hashes are logged" do
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
AddressBalanceFetcherCase.start_supervised!()
insert(:transaction, hash: "0x03cd5899a63b6f6222afda8705d059fd5a7d126bcabe962fb654d9736e6bcafa")
@ -82,7 +82,7 @@ defmodule Explorer.Indexer.InternalTransactionFetcherTest do
end
test "duplicate transaction hashes only retry uniques" do
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
AddressBalanceFetcherCase.start_supervised!()
# not a real transaction hash, so that it fails

@ -1,16 +1,16 @@
defmodule Explorer.Indexer.PendingTransactionFetcherTest do
defmodule Indexer.PendingTransactionFetcherTest do
# `async: false` due to use of named GenServer
use Explorer.DataCase, async: false
alias Explorer.Chain.Transaction
alias Explorer.Indexer.PendingTransactionFetcher
alias Indexer.PendingTransactionFetcher
describe "start_link/1" do
# this test may fail if Sokol so low volume that the pending transactions are empty for too long
test "starts fetching pending transactions" do
assert Repo.aggregate(Transaction, :count, :hash) == 0
start_supervised!({Task.Supervisor, name: Explorer.Indexer.TaskSupervisor})
start_supervised!({Task.Supervisor, name: Indexer.TaskSupervisor})
start_supervised!(PendingTransactionFetcher)
wait_for_results(fn ->

@ -1,7 +1,7 @@
defmodule Explorer.Indexer.SequenceTest do
defmodule Indexer.SequenceTest do
use ExUnit.Case
alias Explorer.Indexer.Sequence
alias Indexer.Sequence
test "start_link" do
{:ok, pid} = Sequence.start_link([1..4], 5, 1)

@ -1,8 +1,6 @@
defmodule Explorer.IndexerTest do
defmodule IndexerTest do
use Explorer.DataCase, async: true
alias Explorer.Indexer
import Explorer.Factory
doctest Indexer

@ -1,5 +1,5 @@
defmodule Explorer.Indexer.AddressBalanceFetcherCase do
alias Explorer.Indexer.AddressBalanceFetcher
defmodule Indexer.AddressBalanceFetcherCase do
alias Indexer.AddressBalanceFetcher
def start_supervised!(options \\ []) when is_list(options) do
options

@ -1,5 +1,5 @@
defmodule Explorer.Indexer.InternalTransactionFetcherCase do
alias Explorer.Indexer.InternalTransactionFetcher
defmodule Indexer.InternalTransactionFetcherCase do
alias Indexer.InternalTransactionFetcher
def start_supervised!(options \\ []) when is_list(options) do
options

@ -0,0 +1,20 @@
# https://github.com/CircleCI-Public/circleci-demo-elixir-phoenix/blob/a89de33a01df67b6773ac90adc74c34367a4a2d6/test/test_helper.exs#L1-L3
junit_folder = Mix.Project.build_path() <> "/junit/#{Mix.Project.config()[:app]}"
File.mkdir_p!(junit_folder)
:ok = Application.put_env(:junit_formatter, :report_dir, junit_folder)
# start all dependencies, but not Indexer itself as we need to unit test the supervision tree without and don't want the
# genesis task scanning in the background
Application.load(:indexer)
for application <- Application.spec(:indexer, :applications) do
Application.ensure_all_started(application)
end
# no declared in :applications since it is test-only
{:ok, _} = Application.ensure_all_started(:ex_machina)
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Explorer.Repo, :manual)

@ -1,7 +1,7 @@
{
"coverage_options": {
"treat_no_relevant_lines_as_covered": true,
"minimum_coverage": 93.7
"minimum_coverage": 94.4
},
"terminal_options": {
"file_column_width": 120

@ -28,11 +28,19 @@ defmodule ExplorerUmbrella.Mixfile do
## Private Functions
defp aliases(:dev) do
defp aliases(env) do
[
# to match behavior of `mix test` in `apps/indexer`, which needs to not start applications for `indexer` to
# prevent its supervision tree from starting, which is undesirable in test
test: "test --no-start"
] ++ env_aliases(env)
end
defp env_aliases(:dev) do
[]
end
defp aliases(_env) do
defp env_aliases(_env) do
[
compile: "compile --warnings-as-errors"
]

Loading…
Cancel
Save