trebuchet-lt 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []