agent_fix 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +12 -0
- data/CONTRIBUTION_GUIDELINES.md +22 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +86 -0
- data/LICENSE.txt +14 -0
- data/QUICKFIX_LICENSE.txt +46 -0
- data/README.md +210 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/agent_fix.gemspec +83 -0
- data/config/fix_agents.rb +14 -0
- data/config/logging.properties +6 -0
- data/features/inspect_all.feature +28 -0
- data/features/scope.feature +68 -0
- data/features/step_definitions/steps.rb +32 -0
- data/features/support/FIX42.xml +2670 -0
- data/features/support/env.rb +29 -0
- data/lib/agent_fix/agent.rb +157 -0
- data/lib/agent_fix/configuration.rb +46 -0
- data/lib/agent_fix/cucumber/report.rb +79 -0
- data/lib/agent_fix/cucumber.rb +146 -0
- data/lib/agent_fix/message_cache.rb +31 -0
- data/lib/agent_fix.rb +75 -0
- data/spec/agent_fix/configuration_spec.rb +12 -0
- data/spec/agent_fix/message_cache_spec.rb +16 -0
- data/spec/spec_helper.rb +8 -0
- metadata +189 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
$: << File.expand_path("../../../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'agent_fix/cucumber'
|
4
|
+
require 'agent_fix/cucumber/report'
|
5
|
+
require 'fix_spec/cucumber'
|
6
|
+
require 'rspec'
|
7
|
+
require 'anticipate'
|
8
|
+
|
9
|
+
Around('@inspect_all') do |scenario, block|
|
10
|
+
old_scope = AgentFIX.include_session_level?
|
11
|
+
AgentFIX::include_session_level = true
|
12
|
+
|
13
|
+
#hard reset, forces logout/logon
|
14
|
+
AgentFIX.hard_reset
|
15
|
+
block.call
|
16
|
+
AgentFIX::include_session_level = old_scope
|
17
|
+
end
|
18
|
+
|
19
|
+
Before('~@inspect_all') do
|
20
|
+
AgentFIX.reset
|
21
|
+
end
|
22
|
+
|
23
|
+
FIXSpec::data_dictionary= quickfix.DataDictionary.new "features/support/FIX42.xml"
|
24
|
+
|
25
|
+
World(Anticipate)
|
26
|
+
|
27
|
+
AgentFIX.start
|
28
|
+
at_exit {AgentFIX.stop}
|
29
|
+
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'agent_fix/message_cache'
|
3
|
+
|
4
|
+
module AgentFIX
|
5
|
+
class Agent
|
6
|
+
include quickfix.Application
|
7
|
+
|
8
|
+
attr_reader :name, :connection_type
|
9
|
+
attr_accessor :default, :session
|
10
|
+
|
11
|
+
attr_accessor :bookmark
|
12
|
+
|
13
|
+
def initialize name, connection_type
|
14
|
+
@name = name
|
15
|
+
@connection_type = connection_type
|
16
|
+
@logged_on = false
|
17
|
+
@bookmark = 0
|
18
|
+
@all_messages = MessageCache.new
|
19
|
+
@logger = Java::org.slf4j.LoggerFactory.getLogger("AgentFIX.Agent")
|
20
|
+
end
|
21
|
+
|
22
|
+
def init
|
23
|
+
parse_settings
|
24
|
+
@connector = case @connection_type
|
25
|
+
when :acceptor then quickfix.SocketAcceptor.new(self, @storeFactory, @settings, @logFactory, @messageFactory)
|
26
|
+
when :initiator then quickfix.SocketInitiator.new(self, @storeFactory, @settings, @logFactory, @messageFactory)
|
27
|
+
else nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def onCreate(sessionId)
|
32
|
+
@default_session = sessionId
|
33
|
+
end
|
34
|
+
|
35
|
+
def onLogon(sessionId)
|
36
|
+
@logger.debug "#{@name} onLogon: #{sessionId.to_s}"
|
37
|
+
|
38
|
+
lock.synchronize do
|
39
|
+
@logged_on = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def onLogout(sessionId)
|
44
|
+
@logger.debug "#{@name} onLogout: #{sessionId.to_s}"
|
45
|
+
|
46
|
+
lock.synchronize do
|
47
|
+
@logged_on = false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def toApp(message, sessionId)
|
52
|
+
@logger.debug "#{@name} toApp #{sessionId.to_s}: #{message.to_s.gsub("","|")}"
|
53
|
+
@all_messages.add_message(message:message,sent:true,admin:false)
|
54
|
+
end
|
55
|
+
|
56
|
+
def fromApp(message, sessionId)
|
57
|
+
@logger.debug "#{@name} fromApp #{sessionId.to_s}: #{message.to_s.gsub("","|")}"
|
58
|
+
@all_messages.add_message(message:message,sent:false,admin:false)
|
59
|
+
end
|
60
|
+
|
61
|
+
def toAdmin(message, sessionId)
|
62
|
+
@logger.debug "#{@name} toAdmin #{sessionId.to_s}: #{message.to_s.gsub("","|")}"
|
63
|
+
@all_messages.add_message(message:message,sent:true,admin:true)
|
64
|
+
end
|
65
|
+
|
66
|
+
def fromAdmin(message, sessionId)
|
67
|
+
@logger.debug "#{@name} fromAdmin #{sessionId.to_s}: #{message.to_s.gsub("","|")}"
|
68
|
+
@all_messages.add_message(message:message,sent:false,admin:true)
|
69
|
+
end
|
70
|
+
|
71
|
+
def loggedOn?
|
72
|
+
lock.synchronize do
|
73
|
+
return @logged_on
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def sendToTarget msg
|
78
|
+
msg.getHeader.setField(quickfix.field.BeginString.new(@default_session.getBeginString))
|
79
|
+
msg.getHeader.setField(quickfix.field.TargetCompID.new(@default_session.getTargetCompID))
|
80
|
+
msg.getHeader.setField(quickfix.field.SenderCompID.new(@default_session.getSenderCompID))
|
81
|
+
|
82
|
+
quickfix.Session.sendToTarget(msg)
|
83
|
+
end
|
84
|
+
|
85
|
+
def reset
|
86
|
+
clear_state!
|
87
|
+
end
|
88
|
+
|
89
|
+
def start
|
90
|
+
@connector.start
|
91
|
+
end
|
92
|
+
|
93
|
+
def stop
|
94
|
+
@connector.stop
|
95
|
+
clear_state!
|
96
|
+
end
|
97
|
+
|
98
|
+
def history opts={}
|
99
|
+
opts[:since] ||= 0
|
100
|
+
opts[:received_only] ||= false
|
101
|
+
opts[:include_session]||= AgentFIX::include_session_level?
|
102
|
+
|
103
|
+
indexed_msgs = []
|
104
|
+
@all_messages.messages.each_with_index { |m,i| indexed_msgs << m.merge(index:i) }
|
105
|
+
indexed_msgs = indexed_msgs.slice(opts[:since], indexed_msgs.length)
|
106
|
+
|
107
|
+
if opts[:received_only]
|
108
|
+
indexed_msgs = indexed_msgs.find_all {|m| !m[:sent]}
|
109
|
+
end
|
110
|
+
|
111
|
+
unless opts[:include_session]
|
112
|
+
indexed_msgs = indexed_msgs.find_all {|m| !m[:admin]}
|
113
|
+
end
|
114
|
+
|
115
|
+
indexed_msgs
|
116
|
+
end
|
117
|
+
|
118
|
+
def messages_received opts = {}
|
119
|
+
history opts.merge(:received_only=>true)
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
|
124
|
+
def clear_state!
|
125
|
+
@all_messages.clear!
|
126
|
+
@bookmark = 0
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse_settings
|
130
|
+
session_settings = "[DEFAULT]\n"
|
131
|
+
session_settings << "ConnectionType=#{@connection_type}\n"
|
132
|
+
|
133
|
+
@default ||= {}
|
134
|
+
AgentFIX::session_defaults.merge(@default).each do |k,v|
|
135
|
+
session_settings << "#{k}=#{v}\n"
|
136
|
+
end
|
137
|
+
|
138
|
+
unless @session.nil?
|
139
|
+
session_settings << "[SESSION]\n"
|
140
|
+
@session.each { |k,v| session_settings << "#{k}=#{v}\n"}
|
141
|
+
end
|
142
|
+
|
143
|
+
@logger.info "Settings for #{@name}: #{session_settings}"
|
144
|
+
|
145
|
+
@storeFactory = quickfix.MemoryStoreFactory.new()
|
146
|
+
@messageFactory = quickfix.DefaultMessageFactory.new()
|
147
|
+
@settings = quickfix.SessionSettings.new( Java::java.io.ByteArrayInputStream.new(session_settings.to_java_bytes) )
|
148
|
+
@logFactory = quickfix.FileLogFactory.new(@settings)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def lock
|
154
|
+
@lock||=Mutex.new
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module AgentFIX
|
2
|
+
module Configuration
|
3
|
+
REASONABLE_SESSION_DEFAULTS = {
|
4
|
+
StartTime: "00:00:00",
|
5
|
+
EndTime: "00:00:00",
|
6
|
+
FileLogPath: "fixlog",
|
7
|
+
HeartBtInt: 60
|
8
|
+
}
|
9
|
+
|
10
|
+
def include_session_level=(opt)
|
11
|
+
@include_session_level = opt
|
12
|
+
end
|
13
|
+
|
14
|
+
def include_session_level?
|
15
|
+
@include_session_level ||=false
|
16
|
+
end
|
17
|
+
|
18
|
+
def cucumber_sleep_seconds=(secs)
|
19
|
+
@cucumber_sleep_seconds = secs
|
20
|
+
end
|
21
|
+
|
22
|
+
def cucumber_sleep_seconds
|
23
|
+
@cucumber_sleep_seconds ||= 0.5
|
24
|
+
end
|
25
|
+
|
26
|
+
def cucumber_retries=(retries)
|
27
|
+
@cucumber_retries = retries
|
28
|
+
end
|
29
|
+
|
30
|
+
def cucumber_retries
|
31
|
+
@cucumber_retries ||= 10
|
32
|
+
end
|
33
|
+
|
34
|
+
def session_defaults=(defaults)
|
35
|
+
@session_defaults = defaults
|
36
|
+
end
|
37
|
+
|
38
|
+
def session_defaults
|
39
|
+
@session_defaults ||= REASONABLE_SESSION_DEFAULTS
|
40
|
+
end
|
41
|
+
|
42
|
+
def reset_config
|
43
|
+
instance_variables.each{|ivar| remove_instance_variable(ivar) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class String
|
2
|
+
# colorization
|
3
|
+
def colorize(color_code)
|
4
|
+
"\e[#{color_code}m#{self}\e[0m"
|
5
|
+
end
|
6
|
+
|
7
|
+
def red
|
8
|
+
colorize(31)
|
9
|
+
end
|
10
|
+
|
11
|
+
def green
|
12
|
+
colorize(32)
|
13
|
+
end
|
14
|
+
|
15
|
+
def yellow
|
16
|
+
colorize(33)
|
17
|
+
end
|
18
|
+
|
19
|
+
def pink
|
20
|
+
colorize(35)
|
21
|
+
end
|
22
|
+
|
23
|
+
def white
|
24
|
+
colorize(37)
|
25
|
+
end
|
26
|
+
|
27
|
+
def blue
|
28
|
+
colorize(34)
|
29
|
+
end
|
30
|
+
|
31
|
+
def magenta
|
32
|
+
colorize(35)
|
33
|
+
end
|
34
|
+
|
35
|
+
def cyan
|
36
|
+
colorize(36)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def print_results agent
|
41
|
+
STDERR.puts "\nMessages for ".yellow + agent.name.to_s.white + ": ".yellow
|
42
|
+
|
43
|
+
agent.history(:include_session=>true).each do |msg|
|
44
|
+
if msg[:sent]
|
45
|
+
STDERR.puts "\tsent >>\t #{msg[:message].to_s.gsub!(/\001/, '|')}".green
|
46
|
+
else
|
47
|
+
outbound = "\trecv <<\t #{msg[:message].to_s.gsub!(/\001/, '|')}"
|
48
|
+
|
49
|
+
if @message!=nil and msg[:message] == @message
|
50
|
+
STDERR.puts outbound.red
|
51
|
+
else
|
52
|
+
if msg[:index] >= @agent.bookmark
|
53
|
+
STDERR.puts outbound.blue
|
54
|
+
else
|
55
|
+
|
56
|
+
if @message_scope.include? msg[:message]
|
57
|
+
STDERR.puts outbound.pink
|
58
|
+
else
|
59
|
+
STDERR.puts outbound.green
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
After do |scenario|
|
68
|
+
if scenario.failed? then
|
69
|
+
#last selected agent gets priority
|
70
|
+
unless @agent.nil?
|
71
|
+
print_results(@agent)
|
72
|
+
end
|
73
|
+
|
74
|
+
AgentFIX.agents_hash.values.each do |agent|
|
75
|
+
next if agent == @agent
|
76
|
+
print_results(agent)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require File.expand_path("../../agent_fix", __FILE__)
|
2
|
+
|
3
|
+
require 'fix_spec/builder'
|
4
|
+
require 'fix_spec/cucumber'
|
5
|
+
|
6
|
+
module FIXMessageCache
|
7
|
+
# accessor for fix_spec
|
8
|
+
def last_fix
|
9
|
+
@message
|
10
|
+
end
|
11
|
+
|
12
|
+
def recall_agent agent
|
13
|
+
agent = AgentFIX.agents_hash[agent.to_sym]
|
14
|
+
throw "Unknown agent #{agent}" if agent.nil?
|
15
|
+
|
16
|
+
agent
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
World(FIXMessageCache)
|
21
|
+
|
22
|
+
def anticipate_fix
|
23
|
+
sleeping(AgentFIX.cucumber_sleep_seconds).seconds.between_tries.failing_after(AgentFIX.cucumber_retries).tries do
|
24
|
+
yield
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
When(/^I send the following FIX message(?:s)? from agent "(.*?)":$/) do |agent, fix|
|
29
|
+
messages = fix.split("\n")
|
30
|
+
|
31
|
+
messages.each do |msg|
|
32
|
+
steps %Q{
|
33
|
+
Given the following fix message:
|
34
|
+
"""
|
35
|
+
#{msg}
|
36
|
+
"""
|
37
|
+
}
|
38
|
+
|
39
|
+
AgentFIX.agents_hash[agent.to_sym].sendToTarget(FIXSpec::Builder.message)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Then(/^I should receive (exactly )?(\d+)(?: FIX|fix)? messages(?: (?:on|over) FIX)?(?: of type "(.*?)")? with agent "(.*?)"$/) do |exact, count, type, agent|
|
44
|
+
@agent = recall_agent(agent)
|
45
|
+
count = count.to_i
|
46
|
+
|
47
|
+
scope = []
|
48
|
+
anticipate_fix do
|
49
|
+
messages = @agent.messages_received :since=>@agent.bookmark
|
50
|
+
|
51
|
+
if exact
|
52
|
+
(messages.length).should be == count, "Expected exactly #{count} messages, but got #{messages.length}"
|
53
|
+
else
|
54
|
+
(messages.length).should be >= count, "Expected #{count} messages, but got #{messages.length}"
|
55
|
+
end
|
56
|
+
|
57
|
+
scope=messages.slice(0, count)
|
58
|
+
|
59
|
+
unless type.nil?
|
60
|
+
unless FIXSpec::data_dictionary.nil?
|
61
|
+
type = FIXSpec::data_dictionary.get_msg_type(type)
|
62
|
+
end
|
63
|
+
|
64
|
+
@scope.each do |msg|
|
65
|
+
msg[:message].header.get_string(35).should == type
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
unless scope.empty?
|
71
|
+
@agent.bookmark = scope.last[:index]+1
|
72
|
+
end
|
73
|
+
|
74
|
+
@message_scope=scope.collect {|m| m[:message]}
|
75
|
+
|
76
|
+
#if we only requested one message for the scope, inspect that message
|
77
|
+
if count == 1
|
78
|
+
@message = @message_scope.first
|
79
|
+
else
|
80
|
+
@message = nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Then(/^I should not receive any(?: more)?(?: FIX| fix)? messages with agent "(.*?)"$/) do |agent|
|
85
|
+
steps %Q{Then I should receive exactly 0 FIX messages with agent "#{agent}"}
|
86
|
+
end
|
87
|
+
|
88
|
+
Then(/^I should receive a(?: FIX| fix)? message(?: (?:on|over) FIX)?(?: of type "(.*?)")? with agent "(.*?)"$/) do |type, agent|
|
89
|
+
if type.nil?
|
90
|
+
steps %Q{Then I should receive 1 FIX messages with agent "#{agent}"}
|
91
|
+
else
|
92
|
+
steps %Q{Then I should receive 1 FIX messages of type "#{type}" with agent "#{agent}"}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
When(/^I inspect the (\d+)(?:.*?)(?: FIX| fix)? message$/) do |index|
|
97
|
+
index = index.to_i-1
|
98
|
+
|
99
|
+
@message_scope.should_not be_nil, "No message scope defined"
|
100
|
+
@message_scope.length.should be >index, "There are only #{@message_scope.length} messages in the scope"
|
101
|
+
@message = @message_scope[index]
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
Then(/^the (\d+)(?:.*?)(?: FIX| fix)? message should have the following:$/) do |index, table|
|
106
|
+
table_raw =""
|
107
|
+
table.raw.each do |path, val|
|
108
|
+
table_raw << "|#{path}|#{val}|\n"
|
109
|
+
end
|
110
|
+
|
111
|
+
steps %Q{
|
112
|
+
When I inspect the #{index}th FIX message
|
113
|
+
Then the FIX message should have the following:
|
114
|
+
#{table_raw}
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
Then(/^the(?: FIX|fix)? messages should include(?: a message with)? the following:$/) do |table|
|
119
|
+
@message_scope.should_not be_nil, "No message scope defined"
|
120
|
+
|
121
|
+
table_raw =""
|
122
|
+
table.raw.each do |path, val|
|
123
|
+
table_raw << "|#{path}|#{val}|\n"
|
124
|
+
end
|
125
|
+
|
126
|
+
found = false
|
127
|
+
error_accum = ""
|
128
|
+
index = 1
|
129
|
+
@message_scope.each do |m|
|
130
|
+
@message = m
|
131
|
+
begin
|
132
|
+
steps %Q{
|
133
|
+
When I inspect the #{index}th FIX message
|
134
|
+
Then the FIX message should have the following:
|
135
|
+
#{table_raw}
|
136
|
+
}
|
137
|
+
found = true
|
138
|
+
rescue Exception => e
|
139
|
+
error_accum << "\n#{m.to_s.gsub!(/\001/, '|')}\n #{e}"
|
140
|
+
end
|
141
|
+
index += 1
|
142
|
+
end
|
143
|
+
|
144
|
+
found.should be_true, "Message not included in FIX messages\n #{error_accum}"
|
145
|
+
|
146
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'thread'
|
2
|
+
module AgentFIX
|
3
|
+
class MessageCache
|
4
|
+
def messages
|
5
|
+
lock.synchronize do
|
6
|
+
return msgs.dup
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_message msg
|
11
|
+
lock.synchronize do
|
12
|
+
msgs << msg
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear!
|
17
|
+
lock.synchronize do
|
18
|
+
msgs.clear
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def msgs
|
24
|
+
@messages||=[]
|
25
|
+
end
|
26
|
+
|
27
|
+
def lock
|
28
|
+
@lock||=Mutex.new
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/agent_fix.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'quickfix'
|
2
|
+
require 'agent_fix/configuration'
|
3
|
+
require 'agent_fix/agent'
|
4
|
+
|
5
|
+
module AgentFIX
|
6
|
+
extend Configuration
|
7
|
+
extend self
|
8
|
+
|
9
|
+
def agent_path
|
10
|
+
"./config/fix_agents.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
def agents
|
14
|
+
return @agents if @agents
|
15
|
+
|
16
|
+
(@agents=[]).tap do
|
17
|
+
load_agents if agent_files_loaded.empty?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def agent_files_loaded
|
22
|
+
@agent_files_loaded ||=[]
|
23
|
+
end
|
24
|
+
|
25
|
+
def load_agents path=nil
|
26
|
+
path = File.expand_path(path || agent_path, Dir.pwd)
|
27
|
+
return if agent_files_loaded.include? path
|
28
|
+
agent_files_loaded << path
|
29
|
+
load path
|
30
|
+
|
31
|
+
agents.each {|a| a.init}
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_agent(agent, &blk)
|
35
|
+
yield agent
|
36
|
+
agents << agent
|
37
|
+
end
|
38
|
+
|
39
|
+
def define_acceptor(name, &blk)
|
40
|
+
define_agent(Agent.new(name, :acceptor), &blk)
|
41
|
+
end
|
42
|
+
|
43
|
+
def define_initiator(name, &blk)
|
44
|
+
define_agent(Agent.new(name, :initiator), &blk)
|
45
|
+
end
|
46
|
+
|
47
|
+
#starts all configured agents
|
48
|
+
def start
|
49
|
+
raise RuntimeError, "No FIX Agents Defined" if agents.empty?
|
50
|
+
|
51
|
+
agents.each do |a|
|
52
|
+
a.start
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def stop
|
57
|
+
agents.each {|a| a.stop}
|
58
|
+
end
|
59
|
+
|
60
|
+
def reset
|
61
|
+
agents.each {|a| a.reset}
|
62
|
+
end
|
63
|
+
|
64
|
+
def hard_reset
|
65
|
+
stop
|
66
|
+
sleep 0.5
|
67
|
+
start
|
68
|
+
end
|
69
|
+
|
70
|
+
def agents_hash
|
71
|
+
Hash[agents.map { |a| [a.name.to_sym, a]}]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AgentFIX::Configuration do
|
4
|
+
it "inspects just app messages by default" do
|
5
|
+
AgentFIX.include_session_level?.should be_false
|
6
|
+
end
|
7
|
+
|
8
|
+
it "can inspect both app and session level messages" do
|
9
|
+
AgentFIX.include_session_level = true
|
10
|
+
AgentFIX.include_session_level?.should be_true
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AgentFIX::MessageCache do
|
4
|
+
it "is basically a read-only queue" do
|
5
|
+
cache = AgentFIX::MessageCache.new
|
6
|
+
cache.add_message "1"
|
7
|
+
cache.add_message "2"
|
8
|
+
cache.add_message "3"
|
9
|
+
|
10
|
+
msgs = cache.messages
|
11
|
+
msgs.should == ["1","2","3"]
|
12
|
+
|
13
|
+
cache.clear!
|
14
|
+
msgs.should == ["1","2","3"]
|
15
|
+
end
|
16
|
+
end
|