Skip to content

Commit

Permalink
chore: Integration tests (#61)
Browse files Browse the repository at this point in the history
- [x] no step function
- [x] step run function
- [x] step sleep function
- [x] step sleep_until function
- [x] step wait_for_event function
  - [x] fulfill
  - [x] timeout
- [x] step send_event function

---------

Co-authored-by: Darwin D Wu <[email protected]>
  • Loading branch information
darwin67 and darwin67 committed Nov 7, 2023
1 parent 758e8f5 commit d83e446
Show file tree
Hide file tree
Showing 22 changed files with 424 additions and 36 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ jobs:
otp-version: 25.3
elixir-version: 1.14.4

- name: Set Node.js 20.x
uses: actions/setup-node@v3
with:
node-version: 20.x

- name: Install inngest-cli
run: npm i -g inngest-cli

- name: Dependency cache
uses: actions/cache@v3
with:
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ dev:
deps:
mix deps.get

.PHONY: unit-test
unit-test:
MIX_ENV=test UNIT=true mix test

.PHONY: test
test:
MIX_ENV=test mix test
Expand Down
12 changes: 9 additions & 3 deletions lib/inngest/client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@ defmodule Inngest.Client do
@doc """
Send one or a batch of events to Inngest
"""
@spec send(Event.t() | list(Event.t()), Keyword.t()) :: :ok | {:error, binary()}
@spec send(Event.t() | list(Event.t()), Keyword.t()) :: {:ok, map()} | {:error, binary()}
def send(payload, opts \\ []) do
event_key = Config.event_key()
client = httpclient(:event, opts)

case Tesla.post(client, "/e/#{event_key}", payload) do
{:ok, %Tesla.Env{status: 200}} ->
:ok
{:ok, %Tesla.Env{status: 200, body: resp}} ->
# NOTE: because resp headers currently says text/plain
# so http client won't automatically decode it as json
if is_binary(resp) do
Jason.decode(resp)
else
{:ok, resp}
end

{:ok, %Tesla.Env{status: 400}} ->
{:error, "invalid event data"}
Expand Down
10 changes: 6 additions & 4 deletions lib/inngest/function.ex
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ defmodule Inngest.Function do
end
end

# TODO:
# def validate_datetime(%Date{} = date), do: nil

def validate_datetime(%DateTime{} = datetime),
do: Timex.format(datetime, "{YYYY}-{0M}-{0D}T{h24}:{m}:{s}Z")

def validate_datetime(datetime) when is_binary(datetime) do
with {:error, _} <- Timex.parse(datetime, "{RFC3339}"),
{:error, _} <- Timex.parse(datetime, "{YYYY}-{MM}-{DD}T{h24}:{mm}:{ss}"),
Expand Down Expand Up @@ -160,10 +166,6 @@ defmodule Inngest.Function do
end
end

# TODO: Allow parsing DateTime, Date
# def validate_datetime(%DateTime{} = datetime) do
# end

def validate_datetime(_), do: {:error, "Expect valid DateTime formatted input"}
end

Expand Down
11 changes: 7 additions & 4 deletions lib/inngest/step_tool.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ defmodule Inngest.StepTool do
throw(%GeneratorOpCode{
id: hashed_id,
name: datetime,
op: op
display_name: datetime,
op: op.op
})

{:error, error} ->
Expand Down Expand Up @@ -108,7 +109,8 @@ defmodule Inngest.StepTool do

throw(%GeneratorOpCode{
id: hashed_id,
name: step_id,
name: Map.get(opts, :event, step_id),
display_name: step_id,
op: op.op,
opts: opts
})
Expand All @@ -129,15 +131,16 @@ defmodule Inngest.StepTool do
end

# if not, execute function
result = Inngest.Client.send(events)
# TODO: handle error responses as well
{:ok, %{"ids" => event_ids, "status" => 200}} = Inngest.Client.send(events)

# cancel execution and return with opcode
throw(%GeneratorOpCode{
id: hashed_id,
name: "sendEvent",
display_name: "Send " <> display_name,
op: op.op,
data: result
data: %{event_ids: event_ids}
})

# if found, return value
Expand Down
28 changes: 28 additions & 0 deletions test/inngest/function/cases/multi_step_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Inngest.Function.Cases.MultiStepTest do
use ExUnit.Case, async: true

alias Inngest.Test.DevServer
import Inngest.Test.Helper

@default_sleep 5_000

@tag :integration
test "should run successfully" do
event_id = send_test_event("test/plug.step")
Process.sleep(@default_sleep)

assert {:ok,
%{
"data" => [
%{
"output" => 5,
"run_id" => _run_id,
"status" => "Completed"
}
]
}} = DevServer.run_ids(event_id)

# TODO: check on step outputs
# assert {:ok, resp} = DevServer.fn_run(run_id) |> IO.inspect()
end
end
24 changes: 24 additions & 0 deletions test/inngest/function/cases/no_step_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Inngest.Function.Cases.NoStepTest do
use ExUnit.Case, async: true

alias Inngest.Test.DevServer
import Inngest.Test.Helper

@default_sleep 5_000

@tag :integration
test "should run successfully" do
event_id = send_test_event("test/plug.no-step")
Process.sleep(@default_sleep)

assert {:ok,
%{
"data" => [
%{
"output" => "hello world",
"status" => "Completed"
}
]
}} = DevServer.run_ids(event_id)
end
end
30 changes: 30 additions & 0 deletions test/inngest/function/cases/send_event_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule Inngest.Function.Cases.SendEventTest do
use ExUnit.Case, async: true

alias Inngest.Test.DevServer
import Inngest.Test.Helper

@default_sleep 5_000

@tag :integration
test "should run successfully" do
event_id = send_test_event("test/plug.send")
Process.sleep(@default_sleep)

assert {:ok,
%{
"data" => [
%{
"output" => %{
"event_ids" => event_ids
},
"run_id" => _run_id,
"status" => "Completed"
}
]
}} = DevServer.run_ids(event_id)

assert Enum.count(event_ids) > 0
assert is_list(event_ids)
end
end
39 changes: 39 additions & 0 deletions test/inngest/function/cases/sleep_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
defmodule Inngest.Function.Cases.SleepTest do
use ExUnit.Case, async: true

alias Inngest.Test.DevServer
import Inngest.Test.Helper

@default_sleep 5_000

@tag :integration
test "should run successfully" do
event_id = send_test_event("test/plug.sleep")
Process.sleep(@default_sleep)

# it should be sleeping so have not completed
assert {:ok,
%{
"data" => [
%{
"run_id" => run_id,
"status" => "Running",
"ended_at" => nil
}
]
}} = DevServer.run_ids(event_id)

# wait till sleep is done
Process.sleep(@default_sleep)

assert {:ok,
%{
"data" => %{
"event_id" => ^event_id,
"run_id" => ^run_id,
"output" => "yolo",
"status" => "Completed"
}
}} = DevServer.fn_run(run_id)
end
end
39 changes: 39 additions & 0 deletions test/inngest/function/cases/sleep_until_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
defmodule Inngest.Function.Cases.SleepUntilTest do
use ExUnit.Case, async: true

alias Inngest.Test.DevServer
import Inngest.Test.Helper

@default_sleep 5_000

@tag :integration
test "should run successfully" do
event_id = send_test_event("test/plug.sleep_until")
Process.sleep(@default_sleep)

# it should be sleeping so have not completed
assert {:ok,
%{
"data" => [
%{
"run_id" => run_id,
"status" => "Running",
"ended_at" => nil
}
]
}} = DevServer.run_ids(event_id)

# wait till sleep is done
Process.sleep(@default_sleep)

assert {:ok,
%{
"data" => %{
"event_id" => ^event_id,
"run_id" => ^run_id,
"output" => "awake",
"status" => "Completed"
}
}} = DevServer.fn_run(run_id)
end
end
71 changes: 71 additions & 0 deletions test/inngest/function/cases/wait_for_event_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
defmodule Inngest.Function.Cases.WaitForEventTest do
use ExUnit.Case, async: true

alias Inngest.Test.DevServer
import Inngest.Test.Helper

@default_sleep 5_000

@tag :integration
test "should have access to event when fulfilled" do
event_id = send_test_event("test/plug.wait-for-event")
Process.sleep(@default_sleep)

# it should be waiting
assert {:ok,
%{
"data" => [
%{
"run_id" => run_id,
"status" => "Running",
"ended_at" => nil
}
]
}} = DevServer.run_ids(event_id)

# send the waited event to continue
assert _ = send_test_event("test/yolo.wait")
Process.sleep(@default_sleep)

assert {:ok,
%{
"data" => %{
"event_id" => ^event_id,
"run_id" => ^run_id,
"output" => "fulfilled",
"status" => "Completed"
}
}} = DevServer.fn_run(run_id)
end

@tag :integration
test "should get nil when not fulfilled" do
event_id = send_test_event("test/plug.wait-for-event")
Process.sleep(@default_sleep)

# it should be waiting
assert {:ok,
%{
"data" => [
%{
"run_id" => run_id,
"status" => "Running",
"ended_at" => nil
}
]
}} = DevServer.run_ids(event_id)

# Don't do anything
Process.sleep(@default_sleep)

assert {:ok,
%{
"data" => %{
"event_id" => ^event_id,
"run_id" => ^run_id,
"output" => "empty",
"status" => "Completed"
}
}} = DevServer.fn_run(run_id)
end
end
6 changes: 6 additions & 0 deletions test/inngest/function_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ defmodule Inngest.FunctionTest do
end
end

test "should accept Datetime objects" do
dt = DateTime.new!(~D[2024-05-24], ~T[13:26:08.003], "Etc/UTC")
expected = "2024-05-24T13:26:08Z"
assert {:ok, ^expected} = Function.validate_datetime(dt)
end

test "should return error for invalid string format" do
assert {:error, "Unknown format for DateTime"} = Function.validate_datetime("yolo")
end
Expand Down
7 changes: 0 additions & 7 deletions test/inngest/router/plug_test.exs

This file was deleted.

2 changes: 1 addition & 1 deletion test/support/cases/no_step_fn.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ defmodule Inngest.Test.Case.NoStepFn do
alias Inngest.{FnOpts, Trigger}

@func %FnOpts{id: "no-step-fn", name: "No Step Function"}
@trigger %Trigger{event: "test/no-step"}
@trigger %Trigger{event: "test/plug.no-step"}

@impl true
def exec(_, _args) do
Expand Down
Loading

0 comments on commit d83e446

Please sign in to comment.