amos 0.0.3 → 0.0.4

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 (44) hide show
  1. data/README.rdoc +20 -3
  2. data/app/controllers/amos_controller.rb +36 -1
  3. data/config/initializers/per_page.rb +5 -0
  4. data/config/routes.rb +1 -0
  5. data/lib/amos.rb +1 -0
  6. data/lib/amos/pagination.rb +18 -0
  7. data/spec/controllers/amos_controller_spec.rb +680 -0
  8. data/spec/factories.rb +13 -0
  9. data/spec/models/per_page_spec.rb +29 -0
  10. data/test/dummy/app/controllers/application_controller.rb +3 -0
  11. data/test/dummy/app/helpers/application_helper.rb +2 -0
  12. data/test/dummy/app/models/ability.rb +13 -0
  13. data/test/dummy/app/models/recipe.rb +3 -0
  14. data/test/dummy/app/models/user.rb +4 -0
  15. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  16. data/test/dummy/config/application.rb +45 -0
  17. data/test/dummy/config/boot.rb +10 -0
  18. data/test/dummy/config/cucumber.yml +8 -0
  19. data/test/dummy/config/database.yml +25 -0
  20. data/test/dummy/config/environment.rb +5 -0
  21. data/test/dummy/config/environments/development.rb +26 -0
  22. data/test/dummy/config/environments/production.rb +49 -0
  23. data/test/dummy/config/environments/test.rb +35 -0
  24. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  25. data/test/dummy/config/initializers/inflections.rb +10 -0
  26. data/test/dummy/config/initializers/mime_types.rb +5 -0
  27. data/test/dummy/config/initializers/secret_token.rb +7 -0
  28. data/test/dummy/config/initializers/session_store.rb +8 -0
  29. data/test/dummy/config/locales/en.yml +5 -0
  30. data/test/dummy/config/routes.rb +2 -0
  31. data/test/dummy/db/migrate/20110930092258_create_user.rb +15 -0
  32. data/test/dummy/db/migrate/20111002092333_create_recipes.rb +16 -0
  33. data/test/dummy/db/migrate/20111003063458_add_user_id_to_recipe.rb +9 -0
  34. data/test/dummy/features/amos.feature +160 -0
  35. data/test/dummy/features/paginate.feature +119 -0
  36. data/test/dummy/features/security.feature +59 -0
  37. data/test/dummy/features/step_definitions/pickle_steps.rb +100 -0
  38. data/test/dummy/features/step_definitions/user_steps.rb +57 -0
  39. data/test/dummy/features/support/env.rb +50 -0
  40. data/test/dummy/features/support/pickle.rb +26 -0
  41. data/test/spec_helper.rb +37 -0
  42. data/test/support/integration_case.rb +5 -0
  43. data/test/test_helper.rb +17 -0
  44. metadata +74 -18
