stormpath-rails 0.4.4 → 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ require 'rails'
2
+
3
+ module Stormpath
4
+ module Rails
5
+ mattr_accessor :logger
6
+
7
+ class Railtie < ::Rails::Railtie
8
+ initializer 'Rails logger' do
9
+ Stormpath::Rails.logger = ::Rails.logger
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,6 @@
1
1
  module Stormpath
2
2
  module Rails
3
- VERSION = "0.4.4"
3
+ VERSION = '1.0.0.beta'
4
+ VERSION_DATE = '2013-06-13'
4
5
  end
5
6
  end
@@ -0,0 +1,222 @@
1
+ require "spec_helper"
2
+
3
+ describe Stormpath::Rails::Client, :vcr do
4
+
5
+ describe ".client" do
6
+ context "given a valid Stormpath API key ID and secret" do
7
+ let(:client) do
8
+ Stormpath::Rails::Client.client
9
+ end
10
+
11
+ it "should instantiate a Stormpath Client" do
12
+ expect(client).to be
13
+ expect(client).to be_kind_of Stormpath::Client
14
+ end
15
+
16
+ it "should instantiate a Stormpath Tenant" do
17
+ expect(client.tenant).to be
18
+ expect(client.tenant).to be_kind_of Stormpath::Resource::Tenant
19
+ end
20
+ end
21
+
22
+ context 'given a composite url' do
23
+ let(:composite_url) { 'http://ASDF1234:ZXCV5678@example.com/foo/bar' }
24
+ let(:application) { double 'application' }
25
+ let(:loaded_client) { double 'client' }
26
+ let(:returned_client) { Stormpath::Rails::Client.client }
27
+
28
+ before do
29
+ ENV['STORMPATH_URL'] = composite_url
30
+ end
31
+
32
+ it 'loads the client from the application' do
33
+ Stormpath::Resource::Application
34
+ .should_receive(:load)
35
+ .with(composite_url)
36
+ .and_return(application)
37
+
38
+ application
39
+ .should_receive(:client)
40
+ .and_return(loaded_client)
41
+
42
+ expect(returned_client).to be
43
+ expect(returned_client).to eq(loaded_client)
44
+ end
45
+
46
+ after do
47
+ ENV['STORMPATH_URL'] = nil
48
+ end
49
+ end
50
+ end
51
+
52
+ describe ".create_account!" do
53
+ context "given a hash of account attributes" do
54
+ let(:attributes) do
55
+ {
56
+ 'email' => 'test+foo+bar@example.com',
57
+ 'given_name' => 'bazzy',
58
+ 'surname' => 'foo',
59
+ 'password' => 'P@66w0rd!',
60
+ 'username' => 'testfoobar'
61
+ }
62
+ end
63
+
64
+ let(:account) do
65
+ Stormpath::Rails::Client.create_account! attributes
66
+ end
67
+
68
+ it "should create an account" do
69
+ expect(account).to be
70
+ expect(account).to be_kind_of Stormpath::Resource::Account
71
+ expect(account.given_name).to eq(attributes['given_name'])
72
+ end
73
+
74
+ after do
75
+ account.delete
76
+ end
77
+ end
78
+ end
79
+
80
+ describe ".authenticate_account" do
81
+ context "given a valid username and password" do
82
+ let(:username) { 'testfoobar' }
83
+ let(:password) { 'Succ3ss!' }
84
+
85
+ let!(:test_account) do
86
+ obtain_test_account(
87
+ 'username' => 'testfoobar',
88
+ 'password' => 'Succ3ss!'
89
+ )
90
+ end
91
+
92
+ let(:authenticated_account) do
93
+ Stormpath::Rails::Client.authenticate_account(
94
+ username, password
95
+ )
96
+ end
97
+
98
+ it "authenticates the account" do
99
+ expect(authenticated_account).to be
100
+ expect(authenticated_account).to be_kind_of Stormpath::Resource::Account
101
+ expect(authenticated_account.username).to eq(username)
102
+ end
103
+
104
+ after do
105
+ authenticated_account.delete
106
+ end
107
+ end
108
+ end
109
+
110
+ describe ".update_account!" do
111
+ context "given a valid account" do
112
+ let(:new_name) { "Bartholomew" }
113
+
114
+ let(:created_account) do
115
+ obtain_test_account 'given_name' => 'Foo'
116
+ end
117
+
118
+ let(:reloaded_account) do
119
+ found_account = nil
120
+
121
+ Stormpath::Rails::Client.all_accounts.each do |a|
122
+ found_account = a unless a.href != created_account.href or !found_account.nil?
123
+ end
124
+
125
+ found_account
126
+ end
127
+
128
+ before do
129
+ Stormpath::Rails::Client.update_account!(
130
+ created_account.href, 'given_name' => new_name
131
+ )
132
+ end
133
+
134
+ it "updates the account" do
135
+ expect(reloaded_account).to be
136
+ expect(reloaded_account.given_name).to eq(new_name)
137
+ end
138
+
139
+ after do
140
+ created_account.delete
141
+ end
142
+ end
143
+ end
144
+
145
+ describe ".find_account" do
146
+ context "given a valid account" do
147
+ let(:created_account) { obtain_test_account }
148
+ let(:returned_account) do
149
+ Stormpath::Rails::Client.find_account(
150
+ created_account.href
151
+ )
152
+ end
153
+
154
+ it "returns the account" do
155
+ expect(returned_account).to be
156
+ expect(returned_account).to be_kind_of Stormpath::Resource::Account
157
+ expect(returned_account.href).to eq(created_account.href)
158
+ end
159
+
160
+ after do
161
+ created_account.delete
162
+ end
163
+ end
164
+ end
165
+
166
+ describe ".send_password_reset_email" do
167
+ context "given a valid account" do
168
+ let(:created_account) { obtain_test_account }
169
+ let(:returned_account) do
170
+ Stormpath::Rails::Client.send_password_reset_email(
171
+ created_account.email
172
+ )
173
+ end
174
+
175
+ it "sends the reset email" do
176
+ expect(returned_account).to be
177
+ expect(returned_account).to be_kind_of Stormpath::Resource::Account
178
+ expect(returned_account.href).to eq(created_account.href)
179
+ end
180
+
181
+ after do
182
+ created_account.delete
183
+ end
184
+ end
185
+ end
186
+
187
+ describe '.verify_password_reset_token' do
188
+ let(:password_reset_token) { 'ASDF1234' }
189
+ let(:application) { double('application') }
190
+
191
+ it 'delegates to the application instance' do
192
+ Stormpath::Rails::Client
193
+ .should_receive(:application)
194
+ .and_return application
195
+
196
+ application
197
+ .should_receive(:verify_password_reset_token)
198
+ .with(password_reset_token)
199
+
200
+ Stormpath::Rails::Client.verify_password_reset_token(
201
+ password_reset_token
202
+ )
203
+ end
204
+ end
205
+
206
+ describe '.verify_account_email' do
207
+ let(:email_verification_token) { 'ASDF1234' }
208
+ let(:accounts) { double('accounts') }
209
+
210
+ it 'delegates to the application instance' do
211
+ Stormpath::Rails::Client
212
+ .stub_chain(:client, :accounts)
213
+ .and_return(accounts)
214
+
215
+ accounts
216
+ .should_receive(:verify_email_token)
217
+ .with email_verification_token
218
+
219
+ Stormpath::Rails::Client.verify_account_email email_verification_token
220
+ end
221
+ end
222
+ end
@@ -7,7 +7,7 @@ describe Stormpath::Rails::Generators::MigrationGenerator do
7
7
  destination File.expand_path("../tmp", __FILE__)
