fakettp 0.2.4.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +6 -0
  2. data/README.rdoc +201 -0
  3. data/Rakefile +113 -0
  4. data/VERSION +1 -0
  5. data/features/control.feature +12 -0
  6. data/features/dashboard.feature +38 -0
  7. data/features/expectations.feature +27 -0
  8. data/features/expectations/expect_get +3 -0
  9. data/features/expectations/get_foo +3 -0
  10. data/features/expectations/get_root +3 -0
  11. data/features/expectations/pass_and_fail +5 -0
  12. data/features/expectations/set_response +5 -0
  13. data/features/step_definitions/expectations.rb +5 -0
  14. data/features/step_definitions/http.rb +42 -0
  15. data/features/step_definitions/simulator.rb +25 -0
  16. data/features/step_definitions/webrat_steps.rb +99 -0
  17. data/features/support/env.rb +5 -0
  18. data/features/support/fakettp.rb +2 -0
  19. data/features/support/paths.rb +12 -0
  20. data/features/support/xpath.rb +10 -0
  21. data/features/verification.feature +49 -0
  22. data/lib/fakettp/commands/fakettp_command.rb +31 -19
  23. data/lib/fakettp/controller.rb +12 -0
  24. data/lib/fakettp/db.rb +7 -0
  25. data/lib/fakettp/error.rb +6 -18
  26. data/lib/fakettp/expectation.rb +28 -44
  27. data/lib/fakettp/fakettp.yml +3 -0
  28. data/lib/fakettp/public/fakettp.css +33 -0
  29. data/lib/fakettp/schema.rb +14 -0
  30. data/lib/fakettp/simulator.rb +16 -10
  31. data/lib/fakettp/views/index.erb +14 -0
  32. data/spec/fakettp/commands/fakettp_command_spec.rb +128 -0
  33. data/spec/fakettp/controller_spec.rb +250 -0
  34. data/spec/fakettp/error_spec.rb +40 -0
  35. data/spec/fakettp/expectation_helper_spec.rb +33 -0
  36. data/spec/fakettp/expectation_spec.rb +142 -0
  37. data/spec/fakettp/simulator_spec.rb +149 -0
  38. data/spec/spec.opts +1 -0
  39. data/spec/spec_helper.rb +18 -0
  40. metadata +73 -24
  41. data/README.html +0 -113
