fakettp 0.2.4.1 → 0.3.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.
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