deja-vu 0.3

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.
Files changed (34) hide show
  1. data/Change.log +4 -0
  2. data/LICENSE +19 -0
  3. data/Makefile +0 -0
  4. data/README +22 -0
  5. data/Rakefile +31 -0
  6. data/example-playback/README +6 -0
  7. data/example-playback/analysis.rb +7 -0
  8. data/example-playback/playback.rb +7 -0
  9. data/example-playback/repo/recordings/DejaVuNS/DejaVu/recordings +1 -0
  10. data/example-playback/repo/recordings/DejaVuNS/Recording/bah7aa==/n--ab7689c618445bb17b626741588b50c0500c8f79 +1 -0
  11. data/example/Makefile +6 -0
  12. data/example/config.ru +9 -0
  13. data/example/deja-vu-recordings/6b44093baa40d257106bae6dbcda53af9a57e61f.session +53 -0
  14. data/example/deja-vu-recordings/BAh7AA==/n--ab7689c618445bb17b626741588b50c0500c8f79.session +598 -0
  15. data/example/deja-vu-recordings/README +1 -0
  16. data/example/myapp.rb +15 -0
  17. data/example/repo/recordings/DejaVuNS/DejaVu/recordings +1 -0
  18. data/example/repo/recordings/DejaVuNS/Recording/bah7aa==/n--ab7689c618445bb17b626741588b50c0500c8f79 +1 -0
  19. data/example/views/index.haml +0 -0
  20. data/example/views/layout.haml +0 -0
  21. data/lib/deja-vu.rb +72 -0
  22. data/lib/deja-vu/analyzer.rb +133 -0
  23. data/lib/deja-vu/init.rb +3 -0
  24. data/lib/deja-vu/model/dejavu.rb +42 -0
  25. data/lib/deja-vu/model/generated_model/DejaVuNS.rb +1536 -0
  26. data/lib/deja-vu/model/init.rb +3 -0
  27. data/lib/deja-vu/model/record.rb +58 -0
  28. data/lib/deja-vu/model/recording.rb +55 -0
  29. data/lib/deja-vu/model/xampl-gen.rb +39 -0
  30. data/lib/deja-vu/model/xml/dejavu.xml +28 -0
  31. data/lib/deja-vu/player.rb +241 -0
  32. data/lib/deja-vu/recorder.rb +93 -0
  33. data/lib/rack-session-listener.rb +29 -0
  34. metadata +94 -0