@@ -0,0 +1,25 @@
1
+ Given /^the simulator is reset$/ do
2
+ req = Net::HTTP::Post.new '/reset'
3
+ Net::HTTP.new('fakettp.local').start {|http| http.request(req) }
4
+ end
5
+
6
+ Given /^we expect (\S*)$/ do |filename|
7
+ body = File.read(File.dirname(__FILE__) + "/../expectations/#{filename}")
8
+ req = Net::HTTP::Post.new '/expect', {'Content-Type' => 'text/plain'}
9
+ req.body = body
10
+ Net::HTTP.new('fakettp.local').start {|http| http.request(req) }
11
+ end
12
+
13
+ Then /^verifying the simulator should report success$/ do
14
+ req = Net::HTTP::Get.new '/verify'
15
+ resp = Net::HTTP.new('fakettp.local').start {|http| http.request(req) }
16
+ resp.body.should == "Verify OK\n"
17
+ resp.class.should == Net::HTTPOK
18
+ end
19
+
20
+ Then /^verifying the simulator should report a failure, with message "(.*)"$/ do |message|
21
+ req = Net::HTTP::Get.new '/verify'
22
+ resp = Net::HTTP.new('fakettp.local').start {|http| http.request(req) }
23
+ resp.body.should =~ Regexp.new(message, Regexp::MULTILINE)
24
+ resp.class.should == Net::HTTPInternalServerError
25
+ end
@@ -0,0 +1,99 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
2
+
3
+ # Commonly used webrat steps
4
+ # http://github.com/brynary/webrat
5
+
6
+ When /^I go to (.+)$/ do |page_name|
7
+ visit path_to(page_name)
8
+ end
9
+
10
+ When /^I press "(.*)"$/ do |button|
11
+ click_button(button)
12
+ end
13
+
14
+ When /^I follow "(.*)"$/ do |link|
15
+ click_link(link)
16
+ end
17
+
18
+ When /^I fill in "(.*)" with "(.*)"$/ do |field, value|
19
+ fill_in(field, :with => value)
20
+ end
21
+
22
+ When /^I select "(.*)" from "(.*)"$/ do |value, field|
23
+ select(value, :from => field)
24
+ end
25
+
26
+ # Use this step in conjunction with Rail's datetime_select helper. For example:
27
+ # When I select "December 25, 2008 10:00" as the date and time
28
+ When /^I select "(.*)" as the date and time$/ do |time|
29
+ select_datetime(time)
30
+ end
31
+
32
+ # Use this step when using multiple datetime_select helpers on a page or
33
+ # you want to specify which datetime to select. Given the following view:
34
+ # <%= f.label :preferred %><br />
35
+ # <%= f.datetime_select :preferred %>
36
+ # <%= f.label :alternative %><br />
37
+ # <%= f.datetime_select :alternative %>
38
+ # The following steps would fill out the form:
39
+ # When I select "November 23, 2004 11:20" as the "Preferred" data and time
40
+ # And I select "November 25, 2004 10:30" as the "Alternative" data and time
41
+ When /^I select "(.*)" as the "(.*)" date and time$/ do |datetime, datetime_label|
42
+ select_datetime(datetime, :from => datetime_label)
43
+ end
44
+
45
+ # Use this step in conjuction with Rail's time_select helper. For example:
46
+ # When I select "2:20PM" as the time
47
+ # Note: Rail's default time helper provides 24-hour time-- not 12 hour time. Webrat
48
+ # will convert the 2:20PM to 14:20 and then select it.
49
+ When /^I select "(.*)" as the time$/ do |time|
50
+ select_time(time)
51
+ end
52
+
53
+ # Use this step when using multiple time_select helpers on a page or you want to
54
+ # specify the name of the time on the form. For example:
55
+ # When I select "7:30AM" as the "Gym" time
56
+ When /^I select "(.*)" as the "(.*)" time$/ do |time, time_label|
57
+ select_time(time, :from => time_label)
58
+ end
59
+
60
+ # Use this step in conjuction with Rail's date_select helper. For example:
61
+ # When I select "February 20, 1981" as the date
62
+ When /^I select "(.*)" as the date$/ do |date|
63
+ select_date(date)
64
+ end
65
+
66
+ # Use this step when using multiple date_select helpers on one page or
67
+ # you want to specify the name of the date on the form. For example:
68
+ # When I select "April 26, 1982" as the "Date of Birth" date
69
+ When /^I select "(.*)" as the "(.*)" date$/ do |date, date_label|
70
+ select_date(date, :from => date_label)
71
+ end
72
+
73
+ When /^I check "(.*)"$/ do |field|
74
+ check(field)
75
+ end
76
+
77
+ When /^I uncheck "(.*)"$/ do |field|
78
+ uncheck(field)
79
+ end
80
+
81
+ When /^I choose "(.*)"$/ do |field|
82
+ choose(field)
83
+ end
84
+
85
+ When /^I attach the file at "(.*)" to "(.*)" $/ do |path, field|
86
+ attach_file(field, path)
87
+ end
88
+
89
+ Then /^I should see "(.*)"$/ do |text|
90
+ response.body.should =~ /#{text}/m
91
+ end
92
+
93
+ Then /^I should not see "(.*)"$/ do |text|
94
+ response.body.should_not =~ /#{text}/m
95
+ end
96
+
97
+ Then /^the "(.*)" checkbox should be checked$/ do |label|
98
+ field_labeled(label).should be_checked
99
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec/expectations'
2
+ require 'net/http'
3
+
4
+ FAKETTP_BASE = File.dirname(__FILE__) + '/../../install'
5
+ require 'fakettp'
@@ -0,0 +1,2 @@
1
+ require 'fakettp/expectation'
2
+
@@ -0,0 +1,12 @@
1
+ def path_to(page_name)
2
+ case page_name
3
+
4
+ when /the homepage/i
5
+ root_path
6
+
7
+ # Add more page name => path mappings here
8
+
9
+ else
10
+ raise "Can't find mapping from \"#{page_name}\" to a path."
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ require 'rexml/document'
2
+
3
+ def xml_node_values xml, xpath
4
+ begin
5
+ doc = REXML::Document.new(xml).root
6
+ REXML::XPath.match(doc, xpath).map { |node| (node.respond_to?(:value) ? node.value : node.text) }
7
+ rescue
8
+ raise "No #{xpath} found in response body (#{xml})"
9
+ end
10
+ end
@@ -0,0 +1,49 @@
1
+ Feature: Verification of expectations
2
+ Scenario: No expectations and no requests
3
+ Given the simulator is reset
4
+ Then verifying the simulator should report success
5
+
6
+ Scenario: Satisfied expectation
7
+ Given the simulator is reset
8
+ And we expect get_root
9
+ When we get / on foo.fake.local
10
+ Then verifying the simulator should report success
11
+
12
+ Scenario: Unsatisfied expectation
13
+ Given the simulator is reset
14
+ And we expect get_root
15
+ Then verifying the simulator should report a failure, with message "Expected request not received"
16
+
17
+ Scenario: Unexpected request
18
+ Given the simulator is reset
19
+ When we get / on foo.fake.local
20
+ Then verifying the simulator should report a failure, with message "Received unexpected request"
21
+
22
+ Scenario: Mismatched expectation
23
+ Given the simulator is reset
24
+ And we expect get_root
25
+ When we get /foo on foo.fake.local
26
+ Then verifying the simulator should report a failure, with message "Error in GET /: expected: "/",.*got: "/foo""
27
+
28
+ Scenario: Two satisfied expectations
29
+ Given the simulator is reset
30
+ And we expect get_root
31
+ And we expect get_foo
32
+ When we get / on foo.fake.local
33
+ And we get /foo on foo.fake.local
34
+ Then verifying the simulator should report success
35
+
36
+ Scenario: Two expectations, one satisfied
37
+ Given the simulator is reset
38
+ And we expect get_root
39
+ And we expect get_foo
40
+ When we get / on foo.fake.local
41
+ Then verifying the simulator should report a failure, with message "Expected request not received"
42
+
43
+ Scenario: Two expectations, with requests received in the wrong order
44
+ Given the simulator is reset
45
+ And we expect get_root
46
+ And we expect get_foo
47
+ When we get /foo on foo.fake.local
48
+ And we get / on foo.fake.local
49
+ Then verifying the simulator should report a failure, with message "Error in GET /: expected: "/",.*got: "/foo".*Error in GET /foo: expected: "/foo",.*got: "/""
@@ -6,7 +6,7 @@ module Fakettp
6
6
  end
