wsdirector-cli 0.5.0 → 1.0.1

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: bedf797c1b3bb2a52a96067fe886a2f016368f2c6eecf82401e4badf8ea60b7e
4
+ data.tar.gz: b1d65aaffcab9703aa90ff156def968a2fbc1a4c0eb237040244bb65fec5f923
5
5
  SHA512:
6
- metadata.gz: '09af449361f79d80a4848b0851aa96ada36e363e997bba177e5d96b01005d1c241abee2a1a05781f3a5277de08732f3b1d8afaeaea467d2097050347d2ca295c'
7
- data.tar.gz: 8deb112a900d7cdbc710be8b86d57aef8aeaa87bbec78595170bf309088bca9bb88fd58de503e2bcfb32b43df5e08903c322791eb10930aa0fb25f00e26afebb
6
+ metadata.gz: cffc09ab1975a5be34796cad59551f2d630c2c0fda5b289a2860e2c00d6f10c11ac4a19be75857b44993856d040ae5bfe866207ce90ac18571a5e3b5a19a2094
7
+ data.tar.gz: e1e6fb969f5983599f00c2d7a8eba51f114ba2481f36f42fdee1f492f719af993d11da6f669b7c2e335bd9965c2640e371fc960171d50202fefb77febeeab238
data/CHANGELOG.md CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.0.1 (2022-09-29)
6
+
7
+ - Fix `wsdirector-cli` dependencies.
8
+
9
+ ## 1.0.0 (2022-09-19)
10
+
11
+ - Add Phoenix Channels protocol support. ([@palkan][])
12
+
13
+ - Make `receive` order-independent. ([@palkan][])
14
+
15
+ Using `receive` now looks up a matching message through all the mailbox (already received or newly arrived messages).
16
+ If you need strict order guarantees, add `ordered: true` to `receive`.
17
+
18
+ - Add `WSDirector::Snapshot`. ([@palkan][])
19
+
20
+ - Add `locals` support when running scenarios programmatically. ([@palkan][])
21
+
22
+ - Add partial receive data matching support (via `data>` field). ([@palkan][])
23
+
24
+ - Add `connection_options` support (headers, cookies, query). ([@palkan][])
25
+
26
+ - Add loading custom protocols support. ([@palkan][])
27
+
28
+ - Allow passing URL without a scheme part. ([@palkan][])
29
+
30
+ - Add `-vv` option to print action logs. ([@palkan][])
31
+
32
+ - Add `--subprotocol` support and `connection_options` in the scenario files. ([@palkan][])
33
+
34
+ - Add `-f/--file` option to specify scenario path. ([@palkan][])
35
+
36
+ - Drop Ruby 2.5 support.
37
+
5
38
  ## 0.5.0 (2021-10-13)
6
39
 
