stormpath-rails 0.4.4 → 1.0.0.beta

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.
@@ -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