@@ -0,0 +1,119 @@
1
+ Feature: Paginate results
2
+ In order access large datasets the server
3
+ should return paginated data
4
+
5
+ Background:
6
+ Given 20 users exist
7
+ And I have setup my ability class
8
+ """
9
+ class Ability
10
+ include CanCan::Ability
11
+
12
+ def initialize(user)
13
+ can :manage, :all
14
+ end
15
+ end
16
+ """
17
+ And I am not logged in
18
+
19
+ Scenario: List users with no pagination
20
+ When the client requests GET /user
21
+ Then the response should be JSON:
22
+ """
23
+ [
24
+ {"name": "J Smith", "email": "smith@smith.com", "id": 1},
25
+ {"name": "J Smith", "email": "smith@smith.com", "id": 2},
26
+ {"name": "J Smith", "email": "smith@smith.com", "id": 3},
27
+ {"name": "J Smith", "email": "smith@smith.com", "id": 4},
28
+ {"name": "J Smith", "email": "smith@smith.com", "id": 5},
29
+ {"name": "J Smith", "email": "smith@smith.com", "id": 6},
30
+ {"name": "J Smith", "email": "smith@smith.com", "id": 7},
31
+ {"name": "J Smith", "email": "smith@smith.com", "id": 8},
32
+ {"name": "J Smith", "email": "smith@smith.com", "id": 9},
33
+ {"name": "J Smith", "email": "smith@smith.com", "id": 10},
34
+ {"name": "J Smith", "email": "smith@smith.com", "id": 11},
35
+ {"name": "J Smith", "email": "smith@smith.com", "id": 12},
36
+ {"name": "J Smith", "email": "smith@smith.com", "id": 13},
37
+ {"name": "J Smith", "email": "smith@smith.com", "id": 14},
38
+ {"name": "J Smith", "email": "smith@smith.com", "id": 15},
39
+ {"name": "J Smith", "email": "smith@smith.com", "id": 16},
40
+ {"name": "J Smith", "email": "smith@smith.com", "id": 17},
41
+ {"name": "J Smith", "email": "smith@smith.com", "id": 18},
42
+ {"name": "J Smith", "email": "smith@smith.com", "id": 19},
43
+ {"name": "J Smith", "email": "smith@smith.com", "id": 20}
44
+ ]
45
+ """
46
+
47
+ Scenario: List users with pagination
48
+ Given pagination is set for "User" model
49
+ And there are 10 items per page
50
+ When the client requests GET /user
51
+ Then the response should be JSON:
52
+ """
53
+ [
54
+ {"name": "J Smith", "email": "smith@smith.com", "id": 1},
55
+ {"name": "J Smith", "email": "smith@smith.com", "id": 2},
56
+ {"name": "J Smith", "email": "smith@smith.com", "id": 3},
57
+ {"name": "J Smith", "email": "smith@smith.com", "id": 4},
58
+ {"name": "J Smith", "email": "smith@smith.com", "id": 5},
59
+ {"name": "J Smith", "email": "smith@smith.com", "id": 6},
60
+ {"name": "J Smith", "email": "smith@smith.com", "id": 7},
61
+ {"name": "J Smith", "email": "smith@smith.com", "id": 8},
62
+ {"name": "J Smith", "email": "smith@smith.com", "id": 9},
63
+ {"name": "J Smith", "email": "smith@smith.com", "id": 10}
64
+ ]
65
+ """
66
+ When the client requests GET /user?page=2
67
+ Then the response should be JSON:
68
+ """
69
+ [
70
+ {"name": "J Smith", "email": "smith@smith.com", "id": 11},
71
+ {"name": "J Smith", "email": "smith@smith.com", "id": 12},
72
+ {"name": "J Smith", "email": "smith@smith.com", "id": 13},
73
+ {"name": "J Smith", "email": "smith@smith.com", "id": 14},
74
+ {"name": "J Smith", "email": "smith@smith.com", "id": 15},
75
+ {"name": "J Smith", "email": "smith@smith.com", "id": 16},
76
+ {"name": "J Smith", "email": "smith@smith.com", "id": 17},
77
+ {"name": "J Smith", "email": "smith@smith.com", "id": 18},
78
+ {"name": "J Smith", "email": "smith@smith.com", "id": 19},
79
+ {"name": "J Smith", "email": "smith@smith.com", "id": 20}
80
+ ]
81
+ """
82
+
83
+ Scenario: List users using dynamic finder and pagination
84
+ Given pagination is set for "User" model
85
+ And there are 10 items per page
86
+ When the client requests GET /users/find/by_name?term=J%20Smith
87
+ Then the response should be JSON:
88
+ """
89
+ [
90
+ {"name": "J Smith", "email": "smith@smith.com", "id": 1},
91
+ {"name": "J Smith", "email": "smith@smith.com", "id": 2},
92
+ {"name": "J Smith", "email": "smith@smith.com", "id": 3},
93
+ {"name": "J Smith", "email": "smith@smith.com", "id": 4},
94
+ {"name": "J Smith", "email": "smith@smith.com", "id": 5},
95
+ {"name": "J Smith", "email": "smith@smith.com", "id": 6},
96
+ {"name": "J Smith", "email": "smith@smith.com", "id": 7},
97
+ {"name": "J Smith", "email": "smith@smith.com", "id": 8},
98
+ {"name": "J Smith", "email": "smith@smith.com", "id": 9},
99
+ {"name": "J Smith", "email": "smith@smith.com", "id": 10}
100
+ ]
101
+ """
102
+
103
+ When the client requests GET /users/find/by_name?term=J%20Smith&page=2
104
+ Then the response should be JSON:
105
+ """
106
+ [
107
+ {"name": "J Smith", "email": "smith@smith.com", "id": 11},
108
+ {"name": "J Smith", "email": "smith@smith.com", "id": 12},
109
+ {"name": "J Smith", "email": "smith@smith.com", "id": 13},
110
+ {"name": "J Smith", "email": "smith@smith.com", "id": 14},
111
+ {"name": "J Smith", "email": "smith@smith.com", "id": 15},
112
+ {"name": "J Smith", "email": "smith@smith.com", "id": 16},
113
+ {"name": "J Smith", "email": "smith@smith.com", "id": 17},
114
+ {"name": "J Smith", "email": "smith@smith.com", "id": 18},
115
+ {"name": "J Smith", "email": "smith@smith.com", "id": 19},
116
+ {"name": "J Smith", "email": "smith@smith.com", "id": 20}
117
+ ]
118
+ """
119
+
@@ -0,0 +1,59 @@
1
+ Feature: Security
2
+ In order access to the data secure
3
+ I need to be able to specify some access control
4
+
5
+
6
+ Background:
7
+ Given the following users exists
8
+ | name | email |
9
+ | J Smith | smith@smith.com |
10
+ | B Bloggs | b@bloggs.com |
11
+ And the following recipes exists
12
+ | name | description |
13
+ | Shopping | Go to the shops |
14
+ | Cakes | Buy stuff |
15
+ | Clean | Hoover room |
16
+ And "Shopping" belongs to "J Smith"
17
+ And "Cakes" belongs to "B Bloggs"
18
+ And "Clean" belongs to "J Smith"
19
+
20
+
21
+ Scenario: Allowing access to all data
22
+ Given I have setup my ability class
23
+ """
24
+ class Ability
25
+ include CanCan::Ability
26
+
27
+ def initialize(user)
28
+ can :manage, :all
29
+ end
30
+ end
31
+ """
32
+ And I am not logged in
33
+ When the client requests GET /user
34
+ Then the response should be JSON:
35
+ """
36
+ [
37
+ {"name": "J Smith", "email": "smith@smith.com", "id": 1},
38
+ {"name": "B Bloggs", "email": "b@bloggs.com", "id": 2}
39
+ ]
40
+ """
41
+
42
+ Scenario: Denying access to all data
43
+ Given I have setup my ability class
44
+ """
45
+ class Ability
46
+ include CanCan::Ability
47
+
48
+ def initialize(user)
49
+ cannot :manage, :all
50
+ end
51
+ end
52
+ """
53
+ And I am not logged in
54
+ When the client requests GET /user
55
+ Then the response should be status "401" with JSON:
56
+ """
57
+ {"error" : "You are not authorized to access this data"}
58
+ """
59
+
@@ -0,0 +1,100 @@
1
+ # this file generated by script/generate pickle
2
+
3
+ # create a model
4
+ Given(/^#{capture_model} exists?(?: with #{capture_fields})?$/) do |name, fields|
5
+ create_model(name, fields)
6
+ end
7
+
8
+ # create n models
9
+ Given(/^(\d+) #{capture_plural_factory} exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
10
+ count.to_i.times { create_model(plural_factory.singularize, fields) }
11
+ end
12
+
13
+ # create models from a table
14
+ Given(/^the following #{capture_plural_factory} exists?:?$/) do |plural_factory, table|
15
+ create_models_from_table(plural_factory, table)
16
+ end
17
+
18
+ # find a model
19
+ Then(/^#{capture_model} should exist(?: with #{capture_fields})?$/) do |name, fields|
20
+ find_model!(name, fields)
21
+ end
22
+
23
+ # not find a model
24
+ Then(/^#{capture_model} should not exist(?: with #{capture_fields})?$/) do |name, fields|
25
+ find_model(name, fields).should be_nil
26
+ end
27
+
28
+ # find models with a table
29
+ Then(/^the following #{capture_plural_factory} should exists?:?$/) do |plural_factory, table|
30
+ find_models_from_table(plural_factory, table).should_not be_any(&:nil?)
31
+ end
32
+
33
+ # find exactly n models
34
+ Then(/^(\d+) #{capture_plural_factory} should exist(?: with #{capture_fields})?$/) do |count, plural_factory, fields|
35
+ find_models(plural_factory.singularize, fields).size.should == count.to_i
36
+ end
37
+
38
+ # assert equality of models
39
+ Then(/^#{capture_model} should be #{capture_model}$/) do |a, b|
40
+ model!(a).should == model!(b)
41
+ end
42
+
43
+ # assert model is in another model's has_many assoc
44
+ Then(/^#{capture_model} should be (?:in|one of|amongst) #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
45
+ model!(owner).send(association).should include(model!(target))
46
+ end
47
+
48
+ # assert model is not in another model's has_many assoc
49
+ Then(/^#{capture_model} should not be (?:in|one of|amongst) #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
50
+ model!(owner).send(association).should_not include(model!(target))
51
+ end
52
+
53
+ # assert model is another model's has_one/belongs_to assoc
54
+ Then(/^#{capture_model} should be #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
55
+ model!(owner).send(association).should == model!(target)
56
+ end
57
+
58
+ # assert model is not another model's has_one/belongs_to assoc
59
+ Then(/^#{capture_model} should not be #{capture_model}(?:'s)? (\w+)$/) do |target, owner, association|
60
+ model!(owner).send(association).should_not == model!(target)
61
+ end
62
+
63
+ # assert model.predicate?
64
+ Then(/^#{capture_model} should (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
65
+ if model!(name).respond_to?("has_#{predicate.gsub(' ', '_')}")
66
+ model!(name).should send("have_#{predicate.gsub(' ', '_')}")
67
+ else
68
+ model!(name).should send("be_#{predicate.gsub(' ', '_')}")
69
+ end
70
+ end
71
+
72
+ # assert not model.predicate?
73
+ Then(/^#{capture_model} should not (?:be|have) (?:an? )?#{capture_predicate}$/) do |name, predicate|
74
+ if model!(name).respond_to?("has_#{predicate.gsub(' ', '_')}")
75
+ model!(name).should_not send("have_#{predicate.gsub(' ', '_')}")
76
+ else
77
+ model!(name).should_not send("be_#{predicate.gsub(' ', '_')}")
78
+ end
79
+ end
80
+
81
+ # model.attribute.should eql(value)
82
+ # model.attribute.should_not eql(value)
83
+ Then(/^#{capture_model}'s (\w+) (should(?: not)?) be #{capture_value}$/) do |name, attribute, expectation, expected|
84
+ actual_value = model(name).send(attribute)
85
+ expectation = expectation.gsub(' ', '_')
86
+
87
+ case expected
88
+ when 'nil', 'true', 'false'
89
+ actual_value.send(expectation, send("be_#{expected}"))
90
+ when /^[+-]?[0-9_]+(\.\d+)?$/
91
+ actual_value.send(expectation, eql(expected.to_f))
92
+ else
93
+ actual_value.to_s.send(expectation, eql(eval(expected)))
94
+ end
95
+ end
96
+
97
+ # assert size of association
98
+ Then /^#{capture_model} should have (\d+) (\w+)$/ do |name, size, association|
99
+ model!(name).send(association).size.should == size.to_i
100
+ end
@@ -0,0 +1,57 @@
1
+
2
+ When /^the client requests GET (.*)$/ do |path|
3
+ get(path)
4
+ end
5
+
6
+ When /^the client requests DELETE (.*)$/ do |path|
7
+ delete(path)
8
+ end
9
+
10
+ When /^the client requests POST (.*) with name "([^"]*)" and email "([^"]*)"$/ do |path, name, email|
11
+ post(path, :name => name, :email => email)
12
+ end
13
+
14
+ When /^the client requests PUT (.*) with name "([^"]*)" and email "([^"]*)"$/ do |path, name, email|
15
+ put(path, :name => name, :email => email)
16
+ end
17
+
18
+ Then /^the response should be JSON:$/ do |json|
19
+ JSON.parse(last_response.body).should == JSON.parse(json)
20
+ end
21
+
22
+ Then /^the response should be status "([^"]*)" with JSON:$/ do |status, json|
23
+ last_response.status.should == status.to_i
24
+ JSON.parse(last_response.body).should == JSON.parse(json)
25
+ end
26
+
27
+
28
+ Given /^"([^"]*)" belongs to "([^"]*)"$/ do |recipe_name, user_name|
29
+ rp = Recipe.find_by_name(recipe_name)
30
+ raise "Cannot find recipe with name #{recipe_name}" if rp.nil?
31
+ u = User.find_by_name(user_name)
32
+ raise "Cannot find user with name #{user_name}" if u.nil?
33
+ u.recipes << rp
34
+ u.save
35
+ end
36
+
37
+ Given /^pagination is set for "([^"]*)" model$/ do |model|
38
+ self.instance_eval("#{model}.paginate_results")
39
+ end
40
+
41
+ Given /^there are (\d+) items per page$/ do |num|
42
+ WillPaginate.per_page = num
43
+ end
44
+
45
+ Given /^I have setup my ability class$/ do |code|
46
+ eval code
47
+ end
48
+
49
+ Given /^I am not logged in$/ do
50
+ class ApplicationController < ActionController::Base
51
+ def current_user
52
+ nil
53
+ end
54
+ end
55
+ end
56
+
57
+
@@ -0,0 +1,50 @@
1
+ # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
2
+ # It is recommended to regenerate this file in the future when you upgrade to a
3
+ # newer version of cucumber-rails. Consider adding your own code to a new file
4
+ # instead of editing this one. Cucumber will automatically load all features/**/*.rb
5
+ # files.
6
+
7
+ require 'cucumber/rails'
8
+
9
+ # Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
10
+ # order to ease the transition to Capybara we set the default here. If you'd
11
+ # prefer to use XPath just remove this line and adjust any selectors in your
12
+ # steps to use the XPath syntax.
13
+ Capybara.default_selector = :css
14
+
15
+ # By default, any exception happening in your Rails application will bubble up
16
+ # to Cucumber so that your scenario will fail. This is a different from how
17
+ # your application behaves in the production environment, where an error page will
18
+ # be rendered instead.
19
+ #
20
+ # Sometimes we want to override this default behaviour and allow Rails to rescue
21
+ # exceptions and display an error page (just like when the app is running in production).
22
+ # Typical scenarios where you want to do this is when you test your error pages.
23
+ # There are two ways to allow Rails to rescue exceptions:
24
+ #
25
+ # 1) Tag your scenario (or feature) with @allow-rescue
26
+ #
27
+ # 2) Set the value below to true. Beware that doing this globally is not
28
+ # recommended as it will mask a lot of errors for you!
29
+ #
30
+ ActionController::Base.allow_rescue = false
31
+
32
+ # Remove/comment out the lines below if your app doesn't have a database.
33
+ # For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
34
+ begin
35
+ DatabaseCleaner.strategy = :transaction
36
+ rescue NameError
37
+ raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
38
+ end
39
+
40
+ # You may also want to configure DatabaseCleaner to use different strategies for certain features and scenarios.
41
+ # See the DatabaseCleaner documentation for details. Example:
42
+ #
43
+ # Before('@no-txn,@selenium,@culerity,@celerity,@javascript') do
44
+ # DatabaseCleaner.strategy = :truncation, {:except => %w[widgets]}
45
+ # end
46
+ #
47
+ # Before('~@no-txn', '~@selenium', '~@culerity', '~@celerity', '~@javascript') do
48
+ # DatabaseCleaner.strategy = :transaction
49
+ # end
50
+ #
@@ -0,0 +1,26 @@
1
+ # this file generated by script/generate pickle [paths] [email]
2
+ #
3
+ # Make sure that you are loading your factory of choice in your cucumber environment
4
+ #
5
+ # For machinist add: features/support/machinist.rb
6
+ #
7
+ # require 'machinist/active_record' # or your chosen adaptor
8
+ # require File.dirname(__FILE__) + '/../../spec/blueprints' # or wherever your blueprints are
9
+ # Before { Sham.reset } # to reset Sham's seed between scenarios so each run has same random sequences
10
+ #
11
+ # For FactoryGirl add: features/support/factory_girl.rb
12
+ #
13
+ require 'factory_girl'
14
+ require File.dirname(__FILE__) + '/../../../../spec/factories' # or wherever your factories are
15
+ #
16
+ # For Fabrication, just include it in the adapter list when configuring pickle as explained below.
17
+ #
18
+ # You may also need to add gem dependencies on your factory of choice in <tt>config/environments/cucumber.rb</tt>
19
+
20
+ require 'pickle/world'
21
+ # Example of configuring pickle:
22
+ #
23
+ # Pickle.configure do |config|
24
+ # config.adapters = [:machinist]
25
+ # config.map 'I', 'myself', 'me', 'my', :to => 'user: "me"'
26
+ # end
@@ -0,0 +1,37 @@
1
+ # Configure Rails Envinronment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require 'rspec/rails'
6
+
7
+ ActionMailer::Base.delivery_method = :test
8
+ ActionMailer::Base.perform_deliveries = true
9
+ ActionMailer::Base.default_url_options[:host] = "test.com"
10
+
11
+ Rails.backtrace_cleaner.remove_silencers!
12
+
13
+ # Run any available migration
14
+ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
15
+
16
+ # Requires supporting ruby files with custom matchers and macros, etc,
17
+ # in spec/support/ and its subdirectories.
18
+ Dir[Rails.root.join("spec/support/**/*.rb"), "spec/factories.rb"].each {|f| require f}
19
+
20
+ RSpec.configure do |config|
21
+ # == Mock Framework
22
+ #
23
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
24
+ #
25
+ # config.mock_with :mocha
26
+ # config.mock_with :flexmock
27
+ # config.mock_with :rr
28
+ config.mock_with :rspec
29
+
30
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
31
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
32
+
33
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
34
+ # examples within a transaction, remove the following line or assign false
35
+ # instead of true.
36
+ config.use_transactional_fixtures = true
37
+ end