8
8
  arguments %w(person)
9
9
 
10
- before(:all) do
10
+ before do
11
11
  Time.stub_chain(:now, :utc, :strftime).and_return("0")
12
12
  prepare_destination
13
13
  run_generator
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,96 @@
1
+ # Note: If SimpleCov starts after your application code is already loaded (via require),
2
+ # it won't be able to track your files and their coverage! The SimpleCov.start must be
3
+ # issued before any of your application code is required!
4
+ require 'simplecov'
5
+ SimpleCov.start
6
+
7
+ require "vcr"
8
+ require "webmock"
9
+ require "pry"
10
+ require "pry-debugger"
11
+ require 'stormpath-rails'
12
+
1
13
  Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
2
14
 
15
+ module Stormpath
16
+ module TestResourceHelpers
17
+ def reload_client
18
+ Stormpath::Rails.send(:remove_const, :Client)
19
+ load 'lib/stormpath/rails/client.rb'
20
+ end
21
+
22
+ def obtain_test_account(opts={})
23
+ defaults = {
24
+ 'surname' => 'testsurname',
25
+ 'given_name' => 'testgivenname',
26
+ 'username' => 'testfoobar',
27
+ 'password' => 'Succ3ss!',
28
+ 'email' => 'test+foo+bar@example.com'
29
+ }
30
+
31
+ begin
32
+ Stormpath::Rails::Client.create_account! defaults.merge!(opts)
33
+ rescue Stormpath::Error => e
34
+ Stormpath::Rails::Client.authenticate_account(opts['username'], opts['password'])
35
+ end
36
+ end
37
+ end
38
+
39
+ class TestEnvironmentConfigurator
40
+ def self.verify_setup
41
+ pfx = 'STORMPATH_RAILS_TEST'
42
+
43
+ unless (ENV["#{pfx}_API_KEY_SECRET"] and ENV["#{pfx}_API_KEY_ID"]) or ENV["#{pfx}_API_KEY_FILE_LOCATION"]
44
+ raise <<-message
45
+ Must specify either STORMPATH_RAILS_TEST_API_KEY_FILE_LOCATION or
46
+ STORMPATH_RAILS_TEST_API_KEY_SECRET and STORMPATH_RAILS_TEST_API_KEY_ID
47
+ in order to run tests.
48
+ message
49
+ end
50
+
51
+ unless ENV["#{pfx}_APPLICATION_URL"]
52
+ raise <<-message
53
+ Must specify STORMPATH_RAILS_TEST_APPLICATION_URL so that tests have
54
+ an Application Resource to run against.
55
+ message
56
+ end
57
+ end
58
+
59
+ def self.create_test_env
60
+ k = %w(SECRET ID FILE_LOCATION ID_PROPERTY_NAME SECRET_PROPERTY_NAME)
61
+
62
+ k.each do |v|
63
+ ENV["STORMPATH_API_KEY_#{v}"] = ENV["STORMPATH_RAILS_TEST_API_KEY_#{v}"]
64
+ end
65
+
66
+ ENV['STORMPATH_APPLICATION_URL'] = ENV['STORMPATH_RAILS_TEST_APPLICATION_URL']
67
+ end
68
+
69
+ def self.prepare_test_environment
70
+ verify_setup
71
+ create_test_env
72
+ end
73
+ end
74
+ end
75
+
3
76
  RSpec.configure do |config|
