wsdirector-cli 0.4.0 → 0.5.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: 28d6654bce4665a9d0c1434c33ba359e31adb6680c51aafc3ccb1c5a91b32d56
4
- data.tar.gz: 6e9c3fd2cfe938ba5f8a5f3e3519204d93cd56d428fed93be89b4056e53f004e
3
+ metadata.gz: b02895fab166dd2d388f48dda802e02407e5b7866eb508f1b5787e1a4e1976d6
4
+ data.tar.gz: e0d5af5ae2de5caed7ccd151538e19ad3c49e08db1217e042f36540d69468314
5
5
  SHA512:
6
- metadata.gz: 1ce990e199cd5562bb03760a8678349b74f549014cf997c821b3ad6f4518e7e45e349a26e89fcfb22762f2a775d57604bf84c35511dd5294097590e14389c47a
7
- data.tar.gz: 0f4287fedbc4f0488e2a19fe59aa6de276da620345e9024bcd7baa5f04a473c1a5fd36556f9ba49f4a82575101934737df6d1d470069c85fa751436fbea16c0f
6
+ metadata.gz: '09af449361f79d80a4848b0851aa96ada36e363e997bba177e5d96b01005d1c241abee2a1a05781f3a5277de08732f3b1d8afaeaea467d2097050347d2ca295c'
7
+ data.tar.gz: 8deb112a900d7cdbc710be8b86d57aef8aeaa87bbec78595170bf309088bca9bb88fd58de503e2bcfb32b43df5e08903c322791eb10930aa0fb25f00e26afebb
data/CHANGELOG.md CHANGED
@@ -2,6 +2,53 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.5.0 (2021-10-13)
6
+
7
+ - Add JSON support. ([@wazzuper][])
8
+
9
+ - Add new commands to CLI.
10
+
11
+ You can pass a JSON scenario directly to the CLI without creating a file:
12
+
13
+ ```bash
14
+ wsdirector -i '[{"receive": {"data":"welcome"}},{"send":{"data":"send message"}},{"receive":{"data":"receive message"}}]' -u ws://websocket.server:9876
15
+ ```
16
+
17
+ or you can pass it as a JSON file:
18
+
19
+ ```bash
20
+ wsdirector scenario.json -u ws://websocket.server:9876
21
+ ```
22
+
23
+ - Add loop option support. ([@last-in-japan][])
24
+
25
+ You can specify a `loop` option to perform a similar set of actions multiple times:
26
+
27
+ ```yml
28
+ # script.yml
29
+ - client:
30
+ name: "listeners"
31
+ loop:
32
+ multiplier: ":scale" # :scale take number from -s param, and run :scale number of clients in this group
33
+ actions:
34
+ - receive:
35
+ data:
36
+ type: "welcome"
37
+ - send:
38
+ data:
39
+ command: "subscribe"
40
+ identifier: "{\"channel\":\"Channel\"}"
41
+ - receive:
42
+ data:
43
+ identifier: "{\"channel\":\"Channel\"}"
44
+ type: "confirm_subscription"
45
+ - wait_all
46
+ - receive:
47
+ multiplier: ":scale + 1"
48
+ ```
49
+
50
+ Useful in combination with `:scale`.
51
+
5
52
  ## 0.4.0 (2020-08-24)
6
53
 
7
54
  - **Drop Ruby 2.4 support**. ([@palkan][])
@@ -64,3 +111,5 @@ Allows to handle multiple messages with unspecified order:
64
111
  [@palkan]: https://github.com/palkan
65
112
  [@Kirillvs]: https://github.com/Kirillvs
66
113
  [@Grandman]: https://github.com/Grandman
114
+ [@wazzuper]: https://github.com/wazzuper
115
+ [@last-in-japan]: https://github.com/last-in-japan
data/README.md CHANGED
@@ -77,6 +77,45 @@ The simpliest scenario is just checking that socket is succesfully connected:
77
77
  # no actions
