anyt 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75c73a6373cc4d26033b8fd5caf3d8b5601d06644227f7ee279818b8fc5e4afd
4
- data.tar.gz: d187153da7f0e4b3d7aae6d5a67594a66817beac1364e7741b0b2fb98b2ef7b3
3
+ metadata.gz: 0c9c827378c7eb12bd020314e569289176896a6c2ea3c08ea649e9ec8674590f
4
+ data.tar.gz: 62da136e9594732d956f1113797209dd7853f929cbd2301b17c79d97836b2934
5
5
  SHA512:
6
- metadata.gz: 1b06df7c02346d0c6986f42e5e71b33875c99ee0924c41a31ea4de574b3b65eaf15069f410962aaf6d62a1af511efd9505f49ade5cbf9815f2bdec00e5a7ff51
7
- data.tar.gz: 4955e07d7fac679f27f55604faea71d513bc66cfaf85abcd2e6f46db375a706a6d9d281ad36529f7d124a2e7242a777d4c83d11ec6020bfe9160f0bfbb076bfe
6
+ metadata.gz: c5c1cef4a681e2814941391092dde7e72709072ec0a5c5f3db63c57ce961255fafdee3524458ba286abe3c85b31a456e0d834e3b921efc6b4480fa963b966741
7
+ data.tar.gz: 4dd4cc71eab70762f8bd1f3d1c16b710d41cf660d58b333012309419d6c8433393612600a70c456fc87f2239d9c3ee5c645aaa3ed72391c6bcc6d3881c290ba7
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  [![Cult Of Martians](http://cultofmartians.com/assets/badges/badge.svg)](https://cultofmartians.com/tasks/anycable-conformance-tool.html#task)
2
2
  [![Gem Version](https://badge.fury.io/rb/anyt.svg)](https://rubygems.org/gems/anyt)
3
3
  ![Test](https://github.com/anycable/anyt/workflows/Test/badge.svg)
4
- [![Gitter](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/anycable/anycablebility)
5
4
 
6
5
  # AnyCable Conformance Testing Tool
7
6
 
data/lib/anyt/cli.rb CHANGED
@@ -32,7 +32,7 @@ module Anyt
32
32
  end
33
33
 
34
34
  # Load all test scenarios
35
- Tests.load_tests
35
+ Tests.load_tests unless @skip_tests
36
36
 
37
37
  Rails.application.initialize!
38
38
 
@@ -50,8 +50,14 @@ module Anyt
50
50
  # Start webosocket server under test
51
51
  Command.run
52
52
 
53
- # Run tests
54
- result = Tests.run ? 0 : 1
53
+ unless @skip_tests
54
+ # Run tests
55
+ result = Tests.run ? 0 : 1
56
+ end
57
+
58
+ wait_till_terminated if @only_rails
59
+ rescue Interrupt => e
60
+ $stdout.puts "#{e.message}. Good-bye!"
55
61
  ensure
56
62
  RPC.stop unless @skip_rpc
57
63
  Command.stop
@@ -91,16 +97,21 @@ module Anyt
91
97
 
92
98
  cli.on("--only-rpc", TrueClass, "Run only RPC server") do |flag|
93
99
  @only_rpc = flag
100
+ @skip_tests = true
101
+ end
102
+
103
+ cli.on("--only-rails", TrueClass, "Run only Rails server") do
104
+ @skip_rpc = true
105
+ @only_rails = true
106
+ @skip_tests = true
107
+
108
+ configure_rails_command!
94
109
  end
95
110
 
96
111
  cli.on("--self-check", "Run tests again Action Cable itself") do
97
112
  @skip_rpc = true
98
- dummy_path = ::File.expand_path(
99
- "config.ru",
100
- ::File.join(::File.dirname(__FILE__), "dummy")
101
- )
102
- Anyt.config.command = "bundle exec puma #{dummy_path}"
103
- Anyt.config.use_action_cable = true
113
+
114
+ configure_rails_command!
104
115
  end
105
116
 
106
117
  cli.on("--only test1,test2,test3", Array, "Run only specified tests") do |only_tests|
@@ -149,6 +160,36 @@ module Anyt
149
160
  puts "Use `anyt --help` to list all available options."
150
161
  exit 1
151
162
  end
163
+
164
+ def configure_rails_command!
165
+ dummy_path = ::File.expand_path(
166
+ "config.ru",
167
+ ::File.join(::File.dirname(__FILE__), "dummy")
168
+ )
169
+ Anyt.config.command = "bundle exec puma #{dummy_path}"
170
+ Anyt.config.use_action_cable = true
171
+ end
172
+
173
+ def wait_till_terminated
174
+ self_read = setup_signals
175
+
176
+ while readable_io = IO.select([self_read]) # rubocop:disable Lint/AssignmentInCondition
177
+ signal = readable_io.first[0].gets.strip
178
+ raise Interrupt, "SIG#{signal} received"
179
+ end
180
+ end
181
+
182
+ def setup_signals
183
+ self_read, self_write = IO.pipe
184
+
185
+ %w[INT TERM].each do |signal|
186
+ trap signal do
187
+ self_write.puts signal
188
+ end
189
+ end
190
+
191
+ self_read
192
+ end
152
193
  end
153
194
  end
154
195
  end
data/lib/anyt/command.rb CHANGED
@@ -11,6 +11,8 @@ module Anyt
11
11
  def run
12
12
  return if running?
13
13
 
14
+ return unless Anyt.config.command
15
+
14
16
  AnyCable.logger.debug "Running command: #{Anyt.config.command}"
15
17
 
16
18
  @process = ChildProcess.build(*Anyt.config.command.split(/\s+/))
data/lib/anyt/config.rb CHANGED
@@ -15,6 +15,9 @@ module Anyt
15
15
  wait_command: 2,
16
16
  timeout_multiplier: 1
17
17
 
18
+ coerce_types only_tests: {type: :string, array: true}
19
+ coerce_types except_tests: {type: :string, array: true}
20
+
18
21
  def tests_path
19
22
  return unless tests_relative_path
20
23
 
@@ -42,6 +42,29 @@ module ApplicationCable
42
42
  end
43
43
  end
44
44
 
45
+ # BenchmarkChannel is useful when running Rails app only or RPC only
46
+ class BenchmarkChannel < ApplicationCable::Channel
47
+ def subscribed
48
+ stream_from "all#{stream_id}"
49
+ end
50
+
51
+ def echo(data)
52
+ transmit data
53
+ end
54
+
55
+ def broadcast(data)
56
+ ActionCable.server.broadcast "all#{stream_id}", data
57
+ data["action"] = "broadcastResult"
58
+ transmit data
59
+ end
60
+
61
+ private
62
+
63
+ def stream_id
64
+ params[:id] || ""
65
+ end
66
+ end
67
+
45
68
  ActionCable.server.config.cable = {"adapter" => "redis"}
46
69
  ActionCable.server.config.connection_class = -> { ApplicationCable::Connection }
47
70
  ActionCable.server.config.disable_request_forgery_protection = true
@@ -12,9 +12,9 @@ module Anyt
12
12
  base.after { @clients&.each { |client| client.close(allow_messages: true) } }
13
13
  end
14
14
 
15
- def build_client(*args)
15
+ def build_client(**args)
16
16
  @clients ||= []
17
- Anyt::Client.new(*args).tap do |client|
17
+ Anyt::Client.new(**args).tap do |client|
18
18
  @clients << client
19
19
  end
20
20
  end
data/lib/anyt/rpc.rb CHANGED
@@ -19,10 +19,9 @@ module Anyt # :nodoc:
19
19
 
20
20
  AnyCable.server_callbacks.each(&:call)
21
21
 
22
- @server = AnyCable::Server.new(
22
+ @server = AnyCable::GRPC::Server.new(
23
23
  host: AnyCable.config.rpc_host,
24
- **AnyCable.config.to_grpc_params,
25
- interceptors: AnyCable.middleware.to_a
24
+ **AnyCable.config.to_grpc_params
26
25
  )
27
26
 
28
27
  AnyCable.middleware.freeze
@@ -7,16 +7,27 @@ feature "Channel state" do
7
7
  def subscribed
8
8
  self.user = {name: params["name"]}
9
9
  self.count = 1
10
+
11
+ stream_from "state_counts"
10
12
  end
11
13
 
12
14
  def tick
13
15
  self.count += 2
14
- transmit(count: count, name: user[:name])
16
+ transmit({count: count, name: user[:name]})
17
+ end
18
+
19
+ def unsubscribed
20
+ return unless params["notify_disconnect"]
21
+
22
+ ActionCable.server.broadcast("state_counts", {data: "user left: #{user[:name]}"})
15
23
  end
16
24
  end
17
25
 
18
26
  let(:identifier) { {channel: channel, name: "chipolino"}.to_json }
19
27
 
28
+ let(:client2) { build_client(ignore: %w[ping welcome]) }
29
+ let(:identifier2) { {channel: channel, name: "chipollone", notify_disconnect: true}.to_json }
30
+
20
31
  before do
21
32
  subscribe_request = {command: "subscribe", identifier: identifier}
22
33
 
@@ -44,4 +55,27 @@ feature "Channel state" do
44
55
 
45
56
  assert_equal msg, client.receive
46
57
  end
58
+
59
+ scenario %(
60
+ Channel state is available in #unsubscribe callbacks
61
+ ) do
62
+ subscribe_request = {command: "subscribe", identifier: identifier2}
63
+
64
+ client2.send(subscribe_request)
65
+
66
+ ack = {
67
+ "identifier" => identifier2, "type" => "confirm_subscription"
68
+ }
69
+
70
+ assert_equal ack, client2.receive
71
+
72
+ client2.close
73
+
74
+ msg = {
75
+ "identifier" => identifier,
76
+ "message" => {"data" => "user left: chipollone"}
77
+ }
78
+
79
+ assert_equal msg, client.receive
80
+ end
47
81
  end
@@ -7,7 +7,7 @@ feature "Request" do
7
7
  end
8
8
 
9
9
  def unsubscribed
10
- ActionCable.server.broadcast("request_a", data: "user left")
10
+ ActionCable.server.broadcast("request_a", {data: "user left"})
11
11
  end
12
12
  end
13
13
 
@@ -17,7 +17,7 @@ feature "Request" do
17
17
  end
18
18
 
19
19
  def unsubscribed
20
- ActionCable.server.broadcast("request_b", data: "user left")
20
+ ActionCable.server.broadcast("request_b", {data: "user left"})
21
21
  end
22
22
  end
23
23
 
@@ -27,7 +27,7 @@ feature "Request" do
27
27
  end
28
28
 
29
29
  def unsubscribed
30
- ActionCable.server.broadcast("request_c", data: "user left#{params[:id].presence}")
30
+ ActionCable.server.broadcast("request_c", {data: "user left#{params[:id].presence}"})
31
31
  end
32
32
  end
33
33
 
@@ -24,7 +24,7 @@ feature "Broadcast data to stream" do
24
24
  ) do
25
25
  ActionCable.server.broadcast(
26
26
  "a",
27
- data: {user_id: 1, status: "left", meta: {connection_time: "10s"}}
27
+ {data: {user_id: 1, status: "left", meta: {connection_time: "10s"}}}
28
28
  )
29
29
 
30
30
  msg = {
@@ -26,7 +26,7 @@ feature "Streams with many clients" do
26
26
  scenario %(
27
27
  Multiple clients receive messages from stream
28
28
  ) do
29
- ActionCable.server.broadcast("a", data: "X")
29
+ ActionCable.server.broadcast("a", {data: "X"})
30
30
 
31
31
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "X"}}
32
32
 
@@ -37,7 +37,7 @@ feature "Streams with many clients" do
37
37
  scenario %(
38
38
  Client receive messages when another client removes subscription
39
39
  ) do
40
- ActionCable.server.broadcast("a", data: "X")
40
+ ActionCable.server.broadcast("a", {data: "X"})
41
41
 
42
42
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "X"}}
43
43
 
@@ -51,7 +51,7 @@ feature "Streams with many clients" do
51
51
  # ActionCable doesn't provide an unsubscription ack :(
52
52
  sleep 1
53
53
 
54
- ActionCable.server.broadcast("a", data: "Y")
54
+ ActionCable.server.broadcast("a", {data: "Y"})
55
55
 
56
56
  msg2 = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "Y"}}
57
57
 
@@ -23,13 +23,13 @@ feature "Multiple streams" do
23
23
  scenario %(
24
24
  Client receives messages from both streams
25
25
  ) do
26
- ActionCable.server.broadcast("a", data: "X")
26
+ ActionCable.server.broadcast("a", {data: "X"})
27
27
 
28
28
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "X"}}
29
29
 