77
+ config.mock_framework = :rspec
4
78
  config.order = 'random'
79
+ config.include Stormpath::TestResourceHelpers
80
+
81
+ config.before(:all) do
82
+ Stormpath::TestEnvironmentConfigurator.prepare_test_environment
83
+ end
84
+
85
+ config.before(:each) do
86
+ reload_client
87
+ end
88
+
89
+ config.treat_symbols_as_metadata_keys_with_true_values = true
90
+ end
91
+
92
+ VCR.configure do |c|
93
+ c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
94
+ c.hook_into :webmock
95
+ c.configure_rspec_metadata!
5
96
  end
@@ -1,119 +1,211 @@
1
+ require "logger"
2
+
1
3
  shared_examples "stormpath account" do
2
- context "after initialize" do
3
- let(:account) { mock("account", get_href: "account_href") }
4
+ let(:mock_account) do
5
+ mock("account", href: "account_href").tap do |account|
6
+ subject.class::STORMPATH_FIELDS.each do |field_name|
7
+ account.stub!("#{field_name}").and_return(field_name.to_s)
8
+ end
9
+ end
10
+ end
4
11
 
5
- let!(:logger) { Logger.new(STDERR) }
12
+ context 'class methods' do
13
+ let(:username) { 'test@example.com' }
14
+ let(:email) { username }
15
+ let(:password) { 'adsf1234' }
16
+ let(:mock_user) { subject.class.new }
6
17
 