78
78
  ```
79
79
 
80
+ Run with loop option:
81
+
82
+ ```yml
83
+ # script.yml
84
+ - client:
85
+ name: "listeners"
86
+ loop:
87
+ multiplier: ":scale" # :scale take number from -s param, and run :scale number of clients in this group
88
+ actions:
89
+ - receive:
90
+ data:
91
+ type: "welcome"
92
+ - send:
93
+ data:
94
+ command: "subscribe"
95
+ identifier: "{\"channel\":\"Channel\"}"
96
+ - receive:
97
+ data:
98
+ identifier: "{\"channel\":\"Channel\"}"
99
+ type: "confirm_subscription"
100
+ - wait_all
101
+ - receive:
102
+ multiplier: ":scale + 1"
103
+ ```
104
+
105
+ Also you can pass a JSON file with some testing scripts:
106
+
107
+ ```bash
108
+ wsdirector scenario.json ws://websocket.server:9876
109
+ ```
110
+
111
+ or pass a JSON scenario directly to the CLI without creating a file:
112
+
113
+ ```bash
114
+ wsdirector -i '[{"receive": {"data":"welcome"}},{"send":{"data":"send message"}},{"receive":{"data":"receive message"}}]' ws://websocket.server:9876
115
+ ```
116
+
117
+ Type `wsdirector --help` to check all commands.
118
+
80
119
  ### Protocols
81
120
 
82
121
  WSDirector uses protocols to handle different actions.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "optparse"
4
+ require "uri"
4
5
 
5
6
  require "wsdirector"
6
7
  require "wsdirector/scenario_reader"
@@ -23,7 +24,7 @@ module WSDirector
23
24
  end
24
25
 
25
26
  scenario = WSDirector::ScenarioReader.parse(
26
- WSDirector.config.scenario_path
27
+ WSDirector.config.scenario_path || WSDirector.config.json_scenario
27
28
  )
28
29
 
29
30
  if WSDirector::Runner.new(scenario).start
@@ -38,6 +39,9 @@ module WSDirector
38
39
 
39
40
  private
40
41
 
42
+ FILE_FORMAT = /.+.(json|yml)\z/.freeze
43
+ private_constant :FILE_FORMAT
44
+
41
45
  def parse_args!
42
46
  # rubocop: disable Metrics/LineLength
43
47
  parser = OptionParser.new do |opts|
@@ -51,6 +55,14 @@ module WSDirector
51
55
  WSDirector.config.sync_timeout = v
52
56
  end
53
57
 
58
+ opts.on("-i JSON", "--include=JSON", String, "Include JSON to parse") do |v|
59
+ WSDirector.config.json_scenario = v
60
+ end
61
+
62
+ opts.on("-u URL", "--url=URL", Object, "Websocket server URL") do |v|
63
+ WSDirector.config.ws_url = v
64
+ end
65
+
54
66
  opts.on("-c", "--[no-]color", "Colorize output") do |v|
55
67
  WSDirector.config.colorize = v
56
68
  end
@@ -64,15 +76,25 @@ module WSDirector
64
76
 
65
77
  parser.parse!
66
78
 
67
- WSDirector.config.scenario_path = ARGV[0]
68
- WSDirector.config.ws_url = ARGV[1]
79
+ WSDirector.config.scenario_path = ARGV.grep(FILE_FORMAT).last
69
80
 
70
- raise(Error, "Scenario path is missing") if WSDirector.config.scenario_path.nil?
81
+ unless WSDirector.config.ws_url
82
+ WSDirector.config.ws_url = ARGV.grep(URI::DEFAULT_PARSER.make_regexp).last
83
+ end
71
84
 
72
- raise(Error, "File doesn't exist #{WSDirector.config.scenario_path}") unless
73
- File.file?(WSDirector.config.scenario_path)
85
+ check_for_errors
86
+ end
87
+
88
+ def check_for_errors
89
+ if WSDirector.config.json_scenario.nil?
90
+ raise(Error, "Scenario is missing") unless WSDirector.config.scenario_path
91
+
92
+ unless File.file?(WSDirector.config.scenario_path)
93
+ raise(Error, "File doesn't exist #{WSDirector.config.scenario_path}")
94
+ end
95
+ end
74
96
 
75
- raise(Error, "Websocket server url is missing") if WSDirector.config.ws_url.nil?
97
+ raise(Error, "Websocket server url is missing") unless WSDirector.config.ws_url
76
98
  end
77
99
  end
78
100
  end
@@ -60,7 +60,7 @@ module WSDirector
60
60
 
61
61
  def ignored?(msg)
62
62
  return false unless @ignore
63
- @ignore.any? { |pattern| msg =~ pattern }
63
+ @ignore.any? { |pattern| msg =~ Regexp.new(pattern) }
64
64
  end
65
65
  end
66
66
  end
@@ -3,8 +3,7 @@
3
3
  module WSDirector
4
4
  # WSDirector configuration
5
5
  class Configuration
6
- attr_accessor :ws_url, :scenario_path, :colorize, :scale,
7
- :sync_timeout
6
+ attr_accessor :ws_url, :scenario_path, :colorize, :scale, :sync_timeout, :json_scenario
8
7
 
9
8
  def initialize
10
9
  reset!
@@ -29,6 +29,12 @@ module WSDirector
29
29
  end
30
30
  end
31
31
  end
32
+
33
+ refine ::Object do
34
+ def deep_dup
35
+ dup
36
+ end
37
+ end
32
38
  end
33
39
  end
34
40
  end
@@ -63,10 +63,10 @@ module WSDirector
63
63
  messages.nil? || messages.empty?
64
64
 
65
65
  expected =
66
- Hash[messages.map do |msg|
66
+ messages.map do |msg|
67
67
  multiplier = parse_multiplier(msg.delete("multiplier") || "1")
68
68
  [msg["data"], multiplier]
69
- end]
69
+ end.to_h
70
70
 
71
71
  total_expected = expected.values.sum
72
72
  total_received = 0
@@ -12,8 +12,10 @@ module WSDirector
12
12
  module Protocols # :nodoc:
13
13
  # Raised when received not expected message
14
14
  class UnmatchedExpectationError < WSDirector::Error; end
15
+
15
16
  # Raised when received message is unexpected
16
17
  class UnexpectedMessageError < WSDirector::Error; end
18
+
17
19
  # Raised when nothing has been received
18
20
  class NoMessageError < WSDirector::Error; end
19
21
 
@@ -1,25 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "erb"
4
+ require "json"
5
+ require "wsdirector/ext/deep_dup"
4
6
 
5
7
  module WSDirector
6
- # Read and parse YAML scenario
8
+ # Read and parse different scenarios
7
9
  class ScenarioReader
10
+ using WSDirector::Ext::DeepDup
11
+
8
12
  class << self
9
13
  include WSDirector::Utils
10
14
 
11
- def parse(file_path)
12
- contents = ::YAML.load(ERB.new(File.read(file_path)).result) # rubocop:disable Security/YAMLLoad
15
+ def parse(scenario)
16
+ contents =
17
+ if File.file?(scenario)
18
+ parse_file(scenario)
19
+ else
20
+ [JSON.parse(scenario)]
21
+ end.flatten
13
22
 
14
23
  if contents.first.key?("client")
24
+ contents = transform_with_loop(contents, multiple: true)
15
25
  parse_multiple_scenarios(contents)
16
26
  else
27
+ contents = transform_with_loop(contents)
17
28
  {"total" => 1, "clients" => [parse_simple_scenario(contents)]}
18
29
  end
19
30
  end
20
31
 
21
32
  private
22
33
 
34
+ JSON_FILE_FORMAT = /.+.(json)\z/.freeze
35
+ private_constant :JSON_FILE_FORMAT
36
+
37
+ def parse_file(file)
38
+ if file.match?(JSON_FILE_FORMAT)
39
+ JSON.parse(File.read(file))
40
+ else
41
+ ::YAML.load(ERB.new(File.read(file)).result) # rubocop:disable Security/YAMLLoad
42
+ end
43
+ end
44
+
23
45
  def handle_steps(steps)
24
46
  steps.flat_map.with_index do |step, id|
25
47
  if step.is_a?(Hash)
@@ -67,6 +89,22 @@ module WSDirector
67
89
  {"total" => total_count, "clients" => clients}
68
90
  end
69
91
 
92
+ def transform_with_loop(contents, multiple: false)
93
+ contents.flat_map do |content|
94
+ loop_data = content.dig("client", "loop") || content.dig("loop")
95
+ next content unless loop_data
96
+
97
+ loop_multiplier = parse_multiplier(loop_data["multiplier"] || "1")
98
+
99
+ if multiple
100
+ content["client"]["actions"] = (loop_data["actions"] * loop_multiplier).map(&:deep_dup)
101
+ content
102
+ else
103
+ loop_data["actions"] * loop_multiplier
104
+ end
105
+ end
106
+ end
107
+
70
108
  def parse_ingore(str)
71
109
  return unless str
72
110
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WSDirector
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wsdirector-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kirill Arkhipov
8
8
  - Grandman
9
9
  - palkan
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-08-24 00:00:00.000000000 Z
13
+ date: 2021-10-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: websocket-client-simple
@@ -202,7 +202,7 @@ homepage: https://github.com/palkan/wsdirector
202
202
  licenses:
203
203
  - MIT
204
204
  metadata: {}
205
- post_install_message:
205
+ post_install_message:
206
206
  rdoc_options: []
207
207
  require_paths:
208
208
  - lib
@@ -217,8 +217,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
217
  - !ruby/object:Gem::Version
218
218
  version: '0'
219
219
  requirements: []
220
- rubygems_version: 3.0.6
221
- signing_key:
220
+ rubygems_version: 3.2.22
221
+ signing_key:
222
222
  specification_version: 4
223
223
  summary: Command line tool for testing websocket servers using scenarios.
224
224
  test_files: []