p2ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +27 -0
- data/HISTORY +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +24 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/bin/olegen.rb +368 -0
- data/features/p2ruby.feature +9 -0
- data/features/step_definitions/p2ruby_steps.rb +0 -0
- data/features/support/env.rb +10 -0
- data/features/support/world.rb +12 -0
- data/lib/extension.rb +19 -0
- data/lib/ole20110223-013209.rb +1677 -0
- data/lib/p2ruby/application.rb +111 -0
- data/lib/p2ruby/base.rb +59 -0
- data/lib/p2ruby/connection.rb +250 -0
- data/lib/p2ruby/data_stream.rb +215 -0
- data/lib/p2ruby/library.rb +24 -0
- data/lib/p2ruby/message.rb +150 -0
- data/lib/p2ruby/message_factory.rb +70 -0
- data/lib/p2ruby/record.rb +104 -0
- data/lib/p2ruby/router.rb +45 -0
- data/lib/p2ruby/table_set.rb +166 -0
- data/lib/p2ruby.rb +156 -0
- data/lib/version.rb +8 -0
- data/lib/win32ole-pr.rb +5540 -0
- data/spec/encoding_spec.rb +15 -0
- data/spec/p2ruby/application_spec.rb +35 -0
- data/spec/p2ruby/connection_spec.rb +293 -0
- data/spec/p2ruby/data_stream_spec.rb +218 -0
- data/spec/p2ruby/library_spec.rb +42 -0
- data/spec/p2ruby/message_factory_spec.rb +69 -0
- data/spec/p2ruby/message_spec.rb +159 -0
- data/spec/p2ruby/record_spec.rb +85 -0
- data/spec/p2ruby/router_spec.rb +54 -0
- data/spec/p2ruby/table_set_spec.rb +132 -0
- data/spec/p2ruby_spec.rb +46 -0
- data/spec/spec_helper.rb +78 -0
- data/tasks/common.rake +18 -0
- data/tasks/doc.rake +14 -0
- data/tasks/gem.rake +40 -0
- data/tasks/git.rake +34 -0
- data/tasks/spec.rake +16 -0
- data/tasks/version.rake +71 -0
- metadata +149 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
# encoding: CP1251
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
def get_message opts ={}
|
5
|
+
@factory.message :name => opts[:name] ||"FutAddOrder",
|
6
|
+
:dest_addr => opts[:dest_addr] || "FINTER_FORTS3.Dispatcher",
|
7
|
+
:field => opts[:field] || {
|
8
|
+
"P2_Category" => opts[:P2_Category] || "FORTS_MSG",
|
9
|
+
:P2_Type => opts[:P2_Type] || 1,
|
10
|
+
"isin" => opts[:isin] || "RTS-3.11",
|
11
|
+
:price => opts[:price] || "186500",
|
12
|
+
:amount => opts[:amount] || 1,
|
13
|
+
"client_code" => opts[:client_code] || "001",
|
14
|
+
"type" => opts[:type] || 1,
|
15
|
+
"dir" => opts[:dir] || 1
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
describe P2::Message do
|
20
|
+
before(:all) do
|
21
|
+
P2::Application.reset CLIENT_INI
|
22
|
+
@factory = P2::MessageFactory.new :ini => MESSAGE_INI
|
23
|
+
end
|
24
|
+
subject { get_message }
|
25
|
+
|
26
|
+
it 'is not instantiated directly, use MessageFactory instead'
|
27
|
+
|
28
|
+
it 'wraps P2ClientGate.P2BLMessage OLE class' do
|
29
|
+
subject.ole_type.name.should == 'IP2BLMessage'
|
30
|
+
show_ole
|
31
|
+
end
|
32
|
+
|
33
|
+
its(:clsid) { should == '{A9A6C936-5A12-4518-9A92-90D75B41AF18}' }
|
34
|
+
its(:progid) { should == 'P2ClientGate.P2BLMessage.1' }
|
35
|
+
its(:opts) { should have_key :name }
|
36
|
+
its(:ole) { should be_a WIN32OLE }
|
37
|
+
its(:Name) { should == "" } # Why? Because there is no Message#Name= setter... :(
|
38
|
+
its(:DestAddr) { should == "FINTER_FORTS3.Dispatcher" }
|
39
|
+
|
40
|
+
context 'working with named property Field' do
|
41
|
+
it 'initializes Field named properties correctly' do
|
42
|
+
subject.Field["P2_Category"].should == "FORTS_MSG"
|
43
|
+
subject.Field["P2_Type"].should == 1
|
44
|
+
subject.Field['isin'].should == "RTS-3.11"
|
45
|
+
subject.Field['price'].should == "186500"
|
46
|
+
subject.Field['amount'].should == 1
|
47
|
+
subject.Field['client_code'].should == "001"
|
48
|
+
subject.Field['type'].should == 1
|
49
|
+
subject.Field['dir'].should == 1
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'manually sets Field named properties as needed' do
|
53
|
+
subject.Field["P2_Category"] = "WHATEVER"
|
54
|
+
subject.Field['isin'] = "RTS-3.12"
|
55
|
+
subject.Field['amount'] = 100
|
56
|
+
subject.Field["P2_Category"].should == "WHATEVER"
|
57
|
+
subject.Field['isin'].should == "RTS-3.12"
|
58
|
+
subject.Field['amount'].should == 100
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'does not test following Fields:' do
|
62
|
+
# [table:message:FutAddOrder]
|
63
|
+
# field = broker_code,c4,,""
|
64
|
+
# field = isin,c25
|
65
|
+
# field = client_code,c3
|
66
|
+
# field = type,i4
|
67
|
+
# field = dir,i4
|
68
|
+
# field = amount,i4
|
69
|
+
# field = price,c17
|
70
|
+
# field = comment,c20,,""
|
71
|
+
# field = broker_to,c20,,""
|
72
|
+
# field = ext_id,i4,,0
|
73
|
+
# field = du,i4,,0
|
74
|
+
# field = date_exp,c8,,""
|
75
|
+
# field = hedge,i4,,0
|
76
|
+
|
77
|
+
p subject.Id()
|
78
|
+
p subject.Version()
|
79
|
+
print "P2_Type "; p subject.Field["P2_Type"] #��������� ����.
|
80
|
+
print "isin "; p subject.Field["isin"]
|
81
|
+
print "price "; p subject.Field["price"]
|
82
|
+
print "client_code "; p subject.Field["client_code"]
|
83
|
+
|
84
|
+
subject.Field["hedge"] = -1
|
85
|
+
print "hedge "; p subject.Field["hedge"]
|
86
|
+
|
87
|
+
print "P2_Type asLL "; p subject.FieldAsLONGLONG["P2_Type"]
|
88
|
+
print "hedge asLL "; p subject.FieldAsLONGLONG["hedge"]
|
89
|
+
|
90
|
+
p subject.Field["dir"]
|
91
|
+
p subject.Field["amount"]
|
92
|
+
p subject.Field["type"]
|
93
|
+
end
|
94
|
+
end # 'working with named property Field'
|
95
|
+
|
96
|
+
context 'with active connection' do
|
97
|
+
before(:all) do
|
98
|
+
start_router
|
99
|
+
P2::Application.reset CLIENT_INI
|
100
|
+
@conn = P2::Connection.new :app_name => 'DSTest',
|
101
|
+
:host => "127.0.0.1", :port => 4001
|
102
|
+
@conn.Connect
|
103
|
+
@conn.should be_connected
|
104
|
+
@conn.should be_logged
|
105
|
+
# Disconnected connection, for comparison
|
106
|
+
@disconn = P2::Connection.new :app_name => 'DSTestDisconnected',
|
107
|
+
:host => "127.0.0.1", :port => 4001
|
108
|
+
end
|
109
|
+
|
110
|
+
after(:all) { stop_router }
|
111
|
+
|
112
|
+
describe '#Send()' do
|
113
|
+
it 'syncronously sends via active connection with timeout' do
|
114
|
+
subject.Send(@conn, 1000)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'syncronously sends via raw connection ole' do
|
118
|
+
subject.Send(@conn.ole, 1000)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'fails to send via inactive connection' do
|
122
|
+
expect { subject.Send(@disconn, 1000) }.to raise_error /Coudln.t send MQ message/
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'returns wrapped server reply message ' do
|
126
|
+
reply = subject.Send(@conn, 1000)
|
127
|
+
reply.should be_a P2::Message
|
128
|
+
reply.Field["P2_Category"].should == "FORTS_MSG"
|
129
|
+
end
|
130
|
+
end #Send()
|
131
|
+
|
132
|
+
describe '#parse_reply' do
|
133
|
+
before(:all) do
|
134
|
+
@correct_order = get_message
|
135
|
+
@wrong_order = get_message :price => '1' # Price outside of limits
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'analyses message as a server reply, returns result text' do
|
139
|
+
reply = @correct_order.Send(@conn, 1000)
|
140
|
+
reply.parse_reply.should =~ /Reply category: FORTS_MSG, type 101. Adding order Ok, Order_id:/
|
141
|
+
|
142
|
+
reply = @wrong_order.Send(@conn, 1000)
|
143
|
+
reply.parse_reply.should =~ /Reply category: FORTS_MSG, type 101. Adding order fail, logic error:/
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'correctly outputs Windows Cyrillics' do
|
147
|
+
pending 'freaking RSpec just does NOT output Cyrillics correctly, no matter what'
|
148
|
+
Encoding.default_internal, Encoding.default_external = ['cp1251'] * 2
|
149
|
+
lit = "������ �������������� ����� �������� ���� ������ ������ ������� �����"
|
150
|
+
reply = @wrong_order.Send(@conn, 1000)
|
151
|
+
puts "Source encoding: #{__ENCODING__}"
|
152
|
+
puts "Def ext/int encoding: #{Encoding.default_external}/#{Encoding.default_internal}"
|
153
|
+
puts "String literal: #{lit} - encoding: #{lit.encoding}"
|
154
|
+
puts "Reply: #{reply.parse_reply} - encoding: #{reply.parse_reply.encoding}"
|
155
|
+
lit.should =~ /miserable_failure/
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
# Impossible to instantiate Record directly (no PROGID), need to receive
|
5
|
+
# it from RTS as part of DataStream event
|
6
|
+
def get_record
|
7
|
+
@record = nil
|
8
|
+
P2::Application.reset CLIENT_INI
|
9
|
+
@conn = P2::Connection.new :app_name => 'RecordTest',
|
10
|
+
:host => "127.0.0.1", :port => 4001
|
11
|
+
@conn.Connect
|
12
|
+
|
13
|
+
@ds = P2::DataStream.new :stream_name => 'RTS_INDEX_REPL',
|
14
|
+
:type => P2::RT_COMBINED_DYNAMIC
|
15
|
+
|
16
|
+
@ds.events.on_event('StreamDataInserted') do |event_name, table, ole|
|
17
|
+
p "EVENT: #{event_name}, #{table}, #{ole}"
|
18
|
+
@record = ole
|
19
|
+
end
|
20
|
+
|
21
|
+
@ds.Open(@conn)
|
22
|
+
@conn.ProcessMessage2(1000) until @record
|
23
|
+
@record
|
24
|
+
end
|
25
|
+
|
26
|
+
describe P2::Record do
|
27
|
+
before(:all) do
|
28
|
+
start_router
|
29
|
+
get_record
|
30
|
+
end
|
31
|
+
|
32
|
+
after(:all) do
|
33
|
+
@ds.Close()
|
34
|
+
@conn.Disconnect()
|
35
|
+
stop_router
|
36
|
+
end
|
37
|
+
|
38
|
+
subject { P2::Record.new :ole => @record }
|
39
|
+
|
40
|
+
describe '.new' do
|
41
|
+
it 'wraps OLE class with IP2Record interface' do
|
42
|
+
subject.ole_type.name.should == 'IP2Record'
|
43
|
+
show_ole
|
44
|
+
end
|
45
|
+
|
46
|
+
its(:clsid) { should == '{76033FC9-8BB0-4415-A785-9BF86AAF4E99}' }
|
47
|
+
its(:progid) { should == nil } # Impossible to instantiate directly!
|
48
|
+
its(:opts) { should be_a Hash }
|
49
|
+
its(:ole) { should be_a WIN32OLE }
|
50
|
+
its(:Count) { should == 13 }
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#to_s' do
|
54
|
+
it 'reveals fields content' do
|
55
|
+
p subject.to_s
|
56
|
+
p subject.to_s.encoding
|
57
|
+
subject.to_s.should =~ /\d+|\d|\d|.+RTS/
|
58
|
+
subject.to_s.scan(/\|/).size.should == 12
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#[]' do
|
63
|
+
it 'provides access to field content by field name' do
|
64
|
+
subject['name'].should =~ /RTS/
|
65
|
+
subject['moment'].should =~ Regexp.new(Time.now.strftime("%Y/%m/"))
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'provides access to field content by field index' do
|
69
|
+
subject[3].should =~ /RTS/
|
70
|
+
subject[4].should =~ Regexp.new(Time.now.strftime("%Y/%m/"))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#each' do
|
75
|
+
it 'enumerates all fields' do
|
76
|
+
subject.each.size.should == 13
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'serves as a basis for mixed in Enumerable methods' do
|
80
|
+
subject.select { |f| f =~ /RTS/ }.should_not == nil
|
81
|
+
subject.any? { |f| f =~ /RTS/ }.should == true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe P2::Router, "Driver for Router server app" do
|
5
|
+
before(:all) { stop_router }
|
6
|
+
after(:all) { stop_router }
|
7
|
+
|
8
|
+
it "raises error on invalid Router path" do
|
9
|
+
expect { described_class.new :path => "blah", :ini => ROUTER_INI }.
|
10
|
+
to raise_error /Unable to launch "blah"/
|
11
|
+
end
|
12
|
+
|
13
|
+
it "raises error on invalid ini file" do
|
14
|
+
expect { described_class.new :path => ROUTER_PATH, :ini => 'blah' }.
|
15
|
+
to raise_error P2::Error, /Wrong ini file name/
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'is impossible to find unlaunched Router' do
|
19
|
+
@app = P2::Router.find
|
20
|
+
@app.should be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
context "router initialized with :path => #{ROUTER_PATH}, :ini => #{ROUTER_INI}" do
|
24
|
+
before(:all) { @router = P2::Router.new :dir => TEST_DIR, # To avoid file litter in BASE_DIR
|
25
|
+
:path => ROUTER_PATH, :ini => ROUTER_INI }
|
26
|
+
subject { @router }
|
27
|
+
|
28
|
+
it 'has P2 Router application/window launched' do
|
29
|
+
app = WinGui::App.find(:title => ROUTER_TITLE)
|
30
|
+
app.should be_an WinGui::App
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'is possible to find already launched Router' do
|
34
|
+
router = P2::Router.find
|
35
|
+
router.should be_a P2::Router
|
36
|
+
end
|
37
|
+
|
38
|
+
its(:opts) { should have_key :path }
|
39
|
+
its(:app) { should be_a WinGui::App }
|
40
|
+
its(:main_window) { should be_a WinGui::Window }
|
41
|
+
its(:title) { should =~ ROUTER_TITLE }
|
42
|
+
|
43
|
+
context 'forcing Router app to quit' do
|
44
|
+
it 'exits gracefully when asked to' do
|
45
|
+
@router.exit
|
46
|
+
sleep 0.6 # needed to ensure Router window had enough time to close down
|
47
|
+
@router.main_window.visible?.should == false
|
48
|
+
@router.main_window.window?.should == false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
# TableSet received from RTS as part of DataStream opening event?
|
5
|
+
def get_table_set
|
6
|
+
P2::Application.reset CLIENT_INI
|
7
|
+
@conn = P2::Connection.new :app_name => 'RecordTest',
|
8
|
+
:host => "127.0.0.1", :port => 4001
|
9
|
+
@conn.Connect
|
10
|
+
|
11
|
+
@ds = P2::DataStream.new :stream_name => 'RTS_INDEX_REPL',
|
12
|
+
:type => P2::RT_COMBINED_DYNAMIC
|
13
|
+
|
14
|
+
@ds.Open(@conn)
|
15
|
+
|
16
|
+
@ds.events.on_event { |*args| p args }
|
17
|
+
2.times { @conn.ProcessMessage2(1000) } # Push @ds to receive its TableSet
|
18
|
+
end
|
19
|
+
|
20
|
+
describe P2::TableSet do
|
21
|
+
before(:all) do
|
22
|
+
start_router
|
23
|
+
get_table_set
|
24
|
+
end
|
25
|
+
|
26
|
+
after(:all) do
|
27
|
+
@ds.Close() if @ds.open?
|
28
|
+
@conn.Disconnect() if @conn.connected?
|
29
|
+
stop_router
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '.new' do
|
33
|
+
context 'with directly instantiated TableSet' do
|
34
|
+
subject { P2::TableSet.new :ini => TABLESET_INI, :life_num => 1313, :rev => {'rts_index'=>13} }
|
35
|
+
|
36
|
+
it 'wraps OLE class with IP2TableSet interface' do
|
37
|
+
subject.ole_type.name.should == 'IP2TableSet'
|
38
|
+
show_ole
|
39
|
+
end
|
40
|
+
|
41
|
+
its(:clsid) { should == '{C52E4892-894B-4C03-841F-97E893F7BCAE}' }
|
42
|
+
its(:progid) { should == 'P2ClientGate.P2TableSet.1' }
|
43
|
+
its(:opts) { should be_a Hash }
|
44
|
+
its(:ole) { should be_a WIN32OLE }
|
45
|
+
its(:Count) { should == 1 } # One table!
|
46
|
+
its(:LifeNum) { should == 1313 }
|
47
|
+
|
48
|
+
it 'should be possible to access named properties' do
|
49
|
+
subject.FieldList['rts_index'].should == "replID,replRev,replAct,name,moment,value,prev_close_value,open_value,max_value,min_value,usd_rate,cap,volume"
|
50
|
+
subject.FieldTypes['rts_index'].should == "replID=i8,replRev=i8,replAct=i8,name=c25,moment=t,value=d18.4,prev_close_value=d18.4,open_value=d18.4,max_value=d18.4,min_value=d18.4,usd_rate=d10.4,cap=d18.4,volume=d18.4"
|
51
|
+
subject.Rev['rts_index'].should == 13
|
52
|
+
subject.rev['rts_index'].should == 13
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should be possible to reset settable properties' do
|
56
|
+
subject.LifeNum = 1
|
57
|
+
subject.Rev['rts_index'] = 1
|
58
|
+
|
59
|
+
subject.LifeNum.should == 1
|
60
|
+
subject.Rev['rts_index'].should == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with TableSet received from RTS' do
|
66
|
+
subject { P2::TableSet.new :ole => @ds.ole.TableSet }
|
67
|
+
describe '#each' do
|
68
|
+
|
69
|
+
it 'is' do
|
70
|
+
p subject
|
71
|
+
p subject.Count()
|
72
|
+
p (subject.each.methods-Object.methods).sort
|
73
|
+
p subject.each { |item| p item }
|
74
|
+
p enum = subject.ole_methods.find { |m| m.name=~ /Enum/ }
|
75
|
+
(enum.methods-Object.methods).each do |m|
|
76
|
+
puts "#{m}: #{(enum.send(m)).inspect}"
|
77
|
+
end
|
78
|
+
puts 'Returned by .NewEnum(), ._NewEnum() and .invoke "_NewEnum" :'
|
79
|
+
p subject.NewEnum()
|
80
|
+
p subject._NewEnum()
|
81
|
+
p subject.invoke "_NewEnum"
|
82
|
+
p "WIN32OLE::ARGV"
|
83
|
+
p WIN32OLE::ARGV
|
84
|
+
p subject.each.to_a.size
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#InitFromIni'
|
93
|
+
describe '#InitFromIni2'
|
94
|
+
|
95
|
+
describe '#InitFromDB'
|
96
|
+
describe '#SetLifeNumToIni'
|
97
|
+
describe '#AddTable'
|
98
|
+
describe '#DeleteTable'
|
99
|
+
|
100
|
+
# describe '#to_s' do
|
101
|
+
# it 'reveals fields content' do
|
102
|
+
# p subject.to_s
|
103
|
+
# p subject.to_s.encoding
|
104
|
+
# subject.to_s.should =~ /\d+|\d|\d|.+RTS/
|
105
|
+
# subject.to_s.scan(/\|/).size.should == 12
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# describe '#[]' do
|
110
|
+
# it 'provides access to field content by field name' do
|
111
|
+
# subject['name'].should =~ /RTS/
|
112
|
+
# subject['moment'].should =~ Regexp.new(Time.now.strftime("%Y/%m/"))
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# it 'provides access to field content by field index' do
|
116
|
+
# subject[3].should =~ /RTS/
|
117
|
+
# subject[4].should =~ Regexp.new(Time.now.strftime("%Y/%m/"))
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# describe '#each' do
|
122
|
+
# it 'enumerates all fields' do
|
123
|
+
# subject.each.size.should == 13
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# it 'serves as a basis for mixed in Enumerable methods' do
|
127
|
+
# subject.select { |f| f =~ /RTS/ }.should_not == nil
|
128
|
+
# subject.any? { |f| f =~ /RTS/ }.should == true
|
129
|
+
# end
|
130
|
+
# end
|
131
|
+
end
|
132
|
+
|
data/spec/p2ruby_spec.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe P2 do
|
4
|
+
include P2
|
5
|
+
|
6
|
+
it 'has P2ClientGate constants pre-defined' do
|
7
|
+
CS_CONNECTION_DISCONNECTED.should == 1
|
8
|
+
CS_CONNECTION_CONNECTED.should == 2
|
9
|
+
CS_CONNECTION_INVALID.should == 4
|
10
|
+
CS_CONNECTION_BUSY.should == 8
|
11
|
+
CS_ROUTER_DISCONNECTED.should == 65536
|
12
|
+
CS_ROUTER_RECONNECTING.should == 131072
|
13
|
+
CS_ROUTER_CONNECTED.should == 262144
|
14
|
+
CS_ROUTER_LOGINFAILED.should == 524288
|
15
|
+
CS_ROUTER_NOCONNECT.should == 1048576
|
16
|
+
|
17
|
+
# module TRequestType
|
18
|
+
RT_LOCAL.should == 0
|
19
|
+
RT_COMBINED_SNAPSHOT.should == 1
|
20
|
+
RT_COMBINED_DYNAMIC.should == 2
|
21
|
+
RT_REMOTE_SNAPSHOT.should == 3
|
22
|
+
RT_REMOVE_DELETED.should == 4
|
23
|
+
RT_REMOTE_ONLINE.should == 8
|
24
|
+
|
25
|
+
# module TDataStreamState
|
26
|
+
DS_STATE_CLOSE.should == 0
|
27
|
+
DS_STATE_LOCAL_SNAPSHOT.should == 1
|
28
|
+
DS_STATE_REMOTE_SNAPSHOT.should == 2
|
29
|
+
DS_STATE_ONLINE.should == 3
|
30
|
+
DS_STATE_CLOSE_COMPLETE.should == 4
|
31
|
+
DS_STATE_REOPEN.should == 5
|
32
|
+
DS_STATE_ERROR.should == 6
|
33
|
+
|
34
|
+
# Error codes
|
35
|
+
P2ERR_OK.should == 0x0000
|
36
|
+
P2ERR_COMMON_BEGIN.should == 0x0000
|
37
|
+
|
38
|
+
P2MQ_ERRORCLASS_OK.should == 0x0000
|
39
|
+
P2MQ_ERRORCLASS_IS_USELESS.should == 0x0001
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'has error handler'do
|
43
|
+
expect { error 'Blah'}.to raise_error P2::Error, /Blah/
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'p2ruby'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.setup
|
7
|
+
Bundler.require :test
|
8
|
+
|
9
|
+
BASE_DIR = (Pathname.new(__FILE__).dirname + '..').realpath
|
10
|
+
SOURCE_DIR = BASE_DIR + 'p2/'
|
11
|
+
TMP_DIR = BASE_DIR + 'tmp/'
|
12
|
+
TEST_DIR = BASE_DIR + 'tmp/p2/'
|
13
|
+
CONFIG_DIR = BASE_DIR + 'config/ini/'
|
14
|
+
|
15
|
+
CLIENT_INI = CONFIG_DIR + 'P2ClientGate.ini'
|
16
|
+
CLIENT_INI1 = CONFIG_DIR + 'P2ClientGate1.ini'
|
17
|
+
MESSAGE_INI = CONFIG_DIR + 'p2fortsgate_messages.ini'
|
18
|
+
TABLESET_INI = CONFIG_DIR + 'rts_index.ini'
|
19
|
+
ROUTER_INI = CONFIG_DIR + 'client_router.ini'
|
20
|
+
ROUTER_PATH = TEST_DIR + 'p2bin/P2MQRouter.exe'
|
21
|
+
ROUTER_ARGS = "/ini:#{ROUTER_INI}"
|
22
|
+
ROUTER_LOGIN = "FORTS_FZ36001_" # Login (incomplete) to RTS test server
|
23
|
+
ROUTER_TITLE = Regexp.new('P2MQRouter - ') # + ROUTER_LOGIN
|
24
|
+
|
25
|
+
RSpec.configure do |config|
|
26
|
+
# config.exclusion_filter = { :slow => true }
|
27
|
+
# config.filter = { :focus => true }
|
28
|
+
# config.include(UserExampleHelpers)
|
29
|
+
end
|
30
|
+
|
31
|
+
def show_ole
|
32
|
+
print 'Implemented OLE types: '; p subject.ole_type.implemented_ole_types
|
33
|
+
print 'Source OLE types: '; p subject.ole_type.source_ole_types
|
34
|
+
print 'OLE methods: '
|
35
|
+
p subject.ole_methods.map { |m| "#{m.invoke_kind} #{m.name}(#{m.params.join ', '})" }.sort
|
36
|
+
end
|
37
|
+
|
38
|
+
# Closes any open Router application
|
39
|
+
def stop_router
|
40
|
+
while router_app = WinGui::App.find(:title => ROUTER_TITLE)
|
41
|
+
router_app.exit(timeout=10)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Starts new Router application. Options:
|
46
|
+
# :force - force Router to start, even if it's already running (default *false*)
|
47
|
+
# :title - look for specific Router title
|
48
|
+
# :dir - cd to this dir before starting router
|
49
|
+
# :path - start Router at specific path
|
50
|
+
# :args - start Router with specific command line args
|
51
|
+
# :timeout - wait for timeout seconds for Router to start (default *5*)
|
52
|
+
#
|
53
|
+
def start_router opts ={}
|
54
|
+
title = opts[:title] || ROUTER_TITLE
|
55
|
+
path = opts[:path] || ROUTER_PATH
|
56
|
+
dir = opts[:dir] || TEST_DIR
|
57
|
+
args = opts[:args] || ROUTER_ARGS
|
58
|
+
timeout = opts[:timeout] || 5
|
59
|
+
if not WinGui::Window.find(:title => title) or opts[:force]
|
60
|
+
WinGui::App.launch(:dir => dir, :path => path, :args => args,
|
61
|
+
:title => title, :timeout => timeout)
|
62
|
+
end
|
63
|
+
sleep 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def restart_router
|
67
|
+
stop_router
|
68
|
+
start_router :force => true
|
69
|
+
end
|
70
|
+
|
71
|
+
# Prepares test stand by copying P2 files to /tmp
|
72
|
+
def prepare_test_stand
|
73
|
+
FileUtils.rm_rf TMP_DIR
|
74
|
+
FileUtils.cp_r SOURCE_DIR, TEST_DIR #TMP_DIR
|
75
|
+
end
|
76
|
+
|
77
|
+
prepare_test_stand
|
78
|
+
#FileUtils.cd "#{TEST_DIR}"
|
data/tasks/common.rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#task :default => 'test:run'
|
2
|
+
#task 'gem:release' => 'test:run'
|
3
|
+
|
4
|
+
task :notes do
|
5
|
+
puts 'Output annotations (TBD)'
|
6
|
+
end
|
7
|
+
|
8
|
+
#Bundler not ready for prime time just yet
|
9
|
+
#desc 'Bundle dependencies'
|
10
|
+
#task :bundle do
|
11
|
+
# output = `bundle check 2>&1`
|
12
|
+
#
|
13
|
+
# unless $?.to_i == 0
|
14
|
+
# puts output
|
15
|
+
# system "bundle install"
|
16
|
+
# puts
|
17
|
+
# end
|
18
|
+
#end
|
data/tasks/doc.rake
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
desc 'Alias to doc:rdoc'
|
2
|
+
task :doc => 'doc:rdoc'
|
3
|
+
|
4
|
+
namespace :doc do
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
Rake::RDocTask.new do |rdoc|
|
7
|
+
# Rake::RDocTask.new(:rdoc => "rdoc", :clobber_rdoc => "clobber", :rerdoc => "rerdoc") do |rdoc|
|
8
|
+
rdoc.rdoc_dir = DOC_PATH.basename.to_s
|
9
|
+
rdoc.title = "#{NAME} #{CLASS_NAME::VERSION} Documentation"
|
10
|
+
rdoc.main = "README.doc"
|
11
|
+
rdoc.rdoc_files.include('README*')
|
12
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
13
|
+
end
|
14
|
+
end
|
data/tasks/gem.rake
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
desc "Alias to gem:release"
|
2
|
+
task :release => 'gem:release'
|
3
|
+
|
4
|
+
desc "Alias to gem:install"
|
5
|
+
task :install => 'gem:install'
|
6
|
+
|
7
|
+
desc "Alias to gem:build"
|
8
|
+
task :gem => 'gem:build'
|
9
|
+
|
10
|
+
namespace :gem do
|
11
|
+
gem_file = "#{NAME}-#{CLASS_NAME::VERSION}.gem"
|
12
|
+
|
13
|
+
desc "(Re-)Build gem"
|
14
|
+
task :build do
|
15
|
+
puts "Remove existing gem package"
|
16
|
+
rm_rf PKG_PATH
|
17
|
+
puts "Build new gem package"
|
18
|
+
system "gem build #{NAME}.gemspec"
|
19
|
+
puts "Move built gem to package dir"
|
20
|
+
mkdir_p PKG_PATH
|
21
|
+
mv gem_file, PKG_PATH
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Cleanup already installed gem(s)"
|
25
|
+
task :cleanup do
|
26
|
+
puts "Cleaning up installed gem(s)"
|
27
|
+
system "gem cleanup #{NAME}"
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Build and install gem"
|
31
|
+
task :install => :build do
|
32
|
+
system "gem install #{PKG_PATH}/#{gem_file}"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Build and push gem to Gemcutter"
|
36
|
+
task :release => [:build, 'git:tag'] do
|
37
|
+
puts "Pushing gem to Gemcutter"
|
38
|
+
system "gem push #{PKG_PATH}/#{gem_file}"
|
39
|
+
end
|
40
|
+
end
|
data/tasks/git.rake
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
desc "Alias to git:commit"
|
2
|
+
task :git => 'git:commit'
|
3
|
+
|
4
|
+
namespace :git do
|
5
|
+
|
6
|
+
desc "Stage and commit your work [with message]"
|
7
|
+
task :commit, [:message] do |t, args|
|
8
|
+
puts "Staging new (unversioned) files"
|
9
|
+
system "git add --all"
|
10
|
+
if args.message
|
11
|
+
puts "Committing with message: #{args.message}"
|
12
|
+
system %Q[git commit -a -m "#{args.message}" --author arvicco]
|
13
|
+
else
|
14
|
+
puts "Committing"
|
15
|
+
system %Q[git commit -a -m "No message" --author arvicco]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Push local changes to Github"
|
20
|
+
task :push => :commit do
|
21
|
+
puts "Pushing local changes to remote"
|
22
|
+
system "git push"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Create (release) tag on Github"
|
26
|
+
task :tag => :push do
|
27
|
+
tag = CLASS_NAME::VERSION
|
28
|
+
puts "Creating git tag: #{tag}"
|
29
|
+
system %Q{git tag -a -m "Release tag #{tag}" #{tag}}
|
30
|
+
puts "Pushing #{tag} to remote"
|
31
|
+
system "git push origin #{tag}"
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/tasks/spec.rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
desc 'Alias to spec:spec'
|
2
|
+
task :spec => 'spec:spec'
|
3
|
+
|
4
|
+
namespace :spec do
|
5
|
+
# require 'spec/rake/spectask'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
desc "Run all specs"
|
9
|
+
RSpec::Core::RakeTask.new(:spec){|task|}
|
10
|
+
|
11
|
+
desc "Run specs with RCov"
|
12
|
+
RSpec::Core::RakeTask.new(:rcov) do |task|
|
13
|
+
task.rcov = true
|
14
|
+
task.rcov_opts = ['--exclude', 'spec']
|
15
|
+
end
|
16
|
+
end
|