sippy_cup 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
- # [0.1.1](https://github.com/bklang/sippy_cup)
1
+ # [0.2.0](https://github.com/bklang/sippy_cup/compare/v0.1.1...v0.2.0)
2
+ * Add new command-line ability to parse and run Sippy Cup YAML
3
+ * Bugfixes & documentation
4
+
5
+ # [0.1.1](https://github.com/bklang/sippy_cup/compare/v0.1.0...v0.1.1)
2
6
  * Allow running SIPp directly from SippyCup
3
7
  * New shortcut command for common answer scenario: #wait_for_answer
4
8
  * Allow specifying output file name/location
5
9
 
10
+ # [0.1.0](https://github.com/bklang/sippy_cup/releases/tag/v0.1.0)
11
+ * Initial Release
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Mojo Lingo LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.markdown CHANGED
@@ -1,20 +1,37 @@
1
- Sippy Cup
2
- =========
1
+ # Sippy Cup
3
2
 
4
- Sippy Cup is a tool to generate [SIPp](http://sipp.sourceforge.net/) load test profiles and the corresponding media in PCAP format. The goal is to take an input document that describes a load test in a very simple way (call this number, wait this many seconds, send this digit, wait a few more seconds, etc). The ideas are taken from [LoadBot](https://github.com/mojolingo/ahn-loadbot), but the goal is for a more performant load generating tool with no dependency on Asterisk.
3
+ ## Overview
4
+
5
+ ### The Problem
6
+
7
+ Load testing voice systems, and voice applications in particular, is tricky. While several commercial tools exist, there is really only one tool in the Open Source world that is good at efficiently generating SIP load: [SIPp](http://sipp.sourceforge.net/). While SIPp does a good job of generating load, it is somewhat clumsy to use, due to a verbose XML format for scenarios, a confusing set of command line parameters, and worst of all, a lack of tools to create media needed to interact with voice applications.
8
+
9
+ The last problem is especially tricky: Imagine you want to load test an IVR. Testing requires:
10
+
11
+ * calling a test number
12
+ * waiting a certain amount of time
13
+ * sending some DTMF
14
+ * waiting some more
15
+ * sending more DTMF
16
+ * etc....
5
17
 
18
+ To test this with SIPp you need a PCAP file that contains the properly timed DTMF interactions. Since there is no tool to create this media, it is usually necessary to call into the system and record the PCAP, isolate the RTP from the captured packets with something like Wireshark, then connect the pcap file into the SIPp scenario. This process is time consuming and error prone, meaning that testing isn't done as often as it should.
6
19
 
7
- Requirements
8
- ------------
20
+ SippyCup aims to help solve these problems.
21
+
22
+ ### The Solution
23
+
24
+ Sippy Cup is a tool to generate [SIPp](http://sipp.sourceforge.net/) load test profiles and the corresponding media in PCAP format. The goal is to take an input document that describes a load test in a very simple way (call this number, wait this many seconds, send this digit, wait a few more seconds, etc). The ideas are taken from [LoadBot](https://github.com/mojolingo/ahn-loadbot), but the goal is for a more performant load generating tool with no dependency on Asterisk.
25
+
26
+ ## Requirements
9
27
 
10
28
  SippyCup relies on the following to generate scenarios and the associated media PCAP files:
11
29
 
12
- * Ruby 1.9.3 (2.0.0 NOT YET SUPPORTED; see [PacketFu Issue #28](https://github.com/todb/packetfu/issues/28)
30
+ * Ruby 1.9.3 (2.0.0 NOT YET SUPPORTED; see [PacketFu Issue #28](https://github.com/todb/packetfu/issues/28))
13
31
  * [SIPp](http://sipp.sourceforge.net/) - Download from http://sourceforge.net/projects/sipp/files/
32
+ * "root" user access via sudo: needed to run SIPp so it can bind to raw network sockets
14
33
 
15
-
16
- Installation
17
- ------------
34
+ ## Installation
18
35
 
19
36
  If you do not have Ruby 1.9.3 available (check using `ruby --version`), we recommend installing Ruby with [RVM](http://rvm.io)
20
37
 
@@ -26,9 +43,41 @@ gem install sippy_cup
26
43
 
27
44
  Now you can start creating scenario files like in the examples below.
28
45
 
46
+ ## Examples
29
47
 
30
- Example
31
- -------
48
+ ### Simple Example
49
+
50
+ ```YAML
51
+ ---
52
+ source: 192.0.2.15
53
+ destination: 192.0.2.200
54
+ max_concurrent: 10
55
+ calls_per_second: 5
56
+ number_of_calls: 20
57
+ steps:
58
+ - invite
59
+ - wait_for_answer
60
+ - ack_answer
61
+ - sleep 3
62
+ - send_digits '3125551234'
63
+ - sleep 5
64
+ - send_digits '#'
65
+ - wait_for_bye
66
+ ```
67
+
68
+ Both `source` and `destination` above may be optionally supplied with a port number, eg. `192.0.2.200:5061`
69
+
70
+ Next, compile and run the scenario:
71
+
72
+ ```Shell
73
+ $ sippy_cup -cr my_test_scenario.yml
74
+ Compiling media to /Users/bklang/src/sippy_cup/my_test_scenario_xml.pcap...done.
75
+ Compiling scenario to /Users/bklang/src/sippy_cup/my_test_scenario_xml.pcap...done.
76
+ "Preparing to run SIPp command: sudo sipp -i 192.0.2.15 -p 8836 -sf /Users/bklang/src/sippy_cup/my_test_scenario.xml -l 10 -m 20 -r 5 -s 1 > /dev/null 2>&1"
77
+ $
78
+ ```
79
+
80
+ ### Example embedding SIPp in another Ruby process
32
81
 
33
82
  ```Ruby
34
83
  require 'sippy_cup'
@@ -43,13 +92,11 @@ scenario = SippyCup::Scenario.new 'Sippy Cup', source: '192.168.5.5:10001', dest
43
92
  s.sleep 5
44
93
  s.send_digits '#'
45
94
 
46
- s.receive_bye
47
- s.ack_bye
95
+ s.wait_for_bye
48
96
  end
49
97
 
50
- # Create the scenario XML, PCAP media, and YAML options. File will be named after the scenario name, in our case:
98
+ # Create the scenario XML and PCAP media. File will be named after the scenario name, in our case:
51
99
  # * sippy_cup.xml
52
- # * sippy_cup.yml
53
100
  # * sippy_cup.pcap
54
101
  scenario.compile!
55
102
  ```
@@ -58,21 +105,48 @@ The above code can either be executed as a standalone Ruby script and run with S
58
105
  ```Ruby
59
106
  require 'sippy_cup/tasks'
60
107
  ```
108
+
61
109
  Then running the rake task `rake sippy_cup:compile[sippy_cup.rb]`
62
110
 
63
111
  And finally running `rake sippy_cup:run[sippy_cup.yml]` to execute the scenario.
64
112
 
65
- Customize Your Scenarios
66
- ------------------------
113
+ ## Customize Your Scenarios
67
114
 
68
- ### Alternate File Path
115
+ ### Available Scenario Steps
69
116
 
70
- Don't want your scenario to end up in the same directory as your script? Need the filename to be different than the scenario name? No problem! Try:
117
+ Each command below can take [SIPp attributes](http://sipp.sourceforge.net/doc/reference.html) as optional arguments.
118
+
119
+ * `sleep <seconds>` Wait a specified number of seconds
120
+ * `invite` Send a SIP INVITE to the specified target
121
+ * `receive_trying` Expect to receive a `100 Trying` response from the target
122
+ * `receive_ringing` Expect to receive a `180 Ringing` response from the target
123
+ * `receive_progress` Expect to receive a `183 Progress` response from the target
124
+ * `receive_answer` Expect to receive a `200 OK` (answering the call) response from the target
125
+ * `wait_for_answer` Convenient shortcut for `receive_trying; receive_ringing; receive_progress; receive_answer`, with all but the `answer` marked as optional
126
+ * `ack_answer` Send an `ACK` in response to a `200 OK`
127
+ * `send_digits <string>` Send a DTMF string. May send one or many digits, including `0-9`, `*`, `#`, and `A-D`
128
+ * `send_bye` Send a `BYE` (hangup request)
129
+ * `receive_bye` Expect to receive a `BYE` from the target
130
+ * `ack_bye` Send an `ACK` in response to a `BYE`
131
+ * `wait_for_hangup` Convenient shortcut for `receive_bye; ack_bye`
132
+
133
+ ### Alternate Output File Path
134
+
135
+ Don't want your scenario to end up in the same directory as your script? Need the filename to be different than the scenario name? No problem!
136
+
137
+ For the `sippy_cup` YAML specification, use `scenario`:
138
+
139
+ ```YAML
140
+ ---
141
+ scenario: /path/to/scenario.xml
142
+ ```
143
+
144
+ Or, in Ruby:
71
145
 
72
146
  ```Ruby
73
147
  my_opts = { source: '192.168.5.5:10001', destination: '10.10.0.3:19995', filename: '/path/to/somewhere' }
74
148
  s = SippyCup::Scenario.new 'SippyCup', my_opts do
75
- ...
149
+ # scenario definitions here...
76
150
  end
77
151
  ```
78
152
 
@@ -80,40 +154,27 @@ This will create the files `somewhere.xml`, `somewhere.pcap`, and `somewhere.yml
80
154
 
81
155
  ### Customizing the Test Run
82
156
 
83
- By default, sippy cup will automatically generate a YAML file with the following contents:
84
- ```YAML
85
- ---
86
- :source: 127.0.0.1
87
- :destination: 127.0.0.1
88
- :scenario: /path/to/scenario.xml
89
- :max_concurrent: 10
90
- :calls_per_second: 5
91
- :number_of_calls: 20
92
- ```
93
157
 
94
158
  Each parameter has an impact on the test, and may either be changed once the YAML file is generated or specified in the options hash for `SippyCup::Scenario.new`. In addition to the default parameters, some additional parameters can be set:
95
159
  <dl>
96
- <dt>:source_port:</dt>
97
- <dd>The local port from which to originate SIP traffic. This defaults to port 8836</dd>
98
-
99
- <dt>:stats_file:</dt>
160
+ <dt>stats_file</dt>
100
161
  <dd>Path to a file where call statistics will be stored in a CSV format, defaults to not storing stats</dd>
101
162
 
102
- <dt>:stats_interval</dt>
163
+ <dt>stats_interval</dt>
103
164
  <dd>Frequency (in seconds) of statistics collections. Defaults to 10. Has no effect unless :stats_file is also specified</dd>
104
165
 
105
- <dt>:sip_user:</dt>
166
+ <dt>sip_user</dt>
106
167
  <dd>SIP username to use. Defaults to "1" (as in 1@127.0.0.1)</dd>
107
168
 
108
- <dt>:full_sipp_output:</dt>
169
+ <dt>full_sipp_output</dt>
109
170
  <dd>By default, SippyCup will hide SIPp's command line output while running a scenario. Set this parameter to `true` to see full command line output</dd>
110
171
  </dl>
111
172
 
112
- ### Additional SIPp Attributes
173
+ ### Additional SIPp Scenario Attributes
113
174
 
114
175
  With Sippy Cup, you can add additional attributes to each step of the scenario:
115
- ```Ruby
116
176
 
177
+ ```Ruby
117
178
  #This limits the amount of time the server has to reply to an invite (3 seconds)
118
179
  s.receive_answer timeout: 3000
119
180
 
@@ -125,4 +186,14 @@ s.receive_answer optional: true
125
186
  s.receive_answer timeout: 3000, crlf: true
126
187
  ```
127
188
 
128
- For more information on possible attributes, visit the [SIPp Documentation](http://sipp.sourceforge.net/doc/reference.html)
189
+ For more information on possible attributes, visit the [SIPp Documentation](http://sipp.sourceforge.net/doc/reference.html).
190
+
191
+ ## Credits
192
+
193
+ Copyright (C) 2013 [Mojo Lingo LLC](https://mojolingo.com)
194
+
195
+ Sippy Cup is released under the [MIT license](http://opensource.org/licenses/MIT). Please see the [LICENSE](https://github.com/bklang/sippy_cup/blob/master/LICENSE) file for details.
196
+
197
+ Sippy Cup was created by [Ben Klang](https://twitter.com/bklang) and [Will Drexler](https://github.com/wdrexler) with support from [Mojo Lingo](https://mojolingo.com) and their clients.
198
+
199
+ "Sippy Cup" name suggested by [Jamey Owens](https://github.com/vindir)
data/bin/sippy_cup CHANGED
@@ -1,3 +1,78 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'sippy_cup'
4
+ require 'getoptlong'
5
+
6
+ def usage
7
+ puts "#{$0} [OPTS] </path/to/sippy_cup_definition.yml>"
8
+ puts
9
+ puts "--compile, -c Compile the given scenario YAML to XML and PCAP"
10
+ puts "--run, -r Run the scenario. If used without -c, must supply a previously"
11
+ puts " compiled SippyCup file"
12
+ puts "--help, -h Print this usage information"
13
+ puts "--version, -v Print SippyCup version"
14
+ end
15
+
16
+ opts = GetoptLong.new(
17
+ ['--compile', '-c', GetoptLong::NO_ARGUMENT],
18
+ ['--run', '-r', GetoptLong::NO_ARGUMENT],
19
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
20
+ ['--version', '-V', GetoptLong::NO_ARGUMENT]
21
+ )
22
+
23
+ @compile = false
24
+ @run = false
25
+ opts.each do |opt, arg|
26
+ case opt
27
+ when '--compile'
28
+ @compile = true
29
+ @definition_file = arg
30
+ when '--run'
31
+ @run = true
32
+ @compiled_file = arg
33
+ when '--help'
34
+ usage
35
+ exit 0
36
+ when '--version'
37
+ puts "SippyCup version #{SippyCup::VERSION}"
38
+ exit 0
39
+ end
40
+ end
41
+
42
+ unless ARGV.count == 1
43
+ puts "ERROR: Must supply the SippyCup definition file"
44
+ puts
45
+ usage
46
+ exit 1
47
+ end
48
+
49
+ @definition_file = ARGV.shift
50
+
51
+ unless File.readable? @definition_file
52
+ puts "ERROR: Unable to read definition file"
53
+ puts
54
+ usage
55
+ exit 1
56
+ end
57
+
58
+ unless @compile || @run
59
+ puts "No action (compile or run) specified. Exiting."
60
+ usage
61
+ exit 1
62
+ end
63
+
64
+ @definition = YAML.load File.read @definition_file
65
+ @scenario_base = @definition_file.gsub /\.yml$/, ''
66
+
67
+ unless @definition.has_key? :scenario
68
+ @definition[:scenario] = "#{@scenario_base}.xml"
69
+ end
70
+ unless @definition.has_key? :name
71
+ @definition[:name] = @definition[:scenario]
72
+ end
73
+
74
+
75
+ runner = SippyCup::Runner.new @definition
76
+ runner.compile if @compile
77
+ runner.run if @run
78
+
data/lib/sippy_cup.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  %w{
2
2
  scenario
3
3
  media
4
+ runner
4
5
  }.each {|r| require "sippy_cup/#{r}"}
5
6
 
6
7
  module SippyCup
@@ -1,14 +1,31 @@
1
1
  require 'yaml'
2
+ require 'active_support/core_ext/hash'
2
3
 
3
4
  module SippyCup
4
5
  class Runner
5
6
  def initialize(opts = {})
6
- @options = opts
7
+ @options = ActiveSupport::HashWithIndifferentAccess.new opts
8
+ end
9
+
10
+ def compile
11
+ raise ArgumentError, "Must provide scenario steps" unless @options[:steps]
12
+ scenario = SippyCup::Scenario.new @options[:name].titleize, source: @options[:source], destination: @options[:destination]
13
+ @options[:steps].each do |step|
14
+ instruction, arg = step.split ' ', 2
15
+ if arg && !arg.empty?
16
+ # Strip leading/trailing quotes if present
17
+ arg.gsub!(/^'|^"|'$|"$/, '')
18
+ scenario.send instruction.to_sym, arg
19
+ else
20
+ scenario.send instruction
21
+ end
22
+ end
23
+ scenario.compile!
7
24
  end
8
25
 
9
26
  def prepare_command
10
27
  [:scenario, :source, :destination, :max_concurrent, :calls_per_second, :number_of_calls].each do |arg|
11
- raise "Must provide #{arg}!" unless @options[arg]
28
+ raise ArgumentError, "Must provide #{arg}!" unless @options[arg]
12
29
  end
13
30
  command = "sudo sipp"
14
31
  source_port = @options[:source_port] || '8836'
@@ -34,4 +51,4 @@ module SippyCup
34
51
  end
35
52
 
36
53
  end
37
- end
54
+ end
@@ -15,7 +15,7 @@ module SippyCup
15
15
  @filename = args[:filename] || name.downcase.gsub(/\W+/, '_')
16
16
  @filename = File.expand_path @filename
17
17
  @doc = builder.doc
18
- @media = Media.new @from_addr, @from_port, @to_addr, @to_port
18
+ @media = Media.new '127.0.0.255', 55555, '127.255.255.255', 5060
19
19
  @scenario_opts = get_scenario_opts args
20
20
  @scenario = @doc.xpath('//scenario').first
21
21
 
@@ -45,6 +45,7 @@ module SippyCup
45
45
  end
46
46
 
47
47
  def sleep(seconds)
48
+ seconds = seconds.to_i
48
49
  # TODO play silent audio files to the server to fill the gap
49
50
  pause seconds * MSEC
50
51
  @media << "silence:#{seconds * MSEC}"
@@ -179,6 +180,14 @@ module SippyCup
179
180
  @scenario << new_send(msg, opts)
180
181
  end
181
182
 
183
+ ##
184
+ # Shortcut method that tells SIPp receive a BYE and acknowledge it
185
+ def wait_for_hangup(opts = {})
186
+ receive_bye(opts)
187
+ ack_bye(opts)
188
+ end
189
+
190
+
182
191
  def receive_bye(opts = {})
183
192
  opts.merge! request: 'BYE'
184
193
  @scenario << new_recv(opts)
@@ -206,14 +215,15 @@ module SippyCup
206
215
  end
207
216
 
208
217
  def compile!
218
+ print "Compiling media to #{@filename}.pcap..."
209
219
  File.open "#{@filename}.xml", 'w' do |file|
210
220
  file.write @doc.to_xml
211
221
  end
222
+ puts "done."
212
223
 
213
- File.open "#{@filename}.yml", 'w' do |file|
214
- file.write @scenario_opts.to_yaml
215
- end
224
+ print "Compiling scenario to #{@filename}.pcap..."
216
225
  compile_media.to_file filename: "#{@filename}.pcap"
226
+ puts "done."
217
227
  end
218
228
 
219
229
  private
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module SippyCup
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
data/sippy_cup.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_runtime_dependency 'packetfu'
21
21
  s.add_runtime_dependency 'nokogiri', ["~> 1.6.0"]
22
+ s.add_runtime_dependency 'activesupport', ["> 3.0"]
22
23
 
23
24
  s.add_development_dependency 'guard-rspec'
24
25
  s.add_development_dependency 'rspec', ["~> 2.11"]
@@ -4,7 +4,7 @@ describe SippyCup::Scenario do
4
4
  let(:default_args) { {source: '127.0.0.1:5060', destination: '10.0.0.1:5080'} }
5
5
 
6
6
  it %q{should create a media stream on initialization} do
7
- SippyCup::Media.should_receive(:new).once.with('127.0.0.1', '5060', '127.0.0.2', '5061')
7
+ SippyCup::Media.should_receive(:new).once
8
8
  SippyCup::Scenario.new 'Test', source: '127.0.0.1:5060', destination: '127.0.0.2:5061'
9
9
  end
10
10
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: sippy_cup
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.1
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ben Klang
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2013-08-08 00:00:00 Z
14
+ date: 2013-08-23 00:00:00 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: packetfu
@@ -36,60 +36,71 @@ dependencies:
36
36
  type: :runtime
37
37
  version_requirements: *id002
38
38
  - !ruby/object:Gem::Dependency
39
- name: guard-rspec
39
+ name: activesupport
40
40
  prerelease: false
41
41
  requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">"
45
+ - !ruby/object:Gem::Version
46
+ version: "3.0"
47
+ type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: guard-rspec
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
42
53
  none: false
43
54
  requirements:
44
55
  - - ">="
45
56
  - !ruby/object:Gem::Version
46
57
  version: "0"
47
58
  type: :development
48
- version_requirements: *id003
59
+ version_requirements: *id004
49
60
  - !ruby/object:Gem::Dependency
50
61
  name: rspec
51
62
  prerelease: false
52
- requirement: &id004 !ruby/object:Gem::Requirement
63
+ requirement: &id005 !ruby/object:Gem::Requirement
53
64
  none: false
54
65
  requirements:
55
66
  - - ~>
56
67
  - !ruby/object:Gem::Version
57
68
  version: "2.11"
58
69
  type: :development
59
- version_requirements: *id004
70
+ version_requirements: *id005
60
71
  - !ruby/object:Gem::Dependency
61
72
  name: simplecov
62
73
  prerelease: false
63
- requirement: &id005 !ruby/object:Gem::Requirement
74
+ requirement: &id006 !ruby/object:Gem::Requirement
64
75
  none: false
65
76
  requirements:
66
77
  - - ">="
67
78
  - !ruby/object:Gem::Version
68
79
  version: "0"
69
80
  type: :development
70
- version_requirements: *id005
81
+ version_requirements: *id006
71
82
  - !ruby/object:Gem::Dependency
72
83
  name: simplecov-rcov
73
84
  prerelease: false
74
- requirement: &id006 !ruby/object:Gem::Requirement
85
+ requirement: &id007 !ruby/object:Gem::Requirement
75
86
  none: false
76
87
  requirements:
77
88
  - - ">="
78
89
  - !ruby/object:Gem::Version
79
90
  version: "0"
80
91
  type: :development
81
- version_requirements: *id006
92
+ version_requirements: *id007
82
93
  - !ruby/object:Gem::Dependency
83
94
  name: ci_reporter
84
95
  prerelease: false
85
- requirement: &id007 !ruby/object:Gem::Requirement
96
+ requirement: &id008 !ruby/object:Gem::Requirement
86
97
  none: false
87
98
  requirements:
88
99
  - - ">="
89
100
  - !ruby/object:Gem::Version
90
101
  version: "0"
91
102
  type: :development
92
- version_requirements: *id007
103
+ version_requirements: *id008
93
104
  description: This tool makes it easier to generate SIPp load tests with DTMF interactions.
94
105
  email:
95
106
  - bklang&mojolingo.com
@@ -106,6 +117,7 @@ files:
106
117
  - CHANGELOG.md
107
118
  - Gemfile
108
119
  - Guardfile
120
+ - LICENSE
109
121
  - README.markdown
110
122
  - Rakefile
111
123
  - bin/sippy_cup