Skip to content

Commit cf0238e

Browse files
committed
feat: add cluster connection helper script for manual testing
Add scripts/cluster_connect.exs to automate cluster node connection and verification for manual distributed testing. Features: - Auto-connects to n1, n2, n3 nodes on localhost - Waits for Raft cluster initialization - Verifies cluster status and leadership - Provides helper functions: - ClusterHelper.connect_all() - Connect all nodes - ClusterHelper.status() - Check cluster status - ClusterHelper.test_put_get() - Test basic operations Usage: # Terminal 1 iex --name n1@127.0.0.1 --cookie concord_test -S mix import_file("scripts/cluster_connect.exs") # Terminals 2 & 3 iex --name n2@127.0.0.1 --cookie concord_test -S mix iex --name n3@127.0.0.1 --cookie concord_test -S mix This makes manual testing much easier and prevents the 'cluster_not_ready' errors from missed connection steps.
1 parent 4d7d753 commit cf0238e

File tree

2 files changed

+161
-2
lines changed

2 files changed

+161
-2
lines changed

e2e_test/README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,33 @@ The e2e tests are **completely separate** from unit tests (`test/`) and focus on
2828

2929
## Manual Testing (Current Recommended Approach)
3030

31-
Until the OTP 28 compatibility issues are resolved, you can test Concord's distributed features manually:
31+
Until the OTP 28 compatibility issues are resolved, you can test Concord's distributed features manually.
3232

33-
### Starting Multiple Nodes
33+
### Quick Start with Helper Script
34+
35+
**Terminal 1:**
36+
```bash
37+
iex --name n1@127.0.0.1 --cookie concord_test -S mix
38+
```
39+
40+
Then in the IEx session:
41+
```elixir
42+
import_file("scripts/cluster_connect.exs")
43+
```
44+
45+
This will automatically connect to n2 and n3, wait for cluster formation, and verify it's ready.
46+
47+
**Terminal 2:**
48+
```bash
49+
iex --name n2@127.0.0.1 --cookie concord_test -S mix
50+
```
51+
52+
**Terminal 3:**
53+
```bash
54+
iex --name n3@127.0.0.1 --cookie concord_test -S mix
55+
```
56+
57+
### Manual Setup (Without Helper Script)
3458

3559
Open 3 terminal windows and run:
3660

scripts/cluster_connect.exs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Helper script to connect nodes in a manual test cluster
2+
#
3+
# Usage:
4+
# # Start nodes in separate terminals:
5+
# iex --name n1@127.0.0.1 --cookie concord_test -S mix
6+
# iex --name n2@127.0.0.1 --cookie concord_test -S mix
7+
# iex --name n3@127.0.0.1 --cookie concord_test -S mix
8+
#
9+
# # In the first node (n1), run:
10+
# import_file("scripts/cluster_connect.exs")
11+
12+
defmodule ClusterHelper do
13+
@moduledoc """
14+
Helper functions for manual cluster testing.
15+
"""
16+
17+
def connect_all do
18+
IO.puts("\n=== Connecting Cluster Nodes ===\n")
19+
20+
nodes = [
21+
:"n1@127.0.0.1",
22+
:"n2@127.0.0.1",
23+
:"n3@127.0.0.1"
24+
]
25+
26+
# Connect to all other nodes
27+
Enum.each(nodes, fn node ->
28+
if node != Node.self() do
29+
case Node.connect(node) do
30+
true ->
31+
IO.puts("✓ Connected to #{node}")
32+
false ->
33+
IO.puts("✗ Failed to connect to #{node}")
34+
:ignored ->
35+
IO.puts("⚠ Already connected to #{node}")
36+
end
37+
end
38+
end)
39+
40+
# Wait for connections to stabilize
41+
Process.sleep(1000)
42+
43+
IO.puts("\n=== Cluster Status ===\n")
44+
IO.puts("Current node: #{node()}")
45+
IO.puts("Connected nodes: #{inspect(Node.list())}")
46+
47+
# Wait for Raft cluster to initialize
48+
IO.puts("\nWaiting for Raft cluster to initialize...")
49+
Process.sleep(2000)
50+
51+
case :ra.members({:concord_cluster, node()}) do
52+
{:ok, members, {:concord_cluster, leader}} ->
53+
IO.puts("\n✓ Raft cluster ready!")
54+
IO.puts("Leader: #{leader}")
55+
IO.puts("Members: #{inspect(members)}")
56+
IO.puts("\nYou can now use Concord.put/2 and Concord.get/1")
57+
58+
{:error, reason} ->
59+
IO.puts("\n✗ Raft cluster not ready: #{inspect(reason)}")
60+
IO.puts("Wait a few more seconds and try: :ra.members({:concord_cluster, node()})")
61+
62+
{:timeout, _} ->
63+
IO.puts("\n⚠ Raft cluster is still initializing...")
64+
IO.puts("Wait a few more seconds and try: :ra.members({:concord_cluster, node()})")
65+
end
66+
67+
:ok
68+
end
69+
70+
def status do
71+
IO.puts("\n=== Cluster Status ===\n")
72+
IO.puts("Current node: #{node()}")
73+
IO.puts("Connected nodes: #{inspect(Node.list())}")
74+
75+
case :ra.members({:concord_cluster, node()}) do
76+
{:ok, members, {:concord_cluster, leader}} ->
77+
IO.puts("\nRaft cluster status: READY")
78+
IO.puts("Leader: #{leader}")
79+
IO.puts("Members: #{inspect(members)}")
80+
81+
error ->
82+
IO.puts("\nRaft cluster status: NOT READY")
83+
IO.puts("Error: #{inspect(error)}")
84+
end
85+
86+
:ok
87+
end
88+
89+
def test_put_get do
90+
IO.puts("\n=== Testing Concord Operations ===\n")
91+
92+
key = "test_key_#{System.system_time(:second)}"
93+
value = "test_value_#{:rand.uniform(1000)}"
94+
95+
IO.puts("Putting: #{key} = #{value}")
96+
97+
case Concord.put(key, value) do
98+
:ok ->
99+
IO.puts("✓ Put successful")
100+
101+
IO.puts("Getting: #{key}")
102+
103+
case Concord.get(key) do
104+
{:ok, ^value} ->
105+
IO.puts("✓ Get successful: #{inspect(value)}")
106+
IO.puts("\n✓✓✓ Concord cluster is working! ✓✓✓")
107+
108+
{:ok, other} ->
109+
IO.puts("✗ Got unexpected value: #{inspect(other)}")
110+
111+
error ->
112+
IO.puts("✗ Get failed: #{inspect(error)}")
113+
end
114+
115+
error ->
116+
IO.puts("✗ Put failed: #{inspect(error)}")
117+
IO.puts("The cluster may not be ready yet. Wait a few seconds and try: ClusterHelper.status()")
118+
end
119+
120+
:ok
121+
end
122+
end
123+
124+
# Auto-connect when script is loaded
125+
IO.puts("\n" <> String.duplicate("=", 60))
126+
IO.puts("Concord Cluster Helper Loaded")
127+
IO.puts(String.duplicate("=", 60))
128+
IO.puts("\nAvailable commands:")
129+
IO.puts(" ClusterHelper.connect_all() - Connect to all nodes")
130+
IO.puts(" ClusterHelper.status() - Check cluster status")
131+
IO.puts(" ClusterHelper.test_put_get() - Test basic operations")
132+
IO.puts("\nConnecting to cluster nodes...")
133+
IO.puts(String.duplicate("=", 60) <> "\n")
134+
135+
ClusterHelper.connect_all()

0 commit comments

Comments
 (0)