7
- before(:each) do
8
- subject.class::STORMPATH_FIELDS.each do |field_name|
9
- account.stub!("get_#{field_name}").and_return(field_name.to_s)
18
+ describe '.authenticate' do
19
+ before do
20
+ Stormpath::Rails::Client.stub!(:authenticate_account).and_return(mock_account)
21
+ subject.class.stub_chain(:where, :first).and_return(mock_user)
22
+ end
23
+
24
+ it 'returns an instance of the class into which the Account module was mixed in' do
25
+ instance = subject.class.authenticate username, password
26
+ instance.should be_a_kind_of(subject.class)
27
+ end
28
+ end
29
+
30
+ describe '.send_password_reset_email' do
31
+ before do
32
+ Stormpath::Rails::Client.stub!(:send_password_reset_email).and_return(mock_account)
33
+ subject.class.stub_chain(:where, :first).and_return(mock_user)
34
+ end
35
+
36
+ it 'returns an instance of the class into which the Account module was mixed in' do
37
+ instance = subject.class.send_password_reset_email email
38
+ instance.should be_a_kind_of(subject.class)
39
+ end
40
+ end
41
+
42
+ describe '.verify_password_reset_token' do
43
+ let(:token) { 'ASDF1324' }
44
+
45
+ before do
46
+ Stormpath::Rails::Client.stub!(:verify_password_reset_token).and_return(mock_account)
47
+ subject.class.stub_chain(:where, :first).and_return(mock_user)
48
+ end
49
+
50
+ it 'returns an instance of the class into which the Account module was mixed in' do
51
+ instance = subject.class.verify_password_reset_token token
52
+ instance.should be_a_kind_of(subject.class)
53
+ end
54
+ end
55
+
56
+ describe '.verify_account_email' do
57
+ let(:token) { 'ASDF1324' }
58
+
59
+ before do
60
+ Stormpath::Rails::Client.stub!(:verify_account_email).and_return(mock_account)
61
+ subject.class.stub_chain(:where, :first).and_return(mock_user)
62
+ end
63
+
64
+ it 'returns an instance of the class into which the Account module was mixed in' do
65
+ instance = subject.class.verify_account_email token
66
+ instance.should be_a_kind_of(subject.class)
10
67
  end
11
- Logger.stub!(:new).and_return(logger)
12
- Stormpath::Rails::Client.stub!(:find_account).and_return(account)
13
68
  end
69
+ end
70
+
71
+ before(:each) do
72
+ Stormpath::Rails::Client.stub!(:find_account).and_return(mock_account)
73
+ Stormpath::Rails.logger = Logger.new(STDERR)
74
+ end
14
75
 
15
- it "should silently skip stormpath load if no stormpath_url set" do
16
- Stormpath::Rails::Client.should_not_receive(:find_account)
17
- expect { subject }.to_not raise_error
76
+ context "after initialize" do
77
+ context 'when no Stormpath URL property is set' do
78
+ it "does NOT load data from stormpath on initialization" do
79
+ Stormpath::Rails::Client.should_not_receive(:find_account)
80
+ expect { subject }.to_not raise_error
81
+ end
18
82
  end
19
83
 
20
- context "on find" do
84
+ context 'when a Stormpath URL property is set' do
85
+ let(:reloaded_subject) { subject.class.all.first }
86
+
21
87
  before(:each) do
22
- Stormpath::Rails::Client.stub!(:create_account!).and_return(account)
88
+ Stormpath::Rails::Client.stub!(:create_account!).and_return(mock_account)
23
89
  subject.save!