30
30
  assert_equal msg, client.receive
31
31
 
32
- ActionCable.server.broadcast("b", data: "Y")
32
+ ActionCable.server.broadcast("b", {data: "Y"})
33
33
 
34
34
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "Y"}}
35
35
 
@@ -39,7 +39,7 @@ feature "Multiple streams" do
39
39
  scenario %(
40
40
  Client does not receive messages from any stream after removing subscription
41
41
  ) do
42
- ActionCable.server.broadcast("a", data: "X")
42
+ ActionCable.server.broadcast("a", {data: "X"})
43
43
 
44
44
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "X"}}
45
45
 
@@ -52,8 +52,8 @@ feature "Multiple streams" do
52
52
  # ActionCable doesn't provide an unsubscription ack :(
53
53
  sleep 1
54
54
 
55
- ActionCable.server.broadcast("a", data: "Y")
56
- ActionCable.server.broadcast("b", data: "Z")
55
+ ActionCable.server.broadcast("a", {data: "Y"})
56
+ ActionCable.server.broadcast("b", {data: "Z"})
57
57
 
58
58
  assert_raises(Anyt::Client::TimeoutError) { client.receive(timeout: 0.5) }
59
59
  end
@@ -22,13 +22,13 @@ feature "Single stream" do
22
22
  scenario %(
23
23
  Client receives messages from the stream
24
24
  ) do
