Skip to content

Commit 98e35a3

Browse files
Tests for create endpoint
1 parent a8b8fb9 commit 98e35a3

File tree

3 files changed

+180
-3
lines changed

3 files changed

+180
-3
lines changed

ee/ephemeral_environments/lib/ephemeral_environments/grpc/ephemeral_environments_server.ex

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,13 @@ defmodule EphemeralEnvironments.Grpc.EphemeralEnvironmentsServer do
2525
end
2626

2727
def create(request, _stream) do
28-
{:ok, ret} = EphemeralEnvironments.Service.EphemeralEnvironmentType.create(request.environment_type)
29-
converted = EphemeralEnvironments.Utils.Proto.from_map(%{environment_type: ret}, CreateResponse)
30-
converted
28+
case EphemeralEnvironments.Service.EphemeralEnvironmentType.create(request.environment_type) do
29+
{:ok, ret} ->
30+
EphemeralEnvironments.Utils.Proto.from_map(%{environment_type: ret}, CreateResponse)
31+
32+
{:error, error_message} ->
33+
raise GRPC.RPCError, status: :unknown, message: error_message
34+
end
3135
end
3236

3337
def update(_request, _stream) do
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
defmodule EphemeralEnvironments.Grpc.EphemeralEnvironmentsServerTest do
2+
use ExUnit.Case, async: false
3+
4+
alias EphemeralEnvironments.Repo
5+
alias EphemeralEnvironments.Repo.EphemeralEnvironmentType, as: Schema
6+
7+
alias InternalApi.EphemeralEnvironments.{
8+
CreateRequest,
9+
EphemeralEnvironmentType,
10+
EphemeralEnvironments
11+
}
12+
13+
@org_id Ecto.UUID.generate()
14+
@user_id Ecto.UUID.generate()
15+
@grpc_port 50051
16+
17+
setup do
18+
:ok = Ecto.Adapters.SQL.Sandbox.checkout(Repo)
19+
20+
# Allow the gRPC server process to use this test's DB connection
21+
Ecto.Adapters.SQL.Sandbox.mode(Repo, {:shared, self()})
22+
23+
# Connect to the gRPC server
24+
{:ok, channel} = GRPC.Stub.connect("localhost:#{@grpc_port}")
25+
{:ok, channel: channel}
26+
end
27+
28+
describe "list/2" do
29+
end
30+
31+
describe "describe/2" do
32+
end
33+
34+
describe "create/2" do
35+
test "creates the environment and ignores invalid request attributes", %{channel: channel} do
36+
# Build request with invalid attributes that should be ignored:
37+
# - wrong last_updated_by (should use created_by)
38+
# - wrong state (should default to :draft)
39+
# - old timestamps (should use current DB timestamps)
40+
request = %CreateRequest{
41+
environment_type: %EphemeralEnvironmentType{
42+
org_id: @org_id,
43+
name: "Test Environment",
44+
description: "A test environment type",
45+
created_by: @user_id,
46+
last_updated_by: Ecto.UUID.generate(),
47+
state: :TYPE_STATE_CORDONED,
48+
max_number_of_instances: 5,
49+
created_at: build_old_timestamp(),
50+
updated_at: build_old_timestamp()
51+
}
52+
}
53+
54+
# Make the actual gRPC call through the stub (goes through all interceptors)
55+
{:ok, response} = EphemeralEnvironments.Stub.create(channel, request)
56+
env_type = response.environment_type
57+
58+
# Validate response - invalid attributes were corrected
59+
assert env_type.org_id == @org_id
60+
assert env_type.name == "Test Environment"
61+
assert env_type.description == "A test environment type"
62+
assert env_type.created_by == @user_id
63+
assert env_type.last_updated_by == @user_id
64+
assert env_type.state == :TYPE_STATE_DRAFT
65+
assert env_type.max_number_of_instances == 5
66+
assert_recent_timestamp(DateTime.from_unix!(env_type.updated_at.seconds))
67+
68+
# Validate database record exists
69+
assert Repo.get(Schema, env_type.id)
70+
end
71+
72+
test "fails to create environment type with duplicate name in same org", %{channel: channel} do
73+
{:ok, _} = Support.Factories.EphemeralEnvironmentsType.insert(org_id: @org_id, name: "Test")
74+
75+
duplicate_request = %CreateRequest{
76+
environment_type: %EphemeralEnvironmentType{
77+
org_id: @org_id,
78+
name: "Test",
79+
max_number_of_instances: 1,
80+
created_by: @user_id
81+
}
82+
}
83+
84+
{:error, error} = EphemeralEnvironments.Stub.create(channel, duplicate_request)
85+
assert %GRPC.RPCError{} = error
86+
assert error.status == 2
87+
assert error.message == "duplicate_name: ephemeral environment name has already been taken"
88+
end
89+
90+
test "allows same name in different orgs", %{channel: channel} do
91+
{:ok, _} = Support.Factories.EphemeralEnvironmentsType.insert(org_id: @org_id, name: "Test")
92+
93+
request = %CreateRequest{
94+
environment_type: %EphemeralEnvironmentType{
95+
org_id: Ecto.UUID.generate(),
96+
name: "Test",
97+
max_number_of_instances: 1,
98+
created_by: @user_id
99+
}
100+
}
101+
102+
assert {:ok, _} = EphemeralEnvironments.Stub.create(channel, request)
103+
end
104+
end
105+
106+
describe "update/2" do
107+
end
108+
109+
describe "delete/2" do
110+
end
111+
112+
describe "cordon/2" do
113+
end
114+
115+
###
116+
### Helper functions
117+
###
118+
119+
defp build_old_timestamp do
120+
one_hour_ago = DateTime.utc_now() |> DateTime.add(-3600, :second)
121+
%Google.Protobuf.Timestamp{seconds: DateTime.to_unix(one_hour_ago), nanos: 0}
122+
end
123+
124+
defp assert_recent_timestamp(datetime) do
125+
assert DateTime.diff(DateTime.utc_now(), datetime, :second) < 5
126+
end
127+
end
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
defmodule Support.Factories.EphemeralEnvironmentsType do
2+
@moduledoc """
3+
Factory for creating EphemeralEnvironmentType records in tests.
4+
5+
## Usage
6+
7+
# Create with defaults
8+
{:ok, env_type} = Support.Factories.EphemeralEnvironmentsType.insert()
9+
10+
# Create with custom attributes
11+
{:ok, env_type} = Support.Factories.EphemeralEnvironmentsType.insert(
12+
org_id: "some-org-id",
13+
name: "My Environment",
14+
description: "Custom description",
15+
created_by: "user-id",
16+
state: :ready,
17+
max_number_of_instances: 10
18+
)
19+
"""
20+
21+
def insert(options \\ []) do
22+
attrs = %{
23+
org_id: get_id(options[:org_id]),
24+
name: get_name(options[:name]),
25+
description: options[:description],
26+
created_by: get_id(options[:created_by]),
27+
last_updated_by: get_id(options[:created_by]),
28+
state: options[:state] || :draft,
29+
max_number_of_instances: options[:max_number_of_instances] || 1
30+
}
31+
32+
%EphemeralEnvironments.Repo.EphemeralEnvironmentType{}
33+
|> EphemeralEnvironments.Repo.EphemeralEnvironmentType.changeset(attrs)
34+
|> EphemeralEnvironments.Repo.insert()
35+
end
36+
37+
defp get_id(nil), do: Ecto.UUID.generate()
38+
defp get_id(id), do: id
39+
40+
defp get_name(nil), do: "env-" <> random_string(10)
41+
defp get_name(name), do: name
42+
43+
defp random_string(length) do
44+
for(_ <- 1..length, into: "", do: <<Enum.random(~c"abcdefghijklmnopqrstuvwxyz0123456789")>>)
45+
end
46+
end

0 commit comments

Comments
 (0)