deja-vu 0.3

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