anyt 0.8.3 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +4 -1
- data/lib/anyt/cli.rb +32 -6
- data/lib/anyt/client.rb +13 -7
- data/lib/anyt/command.rb +31 -18
- data/lib/anyt/config.rb +15 -7
- data/lib/anyt/dummy/application.rb +9 -11
- data/lib/anyt/dummy/config.ru +4 -0
- data/lib/anyt/dummy/routes.rb +4 -0
- data/lib/anyt/dummy/tmp/development_secret.txt +1 -0
- data/lib/anyt/ext/minitest.rb +23 -6
- data/lib/anyt/remote_control.rb +33 -0
- data/lib/anyt/rpc.rb +4 -6
- data/lib/anyt/tests.rb +5 -7
- data/lib/anyt/tests/core/ping_test.rb +2 -2
- data/lib/anyt/tests/core/welcome_test.rb +3 -3
- data/lib/anyt/tests/features/channel_state_test.rb +79 -0
- data/lib/anyt/tests/features/remote_disconnect_test.rb +30 -0
- data/lib/anyt/tests/features/server_restart_test.rb +28 -0
- data/lib/anyt/tests/request/channel_test.rb +28 -0
- data/lib/anyt/tests/request/connection_test.rb +23 -21
- data/lib/anyt/tests/request/disconnect_reasons_test.rb +23 -0
- data/lib/anyt/tests/request/disconnection_test.rb +50 -32
- data/lib/anyt/tests/streams/broadcast_test.rb +13 -13
- data/lib/anyt/tests/streams/multiple_clients_test.rb +10 -10
- data/lib/anyt/tests/streams/multiple_test.rb +10 -10
- data/lib/anyt/tests/streams/single_test.rb +35 -10
- data/lib/anyt/tests/streams/stop_test.rb +57 -0
- data/lib/anyt/tests/subscriptions/ack_test.rb +9 -11
- data/lib/anyt/tests/subscriptions/params_test.rb +6 -7
- data/lib/anyt/tests/subscriptions/perform_test.rb +16 -18
- data/lib/anyt/tests/subscriptions/transmissions_test.rb +6 -7
- data/lib/anyt/version.rb +1 -1
- metadata +28 -70
- data/.gitignore +0 -43
- data/.rubocop.yml +0 -80
- data/Gemfile +0 -6
- data/LICENSE.txt +0 -21
- data/Makefile +0 -5
- data/anyt.gemspec +0 -42
- data/circle.yml +0 -14
- data/etc/tests/channel_broadcast_test.rb +0 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc9f527d5ead1058291854236f7b011c64df27da0be2559bb27893c1dbb471fc
|
4
|
+
data.tar.gz: 0dce342de8720db9d2208e4fc44c7c1ba3b489c0d82bce7b936152df2c70ccca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6237b496a2cfb034d4b0d83eff127be84c360a124039bf14c32e4886732f9b9cff9def7e1515168dc87027ca85bcc64b78dfdd4d10988a1e84206b9fc4be7b3a
|
7
|
+
data.tar.gz: 9cd9d41ebdaf1321d13a08685b1955fe92875fb86fda8c4a230b1df9d30e7e39e5564a2614fb1693666a203926770cbdf3d9a0fda7265f3893524baa7cb8f89a
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
[![
|
1
|
+
[![Cult Of Martians](http://cultofmartians.com/assets/badges/badge.svg)](https://cultofmartians.com/tasks/anycable-conformance-tool.html#task)
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/anyt.svg)](https://rubygems.org/gems/anyt)
|
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)
|
2
5
|
|
3
6
|
# AnyCable Conformance Testing Tool
|
4
7
|
|
data/lib/anyt/cli.rb
CHANGED
@@ -4,13 +4,13 @@ require "logger"
|
|
4
4
|
require "optparse"
|
5
5
|
|
6
6
|
require "anyt/version"
|
7
|
+
require "anyt/remote_control"
|
7
8
|
require "anyt/rpc"
|
8
9
|
require "anyt/command"
|
9
10
|
require "anyt/tests"
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
# rubocop: disable Metrics/BlockLength
|
12
|
+
$stdout.sync = true
|
13
|
+
|
14
14
|
module Anyt
|
15
15
|
module Cli # :nodoc:
|
16
16
|
class << self
|
@@ -25,14 +25,26 @@ module Anyt
|
|
25
25
|
$stdout.puts "Starting AnyT v#{Anyt::VERSION} (pid: #{Process.pid})\n"
|
26
26
|
|
27
27
|
begin
|
28
|
+
# "Enable" AnyCable as early as possible to activate all the features in tests
|
29
|
+
unless Anyt.config.use_action_cable
|
30
|
+
ActionCable.server.config.cable = {"adapter" => "any_cable"}
|
31
|
+
require "anycable-rails"
|
32
|
+
end
|
33
|
+
|
28
34
|
# Load all test scenarios
|
29
35
|
Tests.load_tests
|
30
36
|
|
37
|
+
Rails.application.initialize!
|
38
|
+
|
31
39
|
# Start RPC server (unless specified otherwise, e.g. when
|
32
40
|
# we want to test Action Cable itself)
|
33
41
|
unless @skip_rpc
|
34
|
-
require "anycable-rails"
|
35
42
|
RPC.start
|
43
|
+
|
44
|
+
if @only_rpc
|
45
|
+
RPC.server.wait_till_terminated
|
46
|
+
return
|
47
|
+
end
|
36
48
|
end
|
37
49
|
|
38
50
|
# Start webosocket server under test
|
@@ -77,6 +89,10 @@ module Anyt
|
|
77
89
|
@skip_rpc = flag
|
78
90
|
end
|
79
91
|
|
92
|
+
cli.on("--only-rpc", TrueClass, "Run only RPC server") do |flag|
|
93
|
+
@only_rpc = flag
|
94
|
+
end
|
95
|
+
|
80
96
|
cli.on("--self-check", "Run tests again Action Cable itself") do
|
81
97
|
@skip_rpc = true
|
82
98
|
dummy_path = ::File.expand_path(
|
@@ -84,19 +100,29 @@ module Anyt
|
|
84
100
|
::File.join(::File.dirname(__FILE__), "dummy")
|
85
101
|
)
|
86
102
|
Anyt.config.command = "bundle exec puma #{dummy_path}"
|
103
|
+
Anyt.config.use_action_cable = true
|
87
104
|
end
|
88
105
|
|
89
106
|
cli.on("--only test1,test2,test3", Array, "Run only specified tests") do |only_tests|
|
90
107
|
Anyt.config.only_tests = only_tests
|
91
108
|
end
|
92
109
|
|
110
|
+
cli.on("--except test1,test2,test3", Array, "Exclude specified tests") do |except_tests|
|
111
|
+
Anyt.config.except_tests = except_tests
|
112
|
+
end
|
113
|
+
|
93
114
|
cli.on("--wait-command=TIMEOUT", Integer,
|
94
|
-
|
115
|
+
"Number of seconds to wait for WS server initialization") do |timeout|
|
95
116
|
Anyt.config.wait_command = timeout
|
96
117
|
end
|
97
118
|
|
119
|
+
cli.on("--timeout-multiplier=VALUE", Float,
|
120
|
+
"Default exceptation timeouts multiplier") do |val|
|
121
|
+
Anyt.config.timeout_multiplier = val
|
122
|
+
end
|
123
|
+
|
98
124
|
cli.on("-rPATH", "--require=PATH",
|
99
|
-
|
125
|
+
"Path to additional tests (e.g. features/*.rb") do |path|
|
100
126
|
Anyt.config.tests_relative_path = path
|
101
127
|
ENV["ANYT_TESTS_RELATIVE_PATH"] = path
|
102
128
|
end
|
data/lib/anyt/client.rb
CHANGED
@@ -17,14 +17,17 @@ module Anyt
|
|
17
17
|
# rubocop: disable Metrics/BlockLength
|
18
18
|
def initialize(
|
19
19
|
ignore: [], url: Anyt.config.target_url, qs: "",
|
20
|
-
cookies: "", headers: {}
|
20
|
+
cookies: "", headers: {},
|
21
|
+
timeout_multiplier: Anyt.config.timeout_multiplier
|
21
22
|
)
|
22
23
|
ignore_message_types = @ignore_message_types = ignore
|
23
24
|
messages = @messages = Queue.new
|
24
25
|
closed = @closed = Concurrent::Event.new
|
25
26
|
has_messages = @has_messages = Concurrent::Semaphore.new(0)
|
26
27
|
|
27
|
-
|
28
|
+
@timeout_multiplier = timeout_multiplier
|
29
|
+
|
30
|
+
headers = headers.merge("cookie" => cookies)
|
28
31
|
|
29
32
|
open = Concurrent::Promise.new
|
30
33
|
|
@@ -48,6 +51,7 @@ module Anyt
|
|
48
51
|
end
|
49
52
|
|
50
53
|
ws.on(:message) do |event|
|
54
|
+
next if event.type == :ping
|
51
55
|
if event.type == :close
|
52
56
|
closed.set
|
53
57
|
else
|
@@ -67,13 +71,15 @@ module Anyt
|
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
70
|
-
open.wait!(WAIT_WHEN_EXPECTING_EVENT)
|
74
|
+
open.wait!(WAIT_WHEN_EXPECTING_EVENT * @timeout_multiplier)
|
71
75
|
end
|
72
76
|
# rubocop: enable Metrics/BlockLength
|
73
77
|
# rubocop: enable Metrics/AbcSize
|
74
78
|
# rubocop: enable Metrics/MethodLength
|
75
79
|
|
76
80
|
def receive(timeout: WAIT_WHEN_EXPECTING_EVENT)
|
81
|
+
timeout *= @timeout_multiplier
|
82
|
+
|
77
83
|
raise TimeoutError, "Timed out to receive message" unless
|
78
84
|
@has_messages.try_acquire(1, timeout)
|
79
85
|
|
@@ -87,17 +93,17 @@ module Anyt
|
|
87
93
|
@ws.send(JSON.generate(message))
|
88
94
|
end
|
89
95
|
|
90
|
-
def close
|
91
|
-
sleep WAIT_WHEN_NOT_EXPECTING_EVENT
|
96
|
+
def close(allow_messages: false)
|
97
|
+
sleep WAIT_WHEN_NOT_EXPECTING_EVENT * @timeout_multiplier
|
92
98
|
|
93
|
-
raise "#{@messages.size} messages unprocessed" unless @messages.empty?
|
99
|
+
raise "#{@messages.size} messages unprocessed" unless allow_messages || @messages.empty?
|
94
100
|
|
95
101
|
@ws.close
|
96
102
|
wait_for_close
|
97
103
|
end
|
98
104
|
|
99
105
|
def wait_for_close
|
100
|
-
@closed.wait(WAIT_WHEN_EXPECTING_EVENT)
|
106
|
+
@closed.wait(WAIT_WHEN_EXPECTING_EVENT * @timeout_multiplier)
|
101
107
|
end
|
102
108
|
|
103
109
|
def closed?
|
data/lib/anyt/command.rb
CHANGED
@@ -1,50 +1,63 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "childprocess"
|
4
|
+
|
3
5
|
module Anyt
|
4
6
|
# Runs system command (websocket server)
|
5
7
|
module Command
|
6
8
|
class << self
|
7
|
-
attr_accessor :running
|
8
|
-
|
9
9
|
# rubocop: disable Metrics/MethodLength
|
10
10
|
# rubocop: disable Metrics/AbcSize
|
11
11
|
def run
|
12
|
-
return if
|
12
|
+
return if running?
|
13
13
|
|
14
14
|
AnyCable.logger.debug "Running command: #{Anyt.config.command}"
|
15
15
|
|
16
|
-
|
16
|
+
@process = ChildProcess.build(*Anyt.config.command.split(/\s+/))
|
17
|
+
|
18
|
+
process.io.inherit! if AnyCable.config.debug
|
17
19
|
|
18
|
-
|
19
|
-
Anyt.config.command,
|
20
|
-
out: out,
|
21
|
-
err: out
|
22
|
-
)
|
20
|
+
process.detach = true
|
23
21
|
|
24
|
-
|
22
|
+
process.environment["ANYCABLE_DEBUG"] = "1" if AnyCable.config.debug?
|
23
|
+
process.environment["ANYT_REMOTE_CONTROL_PORT"] = Anyt.config.remote_control_port
|
25
24
|
|
26
|
-
|
25
|
+
process.start
|
27
26
|
|
28
|
-
|
27
|
+
AnyCable.logger.debug "Command PID: #{process.pid}"
|
29
28
|
|
30
29
|
sleep Anyt.config.wait_command
|
30
|
+
raise "Command failed to start" unless running?
|
31
31
|
end
|
32
32
|
# rubocop: enable Metrics/MethodLength
|
33
33
|
# rubocop: enable Metrics/AbcSize
|
34
34
|
|
35
|
-
def
|
36
|
-
return unless
|
35
|
+
def restart
|
36
|
+
return unless running?
|
37
37
|
|
38
|
-
AnyCable.logger.debug "
|
38
|
+
AnyCable.logger.debug "Restarting command PID: #{process.pid}"
|
39
39
|
|
40
|
-
|
40
|
+
stop
|
41
|
+
process.wait
|
41
42
|
|
42
|
-
|
43
|
+
run
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop
|
47
|
+
return unless running?
|
48
|
+
|
49
|
+
AnyCable.logger.debug "Terminate PID: #{process.pid}"
|
50
|
+
|
51
|
+
process.stop
|
43
52
|
end
|
44
53
|
|
45
54
|
def running?
|
46
|
-
|
55
|
+
process&.alive?
|
47
56
|
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
attr_reader :process
|
48
61
|
end
|
49
62
|
end
|
50
63
|
end
|
data/lib/anyt/config.rb
CHANGED
@@ -6,10 +6,14 @@ module Anyt
|
|
6
6
|
# Anyt configuration
|
7
7
|
class Config < Anyway::Config
|
8
8
|
attr_config :command,
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
:only_tests,
|
10
|
+
:except_tests,
|
11
|
+
:tests_relative_path,
|
12
|
+
remote_control_port: 8919,
|
13
|
+
use_action_cable: false,
|
14
|
+
target_url: "ws://localhost:9292/cable",
|
15
|
+
wait_command: 2,
|
16
|
+
timeout_multiplier: 1
|
13
17
|
|
14
18
|
def tests_path
|
15
19
|
return unless tests_relative_path
|
@@ -18,12 +22,16 @@ module Anyt
|
|
18
22
|
end
|
19
23
|
|
20
24
|
def filter_tests?
|
21
|
-
|
25
|
+
only_tests || except_tests
|
22
26
|
end
|
23
27
|
|
24
28
|
def tests_filter
|
25
|
-
|
26
|
-
|
29
|
+
only_rxp = /(#{only_tests.join('|')})/ if only_tests
|
30
|
+
except_rxp = /(#{except_tests.join('|')})/ if except_tests
|
31
|
+
|
32
|
+
@tests_filter ||= lambda do |path|
|
33
|
+
(only_rxp.nil? || only_rxp.match?(path)) &&
|
34
|
+
(except_rxp.nil? || !except_rxp.match?(path))
|
27
35
|
end
|
28
36
|
end
|
29
37
|
end
|
@@ -10,31 +10,29 @@ require "anycable-rails"
|
|
10
10
|
require "action_dispatch/middleware/cookies"
|
11
11
|
|
12
12
|
class TestApp < Rails::Application
|
13
|
-
secrets.secret_token
|
13
|
+
secrets.secret_token = "secret_token"
|
14
14
|
secrets.secret_key_base = "secret_key_base"
|
15
15
|
|
16
16
|
config.logger = Logger.new(STDOUT)
|
17
|
-
config.log_level =
|
17
|
+
config.log_level = AnyCable.config.log_level
|
18
18
|
config.eager_load = true
|
19
19
|
|
20
|
-
|
21
|
-
Rails.application.routes.draw do
|
22
|
-
mount ActionCable.server => "/cable"
|
23
|
-
end
|
24
|
-
end
|
20
|
+
config.paths["config/routes.rb"] << File.join(__dir__, "routes.rb")
|
25
21
|
end
|
26
22
|
|
27
23
|
module ApplicationCable
|
28
24
|
class Connection < ActionCable::Connection::Base
|
29
25
|
delegate :params, to: :request
|
30
26
|
|
27
|
+
identified_by :uid
|
28
|
+
|
31
29
|
def connect
|
32
|
-
logger.
|
30
|
+
logger.debug "Connected"
|
33
31
|
Anyt::ConnectHandlers.call(self)
|
34
32
|
end
|
35
33
|
|
36
34
|
def disconnect
|
37
|
-
logger.
|
35
|
+
logger.debug "Disconnected"
|
38
36
|
end
|
39
37
|
end
|
40
38
|
end
|
@@ -44,8 +42,8 @@ module ApplicationCable
|
|
44
42
|
end
|
45
43
|
end
|
46
44
|
|
47
|
-
ActionCable.server.config.cable = {
|
45
|
+
ActionCable.server.config.cable = {"adapter" => "redis"}
|
48
46
|
ActionCable.server.config.connection_class = -> { ApplicationCable::Connection }
|
49
47
|
ActionCable.server.config.disable_request_forgery_protection = true
|
50
48
|
ActionCable.server.config.logger =
|
51
|
-
Rails.logger
|
49
|
+
Rails.logger
|
data/lib/anyt/dummy/config.ru
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
require_relative "./application"
|
4
4
|
|
5
5
|
require_relative "../tests"
|
6
|
+
require_relative "../remote_control"
|
7
|
+
|
8
|
+
# Start remote control
|
9
|
+
Anyt::RemoteControl::Server.start(Anyt.config.remote_control_port)
|
6
10
|
|
7
11
|
# Load channels from tests
|
8
12
|
Anyt::Tests.load_all_tests
|
@@ -0,0 +1 @@
|
|
1
|
+
fe2ecbcf229d5547a64bcdaa9ef4e543404ca3fc9d4ee83aaa7ddab34b6a378fe090c2b1836c9ebd3e5ebbf01c239ddac95e219358baaefc1afaa04cd07bf78c
|
data/lib/anyt/ext/minitest.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
ENV["TERM"] = "#{ENV["TERM"]}color" unless ENV["TERM"]&.match?(/color/)
|
3
4
|
require "minitest/spec"
|
4
5
|
require "minitest/reporters"
|
5
6
|
|
@@ -8,10 +9,26 @@ module Anyt
|
|
8
9
|
module TestHelpers
|
9
10
|
def self.included(base)
|
10
11
|
base.let(:client) { build_client(ignore: %w[ping welcome]) }
|
12
|
+
base.after { @clients&.each { |client| client.close(allow_messages: true) } }
|
11
13
|
end
|
12
14
|
|
13
15
|
def build_client(*args)
|
14
|
-
|
16
|
+
@clients ||= []
|
17
|
+
Anyt::Client.new(*args).tap do |client|
|
18
|
+
@clients << client
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def restart_server!
|
23
|
+
if Anyt.config.use_action_cable
|
24
|
+
remote_client.restart_action_cable
|
25
|
+
else
|
26
|
+
Command.restart
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def remote_client
|
31
|
+
@remote_client ||= RemoteControl::Client.connect(Anyt.config.remote_control_port)
|
15
32
|
end
|
16
33
|
end
|
17
34
|
end
|
@@ -38,7 +55,7 @@ module Anyt
|
|
38
55
|
|
39
56
|
def handlers_for(connection)
|
40
57
|
handlers.select do |(tag, _)|
|
41
|
-
connection.params[
|
58
|
+
connection.params["test"] == tag
|
42
59
|
end
|
43
60
|
end
|
44
61
|
|
@@ -74,7 +91,7 @@ module Minitest::Spec::DSL
|
|
74
91
|
# Generates Channel class dynamically and
|
75
92
|
# add memoized helper to access its name
|
76
93
|
def channel(id = nil, &block)
|
77
|
-
class_name = @name.gsub(/\s+/,
|
94
|
+
class_name = @name.gsub(/\s+/, "_")
|
78
95
|
class_name += "_#{id}" if id
|
79
96
|
class_name += "_channel"
|
80
97
|
|
@@ -99,15 +116,15 @@ module Anyt
|
|
99
116
|
module MinitestPatch
|
100
117
|
def load_plugins
|
101
118
|
super
|
102
|
-
extensions.delete(
|
119
|
+
extensions.delete("rails")
|
103
120
|
end
|
104
121
|
end
|
105
122
|
|
106
123
|
# Patch Spec reporter
|
107
124
|
module ReporterPatch # :nodoc:
|
108
125
|
def record_print_status(test)
|
109
|
-
test_name = test.name.gsub(/^test_/,
|
110
|
-
print pad_test(test_name)
|
126
|
+
test_name = test.name.gsub(/^test_/, "").strip
|
127
|
+
print(magenta { pad_test(test_name) })
|
111
128
|
print_colored_status(test)
|
112
129
|
print(" (%.2fs)" % test.time) unless test.time.nil?
|
113
130
|
puts
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "drb/drb"
|
4
|
+
|
5
|
+
module Anyt
|
6
|
+
# Invoke commands within the running Ruby (Action Cable) server
|
7
|
+
module RemoteControl
|
8
|
+
class Server
|
9
|
+
class << self
|
10
|
+
alias start new
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(port)
|
14
|
+
DRb.start_service(
|
15
|
+
"druby://localhost:#{port}",
|
16
|
+
Client.new
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Client
|
22
|
+
def self.connect(port)
|
23
|
+
DRb.start_service
|
24
|
+
|
25
|
+
DRbObject.new_with_uri("druby://localhost:#{port}")
|
26
|
+
end
|
27
|
+
|
28
|
+
def restart_action_cable
|
29
|
+
ActionCable.server.restart
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|