1 package transport_test
2
3 import (
4 "bufio"
5 "io"
6 "net/http"
7 "net/http/httptest"
8 "strings"
9 "sync"
10 "testing"
11
12 "github.com/stretchr/testify/assert"
13 "github.com/stretchr/testify/require"
14
15 "github.com/99designs/gqlgen/graphql/handler/testserver"
16 "github.com/99designs/gqlgen/graphql/handler/transport"
17 )
18
19 func TestSSE(t *testing.T) {
20 initialize := func() *testserver.TestServer {
21 h := testserver.New()
22 h.AddTransport(transport.SSE{})
23 return h
24 }
25
26 initializeWithServer := func() (*testserver.TestServer, *httptest.Server) {
27 h := initialize()
28 return h, httptest.NewServer(h)
29 }
30
31 createHTTPTestRequest := func(query string) *http.Request {
32 req := httptest.NewRequest(http.MethodPost, "/graphql", strings.NewReader(query))
33 req.Header.Set("Accept", "text/event-stream")
34 req.Header.Set("content-type", "application/json; charset=utf-8")
35 return req
36 }
37
38 createHTTPRequest := func(url string, query string) *http.Request {
39 req, err := http.NewRequest("POST", url, strings.NewReader(query))
40 require.NoError(t, err, "Request threw error -> %s", err)
41 req.Header.Set("Accept", "text/event-stream")
42 req.Header.Set("content-type", "application/json; charset=utf-8")
43 return req
44 }
45
46 readLine := func(br *bufio.Reader) string {
47 bs, err := br.ReadString('\n')
48 require.NoError(t, err)
49 return bs
50 }
51
52 t.Run("stream failure", func(t *testing.T) {
53 h := initialize()
54 req := httptest.NewRequest(http.MethodPost, "/graphql", strings.NewReader(`{"query":"subscription { name }"}`))
55 req.Header.Set("content-type", "application/json; charset=utf-8")
56 w := httptest.NewRecorder()
57 h.ServeHTTP(w, req)
58 assert.Equal(t, 400, w.Code, "Request return wrong status -> %d", w.Code)
59 assert.Equal(t, `{"errors":[{"message":"transport not supported"}],"data":null}`, w.Body.String())
60 })
61
62 t.Run("decode failure", func(t *testing.T) {
63 h := initialize()
64 req := createHTTPTestRequest("notjson")
65 w := httptest.NewRecorder()
66 h.ServeHTTP(w, req)
67 assert.Equal(t, 400, w.Code, "Request return wrong status -> %d", w.Code)
68 assert.Equal(t, `{"errors":[{"message":"json request body could not be decoded: invalid character 'o' in literal null (expecting 'u') body:notjson"}],"data":null}`, w.Body.String())
69 })
70
71 t.Run("parse failure", func(t *testing.T) {
72 h := initialize()
73 req := createHTTPTestRequest(`{"query":"subscription {{ name }"}`)
74 w := httptest.NewRecorder()
75 h.ServeHTTP(w, req)
76
77 assert.Equal(t, 200, w.Code, "Request return wrong status -> %d", w.Code)
78 assert.Equal(t, "keep-alive", w.Header().Get("Connection"))
79 assert.Equal(t, "text/event-stream", w.Header().Get("Content-Type"))
80
81 br := bufio.NewReader(w.Body)
82
83 assert.Equal(t, ":\n", readLine(br))
84 assert.Equal(t, "\n", readLine(br))
85 assert.Equal(t, "event: next\n", readLine(br))
86 assert.Equal(t, "data: {\"errors\":[{\"message\":\"Expected Name, found {\",\"locations\":[{\"line\":1,\"column\":15}],\"extensions\":{\"code\":\"GRAPHQL_PARSE_FAILED\"}}],\"data\":null}\n", readLine(br))
87 assert.Equal(t, "\n", readLine(br))
88 assert.Equal(t, "event: complete\n", readLine(br))
89 assert.Equal(t, "\n", readLine(br))
90
91 _, err := br.ReadByte()
92 assert.Equal(t, err, io.EOF)
93 })
94
95 t.Run("subscribe", func(t *testing.T) {
96 handler, srv := initializeWithServer()
97 defer srv.Close()
98
99 var wg sync.WaitGroup
100 wg.Add(1)
101 go func() {
102 defer wg.Done()
103 handler.SendNextSubscriptionMessage()
104 }()
105
106 client := &http.Client{}
107 req := createHTTPRequest(srv.URL, `{"query":"subscription { name }"}`)
108 res, err := client.Do(req)
109 require.NoError(t, err, "Request threw error -> %s", err)
110 defer func() {
111 require.NoError(t, res.Body.Close())
112 }()
113
114 assert.Equal(t, 200, res.StatusCode, "Request return wrong status -> %d", res.Status)
115 assert.Equal(t, "keep-alive", res.Header.Get("Connection"))
116 assert.Equal(t, "text/event-stream", res.Header.Get("Content-Type"))
117
118 br := bufio.NewReader(res.Body)
119
120 assert.Equal(t, ":\n", readLine(br))
121 assert.Equal(t, "\n", readLine(br))
122 assert.Equal(t, "event: next\n", readLine(br))
123 assert.Equal(t, "data: {\"data\":{\"name\":\"test\"}}\n", readLine(br))
124 assert.Equal(t, "\n", readLine(br))
125
126 wg.Add(1)
127 go func() {
128 defer wg.Done()
129 handler.SendNextSubscriptionMessage()
130 }()
131
132 assert.Equal(t, "event: next\n", readLine(br))
133 assert.Equal(t, "data: {\"data\":{\"name\":\"test\"}}\n", readLine(br))
134 assert.Equal(t, "\n", readLine(br))
135
136 wg.Add(1)
137 go func() {
138 defer wg.Done()
139 handler.SendCompleteSubscriptionMessage()
140 }()
141
142 assert.Equal(t, "event: complete\n", readLine(br))
143 assert.Equal(t, "\n", readLine(br))
144
145 _, err = br.ReadByte()
146 assert.Equal(t, err, io.EOF)
147
148 wg.Wait()
149 })
150 }
151
View as plain text