fiveruns_tuneup_core 0.5.0
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.
- data/Manifest +13 -0
- data/Rakefile +19 -0
- data/fiveruns_tuneup_core.gemspec +120 -0
- data/lib/fiveruns/tuneup/bar.rb +41 -0
- data/lib/fiveruns/tuneup/helpers.rb +44 -0
- data/lib/fiveruns/tuneup/panel.rb +64 -0
- data/lib/fiveruns/tuneup/run.rb +139 -0
- data/lib/fiveruns/tuneup/step.rb +303 -0
- data/lib/fiveruns/tuneup/templating.rb +19 -0
- data/lib/fiveruns_tuneup_core.rb +13 -0
- data/test/fixtures/a.json +1 -0
- data/test/run_test.rb +59 -0
- data/test/step_test.rb +36 -0
- data/test/test_helper.rb +16 -0
- metadata +118 -0
data/Manifest
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
lib/fiveruns/tuneup/bar.rb
|
2
|
+
lib/fiveruns/tuneup/helpers.rb
|
3
|
+
lib/fiveruns/tuneup/panel.rb
|
4
|
+
lib/fiveruns/tuneup/run.rb
|
5
|
+
lib/fiveruns/tuneup/step.rb
|
6
|
+
lib/fiveruns/tuneup/templating.rb
|
7
|
+
lib/fiveruns_tuneup_core.rb
|
8
|
+
Manifest
|
9
|
+
Rakefile
|
10
|
+
test/fixtures/a.json
|
11
|
+
test/run_test.rb
|
12
|
+
test/step_test.rb
|
13
|
+
test/test_helper.rb
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'echoe'
|
3
|
+
|
4
|
+
Echoe.new 'fiveruns_tuneup_core' do |p|
|
5
|
+
p.version = '0.5.0'
|
6
|
+
p.author = "FiveRuns Development Team"
|
7
|
+
p.email = 'dev@fiveruns.com'
|
8
|
+
p.project = 'fiveruns'
|
9
|
+
p.summary = "Core utilities for FiveRuns TuneUp panels"
|
10
|
+
p.url = "http://tuneup.fiveruns.com"
|
11
|
+
p.include_rakefile = true
|
12
|
+
p.runtime_dependencies = %w(json)
|
13
|
+
p.development_dependencies = %w(echoe FakeWeb Shoulda)
|
14
|
+
p.rcov_options = '--exclude gems --exclude version.rb --sort coverage --text-summary --html -o coverage'
|
15
|
+
end
|
16
|
+
|
17
|
+
task :coverage do
|
18
|
+
system "open coverage/index.html" if PLATFORM['darwin']
|
19
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
|
2
|
+
# Gem::Specification for Fiveruns_tuneup_core-0.5.0
|
3
|
+
# Originally generated by Echoe
|
4
|
+
|
5
|
+
--- !ruby/object:Gem::Specification
|
6
|
+
name: fiveruns_tuneup_core
|
7
|
+
version: !ruby/object:Gem::Version
|
8
|
+
version: 0.5.0
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- FiveRuns Development Team
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
|
15
|
+
date: 2008-10-11 00:00:00 -07:00
|
16
|
+
default_executable:
|
17
|
+
dependencies:
|
18
|
+
- !ruby/object:Gem::Dependency
|
19
|
+
name: json
|
20
|
+
type: :runtime
|
21
|
+
version_requirement:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: "0"
|
27
|
+
version:
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: echoe
|
30
|
+
type: :development
|
31
|
+
version_requirement:
|
32
|
+
version_requirements: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: "0"
|
37
|
+
version:
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: FakeWeb
|
40
|
+
type: :development
|
41
|
+
version_requirement:
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: Shoulda
|
50
|
+
type: :development
|
51
|
+
version_requirement:
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
description: Core utilities for FiveRuns TuneUp panels
|
59
|
+
email: dev@fiveruns.com
|
60
|
+
executables: []
|
61
|
+
|
62
|
+
extensions: []
|
63
|
+
|
64
|
+
extra_rdoc_files:
|
65
|
+
- lib/fiveruns/tuneup/bar.rb
|
66
|
+
- lib/fiveruns/tuneup/helpers.rb
|
67
|
+
- lib/fiveruns/tuneup/panel.rb
|
68
|
+
- lib/fiveruns/tuneup/run.rb
|
69
|
+
- lib/fiveruns/tuneup/step.rb
|
70
|
+
- lib/fiveruns/tuneup/templating.rb
|
71
|
+
- lib/fiveruns_tuneup_core.rb
|
72
|
+
files:
|
73
|
+
- lib/fiveruns/tuneup/bar.rb
|
74
|
+
- lib/fiveruns/tuneup/helpers.rb
|
75
|
+
- lib/fiveruns/tuneup/panel.rb
|
76
|
+
- lib/fiveruns/tuneup/run.rb
|
77
|
+
- lib/fiveruns/tuneup/step.rb
|
78
|
+
- lib/fiveruns/tuneup/templating.rb
|
79
|
+
- lib/fiveruns_tuneup_core.rb
|
80
|
+
- Manifest
|
81
|
+
- Rakefile
|
82
|
+
- test/fixtures/a.json
|
83
|
+
- test/run_test.rb
|
84
|
+
- test/step_test.rb
|
85
|
+
- test/test_helper.rb
|
86
|
+
- fiveruns_tuneup_core.gemspec
|
87
|
+
has_rdoc: true
|
88
|
+
homepage: http://tuneup.fiveruns.com
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options:
|
91
|
+
- --line-numbers
|
92
|
+
- --inline-source
|
93
|
+
- --title
|
94
|
+
- Fiveruns_tuneup_core
|
95
|
+
- --main
|
96
|
+
- README.rdoc
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: "0"
|
104
|
+
version:
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: "1.2"
|
110
|
+
version:
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project: fiveruns
|
114
|
+
rubygems_version: 1.3.0
|
115
|
+
specification_version: 2
|
116
|
+
summary: Core utilities for FiveRuns TuneUp panels
|
117
|
+
test_files:
|
118
|
+
- test/run_test.rb
|
119
|
+
- test/step_test.rb
|
120
|
+
- test/test_helper.rb
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Fiveruns
|
2
|
+
module Tuneup
|
3
|
+
|
4
|
+
class Bar
|
5
|
+
include Templating
|
6
|
+
|
7
|
+
attr_reader :step
|
8
|
+
def initialize(step)
|
9
|
+
@step = step
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def template
|
15
|
+
%(
|
16
|
+
<ul id="<%= 'tuneup-root-bar' if step.is_a?(RootStep) %>" class="tuneup-bar">
|
17
|
+
<% %w(model view controller).each do |layer| %>
|
18
|
+
<%= component layer %>
|
19
|
+
<% end %>
|
20
|
+
</ul>
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def component(layer)
|
25
|
+
width = width_of(layer)
|
26
|
+
return '' unless width > 0
|
27
|
+
%(
|
28
|
+
<li title="#{layer.to_s.capitalize}" style="width: #{width}px;" class="tuneup-layer-#{layer}">#{layer.to_s[0,1].capitalize if width >= 12}</li>
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def width_of(layer)
|
33
|
+
portion = step.layer_portions[layer.to_sym]
|
34
|
+
result = portion * 200 * step.proportion
|
35
|
+
result < 1 && portion != 0 ? 1 : result
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Fiveruns
|
2
|
+
module Tuneup
|
3
|
+
|
4
|
+
def self.format_caller(trace)
|
5
|
+
valid_lines = trace.reject { |line| line =~ /fiveruns_tuneup/ }[0,5]
|
6
|
+
linked_lines = valid_lines.map { |line| editor_link_line(line) }
|
7
|
+
'<pre>%s</pre>' % linked_lines.join("\n")
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.strip_root(text)
|
11
|
+
if defined?(::Fiveruns::Tuneup::STRIP_ROOT)
|
12
|
+
pattern = /^#{Regexp.quote ::Fiveruns::Tuneup::STRIP_ROOT}\/?/o
|
13
|
+
if text =~ pattern
|
14
|
+
result = text.sub(pattern, '')
|
15
|
+
in_app = result !~ /^gems\//
|
16
|
+
return [in_app, result]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
[false, text]
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO: Refactor
|
23
|
+
def self.editor_link_line(line)
|
24
|
+
filename, number, extra = line.match(/^(.+?):(\d+)(?::in\b(.*?))?/)[1, 2]
|
25
|
+
in_app, line = strip_root(line)
|
26
|
+
name = if line.size > 87
|
27
|
+
"…#{CGI.escapeHTML line.sub(/^.*?(.{84})$/, '\1')}"
|
28
|
+
else
|
29
|
+
line
|
30
|
+
end
|
31
|
+
name = if in_app
|
32
|
+
if name =~ /`/
|
33
|
+
name.sub(/^(.*?)\s+`(.*?)'$/, %q(<span class='tuneup-app-line'>\1</span> `<b class='tuneup-app-line'>\2</b>'))
|
34
|
+
else
|
35
|
+
%(<span class='tuneup-app-line'>#{name}</span>)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
name.sub(/([^\/\\]+\.\S+:\d+:in)\s+`(.*?)'$/, %q(\1 `<b>\2</b>'))
|
39
|
+
end
|
40
|
+
%(<a title='%s' href='txmt://open/?url=file://%s&line=%d'>%s</a>%s) % [CGI.escapeHTML(line), filename, number, name, extra]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Fiveruns
|
2
|
+
module Tuneup
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :javascripts_path
|
6
|
+
attr_accessor :stylesheets_path
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.insert_panel(body, run, allow_share = false)
|
10
|
+
return body unless run
|
11
|
+
tag = body[/(<body[^>]*>)/i, 1]
|
12
|
+
return body unless tag
|
13
|
+
panel = Panel.new(run, allow_share)
|
14
|
+
body.sub(/<\/head>/i, head << '</head>').sub(tag, tag + panel.to_html)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.head
|
18
|
+
%(
|
19
|
+
<script src='#{javascripts_path}/init.js' type='text/javascript'></script>
|
20
|
+
<link rel='stylesheet' type='text/css' href='#{stylesheets_path}/tuneup.css'/>
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
class Panel
|
25
|
+
include Templating
|
26
|
+
|
27
|
+
attr_reader :run, :root
|
28
|
+
def initialize(run, allow_share = false)
|
29
|
+
@run = run
|
30
|
+
@root = run.data
|
31
|
+
@allow_share = allow_share
|
32
|
+
end
|
33
|
+
|
34
|
+
def allow_share?
|
35
|
+
@allow_share
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def template
|
41
|
+
%(
|
42
|
+
<div id="tuneup"><h1>FiveRuns TuneUp</h1><div style="display: block;" id="tuneup-content"><div id="tuneup-panel">
|
43
|
+
<div id="tuneup-data">
|
44
|
+
<div id="tuneup-top">
|
45
|
+
<%= root.to_html %>
|
46
|
+
<% if allow_share? %>
|
47
|
+
<a href="/fiveruns_tuneup_merb/share/<%= run.slug %>" id="tuneup-save-link">Share this Run</a>
|
48
|
+
<% end %>
|
49
|
+
</div>
|
50
|
+
<ul id="tuneup-details">
|
51
|
+
<% root.children.each do |child| %>
|
52
|
+
<%= child.to_html %>
|
53
|
+
<% end %>
|
54
|
+
<li style="clear: both;"/>
|
55
|
+
</ul>
|
56
|
+
</div>
|
57
|
+
</div></div></div>
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module Fiveruns
|
2
|
+
module Tuneup
|
3
|
+
|
4
|
+
class Run
|
5
|
+
|
6
|
+
class << self
|
7
|
+
attr_accessor :directory
|
8
|
+
attr_accessor :api_key
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.environment
|
12
|
+
@environment ||= {
|
13
|
+
# :framework needs to be set, as well as <framework>_version
|
14
|
+
:framework => nil,
|
15
|
+
:ruby_version => RUBY_VERSION,
|
16
|
+
:ruby_platform => RUBY_PLATFORM
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.slug_of(filename)
|
21
|
+
url_directory, file = filename.split(File::SEPARATOR)[-2, 2]
|
22
|
+
File.join(url_directory, File.basename(file, '.json.gz'))
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.all(format = :slug)
|
26
|
+
files = Dir[File.join(directory, '*', '*.json.gz')]
|
27
|
+
format == :slug ? files.map { |file| slug_of(file) } : files
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.all_for(url, format = :slug)
|
31
|
+
run_directory = Digest::SHA1.hexdigest(url.to_s)
|
32
|
+
files = Dir[File.join(directory, run_directory, '*.json.gz')]
|
33
|
+
format == :slug ? files.map { |file| slug_of(file) } : files
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.last(format = :slug)
|
37
|
+
all(format).sort_by { |f| File.basename(f) }.last
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.service_uri
|
41
|
+
@service_uri = URI.parse(ENV['TUNEUP_COLLECTOR'] || 'https://tuneup-collector.fiveruns.com')
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.share(slug)
|
45
|
+
if api_key?
|
46
|
+
file = Dir[File.join(directory, "%s.json.gz" % slug)].first
|
47
|
+
if file
|
48
|
+
run = load(File.open(file, 'rb') { |f| f.read })
|
49
|
+
http = Net::HTTP.new(service_uri.host, service_uri.port)
|
50
|
+
http.use_ssl = true if service_uri.scheme == 'https'
|
51
|
+
body = "api_key=#{api_key}&run=#{CGI.escape(run.to_json)}"
|
52
|
+
begin
|
53
|
+
resp = http.post('/runs.json', body, "Content-Type" => 'application/x-www-form-urlencoded')
|
54
|
+
case resp.code.to_i
|
55
|
+
when 201
|
56
|
+
return JSON.load(resp.body)['run_id']
|
57
|
+
else
|
58
|
+
# TODO: return error info
|
59
|
+
return false
|
60
|
+
end
|
61
|
+
rescue Exception => e
|
62
|
+
# TODO: return error info
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
else
|
66
|
+
raise ArgumentError, "Invalid run: #{slug}"
|
67
|
+
end
|
68
|
+
else
|
69
|
+
raise ArgumentError, "No API Key set"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.api_key?
|
74
|
+
@api_key
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.load(compressed)
|
78
|
+
file = JSON.load(Zlib::Inflate.inflate(compressed))
|
79
|
+
step = Fiveruns::Tuneup::Step.load(file['data'])
|
80
|
+
new(file['url'], step, file['environment'], Time.at(file['collected_at']))
|
81
|
+
end
|
82
|
+
|
83
|
+
attr_reader :url, :data, :environment, :collected_at
|
84
|
+
def initialize(url, data, environment = self.class.environment, collected_at = Time.now)
|
85
|
+
@url = url
|
86
|
+
@data = data
|
87
|
+
@environment = environment
|
88
|
+
@collected_at = collected_at
|
89
|
+
validate!
|
90
|
+
end
|
91
|
+
|
92
|
+
def validate!
|
93
|
+
unless environment.is_a?(Hash)
|
94
|
+
raise ArgumentError, "Invalid environment information (must be a Hash): #{environment.inspect}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def save
|
99
|
+
compressed = Zlib::Deflate.deflate(to_json)
|
100
|
+
create_directory
|
101
|
+
File.open(full_path, 'wb') { |f| f.write compressed }
|
102
|
+
end
|
103
|
+
|
104
|
+
def full_path
|
105
|
+
File.join(self.class.directory, path)
|
106
|
+
end
|
107
|
+
|
108
|
+
def slug
|
109
|
+
@slug ||= "%s/%d-%d" % [
|
110
|
+
Digest::SHA1.hexdigest(url),
|
111
|
+
(collected_at.to_f * 1000),
|
112
|
+
(data.time * 1000)
|
113
|
+
]
|
114
|
+
end
|
115
|
+
|
116
|
+
def path
|
117
|
+
"%s.json.gz" % slug
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_json
|
121
|
+
{
|
122
|
+
:id => slug,
|
123
|
+
:url => url,
|
124
|
+
:environment => environment,
|
125
|
+
:collected_at => collected_at.to_f,
|
126
|
+
:data => data
|
127
|
+
}.to_json
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def create_directory
|
133
|
+
FileUtils.mkdir_p File.dirname(full_path)
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,303 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Fiveruns
|
4
|
+
module Tuneup
|
5
|
+
|
6
|
+
class CalculationError < ::RuntimeError; end
|
7
|
+
|
8
|
+
def self.record(&block)
|
9
|
+
Step.reset!
|
10
|
+
root = RootStep.new
|
11
|
+
root.record(&block)
|
12
|
+
root
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.step(name, layer, extras = {}, &block)
|
16
|
+
trace = format_caller(caller)
|
17
|
+
Step.new(name, layer, extras.merge('Caller' => trace), nil).record(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
class RootStep
|
21
|
+
|
22
|
+
include Templating
|
23
|
+
attr_reader :children, :bar
|
24
|
+
attr_accessor :time, :parent
|
25
|
+
def initialize(time = nil)
|
26
|
+
@time = time
|
27
|
+
@children = []
|
28
|
+
@bar = Bar.new(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def root
|
32
|
+
parent ? parent.root : self
|
33
|
+
end
|
34
|
+
|
35
|
+
def record
|
36
|
+
start = Time.now
|
37
|
+
result = Step.inside(self) { yield }
|
38
|
+
@time = Time.now - start
|
39
|
+
result
|
40
|
+
end
|
41
|
+
def disparity
|
42
|
+
result = time - children.inject(0) { |sum, child| sum + child.time }
|
43
|
+
if result < 0
|
44
|
+
#TODO resolve instances where sum of child times exceed parent time
|
45
|
+
#raise CalculationError, "Child steps exceed parent step size"
|
46
|
+
result = 0
|
47
|
+
end
|
48
|
+
result
|
49
|
+
end
|
50
|
+
def add_child(child)
|
51
|
+
child.parent = self
|
52
|
+
children << child
|
53
|
+
end
|
54
|
+
def format_time(time)
|
55
|
+
'%.2fms' % (time * 1000)
|
56
|
+
end
|
57
|
+
def layer_portions
|
58
|
+
children.first.layer_portions
|
59
|
+
end
|
60
|
+
def to_json
|
61
|
+
{:children => children, :time => time}.to_json
|
62
|
+
end
|
63
|
+
|
64
|
+
def proportion
|
65
|
+
time / root.time
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_html_with_children
|
69
|
+
to_html << children.map { |c| c.to_html }.join
|
70
|
+
end
|
71
|
+
|
72
|
+
def template
|
73
|
+
%(
|
74
|
+
<div id="tuneup-summary">
|
75
|
+
<%= bar.to_html %>
|
76
|
+
<%= (time * 1000).to_i %> ms
|
77
|
+
</div>
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
class Step < RootStep
|
84
|
+
|
85
|
+
def self.load(source, depth = 0)
|
86
|
+
hash = source.is_a?(Hash) ? source : JSON.load(source)
|
87
|
+
step = if hash['layer']
|
88
|
+
Step.new(hash['name'], hash['layer'], hash['extras'], hash['time'])
|
89
|
+
elsif depth == 0
|
90
|
+
RootStep.new(hash['time'])
|
91
|
+
else
|
92
|
+
raise ArgumentError, "Could not find data for step in #{hash.inspect}"
|
93
|
+
end
|
94
|
+
hash['children'].each do |child_hash|
|
95
|
+
child = load(child_hash)
|
96
|
+
step.add_child(child)
|
97
|
+
end
|
98
|
+
step
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.stack
|
102
|
+
@stack ||= []
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.reset!
|
106
|
+
stack.clear
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.inside(step)
|
110
|
+
unless stack.empty?
|
111
|
+
stack.last.add_child(step)
|
112
|
+
end
|
113
|
+
stack << step
|
114
|
+
result = yield
|
115
|
+
stack.pop
|
116
|
+
result
|
117
|
+
end
|
118
|
+
|
119
|
+
attr_reader :name, :layer, :extras
|
120
|
+
def initialize(name, layer, raw_extras = {}, time = nil)
|
121
|
+
super(time)
|
122
|
+
@name = name
|
123
|
+
@layer = layer.to_sym
|
124
|
+
@extras = build_extras(raw_extras)
|
125
|
+
end
|
126
|
+
|
127
|
+
def children_with_disparity
|
128
|
+
return children if children.empty?
|
129
|
+
layer_name = layer if respond_to?(:layer)
|
130
|
+
extra_step = DisparityStep.new(layer_name, disparity)
|
131
|
+
extra_step.parent = parent
|
132
|
+
children + [extra_step]
|
133
|
+
end
|
134
|
+
|
135
|
+
def layer_portions
|
136
|
+
@layer_portions ||= begin
|
137
|
+
result = {:model => 0, :view => 0, :controller => 0}
|
138
|
+
if children.empty?
|
139
|
+
result[layer] = 1
|
140
|
+
else
|
141
|
+
times = layer_times
|
142
|
+
|
143
|
+
times[layer] ||= 0
|
144
|
+
times.inject(result) do |all, (l, t)|
|
145
|
+
result[l] = t / time
|
146
|
+
result
|
147
|
+
end
|
148
|
+
end
|
149
|
+
result
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def layer_times
|
154
|
+
if children.empty?
|
155
|
+
return {layer => time}
|
156
|
+
end
|
157
|
+
|
158
|
+
totals = {:model => 0, :view => 0, :controller => 0}
|
159
|
+
children_with_disparity.inject(totals) do |all, child|
|
160
|
+
breakdown = child.layer_times
|
161
|
+
breakdown.each { |l,t| all[l] += t }
|
162
|
+
all
|
163
|
+
end
|
164
|
+
totals
|
165
|
+
end
|
166
|
+
|
167
|
+
def to_json
|
168
|
+
extras_hash = extras.inject({}) { |all, extra| all[extra.name] = extra; all }
|
169
|
+
{:name => name, :children => children, :time => time, :extras => extras_hash, :layer => layer}.to_json
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def build_extras(raw_extras)
|
175
|
+
raw_extras.sort_by { |k, v| k.to_s }.map do |name, data|
|
176
|
+
data = case data
|
177
|
+
when Array
|
178
|
+
data
|
179
|
+
when Hash
|
180
|
+
[data['content'], data['extended']]
|
181
|
+
else
|
182
|
+
[data]
|
183
|
+
end
|
184
|
+
Extra.new(name, *data )
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def template
|
189
|
+
%(
|
190
|
+
<li class="<%= html_class %>">
|
191
|
+
<ul class="tuneup-step-info">
|
192
|
+
<li class="tuneup-title">
|
193
|
+
<span class="time"><%= '%.2f' % (time * 1000) %> ms</span>
|
194
|
+
<a class='tuneup-step-name' title="<%=h name.to_s %>"><%=h name.to_s %></a>
|
195
|
+
<% if !extras.empty? %>
|
196
|
+
<a class='tuneup-step-extras-link'>(?)</a>
|
197
|
+
<% end %>
|
198
|
+
</li>
|
199
|
+
<li class="tuneup-detail-bar"><%= bar.to_html %></li>
|
200
|
+
<li style="clear: both;"/>
|
201
|
+
</ul>
|
202
|
+
<% if !extras.empty? %>
|
203
|
+
<div class='tuneup-step-extras'>
|
204
|
+
<div>
|
205
|
+
<dl>
|
206
|
+
<% extras.each do |extra| %>
|
207
|
+
<%= extra.to_html %>
|
208
|
+
<% end %>
|
209
|
+
</dl>
|
210
|
+
</div>
|
211
|
+
</div>
|
212
|
+
<% end %>
|
213
|
+
<%= html_children %>
|
214
|
+
</li>
|
215
|
+
)
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
def html_class
|
221
|
+
%W(fiveruns_tuneup_step #{'with_children' if children.any?} #{'tuneup-opened' if root.children.first.object_id == self.object_id}).compact.join(' ')
|
222
|
+
end
|
223
|
+
|
224
|
+
def html_children
|
225
|
+
return unless children.any?
|
226
|
+
%(<ul class='fiveruns_tuneup_children'>%s</ul>) % children_with_disparity.map { |child| child.to_html }.join
|
227
|
+
end
|
228
|
+
|
229
|
+
class Extra
|
230
|
+
include Templating
|
231
|
+
|
232
|
+
attr_reader :name, :content, :extended
|
233
|
+
def initialize(name, content, extended = {})
|
234
|
+
@name = name
|
235
|
+
@content = content
|
236
|
+
@extended = extended
|
237
|
+
end
|
238
|
+
|
239
|
+
def to_json
|
240
|
+
{:content => content, :extended => extended}.to_json
|
241
|
+
end
|
242
|
+
|
243
|
+
private
|
244
|
+
|
245
|
+
def template
|
246
|
+
%(
|
247
|
+
<dt><%= h name.to_s %></dt>
|
248
|
+
<dd>
|
249
|
+
<%= content %>
|
250
|
+
<% if extended.any? %>
|
251
|
+
<% extended.each do |name, value| %>
|
252
|
+
<div class='tuneup-step-extra-extended' title='<%= h name.to_s %>'><%= value %></div>
|
253
|
+
<% end %>
|
254
|
+
<% end %>
|
255
|
+
</dd>
|
256
|
+
)
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
class DisparityStep < Step
|
264
|
+
|
265
|
+
def initialize(layer_name, disparity)
|
266
|
+
super '(Other)', layer_name, {}, disparity
|
267
|
+
@extras = build_extras description
|
268
|
+
end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
def description
|
273
|
+
{
|
274
|
+
'What is this?' => %(
|
275
|
+
<p>
|
276
|
+
<b>Other</b> is the amount of time spent executing
|
277
|
+
code that TuneUp doesn't wrap to extract more information.
|
278
|
+
To reduce overhead and make the listing more
|
279
|
+
manageable, we don't generate steps for every operation.
|
280
|
+
</p>
|
281
|
+
<p>#{layer_description}</p>
|
282
|
+
)
|
283
|
+
}
|
284
|
+
end
|
285
|
+
|
286
|
+
def layer_description
|
287
|
+
case layer
|
288
|
+
when :model
|
289
|
+
"In the <i>model</i> layer, this is probably ORM overhead (out of your control)."
|
290
|
+
when :view
|
291
|
+
"In the <i>view</i> layer, this is probably framework overhead during render (out of your control)."
|
292
|
+
when :controller
|
293
|
+
%(
|
294
|
+
In the <i>controller</i> layer, this is probably framework overhead during action execution (out of your control),
|
295
|
+
or time spent executing your code in the action (calls to private methods, libraries, etc).
|
296
|
+
)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'zlib'
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'net/https'
|
5
|
+
|
6
|
+
$:.unshift(File.dirname(__FILE__))
|
7
|
+
|
8
|
+
require 'fiveruns/tuneup/templating'
|
9
|
+
require 'fiveruns/tuneup/step'
|
10
|
+
require 'fiveruns/tuneup/helpers'
|
11
|
+
require 'fiveruns/tuneup/bar'
|
12
|
+
require 'fiveruns/tuneup/panel'
|
13
|
+
require 'fiveruns/tuneup/run'
|
@@ -0,0 +1 @@
|
|
1
|
+
{"name":"Perform Index action in UsersController","time":90.2631282806396,"children":[{"name":"Before filter verify_authenticity_token","caller":[],"time":0.0331401824951172,"extras":{},"children":[],"layer":"controller"},{"name":"Before filter get_settings","caller":[],"time":6.44207000732422,"extras":{},"children":[{"name":"Find Setting","caller":[],"time":2.26306915283203,"extras":{},"children":[{"name":"Find Setting by SQL","caller":[],"time":1.82700157165527,"extras":{"Database Query":{"content":"SELECT * FROM \"settings\" LIMIT 1","extended":{}}},"children":[],"layer":"model"}],"layer":"model"}],"layer":"controller"},{"name":"Before filter auth_token_login","caller":[],"time":0.0472068786621094,"extras":{},"children":[],"layer":"controller"},{"name":"Before filter check_bans","caller":[],"time":0.00810623168945312,"extras":{},"children":[],"layer":"controller"},{"name":"Before filter check_privacy","caller":[],"time":3.39198112487793,"extras":{},"children":[],"layer":"controller"},{"name":"Before filter check_admin_only_create","caller":[],"time":0.281095504760742,"extras":{},"children":[{"name":"Invoke current_controller action","caller":[],"time":0.0150203704833984,"extras":{},"children":[],"layer":"controller"}],"layer":"controller"},{"name":"Before filter set_timezone","caller":[],"time":0.0388622283935547,"extras":{},"children":[],"layer":"controller"},{"name":"Before filter update_online_at","caller":[],"time":0.00810623168945312,"extras":{},"children":[],"layer":"controller"},{"name":"Before filter get_layout_vars","caller":[],"time":23.6580371856689,"extras":{},"children":[{"name":"Find User","caller":[],"time":0.960111618041992,"extras":{},"children":[{"name":"Find User by SQL","caller":[],"time":0.478029251098633,"extras":{"Database Query":{"content":"SELECT * FROM \"users\" ORDER BY users.id DESC LIMIT 1","extended":{}}},"children":[],"layer":"model"}],"layer":"model"}],"layer":"controller"},{"name":"Invoke index action","caller":[],"time":7.27701187133789,"extras":{},"children":[{"name":"Find User","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/vendor\/plugins\/will_paginate\/lib\/will_paginate\/finder.rb",82]],"time":1.47318840026855,"extras":{},"children":[{"name":"Find User by SQL","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/vendor\/plugins\/will_paginate\/lib\/will_paginate\/finder.rb",82]],"time":1.12009048461914,"extras":{"Database Query":{"content":"SELECT * FROM \"users\" ORDER BY profile_updated_at desc LIMIT 30 OFFSET 0","extended":{}}},"children":[],"layer":"model"}],"layer":"model"}],"layer":"controller"},{"name":"Render file users\/index","caller":[],"time":4.08506393432617,"extras":{},"children":[{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/users\/index.html.erb",1]],"time":0.0150203704833984,"extras":{},"children":[],"layer":"controller"}],"layer":"view"},{"name":"Render file layouts\/application","caller":[],"time":31.7168235778809,"extras":{},"children":[{"name":"Invoke current_action action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",30]],"time":0.00786781311035156,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",32]],"time":0.00596046447753906,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_action action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",30]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",32]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",12]],"time":0.00596046447753906,"extras":{},"children":[],"layer":"controller"},{"name":"Render shared\/reminders","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",16]],"time":2.88176536560059,"extras":{},"children":[{"name":"Render file shared\/reminders","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",16]],"time":2.61068344116211,"extras":{},"children":[{"name":"Find Event","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/reminders.html.erb",1]],"time":1.8608570098877,"extras":{},"children":[{"name":"Find Event by SQL","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/reminders.html.erb",1]],"time":0.553131103515625,"extras":{"Database Query":{"content":"SELECT * FROM \"events\" WHERE (\"events\".\"reminder\" = 't' AND \"events\".\"date\" BETWEEN '2008-10-05 21:30:02' AND '2008-10-06 05:30:02') ORDER BY date asc","extended":{}}},"children":[],"layer":"model"}],"layer":"model"}],"layer":"view"}],"layer":"view"},{"name":"Render shared\/tabs","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",20]],"time":2.75588035583496,"extras":{},"children":[{"name":"Render file shared\/tabs","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",20]],"time":2.49886512756348,"extras":{},"children":[{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.0119209289550781,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",59]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/helpers\/application_helper.rb",57]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"}],"layer":"view"}],"layer":"view"},{"name":"Render shared\/nav","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",23]],"time":0.870943069458008,"extras":{},"children":[{"name":"Render file shared\/nav","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",23]],"time":0.646829605102539,"extras":{},"children":[{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav.html.erb",38]],"time":0.00596046447753906,"extras":{},"children":[],"layer":"controller"}],"layer":"view"}],"layer":"view"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",24]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",25]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Render shared\/flash","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",26]],"time":0.363826751708984,"extras":{},"children":[{"name":"Render file shared\/flash","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",26]],"time":0.14495849609375,"extras":{},"children":[],"layer":"view"}],"layer":"view"},{"name":"Render shared\/nav2","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",28]],"time":8.07309150695801,"extras":{},"children":[{"name":"Render file shared\/nav2","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",28]],"time":7.85112380981445,"extras":{},"children":[{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",1]],"time":0.00596046447753906,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",14]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",24]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",32]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",46]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",52]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",60]],"time":0.003814697265625,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",68]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",75]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",87]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",98]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",112]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",118]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",125]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",133]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",145]],"time":0.00810623168945312,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",155]],"time":0.00476837158203125,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",165]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",177]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",185]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",191]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",201]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",208]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",215]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",229]],"time":0.00405311584472656,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",235]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",242]],"time":0.00476837158203125,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_action action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",242]],"time":0.00596046447753906,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",248]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_action action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",248]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_controller action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",256]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"},{"name":"Invoke current_action action","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/nav2.html.erb",256]],"time":0.00500679016113281,"extras":{},"children":[],"layer":"controller"}],"layer":"view"}],"layer":"view"},{"name":"Render shared\/stats","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",29]],"time":2.74991989135742,"extras":{},"children":[{"name":"Render file shared\/stats","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/layouts\/application.html.erb",29]],"time":2.48098373413086,"extras":{},"children":[{"name":"Find User","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/stats.html.erb",3]],"time":1.84106826782227,"extras":{},"children":[{"name":"Find User by SQL","caller":[["\/Users\/bruce\/git\/fiveruns\/el-dorado\/app\/views\/shared\/stats.html.erb",3]],"time":1.22594833374023,"extras":{"Database Query":{"content":"SELECT * FROM \"users\" WHERE (logged_out = 'f' and (online_at > '2008-10-05 23:25:02' or chatting_at > '2008-10-05 23:29:32')) ORDER BY login asc","extended":{}}},"children":[],"layer":"model"}],"layer":"model"}],"layer":"view"}],"layer":"view"}],"layer":"view"}]}
|
data/test/run_test.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.dirname(__FILE__) << "/test_helper"
|
2
|
+
|
3
|
+
class RunTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Persistence" do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@directory = File.expand_path(File.dirname(__FILE__) << "/tmp")
|
9
|
+
FileUtils.rm_rf @directory rescue nil
|
10
|
+
FileUtils.mkdir_p @directory
|
11
|
+
Fiveruns::Tuneup::Run.directory = @directory
|
12
|
+
@json = read_json :a
|
13
|
+
@root = Fiveruns::Tuneup::Step.load(@json)
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
FileUtils.rm_rf @directory rescue nil
|
18
|
+
end
|
19
|
+
|
20
|
+
context "using Run#save" do
|
21
|
+
setup do
|
22
|
+
setup_run
|
23
|
+
end
|
24
|
+
should "write to filesystem" do
|
25
|
+
assert_nothing_raised do
|
26
|
+
@run.save
|
27
|
+
end
|
28
|
+
assert_equal 1, Dir[File.join(@directory, '*')].size
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "loading" do
|
33
|
+
setup do
|
34
|
+
setup_run.save
|
35
|
+
end
|
36
|
+
should "create Run instances" do
|
37
|
+
assert_equal 1, Fiveruns::Tuneup::Run.all_for(@run.url).size
|
38
|
+
Fiveruns::Tuneup::Run.all_for(@run.url, :filename).each do |file|
|
39
|
+
data = File.open(file, 'rb') { |f| f.read }
|
40
|
+
assert_kind_of Fiveruns::Tuneup::Run, Fiveruns::Tuneup::Run.load(data)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def setup_run
|
50
|
+
@timestamp = 1223597107.58871
|
51
|
+
@run = Fiveruns::Tuneup::Run.new(
|
52
|
+
'http://localhost:3000',
|
53
|
+
@root,
|
54
|
+
Fiveruns::Tuneup::Run.environment,
|
55
|
+
Time.at(@timestamp)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/test/step_test.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) << "/test_helper"
|
2
|
+
|
3
|
+
class StepTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "loading from JSON" do
|
6
|
+
setup do
|
7
|
+
@json = read_json(:a)
|
8
|
+
@root = Fiveruns::Tuneup::Step.load(@json)
|
9
|
+
end
|
10
|
+
should "create a RootStep" do
|
11
|
+
assert_kind_of Fiveruns::Tuneup::RootStep, @root
|
12
|
+
assert_equal JSON.load(@json)['children'].size, @root.children.size
|
13
|
+
end
|
14
|
+
should "have normal children" do
|
15
|
+
@root.children.each do |child|
|
16
|
+
assert_normal_node(child)
|
17
|
+
assert_valid_extras(child)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_normal_node(node)
|
23
|
+
assert node.is_a?(Fiveruns::Tuneup::Step)
|
24
|
+
node.children.each do |child|
|
25
|
+
assert_normal_node(child)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def assert_valid_extras(node)
|
30
|
+
node.extras.each do |key, extra|
|
31
|
+
assert_kind_of String, key
|
32
|
+
assert_kind_of Fiveruns::Tuneup::Step::Extra, extra
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'shoulda'
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) << "/../lib/fiveruns_tuneup_core"
|
7
|
+
|
8
|
+
class Test::Unit::TestCase
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def read_json(name)
|
13
|
+
File.read(File.dirname(__FILE__) << "/fixtures/#{name}.json")
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fiveruns_tuneup_core
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- FiveRuns Development Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-11 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: json
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: echoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: FakeWeb
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: Shoulda
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
description: Core utilities for FiveRuns TuneUp panels
|
56
|
+
email: dev@fiveruns.com
|
57
|
+
executables: []
|
58
|
+
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files:
|
62
|
+
- lib/fiveruns/tuneup/bar.rb
|
63
|
+
- lib/fiveruns/tuneup/helpers.rb
|
64
|
+
- lib/fiveruns/tuneup/panel.rb
|
65
|
+
- lib/fiveruns/tuneup/run.rb
|
66
|
+
- lib/fiveruns/tuneup/step.rb
|
67
|
+
- lib/fiveruns/tuneup/templating.rb
|
68
|
+
- lib/fiveruns_tuneup_core.rb
|
69
|
+
files:
|
70
|
+
- lib/fiveruns/tuneup/bar.rb
|
71
|
+
- lib/fiveruns/tuneup/helpers.rb
|
72
|
+
- lib/fiveruns/tuneup/panel.rb
|
73
|
+
- lib/fiveruns/tuneup/run.rb
|
74
|
+
- lib/fiveruns/tuneup/step.rb
|
75
|
+
- lib/fiveruns/tuneup/templating.rb
|
76
|
+
- lib/fiveruns_tuneup_core.rb
|
77
|
+
- Manifest
|
78
|
+
- Rakefile
|
79
|
+
- test/fixtures/a.json
|
80
|
+
- test/run_test.rb
|
81
|
+
- test/step_test.rb
|
82
|
+
- test/test_helper.rb
|
83
|
+
- fiveruns_tuneup_core.gemspec
|
84
|
+
has_rdoc: true
|
85
|
+
homepage: http://tuneup.fiveruns.com
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options:
|
88
|
+
- --line-numbers
|
89
|
+
- --inline-source
|
90
|
+
- --title
|
91
|
+
- Fiveruns_tuneup_core
|
92
|
+
- --main
|
93
|
+
- README.rdoc
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: "0"
|
101
|
+
version:
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: "1.2"
|
107
|
+
version:
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project: fiveruns
|
111
|
+
rubygems_version: 1.3.0
|
112
|
+
signing_key:
|
113
|
+
specification_version: 2
|
114
|
+
summary: Core utilities for FiveRuns TuneUp panels
|
115
|
+
test_files:
|
116
|
+
- test/run_test.rb
|
117
|
+
- test/step_test.rb
|
118
|
+
- test/test_helper.rb
|