7
7
 
8
8
  def run
9
- command = get_command
9
+ command = @args[0]
10
10
  return usage unless command
11
11
  case command
12
12
  when 'install' then
@@ -17,37 +17,49 @@ module Fakettp
17
17
  end
18
18
 
19
19
  private
20
-
21
- def get_command
22
- @args[0]
23
- end
24
20
 
25
21
  def install
26
- dir = get_dir
27
- return usage unless dir
28
- if File.exist? dir
29
- $stderr.puts "File or directory #{dir} already exists."
22
+ @directory, @hostname = @args[1..2]
23
+ return usage unless @directory && @hostname
24
+ if File.exist? @directory
25
+ $stderr.puts "File or directory #{@directory} already exists."
30
26
  return 1
31
27
  end
32
- FileUtils.mkdir_p dir + '/tmp/expectations', :mode => 0777
33
- FileUtils.mkdir_p dir + '/public'
34
- FileUtils.cp File.dirname(__FILE__) + '/../config.ru', dir
35
- FileUtils.cp File.dirname(__FILE__) + '/../../../README.html', dir
28
+ copy_files
29
+ write_config
30
+ create_database
36
31
  return 0
37
32
  end
38
-
39
- def get_dir
40
- @args[1]
41
- end
42
33
 
34
+ def copy_files
35
+ FileUtils.mkdir_p @directory + '/tmp', :mode => 0777
36
+ FileUtils.mkdir_p @directory + '/public'
37
+ FileUtils.cp File.dirname(__FILE__) + '/../config.ru', @directory
38
+ FileUtils.cp File.dirname(__FILE__) + '/../public/fakettp.css', @directory + '/public'
39
+ end
40
+
41
+ def write_config
42
+ config = {'database' => {'adapter' => 'sqlite3', 'database' => 'fakettp.sqlite3'},
43
+ 'hostname' => @hostname
44
+ }
45
+ File.open @directory + '/fakettp.yml', 'w' do |file|
46
+ file.write config.to_yaml
47
+ end
48
+ end
49
+
50
+ def create_database
51
+ system %(ruby -e "FAKETTP_BASE = '#{@directory}';load '#{File.dirname(__FILE__)}/../schema.rb'")
52
+ end
53
+
43
54
  def usage
44
55
  $stderr.puts <<-EOF
45
56
  Usage:
46
57
 
47
- [TODO]
58
+ fakettp install <directory> <hostname>
59
+
48
60
  EOF
49
61
  return 1
50
62
  end
51
63
  end
52
64
  end
53
- end
65
+ end
@@ -7,6 +7,12 @@ require 'fakettp/expectation_helper'
7
7
  require 'fakettp/simulator'
8
8
  require 'fakettp/expectation'
9
9
 