24
90
  end
25
91
 
26
- it "should find account at stormpath" do
27
- Stormpath::Rails::Client.should_receive(:find_account).with(subject.stormpath_url)
28
- subject.class.all.first.stormpath_url.should == subject.stormpath_url
92
+ it "does NOT load data from stormpath on initialization" do
93
+ Stormpath::Rails::Client.should_not_receive(:find_account)
94
+ reloaded_subject.stormpath_url.should == subject.stormpath_url
29
95
  end
96
+ end
97
+ end
98
+
99
+ context 'lazy load Stormpath fields' do
100
+ let(:reloaded_subject) { subject.class.all.first }
30
101
 
31
- it "should setup object with data from stormpath" do
32
- Stormpath::Rails::Client.should_receive(:find_account).with(subject.stormpath_url).and_return(account)
33
- found = subject.class.where(stormpath_url: 'account_href').first
34
- (subject.class::STORMPATH_FIELDS - [:password]).each do |field_name|
35
- found.send(field_name).should == account.send("get_#{field_name}")
102
+ before(:each) do
103
+ Stormpath::Rails::Client.stub!(:create_account!).and_return(mock_account)
104
+ subject.save!
105
+ end
106
+
107
+ context 'when no Stormpath account field has ever been read' do
108
+ (Stormpath::Rails::Account::STORMPATH_FIELDS - [:password]).each do |field_name|
109
+ context "when the #{field_name} is read" do
110
+ it "retrieves the account fields from Stormpath" do
111
+ Stormpath::Rails::Client.should_receive(:find_account).with(subject.stormpath_url)
112
+ reloaded_subject.send(field_name).should == mock_account.send(field_name)
113
+ end
114
+
115
+ it "logs a warning to standard output" do
116
+ Stormpath::Rails::Client.stub!(:find_account).and_raise(Stormpath::Error.new(mock("error", message: "Find failed")))
117
+ Stormpath::Rails.logger.should_receive(:warn).with("Error loading Stormpath account (Find failed)")
118
+ reloaded_subject.send(field_name).should be_nil
119
+ end
36
120
  end
37
121
  end
122
+ end
38
123
 
39
- it "should log warning if stormpath account update failed" do
40
- Stormpath::Rails::Client.stub!(:find_account).and_raise(ResourceError.new(mock("error", get_message: "Find failed")))
41
- logger.should_receive(:warn).with("Error loading Stormpath account (Find failed)")
42
- found = subject.class.where(stormpath_url: 'account_href').first
43
- subject.class::STORMPATH_FIELDS.each do |field_name|
44
- found.send(field_name).should be_nil
124
+ context 'when a Stormpath account field has previously been read' do
125
+ before do
126
+ Stormpath::Rails::Client.should_receive(:find_account).with(subject.stormpath_url).at_most(:once).and_return(mock_account)
127
+ reloaded_subject.send :email
128
+ end
129
+
130
+ (Stormpath::Rails::Account::STORMPATH_FIELDS - [:password]).each do |field_name|
131
+ context "when reading the #{field_name} attribute" do
132
+ it 'does NOT retrieve the full account from Stormpath' do
133
+ reloaded_subject.send(field_name).should == mock_account.send(field_name)
134
+ end
45
135
  end
46
136
  end
47
137
  end
48
-
49
138
  end
50
139
 
51
-
52
140
  context "before create" do
141
+ before(:each) do
142
+ subject.email = 'foo@example.com'
143
+ subject.given_name = 'Foo'
144
+ subject.surname = 'Bar'
145
+
146
+ Stormpath::Rails::Client.stub!(:create_account!).and_return mock_account
147
+ end
148
+
53
149
  it "should create account at stormpath and assign stormpath_url" do
