opensips-mi 0.0.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 +15 -0
- data/.gitignore +28 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +275 -0
- data/Rakefile +20 -0
- data/lib/opensips.rb +4 -0
- data/lib/opensips/mi.rb +23 -0
- data/lib/opensips/mi/command.rb +167 -0
- data/lib/opensips/mi/response.rb +122 -0
- data/lib/opensips/mi/transport.rb +10 -0
- data/lib/opensips/mi/transport/datagram.rb +40 -0
- data/lib/opensips/mi/transport/fifo.rb +90 -0
- data/lib/opensips/mi/transport/xmlrpc.rb +43 -0
- data/lib/opensips/mi/version.rb +5 -0
- data/opensips-mi.gemspec +24 -0
- data/test/fixtures/dlg_list +20 -0
- data/test/fixtures/ul_dump +168 -0
- data/test/helper.rb +53 -0
- data/test/test_command.rb +110 -0
- data/test/test_response.rb +101 -0
- data/test/test_transport.rb +187 -0
- metadata +127 -0
data/test/helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'mocha/setup'
|
3
|
+
require 'stringio'
|
4
|
+
require 'opensips/mi'
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
|
10
|
+
class MiniTest::Unit::TestCase
|
11
|
+
|
12
|
+
def init_class_fifo
|
13
|
+
Dir.stubs(:exists?).once.returns(true)
|
14
|
+
File.stubs(:exists?).once.returns(true)
|
15
|
+
File.stubs(:pipe?).once.returns(true)
|
16
|
+
directory = '/tmp/opensips/fifo'
|
17
|
+
fifo_name = '/tmp/opensips_fifo'
|
18
|
+
replayfifo= 'fifo_reply_file_name'
|
19
|
+
Opensips::MI::Transport::Fifo.new :fifo_name => fifo_name,
|
20
|
+
:reply_dir => directory,
|
21
|
+
:reply_fifo => replayfifo
|
22
|
+
end
|
23
|
+
|
24
|
+
def response_data_cmd_which
|
25
|
+
Array[
|
26
|
+
"200 OK", "get_statistics", "reset_statistics", "uptime", "version",
|
27
|
+
"pwd", "arg", "which", "ps", "kill", "debug", "cache_store",
|
28
|
+
"cache_fetch", "cache_remove", "event_subscribe", "help", "list_blacklists",
|
29
|
+
"t_uac_dlg", "t_uac_cancel", "t_hash", "t_reply", "ul_rm", "ul_rm_contact",
|
30
|
+
"ul_dump", "ul_flush", "ul_add", "ul_show_contact", "ul_sync", ""
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
def response_uldump
|
35
|
+
fix = File.expand_path('fixtures/ul_dump',File.dirname(__FILE__))
|
36
|
+
File.readlines(fix).map{|l| l.chomp}
|
37
|
+
end
|
38
|
+
|
39
|
+
def response_contacts
|
40
|
+
[
|
41
|
+
"200 OK",
|
42
|
+
"Contact:: <sip:7747@10.132.113.198>;q=;expires=100;flags=0x0;cflags=0x0;socket=<udp:10.130.8.21:5060>;methods=0x1F7F;user_agent=<PolycomSoundStationIP-SSIP_6000-UA/3.3.5.0247_0004f2f18103>",
|
43
|
+
"Contact:: <sip:7747@10.130.8.100;line=628f4ffdfa7316e>;q=;expires=3593;flags=0x0;cflags=0x0;socket=<udp:10.130.8.21:5060>;methods=0xFFFFFFFF;user_agent=<Linphone/3.5.2 (eXosip2/3.6.0)>",
|
44
|
+
"",
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
def response_dlg_list
|
49
|
+
fix = File.expand_path('fixtures/dlg_list',File.dirname(__FILE__))
|
50
|
+
File.readlines(fix).map{|l| l.chomp}
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'helper'
|
2
|
+
include Opensips::MI
|
3
|
+
|
4
|
+
describe Command, "commands for transport classes" do
|
5
|
+
before do
|
6
|
+
end
|
7
|
+
|
8
|
+
after do
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "missing methods" do
|
12
|
+
it "must raise if parameter is not Array" do
|
13
|
+
mi = init_class_fifo
|
14
|
+
mi.expects(:command).with('which').returns(mock(:rawdata => ['meth1', 'meth2']))
|
15
|
+
proc {
|
16
|
+
mi.unknown_command
|
17
|
+
}.must_raise NoMethodError
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must raise when missing basic mandatory headers" do
|
21
|
+
mi = init_class_fifo
|
22
|
+
ret = proc {
|
23
|
+
mi.uac_dlg "NOTIFY",
|
24
|
+
"sip:alice@wanderland.com",
|
25
|
+
{"From" => "<sip:opensips@sipproxy.com>"}
|
26
|
+
}.must_raise ArgumentError
|
27
|
+
ret.message.must_match(/header To/)
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must raise when missing body mandatory headers" do
|
32
|
+
mi = init_class_fifo
|
33
|
+
ret = proc {
|
34
|
+
mi.uac_dlg "NOTIFY",
|
35
|
+
"sip:alice@wanderland.com",
|
36
|
+
{"From" => "<sip:opensips>", "To" => "<sip:bob>", "content-type" => "xml"},
|
37
|
+
?., ?., "<body>Hello</body>"
|
38
|
+
}.must_raise ArgumentError
|
39
|
+
ret.message.must_match(/header Content-length/)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "must have good parameters" do
|
43
|
+
mi = init_class_fifo
|
44
|
+
mi.expects(:command).with('t_uac_dlg', [
|
45
|
+
"NOTIFY",
|
46
|
+
"sip:alice@wanderland.com",
|
47
|
+
".",
|
48
|
+
".",
|
49
|
+
%Q/"From: <sip:opensips@sipproxy.com>\r\nTo: <sip:alice@wanderland.com>\r\n"/
|
50
|
+
])
|
51
|
+
mi.uac_dlg "NOTIFY",
|
52
|
+
"sip:alice@wanderland.com",
|
53
|
+
{
|
54
|
+
"From" => "<sip:opensips@sipproxy.com>",
|
55
|
+
"To" => "<sip:alice@wanderland.com>"
|
56
|
+
}
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
it "must raise when invalid event" do
|
61
|
+
mi = init_class_fifo
|
62
|
+
event = :unknown_event
|
63
|
+
res = proc {
|
64
|
+
mi.event_notify "sip:alice@proxy.com", event
|
65
|
+
}.must_raise ArgumentError
|
66
|
+
res.message.must_match(/#{event.to_s}/)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "must send notify event" do
|
70
|
+
mi = init_class_fifo
|
71
|
+
tag = "123456"
|
72
|
+
uri = "sip:alice@wanderland.com"
|
73
|
+
SecureRandom.stubs(:hex).returns(tag)
|
74
|
+
mi.expects(:uac_dlg).with("NOTIFY",
|
75
|
+
uri,
|
76
|
+
{
|
77
|
+
"To" => "<#{uri}>",
|
78
|
+
"From" => "<#{uri}>;tag=#{tag}",
|
79
|
+
"Event" => "check-sync"
|
80
|
+
}
|
81
|
+
)
|
82
|
+
mi.event_notify uri, :polycom_check_cfg
|
83
|
+
end
|
84
|
+
|
85
|
+
it "must send MWI notify" do
|
86
|
+
mi = init_class_fifo
|
87
|
+
tag = "123456"
|
88
|
+
uri = "sip:alice@wanderland.com"
|
89
|
+
new_vm = 5
|
90
|
+
old_vm = 3
|
91
|
+
SecureRandom.stubs(:hex).returns(tag)
|
92
|
+
mi.expects(:uac_dlg).with("NOTIFY",
|
93
|
+
uri,
|
94
|
+
{
|
95
|
+
'To' => "<#{uri}>",
|
96
|
+
'From' => "<#{uri}>;tag=#{tag}",
|
97
|
+
'Event' => 'message-summary',
|
98
|
+
'Subscription-State' => 'active',
|
99
|
+
'Content-Type' => 'application/simple-message-summary',
|
100
|
+
'Content-Length' => 86,
|
101
|
+
'nl' => '',
|
102
|
+
'Messages-Waiting' => 'yes',
|
103
|
+
'Message-Account' => 'sip:*97@asterisk.com',
|
104
|
+
'Voice-Message' => "#{new_vm}/#{old_vm} (0/0)"
|
105
|
+
})
|
106
|
+
mi.mwi_update uri, 'sip:*97@asterisk.com', new_vm, old_vm
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'helper'
|
2
|
+
include Opensips::MI
|
3
|
+
|
4
|
+
describe Response, "response class" do
|
5
|
+
before do
|
6
|
+
@which = response_data_cmd_which
|
7
|
+
@data_ok = ["200 it is OK", "data", ""]
|
8
|
+
@data_nok = ["500 command 'unknown' not available"]
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "processing response" do
|
15
|
+
it "must raise if parameter is not Array" do
|
16
|
+
proc {
|
17
|
+
Response.new "String"
|
18
|
+
}.must_raise InvalidResponseData
|
19
|
+
end
|
20
|
+
|
21
|
+
it "must raise if response data id empty array" do
|
22
|
+
proc {
|
23
|
+
Response.new Array[]
|
24
|
+
}.must_raise EmptyResponseData
|
25
|
+
end
|
26
|
+
|
27
|
+
it "must return Response class" do
|
28
|
+
r = Response.new(@data_ok)
|
29
|
+
r.must_be_instance_of Response
|
30
|
+
end
|
31
|
+
|
32
|
+
it "must raise if invalid response data" do
|
33
|
+
proc {
|
34
|
+
Response.new(["invalid param","343",222])
|
35
|
+
}.must_raise InvalidResponseData
|
36
|
+
end
|
37
|
+
|
38
|
+
it "must parse successfull response" do
|
39
|
+
r = Response.new(@data_ok)
|
40
|
+
r.success.must_equal true
|
41
|
+
r.code.must_equal 200
|
42
|
+
r.message.must_equal "it is OK"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must parse unsuccessfull response" do
|
46
|
+
r = Response.new(@data_nok)
|
47
|
+
r.success.must_equal false
|
48
|
+
r.code.must_equal 500
|
49
|
+
r.message.must_equal "command 'unknown' not available"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "parse ul dump response" do
|
53
|
+
res = Response.new(response_uldump)
|
54
|
+
ul = res.ul_dump
|
55
|
+
ul.result["7962"].wont_equal nil
|
56
|
+
ul.result["7962"]['Callid'].must_equal "5e7a1e47da91c41c"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "process uptime response" do
|
60
|
+
res = Response.new [
|
61
|
+
"200 OK",
|
62
|
+
"Now:: Fri Apr 12 22:04:27 2013",
|
63
|
+
"Up since:: Thu Apr 11 21:43:01 2013",
|
64
|
+
"Up time:: 87686 [sec]",
|
65
|
+
""
|
66
|
+
]
|
67
|
+
response = res.uptime
|
68
|
+
response.result.uptime.must_equal 87686
|
69
|
+
response.result.since.thursday?.must_equal true
|
70
|
+
response.result.since.hour.must_equal 21
|
71
|
+
response.result.since.mon.must_equal 4
|
72
|
+
end
|
73
|
+
|
74
|
+
it "must fetch cache value" do
|
75
|
+
res = Response.new [
|
76
|
+
"200 OK",
|
77
|
+
"userdid = [18005552211]",
|
78
|
+
""
|
79
|
+
]
|
80
|
+
response = res.cache_fetch
|
81
|
+
response.result.userdid.must_equal "18005552211"
|
82
|
+
end
|
83
|
+
|
84
|
+
it "must return userloc contacts" do
|
85
|
+
response = Response.new response_contacts
|
86
|
+
res = response.ul_show_contact.result
|
87
|
+
res.must_be_instance_of Array
|
88
|
+
res.size.must_equal 2
|
89
|
+
res.first[:socket].must_equal "<udp:10.130.8.21:5060>"
|
90
|
+
res.last[:expires].must_equal "3593"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "must process dialogs list" do
|
94
|
+
response = Response.new response_dlg_list
|
95
|
+
res = response.dlg_list.result
|
96
|
+
res.size.must_equal 1
|
97
|
+
res["3212:2099935485"][:callid].must_equal "1854719653"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
describe Opensips::MI::Transport, "testing MI transport layers" do
|
4
|
+
before do
|
5
|
+
@fifo_params = {:fifo_name => '/tmp/opensips_fifo'}
|
6
|
+
end
|
7
|
+
|
8
|
+
after do
|
9
|
+
end
|
10
|
+
|
11
|
+
# Fifo
|
12
|
+
describe "test fifo transport layer" do
|
13
|
+
it "must retrun fifo class instance" do
|
14
|
+
File.stubs(:exists?).once.returns(true)
|
15
|
+
File.stubs(:pipe?).twice.returns(true)
|
16
|
+
Kernel.stubs(:system).returns(true)
|
17
|
+
Opensips::MI.connect(:fifo,@fifo_params).must_be_instance_of Opensips::MI::Transport::Fifo
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must raise when using unknown transport method" do
|
21
|
+
proc {
|
22
|
+
Opensips::MI.connect(:unknown_transport_method,{})
|
23
|
+
}.must_raise NameError
|
24
|
+
end
|
25
|
+
|
26
|
+
it "must raise when no fifo_nameInstanceOf.new parameter passed" do
|
27
|
+
proc {
|
28
|
+
Opensips::MI.connect :fifo, {}
|
29
|
+
}.must_raise ArgumentError
|
30
|
+
end
|
31
|
+
|
32
|
+
it "must raise when fifo_name file not exists" do
|
33
|
+
File.stubs(:exists?).once.returns(false)
|
34
|
+
proc {
|
35
|
+
Opensips::MI.connect :fifo, :fifo_name => '/file/not/exists'
|
36
|
+
}.must_raise ArgumentError
|
37
|
+
end
|
38
|
+
|
39
|
+
it "must raise when fifo_name file is not pipe" do
|
40
|
+
File.stubs(:exists?).once.returns(true)
|
41
|
+
File.stubs(:pipe?).once.returns(false)
|
42
|
+
proc {
|
43
|
+
Opensips::MI.connect :fifo, :fifo_name => '/tmp/opensips_fifo'
|
44
|
+
}.must_raise ArgumentError
|
45
|
+
end
|
46
|
+
|
47
|
+
it "must raise if fifo reply directory not exists" do
|
48
|
+
Dir.stubs(:exists?).once.returns false
|
49
|
+
proc {
|
50
|
+
Opensips::MI.connect :fifo, :fifo_name => '/tmp/opensips_fifo',
|
51
|
+
:reply_dir => '/tmp'
|
52
|
+
}.must_raise ArgumentError
|
53
|
+
end
|
54
|
+
|
55
|
+
it "must set attributes for class instance" do
|
56
|
+
Dir.stubs(:exists?).once.returns(true)
|
57
|
+
File.stubs(:exists?).once.returns(true)
|
58
|
+
File.stubs(:pipe?).once.returns(true)
|
59
|
+
directory = '/tmp/opensips/fifo'
|
60
|
+
fifo_name = '/tmp/opensips_fifo'
|
61
|
+
replayfifo= 'fifo_reply_file_name'
|
62
|
+
fifo = Opensips::MI::Transport::Fifo.new :fifo_name => fifo_name,
|
63
|
+
:reply_dir => directory,
|
64
|
+
:reply_fifo => replayfifo
|
65
|
+
fifo.reply_dir.must_equal directory
|
66
|
+
fifo.fifo_name.must_equal fifo_name
|
67
|
+
fifo.reply_dir.must_equal directory
|
68
|
+
end
|
69
|
+
|
70
|
+
it "must create temporary fifo reply file" do
|
71
|
+
fifo = init_class_fifo
|
72
|
+
Kernel.stubs(:system).returns(true)
|
73
|
+
File.stubs(:pipe?).returns(true)
|
74
|
+
fifo.open
|
75
|
+
end
|
76
|
+
|
77
|
+
it "must raise if can not create reply fifo" do
|
78
|
+
fifo = init_class_fifo
|
79
|
+
Kernel.stubs(:system).returns(true)
|
80
|
+
File.stubs(:pipe?).returns(false)
|
81
|
+
proc { fifo.open }.must_raise SystemCallError
|
82
|
+
end
|
83
|
+
|
84
|
+
it "must send command to fifo" do
|
85
|
+
File.stubs(:exists?).returns(true)
|
86
|
+
File.stubs(:pipe?).returns(true)
|
87
|
+
IO.stubs(:sysopen).returns(5)
|
88
|
+
io_obj = mock()
|
89
|
+
io_obj.expects(:close).twice()
|
90
|
+
io_obj.expects(:syswrite)
|
91
|
+
io_obj.expects(:gets).returns(nil)
|
92
|
+
IO.stubs(:open).twice().returns(io_obj)
|
93
|
+
Opensips::MI::Response.expects(:new).returns(true)
|
94
|
+
|
95
|
+
fifo = Opensips::MI.connect(:fifo,@fifo_params)
|
96
|
+
fifo.command('which')
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
# Datagram
|
101
|
+
describe "test datagram transport layer" do
|
102
|
+
it "must raise if empty host" do
|
103
|
+
proc {
|
104
|
+
Opensips::MI.connect :datagram, {}
|
105
|
+
}.must_raise ArgumentError
|
106
|
+
end
|
107
|
+
|
108
|
+
it "must raise if empty port" do
|
109
|
+
proc {
|
110
|
+
Opensips::MI.connect :datagram, {:host => "10.10.10.10"}
|
111
|
+
}.must_raise ArgumentError
|
112
|
+
end
|
113
|
+
|
114
|
+
it "must raise if invalid host" do
|
115
|
+
host = "256.0.0.300"
|
116
|
+
res = proc {
|
117
|
+
Opensips::MI.connect :datagram, {:host => host, :port => 8088}
|
118
|
+
}.must_raise SocketError
|
119
|
+
res.message.must_match(/#{host}/)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "must raise if invalid port" do
|
123
|
+
proc {
|
124
|
+
Opensips::MI.connect :datagram, {:host => "10.0.0.1", :port => (2**16 + 1)}
|
125
|
+
}.must_raise SocketError
|
126
|
+
|
127
|
+
proc {
|
128
|
+
Opensips::MI.connect :datagram, {:host => "10.0.0.1", :port => 0}
|
129
|
+
}.must_raise SocketError
|
130
|
+
end
|
131
|
+
|
132
|
+
it "must connect to socket" do
|
133
|
+
UDPSocket.expects(:new).returns(mock(:connect => true))
|
134
|
+
res = Opensips::MI.connect :datagram,
|
135
|
+
:host => "192.168.122.128",
|
136
|
+
:port => 8809
|
137
|
+
res.respond_to?(:uac_dlg).must_equal true
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
# XMLRPC
|
143
|
+
describe "test xmlrpc transport layer" do
|
144
|
+
it "must raise if empty host" do
|
145
|
+
proc {
|
146
|
+
Opensips::MI.connect :xmlrpc, {}
|
147
|
+
}.must_raise ArgumentError
|
148
|
+
end
|
149
|
+
|
150
|
+
it "must raise if empty port" do
|
151
|
+
proc {
|
152
|
+
Opensips::MI.connect :xmlrpc, {:host => "10.10.10.10"}
|
153
|
+
}.must_raise ArgumentError
|
154
|
+
end
|
155
|
+
|
156
|
+
it "must raise if invalid host" do
|
157
|
+
host = "256.0.0.300"
|
158
|
+
res = proc {
|
159
|
+
Opensips::MI.connect :xmlrpc, {:host => host, :port => 8088}
|
160
|
+
}.must_raise SocketError
|
161
|
+
res.message.must_match(/#{host}/)
|
162
|
+
end
|
163
|
+
|
164
|
+
it "must raise if invalid port" do
|
165
|
+
proc {
|
166
|
+
Opensips::MI.connect :xmlrpc, {:host => "10.0.0.1", :port => (2**16 + 1)}
|
167
|
+
}.must_raise SocketError
|
168
|
+
|
169
|
+
proc {
|
170
|
+
Opensips::MI.connect :xmlrpc, {:host => "10.0.0.1", :port => 0}
|
171
|
+
}.must_raise SocketError
|
172
|
+
end
|
173
|
+
|
174
|
+
it "must connect to xmlrpc server" do
|
175
|
+
host = "192.168.122.128"
|
176
|
+
port = 8080
|
177
|
+
XMLRPC::Client.stubs(:new_from_uri).
|
178
|
+
with("http://#{host}:#{port}/#{Opensips::MI::Transport::Xmlrpc::RPCSEG}",nil,3)
|
179
|
+
res = Opensips::MI.connect :xmlrpc,
|
180
|
+
:host => host,
|
181
|
+
:port => port
|
182
|
+
res.respond_to?(:uac_dlg).must_equal true
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|