Skip to content

Commit c58f893

Browse files
committed
Merge branch 'release/0.1.10'
2 parents 159a5c4 + 02d6b8c commit c58f893

File tree

3 files changed

+249
-4
lines changed

3 files changed

+249
-4
lines changed

lib/tama_ex/memory.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ defmodule TamaEx.Memory do
2727
2828
"""
2929
def create_entity(client, %TamaEx.Neural.Class{id: class_id}, attrs) when is_binary(class_id) do
30-
with {:ok, validated_client} <- TamaEx.validate_client(client, ["ingest"]),
30+
with {:ok, validated_client} <- TamaEx.validate_client(client, ["memory"]),
3131
{:ok, validated_params} <- EntityParams.validate(attrs) do
32-
url = "/memory/classes/#{class_id}/entities"
32+
url = "/classes/#{class_id}/entities"
3333

3434
validated_client
3535
|> Req.post(url: url, json: %{entity: validated_params})

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule TamaEx.MixProject do
44
def project do
55
[
66
app: :tama_ex,
7-
version: "0.1.9",
7+
version: "0.1.10",
88
elixir: "~> 1.18",
99
start_permanent: Mix.env() == :prod,
1010
deps: deps(),

test/tama_ex/memory_test.exs

Lines changed: 246 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ defmodule TamaEx.MemoryTest do
88
alias TamaEx.Memory.Entity.Params, as: EntityParams
99
alias TamaEx.Neural.Class
1010

11+
setup do
12+
bypass = Bypass.open()
13+
{:ok, bypass: bypass}
14+
end
15+
1116
# Test helper for creating a mock class
1217
defp mock_class(id \\ "class_123") do
1318
%Class{
@@ -17,7 +22,247 @@ defmodule TamaEx.MemoryTest do
1722
}
1823
end
1924

20-
describe "create_entity/3" do
25+
describe "create_entity/3 - bypass integration" do
26+
test "successfully creates entity with bypass", %{bypass: bypass} do
27+
base_url = "http://localhost:#{bypass.port}"
28+
client = mock_client("memory", base_url)
29+
class = mock_class("test_class_123")
30+
31+
attrs = %{
32+
"identifier" => "test-entity-bypass",
33+
"record" => %{"name" => "Test Entity", "value" => 42},
34+
"validate_record" => true
35+
}
36+
37+
expected_response = %{
38+
"data" => %{
39+
"id" => "entity_created_456",
40+
"class_id" => "test_class_123",
41+
"current_state" => "active",
42+
"identifier" => "test-entity-bypass"
43+
}
44+
}
45+
46+
Bypass.expect(bypass, "POST", "/memory/classes/test_class_123/entities", fn conn ->
47+
{:ok, body, conn} = Plug.Conn.read_body(conn)
48+
request_data = Jason.decode!(body)
49+
50+
# Verify the request structure
51+
assert request_data["entity"]["identifier"] == "test-entity-bypass"
52+
assert request_data["entity"]["record"]["name"] == "Test Entity"
53+
assert request_data["entity"]["record"]["value"] == 42
54+
assert request_data["entity"]["validate_record"] == true
55+
56+
conn
57+
|> Plug.Conn.put_resp_content_type("application/json")
58+
|> Plug.Conn.resp(201, Jason.encode!(expected_response))
59+
end)
60+
61+
# Make the actual API call
62+
assert {:ok, %Entity{} = entity} = Memory.create_entity(client, class, attrs)
63+
64+
# Verify the parsed entity
65+
assert entity.id == "entity_created_456"
66+
assert entity.class_id == "test_class_123"
67+
assert entity.current_state == "active"
68+
assert entity.identifier == "test-entity-bypass"
69+
end
70+
71+
test "handles API error responses with bypass", %{bypass: bypass} do
72+
base_url = "http://localhost:#{bypass.port}"
73+
client = mock_client("memory", base_url)
74+
class = mock_class("error_class_123")
75+
76+
attrs = %{
77+
"identifier" => "error-entity",
78+
"record" => %{"invalid" => "data"}
79+
}
80+
81+
error_response = %{
82+
"error" => %{
83+
"message" => "Validation failed",
84+
"details" => %{
85+
"record" => ["is invalid"]
86+
}
87+
}
88+
}
89+
90+
Bypass.expect(bypass, "POST", "/memory/classes/error_class_123/entities", fn conn ->
91+
{:ok, body, conn} = Plug.Conn.read_body(conn)
92+
request_data = Jason.decode!(body)
93+
94+
assert request_data["entity"]["identifier"] == "error-entity"
95+
assert request_data["entity"]["record"]["invalid"] == "data"
96+
97+
conn
98+
|> Plug.Conn.put_resp_content_type("application/json")
99+
|> Plug.Conn.resp(422, Jason.encode!(error_response))
100+
end)
101+
102+
# Make the actual API call and expect an error
103+
assert {:error, _error} = Memory.create_entity(client, class, attrs)
104+
end
105+
106+
test "handles server errors with bypass", %{bypass: bypass} do
107+
base_url = "http://localhost:#{bypass.port}"
108+
client = mock_client("memory", base_url)
109+
class = mock_class("server_error_class_123")
110+
111+
attrs = %{
112+
"identifier" => "server-error-entity",
113+
"record" => %{"data" => "test"}
114+
}
115+
116+
# Simulate server error
117+
Bypass.expect(bypass, "POST", "/memory/classes/server_error_class_123/entities", fn conn ->
118+
conn
119+
|> Plug.Conn.put_resp_content_type("application/json")
120+
|> Plug.Conn.resp(500, Jason.encode!(%{"error" => "Internal server error"}))
121+
end)
122+
123+
# Make the actual API call and expect an error
124+
assert {:error, _error} = Memory.create_entity(client, class, attrs)
125+
end
126+
127+
test "handles different class IDs in URL construction", %{bypass: bypass} do
128+
base_url = "http://localhost:#{bypass.port}"
129+
client = mock_client("memory", base_url)
130+
131+
test_cases = [
132+
{"simple", "simple"},
133+
{"class_with_underscores", "class_with_underscores"},
134+
{"class-with-dashes", "class-with-dashes"},
135+
{"Class123", "Class123"}
136+
]
137+
138+
Enum.each(test_cases, fn {class_id, expected_url_part} ->
139+
class = mock_class(class_id)
140+
attrs = %{"identifier" => "test-#{class_id}", "record" => %{}}
141+
142+
expected_response = %{
143+
"data" => %{
144+
"id" => "entity_#{class_id}",
145+
"class_id" => class_id,
146+
"current_state" => "active",
147+
"identifier" => "test-#{class_id}"
148+
}
149+
}
150+
151+
Bypass.expect_once(
152+
bypass,
153+
"POST",
154+
"/memory/classes/#{expected_url_part}/entities",
155+
fn conn ->
156+
conn
157+
|> Plug.Conn.put_resp_content_type("application/json")
158+
|> Plug.Conn.resp(201, Jason.encode!(expected_response))
159+
end
160+
)
161+
162+
assert {:ok, %Entity{} = entity} = Memory.create_entity(client, class, attrs)
163+
assert entity.class_id == class_id
164+
assert entity.identifier == "test-#{class_id}"
165+
end)
166+
end
167+
168+
test "validates request headers and content type", %{bypass: bypass} do
169+
base_url = "http://localhost:#{bypass.port}"
170+
client = mock_client("memory", base_url)
171+
class = mock_class("headers_test_123")
172+
173+
attrs = %{
174+
"identifier" => "headers-test",
175+
"record" => %{"test" => "data"}
176+
}
177+
178+
Bypass.expect(bypass, "POST", "/memory/classes/headers_test_123/entities", fn conn ->
179+
# Verify headers
180+
assert Plug.Conn.get_req_header(conn, "authorization") == ["Bearer mock_token"]
181+
assert Plug.Conn.get_req_header(conn, "content-type") == ["application/json"]
182+
183+
expected_response = %{
184+
"data" => %{
185+
"id" => "headers_entity_123",
186+
"class_id" => "headers_test_123",
187+
"current_state" => "active",
188+
"identifier" => "headers-test"
189+
}
190+
}
191+
192+
conn
193+
|> Plug.Conn.put_resp_content_type("application/json")
194+
|> Plug.Conn.resp(201, Jason.encode!(expected_response))
195+
end)
196+
197+
assert {:ok, %Entity{}} = Memory.create_entity(client, class, attrs)
198+
end
199+
200+
test "handles complex record structures with bypass", %{bypass: bypass} do
201+
base_url = "http://localhost:#{bypass.port}"
202+
client = mock_client("memory", base_url)
203+
class = mock_class("complex_class_123")
204+
205+
complex_record = %{
206+
"user" => %{
207+
"name" => "John Doe",
208+
"age" => 30,
209+
"preferences" => %{
210+
"theme" => "dark",
211+
"notifications" => true
212+
}
213+
},
214+
"metadata" => %{
215+
"created_at" => "2023-01-01T00:00:00Z",
216+
"tags" => ["important", "test"]
217+
}
218+
}
219+
220+
attrs = %{
221+
"identifier" => "complex-entity",
222+
"record" => complex_record,
223+
"validate_record" => false
224+
}
225+
226+
expected_response = %{
227+
"data" => %{
228+
"id" => "complex_entity_789",
229+
"class_id" => "complex_class_123",
230+
"current_state" => "active",
231+
"identifier" => "complex-entity"
232+
}
233+
}
234+
235+
Bypass.expect(bypass, "POST", "/memory/classes/complex_class_123/entities", fn conn ->
236+
{:ok, body, conn} = Plug.Conn.read_body(conn)
237+
request_data = Jason.decode!(body)
238+
239+
# Verify the complex record structure is preserved
240+
assert request_data["entity"]["identifier"] == "complex-entity"
241+
assert request_data["entity"]["record"]["user"]["name"] == "John Doe"
242+
assert request_data["entity"]["record"]["user"]["age"] == 30
243+
assert request_data["entity"]["record"]["user"]["preferences"]["theme"] == "dark"
244+
assert request_data["entity"]["record"]["user"]["preferences"]["notifications"] == true
245+
246+
assert request_data["entity"]["record"]["metadata"]["created_at"] ==
247+
"2023-01-01T00:00:00Z"
248+
249+
assert request_data["entity"]["record"]["metadata"]["tags"] == ["important", "test"]
250+
assert request_data["entity"]["validate_record"] == false
251+
252+
conn
253+
|> Plug.Conn.put_resp_content_type("application/json")
254+
|> Plug.Conn.resp(201, Jason.encode!(expected_response))
255+
end)
256+
257+
assert {:ok, %Entity{} = entity} = Memory.create_entity(client, class, attrs)
258+
assert entity.id == "complex_entity_789"
259+
assert entity.class_id == "complex_class_123"
260+
assert entity.current_state == "active"
261+
assert entity.identifier == "complex-entity"
262+
end
263+
end
264+
265+
describe "create_entity/3 - unit tests" do
21266
test "creates entity with valid parameters" do
22267
_client = mock_client("ingest")
23268
_class = mock_class()

0 commit comments

Comments
 (0)