lib/sippy_cup/scenario.rb in sippy_cup-0.1.0 vs lib/sippy_cup/scenario.rb in sippy_cup-0.1.1

- old
+ new

@@ -1,6 +1,7 @@ require 'nokogiri' +require 'yaml' module SippyCup class Scenario VALID_DTMF = %w{0 1 2 3 4 5 6 7 8 9 0 * # A B C D}.freeze MSEC = 1_000 @@ -9,17 +10,18 @@ builder = Nokogiri::XML::Builder.new do |xml| xml.scenario name: name end parse_args args - - @filename = name.downcase.gsub(/\W+/, '_') + @filename = args[:filename] || name.downcase.gsub(/\W+/, '_') + @filename = File.expand_path @filename @doc = builder.doc @media = Media.new @from_addr, @from_port, @to_addr, @to_port + @scenario_opts = get_scenario_opts args @scenario = @doc.xpath('//scenario').first - instance_eval &block + instance_eval &block if block_given? end def parse_args(args) raise ArgumentError, "Must include source IP:PORT" unless args.keys.include? :source raise ArgumentError, "Must include destination IP:PORT" unless args.keys.include? :destination @@ -27,10 +29,19 @@ @from_addr, @from_port = args[:source].split ':' @to_addr, @to_port = args[:destination].split ':' @from_user = args[:from_user] || "sipp" end + def get_scenario_opts(args) + defaults = { source: "#{@from_addr}", destination: "#{@to_addr}", + scenario: "#{@filename}.xml", max_concurrent: 10, + calls_per_second: 5, number_of_calls: 20 } + + opts = args.select {|k,v| true unless [:source, :destination, :filename].include? k} + defaults.merge! args + end + def compile_media @media.compile! end def sleep(seconds) @@ -53,11 +64,11 @@ CSeq: [cseq] INVITE Contact: sip:#{@from_user}@[local_ip]:[local_port] Max-Forwards: 100 Content-Type: application/sdp Content-Length: [len] - + v=0 o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip] s=- c=IN IP[media_ip_type] [media_ip] t=0 0 @@ -74,18 +85,18 @@ opts[:optional] = true if opts[:optional].nil? opts.merge! response: 100 @scenario << new_recv(opts) end alias :receive_100 :receive_trying - + def receive_ringing(opts = {}) opts[:optional] = true if opts[:optional].nil? opts.merge! response: 180 @scenario << new_recv(opts) end alias :receive_180 :receive_ringing - + def receive_progress(opts = {}) opts[:optional] = true if opts[:optional].nil? opts.merge! response: 183 @scenario << new_recv(opts) end @@ -98,10 +109,20 @@ recv['rrs'] = true @scenario << recv end alias :receive_200 :receive_answer + ## + # Shortcut method that tells SIPp optionally receive + # SIP 100, 180, and 183 messages, and require a SIP 200 message. + def wait_for_answer(opts = {}) + receive_trying({optional: true}.merge opts) + receive_ringing({optional: true}.merge opts) + receive_progress({optional: true}.merge opts) + receive_answer opts + end + def ack_answer(opts = {}) msg = <<-ACK ACK [next_url] SIP/2.0 Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch] @@ -135,11 +156,11 @@ delay = 0.250 * MSEC # FIXME: Need to pass this down to the media layer digits.split('').each do |digit| raise ArgumentError, "Invalid DTMF digit requested: #{digit}" unless VALID_DTMF.include? digit @media << "dtmf:#{digit}" - @media << "silence:#{delay}" + @media << "silence:#{delay.to_i}" pause delay * 2 end end def send_bye(opts = {}) @@ -183,11 +204,15 @@ def to_xml @doc.to_xml end def compile! - xml_file = File.open "#{@filename}.xml", 'w' do |file| + File.open "#{@filename}.xml", 'w' do |file| file.write @doc.to_xml + end + + File.open "#{@filename}.yml", 'w' do |file| + file.write @scenario_opts.to_yaml end compile_media.to_file filename: "#{@filename}.pcap" end private