@@ -0,0 +1,3 @@
1
+ require ~'dejavu'
2
+ require ~'recording'
3
+ require ~'record'
@@ -0,0 +1,58 @@
1
+ require 'patron'
2
+
3
+ module DejaVuNS
4
+ class Record
5
+ =begin
6
+ <recording pid=""
7
+ cookie=""
8
+ stamp=""
9
+ agent="">
10
+
11
+ <record id=""
12
+ stamp=""
13
+ status=""
14
+ httpmethod=""
15
+ url=""
16
+ request-time="">
17
+ =end
18
+
19
+ # def initialize(pid)
20
+ # super
21
+ # assign_agent('Deja-Vu/1.0')
22
+ # end
23
+
24
+ def assign_agent(agent)
25
+ unless defined? @sess
26
+ @sess = Patron::Session.new
27
+ @sess.timeout = 10
28
+ @sess.headers['User-Agent'] = agent
29
+ end
30
+ end
31
+
32
+ def execute_as(agent = nil)
33
+ assign_agent(agent) if agent
34
+
35
+ resp = nil
36
+ case self.httpmethod
37
+ when 'GET'
38
+ resp = @sess.get(self.url)
39
+ when 'POST'
40
+ resp = @sess.post(self.url)
41
+ when 'PUT'
42
+ resp = @sess.put(self.url)
43
+ when 'DELETE'
44
+ resp = @sess.delete(self.url)
45
+ end
46
+
47
+ return resp
48
+
49
+ # if resp.status < 400
50
+ # puts resp.body
51
+ # end
52
+ # sess.put("/foo/baz", "some data")
53
+ # sess.delete("/foo/baz")
54
+ # sess.post("/foo/stuff", "some data", {"Content-Type" => "text/plain"})
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,55 @@
1
+ =begin
2
+ <recording pid=""
3
+ cookie=""
4
+ stamp=""
5
+ agent="">
6
+
7
+ <record id=""
8
+ stamp=""
9
+ status=""
10
+ method=""
11
+ url=""
12
+ request-time="">
13
+
14
+ <header name="" value=""/>
15
+
16
+ <body><![CDATA[HTML OR WHATEVER HERE]]></body>
17
+
18
+ <param name="" value=""/>
19
+
20
+ <multipart-reference name="" file-path=""/>
21
+
22
+ </record>
23
+
24
+ </recording>
25
+ =end
26
+ module DejaVuNS
27
+ class Recording
28
+
29
+ def self.find_by_identifier(ident)
30
+ DejaVuNS.root.recording.each do |rec|
31
+ return rec if rec.cookie == ident
32
+ end
33
+ nil
34
+ end
35
+
36
+ def self.find_by_pid(pid)
37
+ rec = nil
38
+ DejaVuNS.transaction do
39
+ rec = DejaVuNS.root.recording[pid]
40
+ end
41
+ rec
42
+ end
43
+
44
+ def self.all_recordings
45
+ recordings = []
46
+ DejaVuNS.transaction do
47
+ DejaVuNS.root.recording.each do |rec|
48
+ recordings << rec
49
+ end
50
+ end
51
+ recordings
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby -w -I..
2
+
3
+ if $0 == __FILE__ then
4
+
5
+ class File
6
+ def File.sjoin(*args)
7
+ File.join(args.select{ | o | o })
8
+ end
9
+ end
10
+
11
+ require 'xampl-generator'
12
+
13
+ include XamplGenerator
14
+ include Xampl
15
+
16
+ Xampl.transaction("setup", :in_memory) do
17
+ directory = File.sjoin(".", "generated_model")
18
+
19
+ the_options = Xampl.make(Options) { | options |
20
+ options.new_index_attribute("pid").persisted = true
21
+ options.new_index_attribute("id")
22
+ options.resolve("http://soldierofcode.com/deja-vu", "DejaVuNS", 'dejavu')
23
+ }
24
+
25
+ filenames = Dir.glob("./xml/**/*.xml")
26
+
27
+ generator = Generator.new
28
+ generator.go(:options => the_options,
29
+ :filenames => filenames,
30
+ :directory => directory)
31
+
32
+ #puts generator.print_elements("./generated-elements.xml")
33
+
34
+ $LOAD_PATH.unshift(directory)
35
+
36
+ exit!
37
+ end
38
+
39
+ end
@@ -0,0 +1,28 @@
1
+ <deja-vu xmlns="http://soldierofcode.com/deja-vu" pid="">
2
+
3
+ <recording pid=""
4
+ cookie=""
5
+ stamp=""
6
+ agent=""
7
+ ip="">
8
+
9
+ <record id=""
10
+ stamp=""
11
+ status=""
12
+ httpmethod=""
13
+ url=""
14
+ request-time="">
15
+
16
+ <header name="" value=""/>
17
+
18
+ <body><![CDATA[HTML OR WHATEVER HERE]]></body>
19
+
20
+ <param name="" value=""/>
21
+
22
+ <multipart-reference name="" file-path=""/>
23
+
24
+ </record>
25
+
26
+ </recording>
27
+
28
+ </deja-vu>
@@ -0,0 +1,241 @@
1
+ require ~'model/init'
2
+ require 'patron'
3
+
4
+ module SoldierOfCode
5
+ module DejaVu
6
+
7
+ #
8
+ # Should do the following:
9
+ # - be configurable in
10
+ # - ignore/respect time between requests
11
+ # - ignore/call specific mime type calls (like favicon.ico etc) - css,js etc too
12
+ # - use webrat, curl, wget ...
13
+ # - turn on step through (interactive control of when requests are made)
14
+ # - display server log on each step or not
15
+ #
16
+ class Player
17
+
18
+ attr_accessor :respect_timings, :mime_ignore, :mime_watch, :use_client, :step_through, :display_log
19
+
20
+ def initialize(recording_pid=nil, opts={:respect_timings=>'yes'})
21
+
22
+ # @recording = DejaVuNS::Recording.find_by_pid(recording_pid)
23
+ # @recordings = DejaVuNS::Recording.find_by_pid(recording_pid)
24
+ @recordings = []
25
+ unless recording_pid
26
+ # anlyize all the recordings as a mass
27
+ DejaVuNS::Recording.all_recordings.each do |rec|
28
+ @recordings << rec
29
+ end
30
+ else
31
+ # only analyize overview of the provided pid
32
+ @recordings << DejaVuNS::Recording.find_by_pid(recording_pid)
33
+ end
34
+
35
+ @start_time = opts[:start_time]
36
+ @end_time = opts[:end_time]
37
+ @respect_timings = ('yes' == opts[:respect_timings])
38
+
39
+ # @mime_ignore = opts[:mime_ignore] # => is an array of mime types to ignore
40
+ # @mime_watch = opts[:mime_watch] # => is an array of mime types to exeucte
41
+ # @use_client = opts[:use_client] # => what client interface to use
42
+
43
+ # @step_through = ('yes'==opts[:step_through])
44
+ # @display_log = ('yes'==opts[:display_log])
45
+
46
+ @current_step = 0
47
+
48
+ @frames = []
49
+ build_frames
50
+ end
51
+
52
+ def build_frames
53
+ @recordings.each do |rec|
54
+ rec.record.each do |record|
55
+ if @start_time && !@end_time && record.stamp.to_i >= @start_time # only a start stamp is provided so add all upto this date
56
+ @frames << RequestFrame.new(rec,record)
57
+ elsif @start_time && @end_time && record.stamp.to_i >= @start_time && record.stamp.to_i <= @end_time # start and end stamps provided (envelope of time)
58
+ @frames << RequestFrame.new(rec,record)
59
+ elsif !@start_time && @end_time && record.stamp.to_i <= @end_time # Just an end time provided - everthing upto this time stamp
60
+ @frames << RequestFrame.new(rec,record)
61
+ elsif !@start_time && !@end_time
62
+ @frames << RequestFrame.new(rec,record)
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+ def play
70
+ # plays all frames
71
+ resps = []
72
+ last_time_stamp = @frames.first.stamp.to_i
73
+ @frames.each do |frame|
74
+
75
+ resps << frame.invoke
76
+ last_time_delta = frame.stamp.to_i - last_time_stamp
77
+ last_time_stamp = frame.stamp.to_i
78
+ if @respect_timings then
79
+ puts "#{__FILE__}:#{__LINE__} #{__method__} LAST DELTA: #{last_time_delta} --- CURRENT: #{Time.new.to_i}"
80
+ # local_delta = last_time_delta / 1000.0
81
+ # if local_delta > 1
82
+ # sleep(local_delta)
83
+ # end
84
+ sleep(last_time_delta)
85
+ end
86
+ end
87
+ puts "#{__FILE__}:#{__LINE__} #{__method__} RESPS: #{resps.inspect}"
88
+ resps
89
+ end
90
+
91
+
92
+ def play_frame
93
+ return nil unless @frames
94
+
95
+ return if @current_step > @frames.size
96
+
97
+ frame = @frames[@current_step]
98
+
99
+ resp = frame.invoke
100
+
101
+ @current_step += 1
102
+
103
+ resp
104
+
105
+ end
106
+
107
+ def fast_forward(x=1)
108
+ @current_step += x
109
+ end
110
+
111
+ def rewind(x=1)
112
+ @current_step -= x
113
+ @current_step = 0 if @current_step < 0
114
+ end
115
+ end
116
+
117
+ class RequestFrame
118
+ attr_accessor :url, :response, :status_code, :record, :agent
119
+
120
+ def initialize(recording, record)
121
+ assign_agent(recording.agent)
122
+ @record = record
123
+ @url = record.url
124
+ @status_code = 0
125
+ @response = nil
126
+ end
127
+
128
+ def invoke
129
+ resp = execute_as
130
+ @status_code = @response.status
131
+ resp
132
+ end
133
+
134
+ def stamp
135
+ @record.stamp
136
+ end
137
+
138
+ def httpmethod
139
+ @record.httpmethod
140
+ end
141
+
142
+ def request_time
143
+ @record.request_time
144
+ end
145
+
146
+ def assign_agent(agent)
147
+ unless defined? @sess
148
+ @sess = Patron::Session.new
149
+ @sess.timeout = 10
150
+ @sess.headers['User-Agent'] = agent
151
+ end
152
+ end
153
+
154
+ def execute_as(agent = nil)
155
+ assign_agent(agent) if agent
156
+
157
+ @response = nil
158
+ case self.httpmethod
159
+ when 'GET'
160
+ @response = @sess.get(self.url)
161
+ when 'POST'
162
+ @response = @sess.post(self.url)
163
+ when 'PUT'
164
+ @response = @sess.put(self.url)
165
+ when 'DELETE'
166
+ @response = @sess.delete(self.url)
167
+ end
168
+
169
+ return @response
170
+ end
171
+
172
+ end
173
+ end
174
+ end
175
+
176
+ =begin
177
+ def initialize
178
+
179
+ end
180
+
181
+
182
+ def overview(specific_recording_pid=nil, start_stamp=nil, end_stamp=nil)
183
+
184
+ recordings = []
185
+ unless specific_recording_pid
186
+ # anlyize all the recordings as a mass
187
+ DejaVuNS::Recording.all_recordings.each do |rec|
188
+ recordings << rec
189
+ end
190
+ else
191
+ # only analyize overview of the provided pid
192
+ recordings << DejaVuNS::Recording.find_by_pid(specific_recording_pid)
193
+ end
194
+
195
+ perform_overview(recordings, start_stamp, end_stamp)
196
+
197
+ end
198
+
199
+ def perform_overview(recordings, start_stamp=nil, end_stamp=nil)
200
+
201
+ analysis = Analysis.new
202
+
203
+ analysis.analysis_title = "Single User: #{recordings.first.ip}"
204
+
205
+ records = []
206
+ recordings.each do |rec|
207
+
208
+ analysis.add_user
209
+
210
+ rec.record.each do |record|
211
+ if start_stamp && !end_stamp && record.stamp.to_i >= start_stamp # only a start stamp is provided so add all upto this date
212
+ records << record
213
+ elsif start_stamp && end_stamp && record.stamp.to_i >= start_stamp && record.stamp.to_i <= end_stamp # start and end stamps provided (envelope of time)
214
+ records << record
215
+ elsif !start_stamp && end_stamp && record.stamp.to_i <= end_stamp # Just an end time provided - everthing upto this time stamp
216
+ records << record
217
+ elsif !start_stamp && !end_stamp
218
+ records << record
219
+ end
220
+ end
221
+ end
222
+
223
+ # these are vetted against the stamps
224
+ urls_seen = []
225
+ records.each do |record|
226
+
227
+ analysis.add_request(record.request_time.to_f)
228
+
229
+ unless urls_seen.include?(record.url)
230
+ analysis.add_unique
231
+ urls_seen << record.url
232
+ end
233
+
234
+ analysis.add_error if record.status.to_i >= 400
235
+
236
+ end
237
+
238
+ analysis
239
+ end
240
+
241
+ =end
@@ -0,0 +1,93 @@
1
+ require ~'model/init'
2
+
3
+ module SoldierOfCode
4
+ module DejaVu
5
+ class Recorder
6
+
7
+ # @@writing = {} unless defined? @@writing
8
+ #
9
+ # def self.writing?(file_name)
10
+ # @@writing[file_name]
11
+ # end
12
+ attr_accessor :identifier
13
+
14
+ def initialize(opt)
15
+ @identifier = opt['cookie_name']
16
+ @opt = opt
17
+ end
18
+
19
+ def export(to_file_named)
20
+ # TODO -- IMPLEMENT THIS
21
+ end
22
+
23
+ #
24
+ #
25
+ #
26
+ def record(env, resp, req, start_time, end_time, identifier)
27
+
28
+ # status, headers, body
29
+ # resp[0], resp[1], resp[2]
30
+
31
+ # 1. try to locate the recording
32
+ recording = nil
33
+ DejaVuNS.transaction do
34
+ recording = DejaVuNS::Recording.find_by_identifier(@identifier)
35
+
36
+ # puts "#{__FILE__}:#{__LINE__} #{__method__} #{recording.class.name}"
37
+ # 1.b if not found then create a new one
38
+ unless recording
39
+ recording = DejaVuNS.root.new_recording(DejaVuNS.pid_from_string(@identifier||identifier))
40
+ recording.cookie = req.cookies[@identifier||identifier]
41
+ recording.stamp = Time.new.to_i
42
+ recording.agent = env['HTTP_USER_AGENT']
43
+ recording.ip = env['REMOTE_ADDR']
44
+ end
45
+
46
+ # 2. create a new record
47
+ # puts "#{__FILE__}:#{__LINE__} #{__method__} #{recording.class.name}"
48
+ record = recording.new_record("#{Time.new.to_i}")
49
+ record.stamp = "#{Time.new.to_i}"
50
+ record.status = "#{resp[0]}"
51
+ record.httpmethod = env['REQUEST_METHOD']
52
+ record.url = "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}#{env['REQUEST_URI']}"
53
+ record.request_time = ("#{end_time.to_i}.#{end_time.usec}".to_f - "#{start_time.to_i}.#{start_time.usec}".to_f).to_s
54
+
55
+ # 3. add the body etc elements
56
+ resp[1].each do |k, v|
57
+ h = record.new_header
58
+ h.name = k
59
+ h.value = v
60
+ end
61
+
62
+ record.new_body().content = "<![CDATA[#{resp[2]}]]>"
63
+
64
+ if req.post? && env['CONTENT_TYPE'] =~ %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n
65
+ # its multipart
66
+ # <multipart-reference name="" file-path=""/>
67
+ # can I grab it off the env object?
68
+ puts "#{__FILE__}:#{__LINE__} #{__method__} NOT IMPLEMENTED - MULTIPART"
69
+ else
70
+ # safe param recording
71
+ req.params.each do |k,v|
72
+ p = record.new_param()
73
+ p.name = k
74
+ p.value = v
75
+ end
76
+
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ def identifier_change(new_identifier)
83
+ DejaVuNS.transaction do
84
+ recording = DejaVuNS::Recording.find_by_identifier(@identifier)
85
+ if recording
86
+ @identifier = new_identifier
87
+ recording.cookie = new_identifier
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end