1package sockjs
2
3import (
4	"bufio"
5	"flag"
6	"fmt"
7	"log"
8	"net/http"
9	"net/http/httptest"
10	"net/url"
11	"strings"
12	"sync"
13	"testing"
14	"time"
15
16	"github.com/gorilla/websocket"
17)
18
19func BenchmarkSimple(b *testing.B) {
20	var messages = make(chan string, 10)
21	h := NewHandler("/echo", DefaultOptions, func(session Session) {
22		for m := range messages {
23			_ = session.Send(m)
24		}
25		_ = session.Close(1024, "Close")
26	})
27	server := httptest.NewServer(h)
28	defer server.Close()
29
30	req, _ := http.NewRequest("POST", server.URL+fmt.Sprintf("/echo/server/%d/xhr_streaming", 1000), nil)
31	resp, err := http.DefaultClient.Do(req)
32	if err != nil {
33		log.Fatal(err)
34	}
35	for n := 0; n < b.N; n++ {
36		messages <- "some message"
37	}
38	fmt.Println(b.N)
39	close(messages)
40	resp.Body.Close()
41}
42
43func BenchmarkMessages(b *testing.B) {
44	msg := strings.Repeat("m", 10)
45	h := NewHandler("/echo", DefaultOptions, func(session Session) {
46		for n := 0; n < b.N; n++ {
47			_ = session.Send(msg)
48		}
49		_ = session.Close(1024, "Close")
50	})
51	server := httptest.NewServer(h)
52
53	var wg sync.WaitGroup
54
55	for i := 0; i < 100; i++ {
56		wg.Add(1)
57		go func(session int) {
58			reqc := 0
59			req, _ := http.NewRequest("POST", server.URL+fmt.Sprintf("/echo/server/%d/xhr_streaming", session), nil)
60			for {
61				reqc++
62				resp, err := http.DefaultClient.Do(req)
63				if err != nil {
64					log.Fatal(err)
65				}
66				reader := bufio.NewReader(resp.Body)
67				for {
68					line, err := reader.ReadString('\n')
69					if err != nil {
70						goto AGAIN
71					}
72					if strings.HasPrefix(line, "data: c[1024") {
73						resp.Body.Close()
74						goto DONE
75					}
76				}
77			AGAIN:
78				resp.Body.Close()
79			}
80		DONE:
81			wg.Done()
82		}(i)
83	}
84	wg.Wait()
85	server.Close()
86}
87
88var size = flag.Int("size", 4*1024, "Size of one message.")
89
90func BenchmarkMessageWebsocket(b *testing.B) {
91	flag.Parse()
92
93	msg := strings.Repeat("x", *size)
94	wsFrame := []byte(fmt.Sprintf("[%q]", msg))
95
96	opts := Options{
97		Websocket:       true,
98		SockJSURL:       "//cdnjs.cloudflare.com/ajax/libs/sockjs-client/0.3.4/sockjs.min.js",
99		HeartbeatDelay:  time.Hour,
100		DisconnectDelay: time.Hour,
101		ResponseLimit:   uint32(*size),
102	}
103
104	h := NewHandler("/echo", opts, func(session Session) {
105		for {
106			msg, err := session.Recv()
107			if err != nil {
108				if session.GetSessionState() != SessionActive {
109					break
110				}
111				b.Fatalf("Recv()=%s", err)
112			}
113
114			if err := session.Send(msg); err != nil {
115				b.Fatalf("Send()=%s", err)
116			}
117		}
118	})
119
120	server := httptest.NewServer(h)
121	defer server.Close()
122
123	url := "ws" + server.URL[4:] + "/echo/server/0/websocket"
124
125	client, _, err := websocket.DefaultDialer.Dial(url, nil)
126	if err != nil {
127		b.Fatalf("Dial()=%s", err)
128	}
129
130	_, p, err := client.ReadMessage()
131	if err != nil || string(p) != "o" {
132		b.Fatalf("failed to start new session: frame=%v, err=%v", p, err)
133	}
134
135	b.ReportAllocs()
136	b.ResetTimer()
137
138	for i := 0; i < b.N; i++ {
139		if err := client.WriteMessage(websocket.TextMessage, wsFrame); err != nil {
140			b.Fatalf("WriteMessage()=%s", err)
141		}
142
143		if _, _, err := client.ReadMessage(); err != nil {
144			b.Fatalf("ReadMessage()=%s", err)
145		}
146	}
147
148	if err := client.Close(); err != nil {
149		b.Fatalf("Close()=%s", err)
150	}
151}
152
153func BenchmarkHandler_ParseSessionID(b *testing.B) {
154	h := Handler{prefix: "/prefix"}
155	url, _ := url.Parse("http://server:80/prefix/server/session/whatever")
156
157	b.ReportAllocs()
158	b.ResetTimer()
159	for i := 0; i < b.N; i++ {
160		_, _ = h.parseSessionID(url)
161	}
162}
163