10
+ set :views, File.join(File.dirname(__FILE__), 'views')
11
+
12
+ config_file = File.join(FAKETTP_BASE, 'fakettp.yml')
13
+ config = File.read config_file
14
+ host = YAML.load(config)['hostname']
15
+
10
16
  include Fakettp::ExpectationHelper
11
17
 
12
18
  post '/expect', :host => 'fakettp.local' do
@@ -30,6 +36,12 @@ get '/verify', :host => 'fakettp.local' do
30
36
  end
31
37
  end
32
38
 
39
+ get '/', :host => 'fakettp.local' do
40
+ content_type 'text/html'
41
+ @expectations = Fakettp::Expectation.all
42
+ erb :index
43
+ end
44
+
33
45
  [:get, :post, :put, :delete, :head].each do |method|
34
46
  send method, '/**' do
35
47
  begin
data/lib/fakettp/db.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'activerecord'
2
+
3
+ RAILS_ROOT = FAKETTP_BASE
4
+
5
+ config = File.read(File.join(FAKETTP_BASE, 'fakettp.yml'))
6
+ db_config = YAML.load(config)['database']
7
+ ActiveRecord::Base.establish_connection db_config
data/lib/fakettp/error.rb CHANGED
@@ -1,23 +1,11 @@
1
1
  module Fakettp
2
- class Error
3
- ERROR_FILE = File.join FAKETTP_BASE, 'tmp', 'errors'
4
-
5
- def self.clear_all
6
- FileUtils.rm_rf ERROR_FILE
7
- end
8
-
9
- def self.<< message
10
- File.open ERROR_FILE, 'a' do |f|
11
- f.puts message
12
- end
13
- end
14
-
15
- def self.empty?
16
- !File.exists? ERROR_FILE
17
- end
18
-
2
+ class Error < ActiveRecord::Base
3
+ belongs_to :expectation
4
+
19
5
  def self.list
20
- empty? ? '' : File.read(ERROR_FILE)
6
+ errors = Error.all
7
+ return '' if errors.empty?
8
+ errors.map {|e| e.message}.join("\n") + "\n"
21
9
  end
22
10
  end
23
11
  end
@@ -1,56 +1,40 @@
1
+ require 'fakettp/db'
2
+
1
3
  module Fakettp
2
- class Expectation
3
- class Error < Exception; end
4
-
5
- EXPECTATION_DIR = File.join FAKETTP_BASE, 'tmp', 'expectations'
6
-
7
- def initialize contents
8
- @contents = contents
4
+ class Expectation < ActiveRecord::Base
5
+ set_table_name :expectations
6
+ has_many :errors
7
+
8
+ class Error < StandardError
9
+ attr_reader :line_number
10
+ def initialize message, line_number = nil
11
+ @line_number = line_number
12
+ super(message)
13
+ end
14
+ end
15
+
16
+ def render
17
+ if executed
18
+ span_class = errors.empty? ? 'pass' : 'fail'
19
+ %(<span class="#{span_class}">#{contents}</span>)
20
+ else
21
+ contents
22
+ end
9
23
  end
10
24
 
11
25
  def execute binding
12
- eval @contents, binding
26
+ self.executed = true
27
+ save
28
+ eval contents, binding
13
29
  # TODO: Include context of expectation file
14
30
  end
15
-
16
- def self.clear_all
17
- FileUtils.rm_rf Dir.glob(File.join(EXPECTATION_DIR, '*'))
18
- end
19
-
20
- def self.empty?
21
- files.empty?
22
- end
23
-
24
- def self.<< expectation
25
- File.open next_file_to_create, 'w' do |f|
26
- f.write expectation
27
- end
31
+
32
+ def self.all_received?
33
+ !exists? :executed => false
28
34
  end
29
35
 
30
36
  def self.next
31
- file = next_file_to_read
32
- contents = File.read file
33
- FileUtils.rm file
34
- Expectation.new contents
35
- end
36
-
37
- private
38
-
39
- def self.next_file_to_create
40
- name = (files.last.to_i + 1).to_s
41
- File.join EXPECTATION_DIR, name
42
- end
43
-
44
- def self.next_file_to_read
45
- name = files.first
46
- raise Error.new('Received unexpected request') unless name
47
- File.join EXPECTATION_DIR, name
48
- end
49
-
50
- def self.files
51
- (Dir.entries(EXPECTATION_DIR) - ['.', '..']).sort_by {|a| a.to_i}
37
+ find_by_executed(false)
52
38
  end
53
-
54
- private_class_method :next_file_to_create, :next_file_to_read, :files
55
39
  end
56
40
  end
@@ -0,0 +1,3 @@
1
+ database:
2
+ adapter: sqlite3
3
+ database: fakettp.sqlite3