samsondav / rihanna

Rihanna is a high performance postgres-backed job queue for Elixir
MIT License
439 stars 49 forks source link

Feature request: test helpers #59

Open KushalP opened 5 years ago

KushalP commented 5 years ago

Testing behaviour and outcomes is an important part of developing software for many teams. Making it easier to test Rihanna job behaviour in ExUnit tests would be helpful to this aim.

Ideally we would have the following functions available:

# clears all jobs in the job queue
Rihanna.Test.purge()

# checks that a job module with the given arguments has been enqueued.
Rihanna.Test.queues_up(job, arguments)

There may be more that would be useful.

Example usage

I'd imagine the first of these functions to be used as part of the initialisation of a test. The second of these could be used to check that some event triggers a job being enqueued.

defmodule APITest do
  use ExUnit.Case

  setup do
    :ok = Rihanna.Test.purge()
  end

  test "new user creation sends email verification" do
    Some.Namespace.Test.HTTP.Module.fires_post_request_creating_new_user(username, email)
    assert Rihanna.Test.queues_up(Some.Namespace.Jobs.SendVerificationEmail, %{username: username, email: email})
  end
end

Attribution/Inspiration

This isn't a new idea. Most of this I'm stealing from rspec-que.

lpil commented 5 years ago

Hi @KushalP! Are you using Ecto? If so you can use the Ecto repo integration and then you can just query the database as per usual, the sandbox takes care of the rest. This is great because the entire queuing system is tested and there's no mocks that result in a difference between tests and production.

I'm querying it using this module:

defmodule MyApp.Job do
  use Ecto.Schema

  defmodule ETF do
    @behaviour Ecto.Type

    def type, do: :bytea

    def load(serialized_mfa) when is_binary(serialized_mfa) do
      {:ok, :erlang.binary_to_term(serialized_mfa)}
    end

    def load(nil, _), do: {:ok, nil}
    def load(_, _), do: :error

    def dump(mfa) do
      {:ok, :erlang.term_to_binary(mfa)}
    end

    def cast(mfa = {mod, fun, args}) when is_atom(mod) and is_atom(fun) and is_list(args) do
      {:ok, mfa}
    end

    def cast(_), do: :error
  end

  schema Rihanna.Job.table() do
    field(:term, __MODULE__.ETF)
    field(:due_at, :utc_datetime)
  end

  def enqueued do
    __MODULE__ |> MyApp.Repo.all()
  end
end

I could imagine this (and a few other Ecto query functions) being quite useful for introspection, perhaps we should publish a new hex package.

KushalP commented 5 years ago

@lpil that's interesting. Can you give an example of how you're using this module in tests please?

lpil commented 5 years ago
assert MyApp.Job.enqueued() == []

No setup or teardown required.

KushalP commented 5 years ago

Interesting. Maybe it's worth making this step easier for our jobs?

lpil commented 5 years ago

What would you be after to make it easier for you? :)