trebuchet-lt 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ trebuchet.yml
2
+ .DS_Store
3
+ *.gem
4
+
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3@trebuchet --create
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://www.rubygems.org"
2
+
3
+ gem "celluloid"
4
+ gem "fog"
5
+
6
+ group :development do
7
+ gem "pry"
8
+ end
@@ -0,0 +1,41 @@
1
+ GEM
2
+ remote: https://www.rubygems.org/
3
+ specs:
4
+ builder (3.2.0)
5
+ celluloid (0.13.0)
6
+ timers (>= 1.0.0)
7
+ coderay (1.0.9)
8
+ excon (0.20.1)
9
+ fog (1.10.1)
10
+ builder
11
+ excon (~> 0.20)
12
+ formatador (~> 0.2.0)
13
+ mime-types
14
+ multi_json (~> 1.0)
15
+ net-scp (~> 1.1)
16
+ net-ssh (>= 2.1.3)
17
+ nokogiri (~> 1.5.0)
18
+ ruby-hmac
19
+ formatador (0.2.4)
20
+ method_source (0.8.1)
21
+ mime-types (1.23)
22
+ multi_json (1.7.2)
23
+ net-scp (1.1.0)
24
+ net-ssh (>= 2.6.5)
25
+ net-ssh (2.6.7)
26
+ nokogiri (1.5.9)
27
+ pry (0.9.12.1)
28
+ coderay (~> 1.0.5)
29
+ method_source (~> 0.8)
30
+ slop (~> 3.4)
31
+ ruby-hmac (0.4.0)
32
+ slop (3.4.4)
33
+ timers (1.1.0)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ celluloid
40
+ fog
41
+ pry
@@ -0,0 +1,26 @@
1
+ Trebuchet
2
+ =========
3
+
4
+ Trebuchet is a gem for distributed performance testing. It spins up
5
+ arbitrary ec2 micro servers, and does performance testing from them.
6
+
7
+ To set up trebuchet, install it normally with gem, then copy down the
8
+ trebuchet.yml.example and rename it trebuchet.yml. Then update it with
9
+ your revelvant information.
10
+
11
+ To run arbitrary load tests, you can use trebuchet from the command line
12
+
13
+ trebuchet -s 5 -c 100 -t 20M http://www.example.com
14
+
15
+ -s: Number of Servers to spin up
16
+ -c: Number of Concurrent Users per Server
17
+ -t: Amount of Time to run the test (ex. 10S, 5M, 1H)
18
+
19
+ When you run from the command line, Trebuchet will spin up the required
20
+ servers in your
21
+
22
+ Alternatively, you can invoke Trebuchet's internal ruby classes to spin
23
+ up servers, and run multiple load tests then terminate all the servers
24
+ it spun up. It will not terminate any other servers you have running in
25
+ EC2.
26
+
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new('test') do |t|
4
+ t.libs.push "test"
5
+ t.test_files = FileList['test/**/*_test.rb']
6
+ t.verbose = true
7
+ end
8
+
@@ -0,0 +1,22 @@
1
+ #! /usr/bin/env ruby
2
+ # Trebuchet Command Line
3
+
4
+ require "trebuchet"
5
+
6
+ trebuchet = Trebuchet::Server.new
7
+ servers = 1
8
+ if ARGV.include? "-s"
9
+ servers = Integer(ARGV[ARGV.index("-s")+ 1])
10
+ end
11
+ if ARGV.include? "-c"
12
+ trebuchet.concurrency = Integer(ARGV[ARGV.index("-c")+ 1])
13
+ end
14
+ if ARGV.include? "-t"
15
+ trebuchet.time = ARGV[ARGV.index("-t")+ 1]
16
+ end
17
+ trebuchet.url = ARGV.last
18
+
19
+ trebuchet.start servers
20
+ trebuchet.run
21
+ trebuchet.stop
22
+
@@ -0,0 +1,8 @@
1
+ require 'trebuchet/server'
2
+ require 'trebuchet/parser'
3
+ require 'trebuchet/result'
4
+ require 'fog'
5
+ require 'yaml'
6
+ require 'net/ssh'
7
+ require 'celluloid'
8
+
@@ -0,0 +1,5 @@
1
+ module Trebuchet
2
+ class Client
3
+
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ module Trebuchet
2
+ class Parser
3
+ attr_reader :failed_requests, :requests, :rps
4
+ def initialize siege_result
5
+ parse siege_result
6
+ end
7
+
8
+ private
9
+ def parse result
10
+ data_lines = result.lines.to_a[4..-1]
11
+ data_lines.each do |line|
12
+ method = "parse_#{line.split(":").first}".downcase.gsub(" ", "_").gsub("\b", "")
13
+ send(method, line.split(":").last) if private_methods.include? method.to_sym
14
+ end
15
+ if @requests.nil? or @failed_requests.nil? or @rps.nil?
16
+ puts result
17
+ @requests = 0 if @requests.nil?
18
+ @failed_requests = 0 if @failed_requests.nil?
19
+ @rps = 0 if @rps.nil?
20
+ end
21
+ end
22
+
23
+ def parse_transactions data
24
+ @requests = Integer(data.match(/\d+/)[0])
25
+ end
26
+
27
+ def parse_failed_transactions data
28
+ @failed_requests = Integer(data.match(/\d+/)[0])
29
+ end
30
+
31
+ def parse_transaction_rate data
32
+ @rps = data.match(/[-+]?[0-9]*\.?[0-9]+/)[0].to_f
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ module Trebuchet
2
+ class Result
3
+ def initialize parse=nil
4
+ @requests = 0
5
+ @failed_requests = 0
6
+ @rps = 0.0
7
+ add_parse parse if parse
8
+ end
9
+
10
+ def add_parse parse
11
+ @requests = requests + parse.requests
12
+ @failed_requests = failed_requests + parse.failed_requests
13
+ @rps = rps + parse.rps
14
+ end
15
+
16
+ def to_s
17
+ "Requests: #{@requests}\nFailed Requests: #{@failed_requests}\nRequests Per Second: #{@rps}"
18
+ end
19
+
20
+ def requests
21
+ @requests || 0
22
+ end
23
+
24
+ def failed_requests
25
+ @failed_requests || 0
26
+ end
27
+
28
+ def rps
29
+ @rps || 0
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,94 @@
1
+ module Trebuchet
2
+ class Server
3
+ attr_accessor :concurrency, :config, :connections, :instances, :result, :time, :url
4
+
5
+ def initialize config=nil
6
+ if File.exists?("trebuchet.yml")
7
+ file = File.open('trebuchet.yml')
8
+ elsif File.exists?("~/.trebuchet")
9
+ file = File.open("~/.trebuchet")
10
+ end
11
+ @config = config || YAML::load(file)
12
+ @concurrency = "1"
13
+ @time = "1M"
14
+ @url = "http://www.example.com"
15
+ regions = @config.fetch("aws-config", {}).fetch("regions", ["us-east-1"])
16
+
17
+ @connections = []
18
+ regions.each do |region|
19
+ @connections << Fog::Compute.new(:provider => "AWS", :aws_access_key_id => @config.fetch("aws-config", {}).fetch("access_key_id"), :aws_secret_access_key => @config.fetch("aws-config", {}).fetch("access_key_secret"), :region => region)
20
+ end
21
+
22
+ refresh_instances
23
+ end
24
+
25
+ def start num_of_servers=1
26
+ puts "Starting #{num_of_servers} servers!"
27
+ futures = []
28
+ num_of_servers.times do
29
+ futures << Celluloid::Future.new do
30
+ @connections.sample.servers.bootstrap(:public_key_path => '~/.ssh/id_rsa.pub', :username => 'ubuntu', :tags => {:temporary => true}) rescue Net::SSH::Disconnect
31
+ end
32
+ end
33
+ futures.each { |future| future.value }
34
+ puts "#{num_of_servers} Servers Started!"
35
+
36
+ refresh_instances
37
+
38
+ puts "Setting up new instances!"
39
+ @instances.each { |instance| setup_instance instance }
40
+
41
+ puts "New instances configured and ready for use!"
42
+ end
43
+
44
+ def stop
45
+ puts "Shutting down all instances"
46
+ @instances.each { |instance| instance.destroy }
47
+ refresh_instances
48
+ end
49
+
50
+ def run
51
+ puts "Beginning Load Test"
52
+ @result = Trebuchet::Result.new
53
+ futures = []
54
+ @instances.each do |instance|
55
+ futures << Celluloid::Future.new { run_siege instance }
56
+ end
57
+ futures.each { |future| future.value }
58
+ puts @result.to_s
59
+
60
+ nil
61
+ end
62
+
63
+ private
64
+ def refresh_instances
65
+ @instances = []
66
+ @connections.each do |connection|
67
+ new_instance = connection.servers.select { |instance| instance.tags.fetch("temporary", false) and instance.state == "running" }
68
+ @instances << new_instance unless new_instance.empty?
69
+ end
70
+ @instances.flatten!
71
+
72
+ nil
73
+ end
74
+
75
+ def setup_instance instance
76
+ ssh = Net::SSH.start(instance.dns_name, "ubuntu")
77
+ ssh.exec! "sudo apt-get install siege"
78
+ ssh.exec! %{echo "verbose = false" > ~/.siegerc}
79
+ ssh.exec! %{sudo sh -c "echo '* hard nofile 1000000' >> /etc/security/limits.conf"}
80
+ ssh.exec! %{sudo sh -c "echo '* soft nofile 1000000' >> /etc/security/limits.conf"}
81
+ ssh.close
82
+ end
83
+
84
+ def run_siege instance
85
+ ssh = Net::SSH.start(instance.dns_name, "ubuntu")
86
+ cmd = "siege -R ~/.siegerc -c #{concurrency} -t #{time} #{url}"
87
+ res = ssh.exec! cmd
88
+ ssh.close
89
+ parse = Trebuchet::Parser.new(res)
90
+ @result.add_parse(parse)
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,16 @@
1
+ ** SIEGE 2.68
2
+ ** Preparing 1 concurrent users for battle.
3
+ The server is now under siege...
4
+ Lifting the server siege.. done.
5
+ Transactions: 57 hits
6
+ Availability: 100.00 %
7
+ Elapsed time: 59.10 secs
8
+ Data transferred: 5.66 MB
9
+ Response time: 0.91 secs
10
+ Transaction rate: 0.96 trans/sec
11
+ Throughput: 0.10 MB/sec
12
+ Concurrency: 0.88
13
+ Successful transactions: 57
14
+ Failed transactions: 0
15
+ Longest transaction: 3.06
16
+ Shortest transaction: 0.74
@@ -0,0 +1,20 @@
1
+ require "test_helper"
2
+
3
+ class ParserTest < Test::Unit::TestCase
4
+ def setup
5
+ @parser = Trebuchet::Parser.new(File.open("test/fixtures/siege_output.txt"))
6
+ end
7
+
8
+ def test_requests
9
+ assert_equal 57, @parser.requests
10
+ end
11
+
12
+ def test_failed_requests
13
+ assert_equal 0, @parser.failed_requests
14
+ end
15
+
16
+ def test_rps
17
+ assert_equal 0.96, @parser.rps
18
+ end
19
+ end
20
+
@@ -0,0 +1,16 @@
1
+ require "test_helper"
2
+
3
+ class ResultTest < Test::Unit::TestCase
4
+ def setup
5
+ @result = Trebuchet::Result.new
6
+ @parser = Trebuchet::Parser.new(File.open("test/fixtures/siege_output.txt"))
7
+ end
8
+
9
+ def test_add_parse
10
+ @result.add_parse @parser
11
+ @result.add_parse @parser
12
+ assert_equal 114, @result.requests
13
+ assert_equal 0, @result.failed_requests
14
+ assert_equal 1.92, @result.rps
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ $:.unshift File.expand_path("../../", __FILE__)
2
+ require "test/unit"
3
+ require "trebuchet"
4
+ require "pry"
5
+
@@ -0,0 +1,8 @@
1
+ #! /usr/bin/env ruby
2
+ # Trebuchet Command Line
3
+
4
+ require "trebuchet"
5
+ trebuchet = Trebuchet::Server.new
6
+ if ARGV.include? "-s"
7
+ trebuchet.start
8
+ end
@@ -0,0 +1,24 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.platform = Gem::Platform::RUBY
5
+ s.name = 'trebuchet-lt'
6
+ s.version = '0.0.1'
7
+ s.summary = 'Distributed Load Testing Made Easy'
8
+ s.description = 'Trebuchet is a gem for distributed performance testing. It spins up arbitrary ec2 micro servers, and does performance testing from them.'
9
+
10
+ s.required_ruby_version = '>= 1.9.3'
11
+
12
+ s.license = 'MIT'
13
+
14
+ s.author = 'Nathaniel Barnes'
15
+ s.email = 'Nathaniel.R.Barnes@gmail.com'
16
+ s.homepage = 'http://github.com/NateBarnes/trebuchet'
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.bindir = 'bin'
20
+ s.executables = ['trebuchet']
21
+
22
+ s.add_dependency 'celluloid'
23
+ s.add_dependency 'fog'
24
+ end
@@ -0,0 +1,8 @@
1
+ aws-config:
2
+ access_key_id: "EXAMPLE_ACCESS_KEY"
3
+ access_key_secret: "EXAMPLE_ACCESS_KEY_SECRET"
4
+ regions:
5
+ - "us-west-1"
6
+ - "us-west-2"
7
+ - "eu-west-1"
8
+
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trebuchet-lt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nathaniel Barnes
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: celluloid
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: fog
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Trebuchet is a gem for distributed performance testing. It spins up arbitrary
47
+ ec2 micro servers, and does performance testing from them.
48
+ email: Nathaniel.R.Barnes@gmail.com
49
+ executables:
50
+ - trebuchet
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - .rvmrc
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - README.md
59
+ - Rakefile
60
+ - bin/trebuchet
61
+ - lib/trebuchet.rb
62
+ - lib/trebuchet/client.rb
63
+ - lib/trebuchet/parser.rb
64
+ - lib/trebuchet/result.rb
65
+ - lib/trebuchet/server.rb
66
+ - test/fixtures/siege_output.txt
67
+ - test/parser_test.rb
68
+ - test/result_test.rb
69
+ - test/test_helper.rb
70
+ - trebuchet
71
+ - trebuchet.gemspec
72
+ - trebuchet.yml.example
73
+ homepage: http://github.com/NateBarnes/trebuchet
74
+ licenses:
75
+ - MIT
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: 1.9.3
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 1.8.25
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Distributed Load Testing Made Easy
98
+ test_files: []