54
- Stormpath::Rails::Client.should_receive(:create_account!).and_return(mock("account", get_href: "account_href"))
55
- subject.save!
150
+ subject.stormpath_url.should be_nil
151
+ Stormpath::Rails::Client.should_receive(:create_account!).once.with(hash_including({
152
+ :email => 'foo@example.com',
153
+ :given_name => 'Foo',
154
+ :surname => 'Bar'
155
+ }))
156
+ subject.save
56
157
  subject.stormpath_url.should == "account_href"
57
158
  end
58
159
 
59
160
  it "should add error if stormpath account creation failed" do
60
- Stormpath::Rails::Client.stub!(:create_account!).and_raise(ResourceError.new(mock("error", get_message: "Create failed")))
161
+ Stormpath::Rails::Client.stub!(:create_account!).and_raise(Stormpath::Error.new(mock("error", message: "Create failed")))
61
162
  subject.save
62
163
  subject.errors[:base].should == ["Create failed"]
63
164
  end
64
165
  end
65
166
 
66
167
  context "before update" do
67
- let(:account) { mock("account", get_href: "account_href") }
68
-
69
168
  before(:each) do
70
- Stormpath::Rails::Client.stub!(:create_account!).and_return(account)
169
+ Stormpath::Rails::Client.stub!(:create_account!).and_return(mock_account)
71
170
  subject.save!
72
171
  end
73
172
 
74
- it "should silently skip stormpath update if no stormpath_url set" do
173
+ it "skip silently stormpath update if no stormpath_url set" do
75
174
  subject.stormpath_url = nil
76
- Stormpath::Rails::Client.should_not_receive(:update_account!)
77
175
  expect { subject.save! }.to_not raise_error
78
176
  end
79
177
 
80
178
  it "should update account at stormpath" do
81
- Stormpath::Rails::Client.should_receive(:update_account!).with(subject.stormpath_url, anything())
179
+ subject.stormpath_account.should_receive(:save)
82
180
  subject.save!
83
181
  end
84
182
 
85
183
  it "should add error if stormpath account update failed" do
86
- Stormpath::Rails::Client.stub!(:update_account!).and_raise(ResourceError.new(mock("error", get_message: "Update failed")))
184
+ subject.stormpath_account.stub!(:save).and_raise(Stormpath::Error.new(mock("error", message: "Update failed")))
87
185
  subject.save.should be_false
88
186
  subject.errors[:base].should == ["Update failed"]
89
187
  end
90
188
  end
91
189
 
92
190
  context "after destroy" do
93
- let(:account) { mock("account", get_href: "account_href") }
94
-
95
- let!(:logger) { Logger.new(STDERR) }
96
-
97
191
  before(:each) do
98
- Logger.stub!(:new).and_return(logger)
99
- Stormpath::Rails::Client.stub!(:create_account!).and_return(account)
192
+ Stormpath::Rails::Client.stub!(:create_account!).and_return(mock_account)
100
193
  subject.save!
101
194
  end
102
195
 
103
196
  it "should silently skip stormpath delete if no stormpath_url set" do
104
197
  subject.stormpath_url = nil
105
- Stormpath::Rails::Client.should_not_receive(:delete_account!)
106
198
  expect { subject.destroy }.to_not raise_error
107
199
  end
108
200
 
109
201
  it "should destroy account at stormpath" do
110
- Stormpath::Rails::Client.should_receive(:delete_account!).with(subject.stormpath_url)
202
+ subject.stormpath_account.should_receive(:delete)
111
203
  subject.destroy
112
204
  end
113
205
 
114
206
  it "should log warning if stormpath account update failed" do
115
- Stormpath::Rails::Client.stub!(:delete_account!).and_raise(ResourceError.new(mock("error", get_message: "Delete failed")))
116
- logger.should_receive(:warn).with("Error destroying Stormpath account (Delete failed)")
207
+ subject.stormpath_account.stub!(:delete).and_raise(Stormpath::Error.new(mock("error", message: "Delete failed")))
208
+ Stormpath::Rails.logger.should_receive(:warn).with("Error destroying Stormpath account (Delete failed)")
117
209
  subject.destroy.should be_true
118
210
  end
119
211
  end