7
40
  - 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,83 @@
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
+
11
+ > 📖 Read also [WebSocket Director: scenario-based integration tests for realtime apps](https://evilmartians.com/chronicles/websocket-director-scenario-based-integration-tests-for-real-time-apps)
10
12
 
11
13
  ## Installation
12
14
 
13
- ```bash
15
+ Install CLI:
16
+
17
+ ```sh
14
18
  gem install wsdirector-cli
15
19
  ```
16
20
 
21
+ Or use WebSockets Director as a library (see below for intructions):
22
+
23
+ ```ruby
24
+ # Gemfile
25
+ gem "wsdirector-core", "~> 1.0"
26
+ ```
27
+
17
28
  ## Usage
18
29
 
19
30
  Create YAML file with simple testing script:
20
31
 
21
32
  ```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
33
+ # script.yml
34
+ - receive: "Welcome" # expect to receive message
35
+ - send:
36
+ data: "send message" # send message, all messages in data will be parse to json
37
+ - receive:
38
+ data: "receive message" # expect to receive json message
28
39
  ```
29
40
 
30
41
  and run it with this command:
31
42
 
32
43
  ```bash
33
- wsdirector script.yml ws://websocket.server:9876/ws
44
+ wsdirector -f script.yml -u ws://websocket.server:9876/ws
34
45
 
35
46
  #=> 1 clients, 0 failures
36
47
  ```
37
48
 
49
+ You can also use positional arguments:
50
+
51
+ ```sh
52
+ wsdirector script.yml ws://websocket.server:9876/ws
53
+ ```
54
+
38
55
  You can create more complex scenarios with multiple client groups:
39
56
 
40
57
  ```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"
58
+ # script.yml
59
+ - client: # first clients group
60
+ name: "publisher" # optional group name
61
+ multiplier: ":scale" # :scale take number from -s param, and run :scale number of clients in this group
62
+ actions:
63
+ - receive:
64
+ data: "Welcome"
65
+ - wait_all # makes all clients in all groups wait untill every client get this point (global barrier)
66
+ - send:
67
+ data: "test message"
68
+ - client:
69
+ name: "listeners"
70
+ multiplier: ":scale * 2"
71
+ actions:
72
+ - receive:
73
+ data: "Welcome"
74
+ - wait_all
75
+ - receive:
76
+ multiplier: ":scale" # you can use multiplier with any action
77
+ data: "test message"
61
78
  ```
62
79
 
63
80
  Run with scale factor:
64
81
 
65
82
  ```bash
66
- wsdirector script.yml ws://websocket.server:9876 -s 10
83
+ wsdirector -f script.yml -u ws://websocket.server:9876 -s 10
67
84
 
68
85
  #=> Group publisher: 10 clients, 0 failures
69
86
  #=> Group listeners: 20 clients, 0 failures
@@ -74,7 +91,7 @@ The simpliest scenario is just checking that socket is succesfully connected:
74
91
  ```yml
75
92
  - client:
76
93
  name: connection check
77
- # no actions
94
+ # no actions
78
95
  ```
79
96
 
80
97
  Run with loop option:
@@ -102,24 +119,100 @@ Run with loop option:
102
119
  multiplier: ":scale + 1"
103
120
  ```
104
121
 
122
+ 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:
123
+
124
+ ```yml
125
+ - client:
126
+ actions:
127
+ - receive:
128
+ data:
129
+ type: "welcome"
130
+ - send:
131
+ data:
132
+ command: "subscribe"
133
+ identifier: "{\"channel\":\"Channel\"}"
134
+ - receive:
135
+ data>:
136
+ type: "confirm_subscription"
137
+ ```
138
+
105
139
  Also you can pass a JSON file with some testing scripts:
106
140
 
107
141
  ```bash
108
- wsdirector scenario.json ws://websocket.server:9876
142
+ wsdirector -f scenario.json -u ws://websocket.server:9876
109
143
  ```
110
144
 
111
145
  or pass a JSON scenario directly to the CLI without creating a file:
112
146
 
113
147
  ```bash
114
- wsdirector -i '[{"receive": {"data":"welcome"}},{"send":{"data":"send message"}},{"receive":{"data":"receive message"}}]' ws://websocket.server:9876
148
+ wsdirector -i '[{"receive": {"data":"welcome"}},{"send":{"data":"send message"}},{"receive":{"data":"receive message"}}]' -u ws://websocket.server:9876
115
149
  ```
116
150
 
117
151
  Type `wsdirector --help` to check all commands.
118
152
 
153
+ ### Receive order
154
+
155
+ By default, the `receive` action scans through all available or newly added message to find a matching one.
156
+ If you want to check the order of incoming messages, add the `ordered: true` option to the `receive` action.
157
+
158
+ ### Connection configuration
159
+
160
+ You can specify client's headers, cookies or query string params via the `connection_options` directive:
161
+
162
+ ```yml
163
+ - client:
164
+ connection_options:
165
+ headers:
166
+ "X-API-KEY": "secret"
167
+ query:
168
+ token: "123"
169
+ cookies:
170
+ session_id: "2022"
171
+ ```
172
+
173
+ **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.
174
+
175
+ ### Using as a library
176
+
177
+ You can integrate WS Director into your library or application by using its APIs:
178
+
179
+ ```ruby
180
+ # Could be a file path or JSON-encoded string as well
181
+ scenario = [
182
+ {
183
+ send: {
184
+ data: "ping"
185
+ }
186
+ },
187
+ {
188
+ receive: {
189
+ data: "pong"
190
+ }
191
+ }
192
+ ]
193
+
194
+ result = WSDirector.run(scenario, url: "ws://my.ws.server:4949/live")
195
+ result.success? #=> true of false
196
+ result.groups #=> result data for each client group
197
+ ```
198
+
199
+ If you're using YAML-based scenarios, you can also pass local variables to be used with ERB via the `locals` option:
200
+
201
+ ```yml
202
+ - client:
203
+ connection_options:
204
+ headers:
205
+ "X-API-TOKEN": <%= token %>
206
+ ```
207
+
208
+ ```ruby
209
+ token = UserToken.generate
210
+ WSDirector.run(scenario, url: "ws://my.ws.server:4949/live", locals: {token:})
211
+ ```
212
+
119
213
  ### Protocols
120
214
 
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.
215
+ WSDirector uses protocols to handle provide convinient actions for some popular protocols.
123
216
 
124
217
  #### ActionCable Example
125
218
 
@@ -170,21 +263,87 @@ Scenario:
170
263
  text: "hello"
171
264
  ```
172
265
 
173
- ## Future Ideas
266
+ #### Phoenix Channels
174
267
 
175
- - Report timings (per-client and aggregates)
268
+ With "phoenix" protocol, you can use communicate with a [Phoenix Channels](https://hexdocs.pm/phoenix/channels.html) server:
269
+
270
+ ```yml
271
+ - client:
272
+ protocol: phoenix
273
+ multiplier: ":scale"
274
+ actions:
275
+ - join:
276
+ topic: room:lobby
277
+ - wait_all
278
+ - send:
279
+ topic: room:lobby
280
+ event: new_msg
281
+ data:
282
+ body: "Hey from WS director!"
283
+ - receive:
284
+ topic: room:lobby
285
+ multiplier: ":scale"
286
+ event: new_msg
287
+ data:
288
+ body: "Hey from WS director!"
289
+ ```
290
+
291
+ **IMPORTANT**: We support only v2 version of the Channels protocol.
176
292
 
177
- - File-less scenarios (JSON-encoded?), e.g.
293
+ #### Custom protocols
178
294
 
179
- ```shell
180
- wsdirector -i '{"receive": "hello"}' localhost:9898/ws
295
+ You can define your own protocol and load it dynamically:
296
+
297
+ ```ruby
298
+ # It's important to put a custom protocol class under WSDirector::Protocols
299
+ module WSDirector::Protocols
300
+ class CustomProtocol < Base
301
+ def send_ping_and_receive_pong
302
+ send("data" => {"type" => "ping"})
303
+ receive("data" => {"type" => "pong"})
304
+ end
305
+ end
306
+ end
307
+ ```
308
+
309
+ Now you can load it via the `-r` option:
310
+
311
+ ```sh
312
+ $ wsdirector -u localhost:3232/ws -i '["send_ping_and_receive_pong"]' -r ./path/to/custom_protocol.rb -vv
313
+
314
+ hh:mm:ss client=default_1 Connecting
315
+ hh:mm:ss client=default_1 Connected (45ms)
316
+ hh:mm:ss client=default_1 Sent message: {"type":"ping"}
317
+ hh:mm:ss client=default_1 Receive message: {"type":"pong"}
318
+ hh:mm:ss client=default_1 Received message: {"type":"pong"} (21ms)
181
319
  ```
182
320
 
183
- - Connection parameters (headers, query params, etc)
321
+ ## Testing frameworks integration
322
+
323
+ 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).
324
+
325
+ The example below implies running tests against an Action Cable server with a token-based authentication
184
326
 
185
- - Testing frameworks integrations
327
+ ```ruby
328
+ module WSDirectorTestHelper
329
+ def run_websocket_scenario(path, token:, url: ActionCable.server.config.url, **options)
330
+ url = "#{url}?jid=#{token}"
331
+ scenario = Rails.root.join "spec" / "fixtures" / "wsdirector" / path
332
+
333
+ WSDirector.run(scenario, url:, **options)
334
+ end
335
+ end
336
+
337
+ # In RSpec, you can include this modules via the configuration
338
+ RSpec.configure do |config|
339
+ # Here we only add this helper to system tests
340
+ config.include WSDirectorTestHelper, type: :system
341
+ end
342
+ ```
186
343
 
187
- - Loading protocols dynamically
344
+ ## Future Ideas
345
+
346
+ - Report timings (per-client and aggregates)
188
347
 
189
348
  - What else? [Submit an issue!](https://github.com/palkan/wsdirector/issues/new)
190
349
 
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.1
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-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: websocket-client-simple
16
+ name: wsdirector-core
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - "~>"
19
+ - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: '0.3'
22
- type: :runtime
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- requirements:
26
- - - "~>"
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
21
+ version: 1.0.1
36
22
  type: :runtime
37
23
  prerelease: false
38
24
  version_requirements: !ruby/object:Gem::Requirement
39
25
  requirements:
40
- - - "~>"
26
+ - - '='
41
27
  - !ruby/object:Gem::Version
42
- version: 1.0.5
28
+ version: 1.0.1
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