Skip to content

Commit 796cc3d

Browse files
committed
feat:add graphql_nodes tests
Signed-off-by: nabil salah <nabil.salah203@gmail.com>
1 parent bbb4b56 commit 796cc3d

1 file changed

Lines changed: 365 additions & 0 deletions

File tree

Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
package graphql
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"net/http/httptest"
8+
"strings"
9+
"testing"
10+
"time"
11+
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
const (
17+
realEndpoint = "https://graphql.dev.threefold.me/graphql"
18+
)
19+
20+
func mockGraphQLServer(t *testing.T, statusCode int, responseBody string) *httptest.Server {
21+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22+
w.Header().Set("Content-Type", "application/json")
23+
w.WriteHeader(statusCode)
24+
fmt.Fprintln(w, responseBody)
25+
}))
26+
t.Cleanup(server.Close)
27+
return server
28+
}
29+
30+
func TestGetUpNodes_Mock(t *testing.T) {
31+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
32+
w.Header().Set("Content-Type", "application/json")
33+
w.WriteHeader(http.StatusOK)
34+
35+
body := make([]byte, r.ContentLength)
36+
r.Body.Read(body)
37+
requestBody := string(body)
38+
39+
var response string
40+
if strings.Contains(requestBody, "nodesConnection") {
41+
// This is the count query
42+
response = `{
43+
"data": {
44+
"items": {
45+
"count": 10
46+
}
47+
}
48+
}`
49+
} else {
50+
// This is the nodes query
51+
response = `{
52+
"data": {
53+
"nodes": [
54+
{
55+
"nodeID": 1,
56+
"publicConfig": {
57+
"ipv4": "192.168.1.1",
58+
"ipv6": "2001:db8::1"
59+
}
60+
},
61+
{
62+
"nodeID": 2,
63+
"publicConfig": {
64+
"ipv4": "192.168.1.2",
65+
"ipv6": "2001:db8::2"
66+
}
67+
}
68+
]
69+
}
70+
}`
71+
}
72+
73+
fmt.Fprintln(w, response)
74+
}))
75+
t.Cleanup(server.Close)
76+
77+
t.Run("basic query", func(t *testing.T) {
78+
gql, err := NewGraphQl(server.URL)
79+
require.NoError(t, err)
80+
81+
ctx := context.Background()
82+
nodes, err := gql.GetUpNodes(ctx, 0, 0, 0, false, false)
83+
84+
require.NoError(t, err)
85+
require.Len(t, nodes, 2)
86+
assert.Equal(t, uint32(1), nodes[0].NodeID)
87+
assert.Equal(t, "192.168.1.1", nodes[0].PublicConfig.Ipv4)
88+
assert.Equal(t, "2001:db8::1", nodes[0].PublicConfig.Ipv6)
89+
})
90+
91+
failServer := mockGraphQLServer(t, http.StatusInternalServerError, `{"errors":[{"message":"internal error"}]}`)
92+
93+
t.Run("server error", func(t *testing.T) {
94+
gql, err := NewGraphQl(failServer.URL)
95+
require.NoError(t, err)
96+
97+
ctx := context.Background()
98+
_, err = gql.GetUpNodes(ctx, 0, 0, 0, false, false)
99+
require.Error(t, err)
100+
})
101+
102+
t.Run("fallback behavior", func(t *testing.T) {
103+
gql, err := NewGraphQl(failServer.URL, server.URL)
104+
require.NoError(t, err)
105+
106+
ctx := context.Background()
107+
nodes, err := gql.GetUpNodes(ctx, 0, 0, 0, false, false)
108+
require.NoError(t, err)
109+
require.Len(t, nodes, 2)
110+
})
111+
}
112+
113+
func TestGetUpNodes_WithFilters(t *testing.T) {
114+
115+
gql, err := NewGraphQl(realEndpoint)
116+
require.NoError(t, err)
117+
ctx := context.Background()
118+
119+
t.Run("with node limit", func(t *testing.T) {
120+
nodes, err := gql.GetUpNodes(ctx, 5, 0, 0, false, false)
121+
require.NoError(t, err)
122+
123+
assert.LessOrEqual(t, len(nodes), 5)
124+
})
125+
126+
t.Run("with ipv4 filter", func(t *testing.T) {
127+
nodes, err := gql.GetUpNodes(ctx, 0, 0, 0, true, false)
128+
require.NoError(t, err)
129+
130+
for _, node := range nodes {
131+
assert.NotEmpty(t, node.PublicConfig.Ipv4)
132+
}
133+
})
134+
135+
t.Run("with ipv6 filter", func(t *testing.T) {
136+
nodes, err := gql.GetUpNodes(ctx, 0, 0, 0, false, true)
137+
require.NoError(t, err)
138+
139+
for _, node := range nodes {
140+
assert.NotEmpty(t, node.PublicConfig.Ipv6)
141+
}
142+
})
143+
}
144+
145+
func TestGetItemTotalCount(t *testing.T) {
146+
successResponse := `{
147+
"data": {
148+
"items": {
149+
"count": 42
150+
}
151+
}
152+
}`
153+
154+
server := mockGraphQLServer(t, http.StatusOK, successResponse)
155+
156+
t.Run("get count", func(t *testing.T) {
157+
gql, err := NewGraphQl(server.URL)
158+
require.NoError(t, err)
159+
160+
ctx := context.Background()
161+
count, err := gql.getItemTotalCount(ctx, "nodes", "where: {}")
162+
163+
require.NoError(t, err)
164+
assert.Equal(t, 42, count)
165+
})
166+
}
167+
168+
// TestExec tests the exec method directly
169+
func TestExec(t *testing.T) {
170+
successResponse := `{
171+
"data": {
172+
"test": "success"
173+
}
174+
}`
175+
176+
failureResponse := `{
177+
"errors": [
178+
{"message": "something went wrong"}
179+
]
180+
}`
181+
182+
successServer := mockGraphQLServer(t, http.StatusOK, successResponse)
183+
failureServer := mockGraphQLServer(t, http.StatusInternalServerError, failureResponse)
184+
185+
t.Run("success on first url", func(t *testing.T) {
186+
gql, err := NewGraphQl(successServer.URL)
187+
require.NoError(t, err)
188+
189+
result := struct {
190+
Test string
191+
}{}
192+
193+
err = gql.exec(context.Background(), "query { test }", &result, nil)
194+
require.NoError(t, err)
195+
assert.Equal(t, "success", result.Test)
196+
})
197+
198+
t.Run("fallback to second url", func(t *testing.T) {
199+
gql, err := NewGraphQl(failureServer.URL, successServer.URL)
200+
require.NoError(t, err)
201+
202+
result := struct {
203+
Test string
204+
}{}
205+
206+
err = gql.exec(context.Background(), "query { test }", &result, nil)
207+
require.NoError(t, err)
208+
assert.Equal(t, "success", result.Test)
209+
})
210+
211+
t.Run("all urls fail", func(t *testing.T) {
212+
gql, err := NewGraphQl(failureServer.URL, failureServer.URL)
213+
require.NoError(t, err)
214+
215+
result := struct {
216+
Test string
217+
}{}
218+
219+
err = gql.exec(context.Background(), "query { test }", &result, nil)
220+
require.Error(t, err)
221+
})
222+
}
223+
224+
225+
226+
func TestIntegration_NodeFiltering(t *testing.T) {
227+
228+
gql, err := NewGraphQl(realEndpoint)
229+
require.NoError(t, err)
230+
231+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
232+
defer cancel()
233+
234+
t.Run("nodes with IPv4 only", func(t *testing.T) {
235+
nodes, err := gql.GetUpNodes(ctx, 20, 0, 0, true, false)
236+
require.NoError(t, err)
237+
for i, node := range nodes {
238+
assert.NotEmpty(t, node.PublicConfig.Ipv4, "Node %d should have IPv4", i)
239+
}
240+
})
241+
242+
t.Run("nodes with IPv6 only", func(t *testing.T) {
243+
nodes, err := gql.GetUpNodes(ctx, 20, 0, 0, false, true)
244+
require.NoError(t, err)
245+
for i, node := range nodes {
246+
assert.NotEmpty(t, node.PublicConfig.Ipv6, "Node %d should have IPv6", i)
247+
}
248+
})
249+
250+
t.Run("nodes with both IPv4 and IPv6", func(t *testing.T) {
251+
nodes, err := gql.GetUpNodes(ctx, 10, 0, 0, true, true)
252+
require.NoError(t, err)
253+
for i, node := range nodes {
254+
assert.NotEmpty(t, node.PublicConfig.Ipv4, "Node %d should have IPv4", i)
255+
assert.NotEmpty(t, node.PublicConfig.Ipv6, "Node %d should have IPv6", i)
256+
}
257+
})
258+
}
259+
260+
261+
func TestIntegration_PaginationAndLimits(t *testing.T) {
262+
263+
gql, err := NewGraphQl(realEndpoint)
264+
require.NoError(t, err)
265+
266+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
267+
defer cancel()
268+
269+
t.Run("different_limits", func(t *testing.T) {
270+
limits := []int{1, 5, 10, 20, 50}
271+
272+
for _, limit := range limits {
273+
nodes, err := gql.GetUpNodes(ctx, limit, 0, 0, false, false)
274+
require.NoError(t, err)
275+
assert.LessOrEqual(t, len(nodes), limit,
276+
"Returned %d nodes but limit was %d", len(nodes), limit)
277+
}
278+
})
279+
}
280+
281+
func TestIntegration_ErrorHandling(t *testing.T) {
282+
283+
t.Run("invalid_endpoint", func(t *testing.T) {
284+
gql, err := NewGraphQl("https://invalid-endpoint-that-does-not-exist.com/graphql")
285+
require.NoError(t, err)
286+
287+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
288+
defer cancel()
289+
290+
_, err = gql.GetUpNodes(ctx, 5, 0, 0, false, false)
291+
require.Error(t, err)
292+
})
293+
294+
t.Run("timeout_handling", func(t *testing.T) {
295+
gql, err := NewGraphQl(realEndpoint)
296+
require.NoError(t, err)
297+
298+
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Microsecond)
299+
defer cancel()
300+
301+
_, err = gql.GetUpNodes(ctx, 5, 0, 0, false, false)
302+
require.Error(t, err)
303+
})
304+
305+
t.Run("fallback_to_valid_endpoint", func(t *testing.T) {
306+
gql, err := NewGraphQl(
307+
"https://invalid-endpoint.com/graphql",
308+
realEndpoint,
309+
)
310+
require.NoError(t, err)
311+
312+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
313+
defer cancel()
314+
315+
nodes, err := gql.GetUpNodes(ctx, 5, 0, 0, false, false)
316+
require.NoError(t, err)
317+
assert.GreaterOrEqual(t, len(nodes), 0)
318+
})
319+
}
320+
321+
func TestIntegration_DataValidation(t *testing.T) {
322+
323+
gql, err := NewGraphQl(realEndpoint)
324+
require.NoError(t, err)
325+
326+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
327+
defer cancel()
328+
329+
nodes, err := gql.GetUpNodes(ctx, 20, 0, 0, false, false)
330+
require.NoError(t, err)
331+
332+
t.Run("node_id_validation", func(t *testing.T) {
333+
nodeIDs := make(map[uint32]bool)
334+
335+
for i, node := range nodes {
336+
assert.Greater(t, node.NodeID, uint32(0), "Node %d has invalid ID", i)
337+
338+
assert.False(t, nodeIDs[node.NodeID], "Duplicate node ID %d found", node.NodeID)
339+
nodeIDs[node.NodeID] = true
340+
}
341+
342+
})
343+
344+
t.Run("public_config_validation", func(t *testing.T) {
345+
var ipv4Count, ipv6Count int
346+
347+
for i, node := range nodes {
348+
hasIPv4 := node.PublicConfig.Ipv4 != ""
349+
hasIPv6 := node.PublicConfig.Ipv6 != ""
350+
351+
if hasIPv4 {
352+
ipv4Count++
353+
assert.Contains(t, node.PublicConfig.Ipv4, ".",
354+
"Node %d IPv4 doesn't look like an IP: %s", i, node.PublicConfig.Ipv4)
355+
}
356+
357+
if hasIPv6 {
358+
ipv6Count++
359+
assert.Contains(t, node.PublicConfig.Ipv6, ":",
360+
"Node %d IPv6 doesn't look like an IP: %s", i, node.PublicConfig.Ipv6)
361+
}
362+
}
363+
364+
})
365+
}

0 commit comments

Comments
 (0)