File: parser_spec.rb

package info (click to toggle)
ruby-websocket-parser 1.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 200 kB
  • ctags: 80
  • sloc: ruby: 623; makefile: 2
file content (182 lines) | stat: -rw-r--r-- 5,648 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
require 'spec_helper'

describe WebSocket::Parser do
  let(:received_messages) { [] }
  let(:received_errors)   { [] }
  let(:received_closes)   { [] }
  let(:received_pings)    { [] }
  let(:received_pongs)    { [] }

  let(:parser) do
    parser = WebSocket::Parser.new

    parser.on_message { |m| received_messages << m }
    parser.on_error   { |m| received_errors << m }
    parser.on_close   { |status, message| received_closes << [status, message] }
    parser.on_ping    { |m| received_pings << m }
    parser.on_pong    { |m| received_pongs << m }

    parser
  end

  it "recognizes a text message" do
    parser << WebSocket::Message.new('Once upon a time').to_data

    expect(received_messages.first).to eq('Once upon a time')
  end

  it "returns parsed messages on parse" do
    msg1 = WebSocket::Message.new('Now is the winter of our discontent').to_data
    msg2 = WebSocket::Message.new('Made glorious summer by this sun of York').to_data

    messages = parser << msg1.slice!(0,5)
    expect(messages).to be_empty # We don't have a complete message yet

    messages = parser << msg1 + msg2

    expect(messages[0]).to eq('Now is the winter of our discontent')
    expect(messages[1]).to eq('Made glorious summer by this sun of York')
  end

  it "does not return control frames" do
    msg = WebSocket::Message.close(1001, 'Goodbye!').to_data

    messages = parser << msg
    expect(messages).to be_empty
  end

  it "can receive a message in parts" do
    data = WebSocket::Message.new('Once upon a time').to_data
    parser << data.slice!(0, 5)

    expect(received_messages).to be_empty

    parser << data

    expect(received_messages.first).to eq('Once upon a time')
  end

  it "can receive succesive messages" do
    msg1 = WebSocket::Message.new('Now is the winter of our discontent')
    msg2 = WebSocket::Message.new('Made glorious summer by this sun of York')

    parser << msg1.to_data
    parser << msg2.to_data

    expect(received_messages[0]).to eq('Now is the winter of our discontent')
    expect(received_messages[1]).to eq('Made glorious summer by this sun of York')
  end

  it "can receive medium size messages" do
    # Medium size messages has a payload length between 127 and 65_535 bytes

    text = 4.times.collect { 'All work and no play makes Jack a dull boy.' }.join("\n\n")
    expect(text.length).to be > 127
    expect(text.length).to be < 65_536

    parser << WebSocket::Message.new(text).to_data
    expect(received_messages.first).to eq(text)
  end

  it "can receive large size messages" do
    # Large size messages has a payload length greater than 65_535 bytes

    text = 1500.times.collect { 'All work and no play makes Jack a dull boy.' }.join("\n\n")
    expect(text.length).to be > 65_536

    parser << WebSocket::Message.new(text).to_data

    # Check lengths first to avoid gigantic error message
    expect(received_messages.first.length).to eq(text.length)
    expect(received_messages.first).to eq(text)
  end

  it "recognizes a ping message" do
    parser << WebSocket::Message.ping.to_data

    expect(received_pings.size).to eq(1)
  end

  it "recognizes a pong message" do
    parser << WebSocket::Message.pong.to_data

    expect(received_pongs.size).to eq(1)
  end

  it "recognizes a close message with status code and message" do
    parser << WebSocket::Message.close(1001, 'Browser leaving page').to_data

    status, message = received_closes.first
    expect(status).to  eq(:peer_going_away) # Status code 1001
    expect(message).to eq('Browser leaving page')
  end

  it "recognizes a close message without status code" do
    parser << WebSocket::Message.close.to_data

    status, message = received_closes.first
    expect(status).to  be_nil
    expect(message).to be_empty
  end

  it "recognizes a masked frame" do
    msg = WebSocket::Message.new('Once upon a time')
    msg.mask!

    parser << msg.to_data

    expect(received_messages.first).to eq('Once upon a time')
  end

  context "examples from the spec" do
    # These are literal examples from the spec

    it "recognizes single-frame unmasked text message" do
      parser << [0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f].pack('C*')

      expect(received_messages.first).to eq('Hello')
    end

    it "recognizes single-frame masked text message" do
      parser << [0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58].pack('C*')

      expect(received_messages.first).to eq('Hello')
    end

    it "recognizes a fragmented unmasked text message" do
      parser << [0x01, 0x03, 0x48, 0x65, 0x6c].pack('C*') # contains "Hel"

      expect(received_messages).to be_empty

      parser << [0x80, 0x02, 0x6c, 0x6f].pack('C*') # contains "lo"

      expect(received_messages.first).to eq('Hello')
    end

    it "recognizes an unnmasked ping request" do
      parser << [0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f].pack('C*')

      expect(received_pings.size).to eq(1)
    end

    it "recognizes a masked pong response" do
      parser << [0x8a, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58].pack('C*')

      expect(received_pongs.size).to eq(1)
    end

    it "recognizes 256 bytes binary message in a single unmasked frame" do
      data = Array.new(256) { rand(256) }.pack('c*')
      parser << [0x82, 0x7E, 0x0100].pack('CCn') + data

      expect(received_messages.first).to eq(data)
    end

    it "recoginzes 64KiB binary message in a single unmasked frame" do
      data = Array.new(65536) { rand(256) }.pack('c*')
      parser << [0x82, 0x7F, 0x0000000000010000].pack('CCQ>') + data

      expect(received_messages.first).to eq(data)
    end
  end
end