25
- ActionCable.server.broadcast("a", data: "X")
25
+ ActionCable.server.broadcast("a", {data: "X"})
26
26
 
27
27
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "X"}}
28
28
 
29
29
  assert_equal msg, client.receive
30
30
 
31
- ActionCable.server.broadcast("a", data: "Y")
31
+ ActionCable.server.broadcast("a", {data: "Y"})
32
32
 
33
33
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "Y"}}
34
34
 
@@ -38,7 +38,7 @@ feature "Single stream" do
38
38
  scenario %(
39
39
  Client does not receive messages from the stream after removing subscription
40
40
  ) do
41
- ActionCable.server.broadcast("a", data: "X")
41
+ ActionCable.server.broadcast("a", {data: "X"})
42
42
 
43
43
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "X"}}
44
44
 
@@ -51,7 +51,7 @@ feature "Single stream" do
51
51
  # ActionCable doesn't provide an unsubscription ack :(
52
52
  sleep 1
53
53
 
54
- ActionCable.server.broadcast("a", data: "Y")
54
+ ActionCable.server.broadcast("a", {data: "Y"})
55
55
 
56
56
  assert_raises(Anyt::Client::TimeoutError) { client.receive(timeout: 0.5) }
57
57
  end
@@ -70,7 +70,7 @@ feature "Single stream" do
70
70
 
