p2ruby 0.1.0
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.
- 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
|