tsquery 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/lazy_tsquery.rb +65 -0
- data/lib/retrying_tsquery.rb +43 -0
- data/lib/tsquery.rb +165 -0
- data/test/lazy_tsquery_test.rb +55 -0
- data/test/retrying_tsquery_test.rb +211 -0
- data/test/tsquery_test.rb +156 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2020e3aad096076aabaf27fb1df6b4ca1ccceb78
|
4
|
+
data.tar.gz: 0a44ae7ec881fbf44fb79bd38d5d67d203b8150b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea76e6eb59f873ca87115f03ae6720b6ce73e2bdf7fff5380dae0a273a6d5c470a85ef464e7483c9711cf80246326e20ab4f1bf9f93998daee79bcc5bdfff197
|
7
|
+
data.tar.gz: 0b70b805c7d44516b7f8d3960739f7aa35cf1448c5e1338b235ec37d5e10e42fd2f2cfc80877fe03ec929d814ce63cdb30f3629306234049a5d3b6f61a922635
|
data/lib/lazy_tsquery.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require_relative './tsquery'
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
|
5
|
+
# LazyTsquery delays the connection and the execution of
|
6
|
+
# following commands (`use`, `login`) until another command
|
7
|
+
# is executed.
|
8
|
+
# This allows to create ready-to-use Tsquery objects without
|
9
|
+
# ever hitting the server.
|
10
|
+
class LazyTsquery < DelegateClass(Tsquery)
|
11
|
+
def connect(lazy: true, **kwargs)
|
12
|
+
if lazy
|
13
|
+
@connection_info = kwargs
|
14
|
+
nil
|
15
|
+
else
|
16
|
+
super(**kwargs)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def execute(command, *args)
|
22
|
+
case command
|
23
|
+
when 'use', 'login'
|
24
|
+
@commands ||= []
|
25
|
+
@commands << [command, args]
|
26
|
+
|
27
|
+
nil
|
28
|
+
else
|
29
|
+
connect **@connection_info, lazy: false
|
30
|
+
|
31
|
+
@commands.each do |command, args|
|
32
|
+
super(command, *args)
|
33
|
+
end
|
34
|
+
@commands = []
|
35
|
+
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Needed for the delegation to work.
|
42
|
+
|
43
|
+
|
44
|
+
def method_missing(command, *args)
|
45
|
+
execute(command.to_s, *args)
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def respond_to_missing?(command, *)
|
50
|
+
!!(command =~ /[[:alnum:]]$/)
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def login(username: 'serveradmin', password:)
|
55
|
+
execute 'login', username, password
|
56
|
+
nil
|
57
|
+
rescue Error
|
58
|
+
false
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def inspect
|
63
|
+
__getobj__.inspect
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative './tsquery'
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
|
5
|
+
# Inspired by https://rubytapas.dpdcart.com/subscriber/post?id=689
|
6
|
+
class RetryingTsquery < DelegateClass(Tsquery)
|
7
|
+
def connect(times: 3, sleep: Kernel.method(:sleep), **keyword_args)
|
8
|
+
super(**keyword_args)
|
9
|
+
rescue Errno::ECONNREFUSED
|
10
|
+
sleep.call 0.5
|
11
|
+
retry if (times -= 1) > 0
|
12
|
+
Kernel.raise
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def execute(*args, times: 3, sleep: Kernel.method(:sleep), **keyword_args)
|
17
|
+
super(*args, **keyword_args)
|
18
|
+
rescue Tsquery::UnknownCommand
|
19
|
+
Kernel.raise
|
20
|
+
rescue Tsquery::Error
|
21
|
+
sleep.call 0.5
|
22
|
+
retry if (times -= 1) > 0
|
23
|
+
Kernel.raise
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# Needed for the delegation to work.
|
28
|
+
|
29
|
+
|
30
|
+
def method_missing(command, *args)
|
31
|
+
execute(command.to_s, *args)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def respond_to_missing?(command, *)
|
36
|
+
!!(command =~ /[[:alnum:]]$/)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def inspect
|
41
|
+
__getobj__.inspect
|
42
|
+
end
|
43
|
+
end
|
data/lib/tsquery.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'net/telnet'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
|
5
|
+
class Tsquery
|
6
|
+
def initialize(logger: Logger.new)
|
7
|
+
@logger = logger
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def execute(command, *args)
|
12
|
+
args = args.each_with_object([]) do |arg, array|
|
13
|
+
case arg
|
14
|
+
when Integer
|
15
|
+
array << arg.to_s
|
16
|
+
when String
|
17
|
+
array << arg
|
18
|
+
when Hash
|
19
|
+
arg.each do |key, value|
|
20
|
+
array << "#{key}=#{value.to_s.gsub(ESCAPE_PATTERNS_REGEXP, ESCAPE_PATTERNS)}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
full_command = ([command] + args).join(' ')
|
26
|
+
@logger.info "=> #{full_command}"
|
27
|
+
|
28
|
+
case command
|
29
|
+
when /list$/
|
30
|
+
parse_list(@telnet.cmd(
|
31
|
+
'String' => full_command,
|
32
|
+
'Timeout' => 3,
|
33
|
+
'Match' => /error id=\d+/
|
34
|
+
))
|
35
|
+
when /info$/, 'whoami', 'version'
|
36
|
+
parse_info(@telnet.cmd(
|
37
|
+
'String' => full_command,
|
38
|
+
'Timeout' => 3,
|
39
|
+
'Match' => /error id=\d+/
|
40
|
+
))
|
41
|
+
else
|
42
|
+
parse(@telnet.cmd(
|
43
|
+
'String' => full_command,
|
44
|
+
'Timeout' => 3,
|
45
|
+
'Match' => /^error id=\d+/
|
46
|
+
))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def login(username: 'serveradmin', password:)
|
52
|
+
execute 'login', username, password
|
53
|
+
true
|
54
|
+
rescue Error
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def method_missing(command, *args)
|
60
|
+
execute(command.to_s, *args)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def respond_to_missing?(command, *)
|
65
|
+
!!(command =~ /[[:alnum:]]$/)
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def connect(server: '127.0.0.1', port: '10011', telnet_class: Net::Telnet)
|
70
|
+
@telnet = telnet_class.new('Host' => server, 'Port' => port, 'Waittime' => 0.1)
|
71
|
+
@telnet.waitfor 'Match' => /^TS3\n/
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def close
|
76
|
+
@telnet.close
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
private
|
81
|
+
# Copied from http://addons.teamspeak.com/directory/addon/integration/TeamSpeak-3-PHP-Framework.html
|
82
|
+
ESCAPE_PATTERNS = {
|
83
|
+
"/" => "\\/", # slash
|
84
|
+
" " => "\\s", # whitespace
|
85
|
+
"|" => "\\p", # pipe
|
86
|
+
";" => "\\;", # semicolon
|
87
|
+
"\a" => "\\a", # bell
|
88
|
+
"\b" => "\\b", # backspace
|
89
|
+
"\f" => "\\f", # formfeed
|
90
|
+
"\n" => "\\n", # newline
|
91
|
+
"\r" => "\\r", # carriage return
|
92
|
+
"\t" => "\\t", # horizontal tab
|
93
|
+
"\v" => "\\v", # vertical tab
|
94
|
+
"\\" => "\\\\" # backslash
|
95
|
+
}.freeze
|
96
|
+
ESCAPE_PATTERNS_REGEXP = Regexp.union(ESCAPE_PATTERNS.keys).freeze
|
97
|
+
|
98
|
+
INVERTED_ESCAPE_PATTERNS = ESCAPE_PATTERNS.invert.freeze
|
99
|
+
INVERTED_ESCAPE_PATTERNS_REGEXP = Regexp.union(INVERTED_ESCAPE_PATTERNS.keys).freeze
|
100
|
+
|
101
|
+
|
102
|
+
def parse_list(response)
|
103
|
+
check_response! response
|
104
|
+
|
105
|
+
first, last = response.split(/\n\r?/)
|
106
|
+
@logger.info "<= #{first}"
|
107
|
+
parse last
|
108
|
+
|
109
|
+
first.split('|').map do |arguments|
|
110
|
+
deserialize_arguments(arguments)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def parse_info(response)
|
116
|
+
check_response! response
|
117
|
+
|
118
|
+
first, last = response.split(/\n\r?/)
|
119
|
+
@logger.info "<= #{first}"
|
120
|
+
parse last
|
121
|
+
|
122
|
+
deserialize_arguments(first)
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
def parse(response)
|
127
|
+
check_response! response
|
128
|
+
|
129
|
+
@logger.info "<= #{response}"
|
130
|
+
|
131
|
+
# Response always starts with "error", so we just remove it
|
132
|
+
response = response.gsub(/^error\s/, '')
|
133
|
+
arguments = deserialize_arguments(response)
|
134
|
+
|
135
|
+
raise Error, arguments['msg'] if Integer(arguments['id']) != 0
|
136
|
+
arguments['msg'] == 'ok'
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
def deserialize_arguments(string)
|
141
|
+
string.split.each_with_object({}) do |string, hash|
|
142
|
+
key, value = string.split('=')
|
143
|
+
value = value.gsub(INVERTED_ESCAPE_PATTERNS_REGEXP, INVERTED_ESCAPE_PATTERNS)
|
144
|
+
|
145
|
+
hash[key] = case value
|
146
|
+
when /^\d+$/
|
147
|
+
value.to_i
|
148
|
+
when /^\d+\.\d+$/
|
149
|
+
value.to_f
|
150
|
+
else
|
151
|
+
value
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
def check_response!(response)
|
158
|
+
raise Error, 'response is nil' if response.nil?
|
159
|
+
raise UnknownCommand, deserialize_arguments(response.gsub(/^error\s/, ''))['msg'] if response =~ /error id=256\D/
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
class Error < StandardError; end
|
164
|
+
class UnknownCommand < Error; end
|
165
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative './test_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class LazyTsqueryTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@telnet = telnet = Minitest::Mock.new
|
7
|
+
@telnet_class = Class.new do
|
8
|
+
define_singleton_method :new do |*|
|
9
|
+
telnet
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
@tsquery = LazyTsquery.new(Tsquery.new(logger: Logger.new(nil)))
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def test_it_delays_execution
|
18
|
+
@tsquery.connect telnet_class: @telnet_class
|
19
|
+
@tsquery.use 1
|
20
|
+
@tsquery.login password: 'password'
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def test_it_executes_if_necessary
|
25
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
26
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'use 1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
27
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'login serveradmin password', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
28
|
+
@telnet.expect :cmd, <<-RESPONSE.gsub(/^\s*/, ''), ['String' => 'version', 'Timeout' => 3, 'Match' => /error id=\d+/]
|
29
|
+
version=3.0.0-alpha4 build=9155 platform=Linux
|
30
|
+
error id=0 msg=ok
|
31
|
+
RESPONSE
|
32
|
+
|
33
|
+
@tsquery.connect telnet_class: @telnet_class
|
34
|
+
@tsquery.use 1
|
35
|
+
@tsquery.login password: 'password'
|
36
|
+
@tsquery.version
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def test_delayed_methods_return_nil
|
41
|
+
assert_nil @tsquery.connect telnet_class: @telnet_class
|
42
|
+
assert_nil @tsquery.use 1
|
43
|
+
assert_nil @tsquery.login password: 'password'
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def test_inspect
|
48
|
+
assert_equal @tsquery.inspect, @tsquery.__getobj__.inspect
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def teardown
|
53
|
+
@telnet.verify
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require_relative './test_helper'
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
|
5
|
+
class RetryingTsqueryTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@telnet = telnet = Minitest::Mock.new
|
8
|
+
@telnet_class = Class.new do
|
9
|
+
define_singleton_method :new do |*|
|
10
|
+
telnet
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
@tsquery = RetryingTsquery.new(Tsquery.new(logger: Logger.new(nil)))
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def test_delegate_methods
|
19
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
20
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'use 1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
21
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'login serveradmin password', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
22
|
+
|
23
|
+
@tsquery.connect telnet_class: @telnet_class
|
24
|
+
@tsquery.use 1
|
25
|
+
assert @tsquery.login password: 'password'
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def test_connect
|
30
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
31
|
+
|
32
|
+
@tsquery.connect telnet_class: @telnet_class
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def test_connect_retries_if_connection_is_refused
|
37
|
+
telnet = @telnet
|
38
|
+
times = 3
|
39
|
+
|
40
|
+
failing_telnet_class = Class.new do
|
41
|
+
define_singleton_method :new do |*|
|
42
|
+
fail Errno::ECONNREFUSED if (times -= 1) > 0
|
43
|
+
telnet
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
48
|
+
|
49
|
+
@tsquery.connect telnet_class: failing_telnet_class, sleep: ->(_){}
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def test_connect_gives_up_after_3_retries
|
54
|
+
telnet = @telnet
|
55
|
+
times = 4
|
56
|
+
|
57
|
+
failing_telnet_class = Class.new do
|
58
|
+
define_singleton_method :new do |*|
|
59
|
+
fail Errno::ECONNREFUSED if (times -= 1) > 0
|
60
|
+
telnet
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
assert_raises Errno::ECONNREFUSED do
|
65
|
+
@tsquery.connect telnet_class: failing_telnet_class, sleep: ->(_){}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def test_execute
|
71
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
72
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'use 1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
73
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'login serveradmin password', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
74
|
+
|
75
|
+
@tsquery.connect telnet_class: @telnet_class
|
76
|
+
@tsquery.use 1
|
77
|
+
assert @tsquery.login password: 'password'
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def test_execute_retries_if_failing
|
82
|
+
times = 3
|
83
|
+
|
84
|
+
failing_telnet = SimpleDelegator.new(@telnet)
|
85
|
+
failing_telnet.define_singleton_method :cmd do |*args|
|
86
|
+
# cmd will fail the first x times.
|
87
|
+
return nil if (times -= 1) > 0
|
88
|
+
|
89
|
+
__getobj__.cmd *args
|
90
|
+
'error id=0 msg=ok'
|
91
|
+
end
|
92
|
+
|
93
|
+
@telnet_class = Class.new do
|
94
|
+
define_singleton_method :new do |*|
|
95
|
+
failing_telnet
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
100
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'use 1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
101
|
+
|
102
|
+
@tsquery.connect telnet_class: @telnet_class
|
103
|
+
@tsquery.execute 'use 1', sleep: ->(*){}
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def test_execute_gives_up_after_3_retries
|
108
|
+
times = 4
|
109
|
+
|
110
|
+
failing_telnet = SimpleDelegator.new(@telnet)
|
111
|
+
failing_telnet.define_singleton_method :cmd do |*args|
|
112
|
+
# cmd will fail the first x times.
|
113
|
+
return nil if (times -= 1) > 0
|
114
|
+
|
115
|
+
__getobj__.cmd *args
|
116
|
+
'error id=0 msg=ok'
|
117
|
+
end
|
118
|
+
|
119
|
+
@telnet_class = Class.new do
|
120
|
+
define_singleton_method :new do |*|
|
121
|
+
failing_telnet
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
126
|
+
|
127
|
+
@tsquery.connect telnet_class: @telnet_class
|
128
|
+
|
129
|
+
assert_raises Tsquery::Error do
|
130
|
+
@tsquery.execute 'login serveradmin password', sleep: ->(*){}
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def test_dynamic_execute_retries_if_failing
|
136
|
+
times = 3
|
137
|
+
|
138
|
+
failing_telnet = SimpleDelegator.new(@telnet)
|
139
|
+
failing_telnet.define_singleton_method :cmd do |*args|
|
140
|
+
# cmd will fail the first x times.
|
141
|
+
return nil if (times -= 1) > 0
|
142
|
+
|
143
|
+
__getobj__.cmd *args
|
144
|
+
'error id=0 msg=ok'
|
145
|
+
end
|
146
|
+
|
147
|
+
@telnet_class = Class.new do
|
148
|
+
define_singleton_method :new do |*|
|
149
|
+
failing_telnet
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
154
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'use 1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
155
|
+
|
156
|
+
|
157
|
+
@tsquery.connect telnet_class: @telnet_class
|
158
|
+
@tsquery.use 1, sleep: ->(*){}
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
def test_dynamic_execute_gives_up_after_3_retries
|
163
|
+
times = 4
|
164
|
+
|
165
|
+
failing_telnet = SimpleDelegator.new(@telnet)
|
166
|
+
failing_telnet.define_singleton_method :cmd do |*args|
|
167
|
+
# cmd will fail the first x times.
|
168
|
+
return nil if (times -= 1) > 0
|
169
|
+
|
170
|
+
__getobj__.cmd *args
|
171
|
+
'error id=0 msg=ok'
|
172
|
+
end
|
173
|
+
|
174
|
+
@telnet_class = Class.new do
|
175
|
+
define_singleton_method :new do |*|
|
176
|
+
failing_telnet
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
181
|
+
|
182
|
+
@tsquery.connect telnet_class: @telnet_class
|
183
|
+
|
184
|
+
assert_raises Tsquery::Error do
|
185
|
+
@tsquery.use 1, sleep: ->(*){}
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
def test_does_not_retry_unknown_commands
|
191
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
192
|
+
@telnet.expect :cmd, 'error id=256 msg=command\snot\sfound', ['String' => 'unknown', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
193
|
+
|
194
|
+
@tsquery.connect telnet_class: @telnet_class
|
195
|
+
|
196
|
+
ex = assert_raises Tsquery::UnknownCommand do
|
197
|
+
@tsquery.execute 'unknown', sleep: ->(*){}
|
198
|
+
end
|
199
|
+
assert_equal 'command not found', ex.message
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
def test_inspect
|
204
|
+
assert_equal @tsquery.inspect, @tsquery.__getobj__.inspect
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
def teardown
|
209
|
+
@telnet.verify
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require_relative './test_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class TsqueryTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@telnet = telnet = Minitest::Mock.new
|
7
|
+
@telnet_class = Class.new do
|
8
|
+
define_singleton_method :new do |*|
|
9
|
+
telnet
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
14
|
+
|
15
|
+
@tsquery = Tsquery.new(logger: Logger.new(nil))
|
16
|
+
@tsquery.connect telnet_class: @telnet_class
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def test_execute_simple_command
|
21
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'quit', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
22
|
+
|
23
|
+
@tsquery.execute 'quit'
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def test_execute_unknown_command
|
28
|
+
@telnet.expect :cmd, 'error id=256 msg=command\snot\sfound', ['String' => 'unknown', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
29
|
+
|
30
|
+
assert_raises Tsquery::UnknownCommand do
|
31
|
+
@tsquery.execute 'unknown'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def test_execute_simple_command_with_args
|
37
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'login serveradmin password', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
38
|
+
|
39
|
+
@tsquery.execute 'login', 'serveradmin', 'password'
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def test_execute_complex_command_with_args
|
44
|
+
command = 'serveredit virtualserver_name=tsjoin virtualserver_welcomemessage=Welcome\smessage'
|
45
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => command, 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
46
|
+
|
47
|
+
@tsquery.execute 'serveredit',
|
48
|
+
'virtualserver_name' => 'tsjoin',
|
49
|
+
'virtualserver_welcomemessage' => 'Welcome message'
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def test_execute_command_with_symbol_args
|
54
|
+
command = 'serveredit virtualserver_name=tsjoin virtualserver_welcomemessage=Welcome\smessage'
|
55
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => command, 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
56
|
+
|
57
|
+
@tsquery.execute 'serveredit',
|
58
|
+
virtualserver_name: 'tsjoin',
|
59
|
+
virtualserver_welcomemessage: 'Welcome message'
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def test_execute_command_with_numeric_args
|
64
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'serverstop sid=1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
65
|
+
|
66
|
+
@tsquery.execute 'serverstop', sid: 1
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def test_execute_commands_are_logged
|
71
|
+
logger = Minitest::Mock.new
|
72
|
+
logger.expect :info, nil, ['=> serverstop sid=1']
|
73
|
+
logger.expect :info, nil, ['<= error id=0 msg=ok']
|
74
|
+
|
75
|
+
@telnet.expect :waitfor, nil, ['Match' => /^TS3\n/]
|
76
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'serverstop sid=1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
77
|
+
|
78
|
+
@tsquery = Tsquery.new(logger: logger)
|
79
|
+
@tsquery.connect telnet_class: @telnet_class
|
80
|
+
@tsquery.execute 'serverstop', sid: 1
|
81
|
+
logger.verify
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def test_execute_failing_command
|
86
|
+
@telnet.expect :cmd, nil, ['String' => 'serverstop sid=1', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
87
|
+
|
88
|
+
assert_raises Tsquery::Error do
|
89
|
+
@tsquery.serverstop sid: 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def test_execute_command_which_returns_properties
|
95
|
+
@telnet.expect :cmd, <<-RESPONSE.gsub(/^\s*/, ''), ['String' => 'instanceinfo', 'Timeout' => 3, 'Match' => /error id=\d+/]
|
96
|
+
serverinstance_database_version=23 serverinstance_filetransfer_port=30033
|
97
|
+
error id=0 msg=ok
|
98
|
+
RESPONSE
|
99
|
+
|
100
|
+
assert_kind_of Hash, properties = @tsquery.instanceinfo
|
101
|
+
assert_equal 23, properties.fetch('serverinstance_database_version')
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def test_execute_command_which_returns_a_list
|
106
|
+
@telnet.expect :cmd, <<-RESPONSE.gsub(/^\s*/, ''), ['String' => 'clientlist', 'Timeout' => 3, 'Match' => /error id=\d+/]
|
107
|
+
clid=1 cid=1 client_database_id=2 client_nickname=mario client_type=0|clid=5 cid=1 client_database_id=1 client_nickname=serveradmin\\sfrom\\s127.0.0.1:10011 client_type=1
|
108
|
+
error id=0 msg=ok
|
109
|
+
RESPONSE
|
110
|
+
|
111
|
+
assert_kind_of Array, clients = @tsquery.clientlist
|
112
|
+
assert_equal 2, clients.count
|
113
|
+
assert_equal 'mario', clients.first.fetch('client_nickname')
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
def test_login
|
118
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'login serveradmin password', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
119
|
+
|
120
|
+
assert @tsquery.login(password: 'password')
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
def test_failing_login
|
125
|
+
@telnet.expect :cmd, 'error id=520 msg=invalid\sloginname\sor\spassword', ['String' => 'login serveradmin wrong', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
126
|
+
|
127
|
+
refute @tsquery.login(password: 'wrong')
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def test_method_missing
|
132
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => 'logout', 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
133
|
+
|
134
|
+
@tsquery.logout
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def test_method_missing_with_arguments
|
139
|
+
command = 'serveredit virtualserver_name=tsjoin virtualserver_welcomemessage=Welcome\smessage'
|
140
|
+
@telnet.expect :cmd, 'error id=0 msg=ok', ['String' => command, 'Timeout' => 3, 'Match' => /^error id=\d+/]
|
141
|
+
|
142
|
+
@tsquery.serveredit 'virtualserver_name' => 'tsjoin', 'virtualserver_welcomemessage' => 'Welcome message'
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def test_close
|
147
|
+
@telnet.expect :close, nil, []
|
148
|
+
|
149
|
+
@tsquery.close
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def teardown
|
154
|
+
@telnet.verify
|
155
|
+
end
|
156
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tsquery
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mario Uher
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- uher.mario@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- lib/lazy_tsquery.rb
|
63
|
+
- lib/retrying_tsquery.rb
|
64
|
+
- lib/tsquery.rb
|
65
|
+
- test/lazy_tsquery_test.rb
|
66
|
+
- test/retrying_tsquery_test.rb
|
67
|
+
- test/tsquery_test.rb
|
68
|
+
homepage: https://github.com/tsjoin/tsquery
|
69
|
+
licenses:
|
70
|
+
- MIT
|
71
|
+
metadata: {}
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.4.8
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: Automate your TeamSpeak3 server with Ruby!
|
92
|
+
test_files:
|
93
|
+
- test/lazy_tsquery_test.rb
|
94
|
+
- test/retrying_tsquery_test.rb
|
95
|
+
- test/tsquery_test.rb
|
96
|
+
has_rdoc:
|