71
71
  assert_equal ack, client.receive
72
72
 
73
- ActionCable.server.broadcast("a", data: "XX")
73
+ ActionCable.server.broadcast("a", {data: "XX"})
74
74
 
75
75
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "XX"}}
76
76
  msg2 = {"identifier" => {channel: channel, some_param: "test"}.to_json, "message" => {"data" => "XX"}}
@@ -8,7 +8,7 @@ feature "Stop streams" do
8
8
  end
9
9
 
10
10
  def ping(data)
11
- ActionCable.server.broadcast data["name"], reply: "pong"
11
+ ActionCable.server.broadcast data["name"], {reply: "pong"}
12
12
  end
13
13
 
14
14
  def unfollow(data)
@@ -33,7 +33,7 @@ feature "Stop streams" do
33
33
  ) do
34
34
  skip if Anyt.config.use_action_cable && (::ActionCable::VERSION::MAJOR < 6 || ::ActionCable::VERSION::MINOR < 1)
35
35
 
36
- ActionCable.server.broadcast("a", data: "X")
36
+ ActionCable.server.broadcast("a", {data: "X"})
37
37
 
38
38
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "X"}}
39
39
 
@@ -47,9 +47,9 @@ feature "Stop streams" do
47
47
  client.send(perform_request)
48
48
  sleep 0.2 # give some time to commit unsubscribe
