wsdirector-cli 0.5.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b02895fab166dd2d388f48dda802e02407e5b7866eb508f1b5787e1a4e1976d6
4
- data.tar.gz: e0d5af5ae2de5caed7ccd151538e19ad3c49e08db1217e042f36540d69468314
3
+ metadata.gz: c0f66338d459486aadbae18daa45b8b3c5dc48c86049fcccfeac2771961ed1f8
4
+ data.tar.gz: 6be12e017b3ff649bc2e6819e515b4f6dab0ffbb7077ccc8f74387cfa21e39b0
5
5
  SHA512:
6
- metadata.gz: '09af449361f79d80a4848b0851aa96ada36e363e997bba177e5d96b01005d1c241abee2a1a05781f3a5277de08732f3b1d8afaeaea467d2097050347d2ca295c'
7
- data.tar.gz: 8deb112a900d7cdbc710be8b86d57aef8aeaa87bbec78595170bf309088bca9bb88fd58de503e2bcfb32b43df5e08903c322791eb10930aa0fb25f00e26afebb
6
+ metadata.gz: 72114ec71d8926e0eaa7c70bbda0fc07faa2b941fb679e5c160555c030be75f77df0b9f8c55c13c3c65cf21e93365ba1f12fcbbf27bb9caa41effa56eaf6340a
7
+ data.tar.gz: 25eec3a5d152683f3c3f8fa4cce48e1ca511442de67ba89c1208f66b8fa8fc51ab0ebbd4b9bf43f9a3002ff4ae59ddb3dfe5dea2201fe6b350b16dcf0c36306b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,35 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.0.0 (2022-09-19)
6
+
7
+ - Add Phoenix Channels protocol support. ([@palkan][])
8
+
9
+ - Make `receive` order-independent. ([@palkan][])
10
+
11
+ Using `receive` now looks up a matching message through all the mailbox (already received or newly arrived messages).
12
+ If you need strict order guarantees, add `ordered: true` to `receive`.
13
+
14
+ - Add `WSDirector::Snapshot`. ([@palkan][])
15
+
16
+ - Add `locals` support when running scenarios programmatically. ([@palkan][])
17
+
18
+ - Add partial receive data matching support (via `data>` field). ([@palkan][])
19
+
20
+ - Add `connection_options` support (headers, cookies, query). ([@palkan][])
21
+
22
+ - Add loading custom protocols support. ([@palkan][])
23
+
24
+ - Allow passing URL without a scheme part. ([@palkan][])
25
+
26
+ - Add `-vv` option to print action logs. ([@palkan][])
27
+
28
+ - Add `--subprotocol` support and `connection_options` in the scenario files. ([@palkan][])
29
+
30
+ - Add `-f/--file` option to specify scenario path. ([@palkan][])
31
+
32
+ - Drop Ruby 2.5 support.
33
+
5
34
  ## 0.5.0 (2021-10-13)
6
35
 
7
36
  - Add JSON support. ([@wazzuper][])
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2017 palkan
3
+ Copyright (c) 2017-2022 palkan
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -4,66 +4,81 @@
4
4
 
5
5
  # WebSocket Director
6
6
 
7
- Command line tool for testing websocket servers using scenarios.
7
+ Command line tool for testing WebSocket servers using scenarios.
8
8
 