49
49
 
50
- ActionCable.server.broadcast("a", data: "Y")
50
+ ActionCable.server.broadcast("a", {data: "Y"})
51
51
  sleep 0.2 # "a" should be broadcasted first
52
- ActionCable.server.broadcast("b", data: "Z")
52
+ ActionCable.server.broadcast("b", {data: "Z"})
53
53
 
54
54
  msg = {"identifier" => {channel: channel}.to_json, "message" => {"data" => "Z"}}
55
55
  assert_equal msg, client.receive
@@ -10,7 +10,7 @@ feature "Subscription perform methods" do
10
10
  end
11
11
 
12
12
  def echo(data)
13
- transmit(response: data["text"])
13
+ transmit({response: data["text"]})
14
14
  end
15
15
  end
16
16
 
data/lib/anyt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anyt
4
- VERSION = "1.0.1"
4
+ VERSION = "1.1.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: anyt
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-07 00:00:00.000000000 Z
11
+ date: 2022-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -58,28 +58,48 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '5.0'
61
+ version: '6.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '5.0'
68
+ version: '6.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: anyway_config
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.2.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.2.0
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: anycable-rails
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ">="
87
+ - - ">"
74
88
  - !ruby/object:Gem::Version
75
- version: 1.0.0
89
+ version: 1.0.99
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '2.0'
76
93
  type: :runtime
77
94
  prerelease: false
78
95
  version_requirements: !ruby/object:Gem::Requirement
79
96
  requirements:
80
- - - ">="
97
+ - - ">"
81
98
  - !ruby/object:Gem::Version
82
- version: 1.0.0
99
+ version: 1.0.99
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '2.0'
83
103
  - !ruby/object:Gem::Dependency
84
104
  name: redis
85
105
  requirement: !ruby/object:Gem::Requirement
@@ -243,7 +263,7 @@ homepage: http://github.com/anycable/anyt
243
263
  licenses:
244
264
  - MIT
245
265
  metadata: {}
246
- post_install_message:
266
+ post_install_message:
247
267
  rdoc_options: []
248
268
  require_paths:
249
269
  - lib
@@ -258,8 +278,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
258
278
  - !ruby/object:Gem::Version
259
279
  version: '0'
260
280
  requirements: []
261
- rubygems_version: 3.0.6
262
- signing_key:
281
+ rubygems_version: 3.2.22
282
+ signing_key:
263
283
  specification_version: 4
264
284
  summary: Anycable conformance testing tool
265
285
  test_files: []