9
- Suitable for testing any websocket server implementation, like [Action Cable](https://github.com/rails/rails/tree/master/actioncable), [Websocket Eventmachine Server](https://github.com/imanel/websocket-eventmachine-server), [Litecable](https://github.com/palkan/litecable) and so on.
9
+ Suitable for testing any websocket server implementation, like [Action Cable](https://github.com/rails/rails/tree/master/actioncable), [AnyCable](https://anycable.io), [Phoenix Channels](https://hexdocs.pm/phoenix/channels.html), [GraphQL WS](https://github.com/enisdenjo/graphql-ws) and so on.
10
10
 
11
11
  ## Installation
12
12
 
13
- ```bash
13
+ Install CLI:
14
+
15
+ ```sh
14
16
  gem install wsdirector-cli
15
17
  ```
16
18
 
19
+ Or use WebSockets Director as a library (see below for intructions):
20
+
21
+ ```ruby
22
+ # Gemfile
23
+ gem "wsdirector-core", "~> 1.0"
24
+ ```
25
+
17
26
  ## Usage
18
27
 
19
28
  Create YAML file with simple testing script:
20
29
 
21
30
  ```yml
22
- # script.yml
23
- - receive: "Welcome" # expect to receive message
24
- - send:
25
- data: "send message" # send message, all messages in data will be parse to json
26
- - receive:
27
- data: "receive message" # expect to receive json message
31
+ # script.yml
32
+ - receive: "Welcome" # expect to receive message
33
+ - send:
34
+ data: "send message" # send message, all messages in data will be parse to json
35
+ - receive:
36
+ data: "receive message" # expect to receive json message
28
37
  ```
29
38
 
30
39
  and run it with this command:
31
40
 
32
41
  ```bash
33
- wsdirector script.yml ws://websocket.server:9876/ws
42
+ wsdirector -f script.yml -u ws://websocket.server:9876/ws
34
43
 
35
44
  #=> 1 clients, 0 failures
36
45
  ```
37
46
 
47
+ You can also use positional arguments:
48
+
49
+ ```sh
50
+ wsdirector script.yml ws://websocket.server:9876/ws
51
+ ```
52
+
38
53
  You can create more complex scenarios with multiple client groups:
39
54
 
40
55
  ```yml
41
- # script.yml
42
- - client: # first clients group
43
- name: "publisher" # optional group name
44
- multiplier: ":scale" # :scale take number from -s param, and run :scale number of clients in this group
45
- actions:
46
- - receive:
47
- data: "Welcome"
48
- - wait_all # makes all clients in all groups wait untill every client get this point (global barrier)
49
- - send:
50
- data: "test message"
51
- - client:
52
- name: "listeners"
53
- multiplier: ":scale * 2"
54
- actions:
55
- - receive:
56
- data: "Welcome"
57
- - wait_all
58
- - receive:
59
- multiplier: ":scale" # you can use multiplier with any action
60
- data: "test message"
56
+ # script.yml
57
+ - client: # first clients group
58
+ name: "publisher" # optional group name
59
+ multiplier: ":scale" # :scale take number from -s param, and run :scale number of clients in this group
60
+ actions:
61
+ - receive:
62
+ data: "Welcome"
63
+ - wait_all # makes all clients in all groups wait untill every client get this point (global barrier)
64
+ - send:
65
+ data: "test message"
66
+ - client:
67
+ name: "listeners"
68
+ multiplier: ":scale * 2"
69
+ actions:
70
+ - receive:
71
+ data: "Welcome"
72
+ - wait_all
73
+ - receive:
74
+ multiplier: ":scale" # you can use multiplier with any action
75
+ data: "test message"
61
76
  ```
62
77
 
63
78
  Run with scale factor:
64
79
 
65
80
  ```bash
66
- wsdirector script.yml ws://websocket.server:9876 -s 10
81
+ wsdirector -f script.yml -u ws://websocket.server:9876 -s 10
67
82
 
68
83
  #=> Group publisher: 10 clients, 0 failures
69
84
  #=> Group listeners: 20 clients, 0 failures
@@ -74,7 +89,7 @@ The simpliest scenario is just checking that socket is succesfully connected:
74
89
  ```yml
75
90
  - client:
76
91
  name: connection check
77
- # no actions
92
+ # no actions
78
93
  ```
79
94
 
80
95
  Run with loop option:
@@ -102,24 +117,100 @@ Run with loop option:
102
117
  multiplier: ":scale + 1"
103
118
  ```
104
119
 
120
+ By default, `receive` action expects the exact `data` match. In some cases, it's useful to only match the specified keys (inclusion). For that, you can use `data>` field instead:
121
+
122
+ ```yml
123
+ - client:
124
+ actions:
125
+ - receive:
126
+ data:
127
+ type: "welcome"
128
+ - send:
129
+ data:
130
+ command: "subscribe"
131
+ identifier: "{\"channel\":\"Channel\"}"
132
+ - receive:
133
+ data>:
134
+ type: "confirm_subscription"
135
+ ```
136
+
105
137
  Also you can pass a JSON file with some testing scripts:
106
138
 
107
139
  ```bash
108
- wsdirector scenario.json ws://websocket.server:9876
140
+ wsdirector -f scenario.json -u ws://websocket.server:9876
109
141
  ```
110
142
 
111
143
  or pass a JSON scenario directly to the CLI without creating a file:
112
144
 
113
145
  ```bash
114
- wsdirector -i '[{"receive": {"data":"welcome"}},{"send":{"data":"send message"}},{"receive":{"data":"receive message"}}]' ws://websocket.server:9876
146
+ wsdirector -i '[{"receive": {"data":"welcome"}},{"send":{"data":"send message"}},{"receive":{"data":"receive message"}}]' -u ws://websocket.server:9876
115
147
  ```
116
148
 
117
149
  Type `wsdirector --help` to check all commands.
118
150
 
151
+ ### Receive order
152
+
153
+ By default, the `receive` action scans through all available or newly added message to find a matching one.
154
+ If you want to check the order of incoming messages, add the `ordered: true` option to the `receive` action.
155
+
156
+ ### Connection configuration
157
+
158
+ You can specify client's headers, cookies or query string params via the `connection_options` directive:
159
+
160
+ ```yml
161
+ - client:
162
+ connection_options:
163
+ headers:
164
+ "X-API-KEY": "secret"
165
+ query:
166
+ token: "123"
167
+ cookies:
168
+ session_id: "2022"
169
+ ```
170
+
171
+ **NOTE**: Query string params could also be passed as a part of the URL. Specifying them in the scenario allows you to provide values via the interpolation.
172
+
173
+ ### Using as a library
174
+
175
+ You can integrate WS Director into your library or application by using its APIs:
176
+
177
+ ```ruby
178
+ # Could be a file path or JSON-encoded string as well
179
+ scenario = [
180
+ {
181
+ send: {
182
+ data: "ping"
183
+ }
184
+ },
185
+ {
186
+ receive: {
187
+ data: "pong"
188
+ }
189
+ }
190
+ ]
191
+
192
+ result = WSDirector.run(scenario, url: "ws://my.ws.server:4949/live")
193
+ result.success? #=> true of false
194
+ result.groups #=> result data for each client group
195
+ ```
196
+
197
+ If you're using YAML-based scenarios, you can also pass local variables to be used with ERB via the `locals` option:
198
+
199
+ ```yml
200
+ - client:
201
+ connection_options:
202
+ headers:
203
+ "X-API-TOKEN": <%= token %>
204
+ ```
205
+
206
+ ```ruby
207
+ token = UserToken.generate
208
+ WSDirector.run(scenario, url: "ws://my.ws.server:4949/live", locals: {token:})
209
+ ```
210
+
119
211
  ### Protocols
120
212
 
121
- WSDirector uses protocols to handle different actions.
122
- Currently, we support "base" protocol (with `send`, `receive`, `wait_all` actions) and "action_cable" protocol, which extends "base" with `subscribe` and `perform` actions.
213
+ WSDirector uses protocols to handle provide convinient actions for some popular protocols.
123
214
 
124
215
  #### ActionCable Example
125
216
 
@@ -170,21 +261,87 @@ Scenario:
170
261
  text: "hello"
171
262
  ```
172
263
 
173
- ## Future Ideas
264
+ #### Phoenix Channels
174
265
 
175
- - Report timings (per-client and aggregates)
266
+ With "phoenix" protocol, you can use communicate with a [Phoenix Channels](https://hexdocs.pm/phoenix/channels.html) server:
267
+
268
+ ```yml
269
+ - client:
270
+ protocol: phoenix
271
+ multiplier: ":scale"
272
+ actions:
273
+ - join:
274
+ topic: room:lobby
275
+ - wait_all
276
+ - send:
277
+ topic: room:lobby
278
+ event: new_msg
279
+ data:
280
+ body: "Hey from WS director!"
281
+ - receive:
282
+ topic: room:lobby
283
+ multiplier: ":scale"
284
+ event: new_msg
285
+ data:
286
+ body: "Hey from WS director!"
287
+ ```
288
+
289
+ **IMPORTANT**: We support only v2 version of the Channels protocol.
176
290
 
177
- - File-less scenarios (JSON-encoded?), e.g.
291
+ #### Custom protocols
178
292
 
179
- ```shell
180
- wsdirector -i '{"receive": "hello"}' localhost:9898/ws
293
+ You can define your own protocol and load it dynamically:
294
+
295
+ ```ruby
296
+ # It's important to put a custom protocol class under WSDirector::Protocols
297
+ module WSDirector::Protocols
298
+ class CustomProtocol < Base
299
+ def send_ping_and_receive_pong
300
+ send("data" => {"type" => "ping"})
301
+ receive("data" => {"type" => "pong"})
302
+ end
303
+ end
304
+ end
305
+ ```
306
+
307
+ Now you can load it via the `-r` option:
308
+
309
+ ```sh
310
+ $ wsdirector -u localhost:3232/ws -i '["send_ping_and_receive_pong"]' -r ./path/to/custom_protocol.rb -vv
311
+
312
+ hh:mm:ss client=default_1 Connecting
313
+ hh:mm:ss client=default_1 Connected (45ms)
314
+ hh:mm:ss client=default_1 Sent message: {"type":"ping"}
315
+ hh:mm:ss client=default_1 Receive message: {"type":"pong"}
316
+ hh:mm:ss client=default_1 Received message: {"type":"pong"} (21ms)
181
317
  ```
182
318
 
183
- - Connection parameters (headers, query params, etc)
319
+ ## Testing frameworks integration
320
+
321
+ WSDirector does not provide any specific helpers for RSpec or Minitest. Instead, we provide an example setup, which you could adjust to your needs (and which is too small to be a part of the library).
322
+
323
+ The example below implies running tests against an Action Cable server with a token-based authentication
184
324
 
185
- - Testing frameworks integrations
325
+ ```ruby
326
+ module WSDirectorTestHelper
327
+ def run_websocket_scenario(path, token:, url: ActionCable.server.config.url, **options)
328
+ url = "#{url}?jid=#{token}"
329
+ scenario = Rails.root.join "spec" / "fixtures" / "wsdirector" / path
330
+
331
+ WSDirector.run(scenario, url:, **options)
332
+ end
333
+ end
334
+
335
+ # In RSpec, you can include this modules via the configuration
336
+ RSpec.configure do |config|
337
+ # Here we only add this helper to system tests
338
+ config.include WSDirectorTestHelper, type: :system
339
+ end
340
+ ```
186
341
 
187
- - Loading protocols dynamically
342
+ ## Future Ideas
343
+
344
+ - Report timings (per-client and aggregates)
188
345
 
189
346
  - What else? [Submit an issue!](https://github.com/palkan/wsdirector/issues/new)
190
347
 
metadata CHANGED
@@ -1,45 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wsdirector-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
+ - Vladimir Dementyev
7
8
  - Kirill Arkhipov
8
9
  - Grandman
9
- - palkan
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-10-13 00:00:00.000000000 Z
13
+ date: 2022-09-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: websocket-client-simple
16
+ name: wsdirector
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - "~>"
19
+ - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: '0.3'
21
+ version: 1.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - "~>"
26
+ - - '='
27
27
  - !ruby/object:Gem::Version
28
- version: '0.3'
29
- - !ruby/object:Gem::Dependency
30
- name: concurrent-ruby
31
- requirement: !ruby/object:Gem::Requirement
32
- requirements:
33
- - - "~>"
34
- - !ruby/object:Gem::Version
35
- version: 1.0.5
36
- type: :runtime
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - "~>"
41
- - !ruby/object:Gem::Version
42
- version: 1.0.5
28
+ version: 1.0.0
43
29
  - !ruby/object:Gem::Dependency
44
30
  name: colorize
45
31
  requirement: !ruby/object:Gem::Requirement
@@ -47,157 +33,25 @@ dependencies:
47
33
  - - ">="
48
34
  - !ruby/object:Gem::Version
49
35
  version: '0'
50
- type: :development
36
+ type: :runtime
51
37
  prerelease: false
52
38
  version_requirements: !ruby/object:Gem::Requirement
53
39
  requirements:
54
40
  - - ">="
55
41
  - !ruby/object:Gem::Version
56
42
  version: '0'
57
- - !ruby/object:Gem::Dependency
58
- name: websocket-eventmachine-server
59
- requirement: !ruby/object:Gem::Requirement
60
- requirements:
61
- - - "~>"
62
- - !ruby/object:Gem::Version
63
- version: 1.0.1
64
- type: :development
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - "~>"
69
- - !ruby/object:Gem::Version
70
- version: 1.0.1
71
- - !ruby/object:Gem::Dependency
72
- name: rack
73
- requirement: !ruby/object:Gem::Requirement
74
- requirements:
75
- - - "~>"
76
- - !ruby/object:Gem::Version
77
- version: '2.0'
78
- type: :development
79
- prerelease: false
80
- version_requirements: !ruby/object:Gem::Requirement
81
- requirements:
82
- - - "~>"
83
- - !ruby/object:Gem::Version
84
- version: '2.0'
85
- - !ruby/object:Gem::Dependency
86
- name: litecable
87
- requirement: !ruby/object:Gem::Requirement
88
- requirements:
89
- - - "~>"
90
- - !ruby/object:Gem::Version
91
- version: '0.5'
92
- type: :development
93
- prerelease: false
94
- version_requirements: !ruby/object:Gem::Requirement
95
- requirements:
96
- - - "~>"
97
- - !ruby/object:Gem::Version
98
- version: '0.5'
99
- - !ruby/object:Gem::Dependency
100
- name: puma
101
- requirement: !ruby/object:Gem::Requirement
102
- requirements:
103
- - - "~>"
104
- - !ruby/object:Gem::Version
105
- version: '3.6'
106
- type: :development
107
- prerelease: false
108
- version_requirements: !ruby/object:Gem::Requirement
109
- requirements:
110
- - - "~>"
111
- - !ruby/object:Gem::Version
112
- version: '3.6'
113
- - !ruby/object:Gem::Dependency
114
- name: bundler
115
- requirement: !ruby/object:Gem::Requirement
116
- requirements:
117
- - - ">="
118
- - !ruby/object:Gem::Version
119
- version: '1.16'
120
- type: :development
121
- prerelease: false
122
- version_requirements: !ruby/object:Gem::Requirement
123
- requirements:
124
- - - ">="
125
- - !ruby/object:Gem::Version
126
- version: '1.16'
127
- - !ruby/object:Gem::Dependency
128
- name: rake
129
- requirement: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - ">="
132
- - !ruby/object:Gem::Version
133
- version: '10.0'
134
- type: :development
135
- prerelease: false
136
- version_requirements: !ruby/object:Gem::Requirement
137
- requirements:
138
- - - ">="
139
- - !ruby/object:Gem::Version
140
- version: '10.0'
141
- - !ruby/object:Gem::Dependency
142
- name: rspec
143
- requirement: !ruby/object:Gem::Requirement
144
- requirements:
145
- - - "~>"
146
- - !ruby/object:Gem::Version
147
- version: '3.5'
148
- type: :development
149
- prerelease: false
150
- version_requirements: !ruby/object:Gem::Requirement
151
- requirements:
152
- - - "~>"
153
- - !ruby/object:Gem::Version
154
- version: '3.5'
155
- - !ruby/object:Gem::Dependency
156
- name: minitest
157
- requirement: !ruby/object:Gem::Requirement
158
- requirements:
159
- - - "~>"
160
- - !ruby/object:Gem::Version
161
- version: '5.9'
162
- type: :development
163
- prerelease: false
164
- version_requirements: !ruby/object:Gem::Requirement
165
- requirements:
166
- - - "~>"
167
- - !ruby/object:Gem::Version
168
- version: '5.9'
169
- description: Command line tool for testing websocket servers using scenarios.
43
+ description: Command line tool for testing WebSocket servers using scenarios.
170
44
  email:
45
+ - dementiev.vm@gmail.com
171
46
  - kirillvs@mail.ru
172
47
  - root@grandman73.ru
173
- - dementiev.vm@gmail.com
174
- executables:
175
- - wsdirector
48
+ executables: []
176
49
  extensions: []
177
50
  extra_rdoc_files: []
178
51
  files:
179
52
  - CHANGELOG.md
180
53
  - LICENSE.txt
181
54
  - README.md
182
- - bin/wsdirector
183
- - lib/wsdirector-cli.rb
184
- - lib/wsdirector.rb
185
- - lib/wsdirector/cli.rb
186
- - lib/wsdirector/client.rb
187
- - lib/wsdirector/clients_holder.rb
188
- - lib/wsdirector/configuration.rb
189
- - lib/wsdirector/ext/deep_dup.rb
190
- - lib/wsdirector/printer.rb
191
- - lib/wsdirector/protocols.rb
192
- - lib/wsdirector/protocols/action_cable.rb
193
- - lib/wsdirector/protocols/base.rb
194
- - lib/wsdirector/result.rb
195
- - lib/wsdirector/results_holder.rb
196
- - lib/wsdirector/runner.rb
197
- - lib/wsdirector/scenario_reader.rb
198
- - lib/wsdirector/task.rb
199
- - lib/wsdirector/utils.rb
200
- - lib/wsdirector/version.rb
201
55
  homepage: https://github.com/palkan/wsdirector
202
56
  licenses:
203
57
  - MIT
@@ -210,15 +64,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
210
64
  requirements:
211
65
  - - ">="
212
66
  - !ruby/object:Gem::Version
213
- version: 2.5.0
67
+ version: 2.6.0
214
68
  required_rubygems_version: !ruby/object:Gem::Requirement
215
69
  requirements:
216
70
  - - ">="
217
71
  - !ruby/object:Gem::Version
218
72
  version: '0'
219
73
  requirements: []
220
- rubygems_version: 3.2.22
74
+ rubygems_version: 3.3.11
221
75
  signing_key:
222
76
  specification_version: 4
223
- summary: Command line tool for testing websocket servers using scenarios.
77
+ summary: Command line tool for testing WebSocket servers using scenarios.
224
78
  test_files: []
data/bin/wsdirector DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "rubygems"
4
-
5
- $:.unshift(File.expand_path(__dir__ + "/../lib"))
6
-
7
- require "wsdirector/cli"
8
-
9
- begin
10
- WSDirector::CLI.new.tap { |cli| cli.run }
11
- rescue => e
12
- STDERR.puts e.message
13
- STDERR.puts e.backtrace.join("\n")
14
- exit 1
15
- end