sunstone 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +29 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +4 -0
- data/Rakefile.rb +37 -0
- data/TODO.md +89 -0
- data/lib/sunstone.rb +361 -0
- data/lib/sunstone/exception.rb +43 -0
- data/lib/sunstone/model.rb +23 -0
- data/lib/sunstone/model/associations.rb +89 -0
- data/lib/sunstone/model/attributes.rb +99 -0
- data/lib/sunstone/model/persistence.rb +168 -0
- data/lib/sunstone/parser.rb +93 -0
- data/lib/sunstone/schema.rb +38 -0
- data/lib/sunstone/type/boolean.rb +19 -0
- data/lib/sunstone/type/date_time.rb +20 -0
- data/lib/sunstone/type/decimal.rb +19 -0
- data/lib/sunstone/type/integer.rb +17 -0
- data/lib/sunstone/type/mutable.rb +16 -0
- data/lib/sunstone/type/string.rb +18 -0
- data/lib/sunstone/type/value.rb +97 -0
- data/sunstone.gemspec +34 -0
- data/test/sunstone/model/associations_test.rb +55 -0
- data/test/sunstone/model/attributes_test.rb +60 -0
- data/test/sunstone/model/persistence_test.rb +173 -0
- data/test/sunstone/model_test.rb +11 -0
- data/test/sunstone/parser_test.rb +124 -0
- data/test/sunstone/schema_test.rb +25 -0
- data/test/sunstone/type/boolean_test.rb +24 -0
- data/test/sunstone/type/date_time_test.rb +31 -0
- data/test/sunstone/type/decimal_test.rb +27 -0
- data/test/sunstone/type/integer_test.rb +29 -0
- data/test/sunstone/type/string_test.rb +54 -0
- data/test/sunstone/type/value_test.rb +27 -0
- data/test/sunstone_test.rb +302 -0
- data/test/test_helper.rb +70 -0
- metadata +318 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'sunstone/type/value'
|
2
|
+
require 'sunstone/type/mutable'
|
3
|
+
require 'sunstone/type/boolean'
|
4
|
+
require 'sunstone/type/date_time'
|
5
|
+
require 'sunstone/type/decimal'
|
6
|
+
require 'sunstone/type/integer'
|
7
|
+
require 'sunstone/type/string'
|
8
|
+
|
9
|
+
module Sunstone
|
10
|
+
class Schema
|
11
|
+
|
12
|
+
attr_accessor :attributes
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@attributes = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def attribute(name, type, options = {})
|
19
|
+
types = Sunstone::Type::Value.subclasses
|
20
|
+
type = types.find {|sc| sc.name.demodulize.downcase == type.to_s}
|
21
|
+
|
22
|
+
@attributes[name.to_s] = type.new(options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def [](name)
|
26
|
+
@attributes[name.to_s]
|
27
|
+
end
|
28
|
+
|
29
|
+
Sunstone::Type::Value.subclasses.each do |type|
|
30
|
+
class_eval <<-EOV, __FILE__, __LINE__ + 1
|
31
|
+
def #{type.name.demodulize.downcase}(name, options = {})
|
32
|
+
attribute(name, "#{type.name.demodulize.downcase}", options)
|
33
|
+
end
|
34
|
+
EOV
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Sunstone
|
2
|
+
module Type
|
3
|
+
class DateTime < Value
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def _type_cast_for_json(value)
|
8
|
+
value.iso8601(3) if value
|
9
|
+
end
|
10
|
+
|
11
|
+
def _cast_value(string)
|
12
|
+
return string unless string.is_a?(::String)
|
13
|
+
return if string.empty?
|
14
|
+
|
15
|
+
::DateTime.iso8601(string) || ::DateTime.parse(string)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sunstone
|
2
|
+
module Type
|
3
|
+
module Mutable # :nodoc:
|
4
|
+
def type_cast_from_user(value)
|
5
|
+
type_cast_from_json(type_cast_for_json(value))
|
6
|
+
end
|
7
|
+
|
8
|
+
# +raw_old_value+ will be the `_before_type_cast` version of the
|
9
|
+
# value (likely a string). +new_value+ will be the current, type
|
10
|
+
# cast value.
|
11
|
+
def changed_in_place?(raw_old_value, new_value)
|
12
|
+
raw_old_value != type_cast_for_json(new_value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Sunstone
|
2
|
+
module Type
|
3
|
+
class Value
|
4
|
+
|
5
|
+
attr_accessor :options
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def type_cast_from_json(value)
|
12
|
+
if @options[:array]
|
13
|
+
value.nil? ? nil : value.map{ |v| _type_cast_from_json(v) }
|
14
|
+
else
|
15
|
+
_type_cast_from_json(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def type_cast_from_user(value)
|
20
|
+
if @options[:array]
|
21
|
+
value.nil? ? nil : value.map{ |v| _type_cast_from_user(v) }
|
22
|
+
else
|
23
|
+
_type_cast_from_user(value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def type_cast_for_json(value)
|
28
|
+
if @options[:array]
|
29
|
+
value.nil? ? nil : value.map{ |v| _type_cast_for_json(v) }
|
30
|
+
else
|
31
|
+
_type_cast_for_json(value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Determines whether a value has changed for dirty checking. +old_value+
|
36
|
+
# and +new_value+ will always be type-cast. Types should not need to
|
37
|
+
# override this method.
|
38
|
+
def changed?(old_value, new_value, _new_value_before_type_cast)
|
39
|
+
old_value != new_value
|
40
|
+
end
|
41
|
+
|
42
|
+
# Determines whether the mutable value has been modified since it was
|
43
|
+
# read. Returns +false+ by default. This method should not need to be
|
44
|
+
# overriden directly. Types which return a mutable value should include
|
45
|
+
# +Type::Mutable+, which will define this method.
|
46
|
+
def changed_in_place?(*)
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
def readonly?
|
51
|
+
@options[:readonly]
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Type casts a value from json into the appropriate ruby type. Classes
|
57
|
+
# which do not need separate type casting behavior for json and user
|
58
|
+
# provided values should override +_cast_value+ instead.
|
59
|
+
def _type_cast_from_json(value)
|
60
|
+
_type_cast(value)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Type casts a value from user input (e.g. from a setter). This value may
|
64
|
+
# be a string from the form builder, or an already type cast value
|
65
|
+
# provided manually to a setter.
|
66
|
+
#
|
67
|
+
# Classes which do not need separate type casting behavior for json
|
68
|
+
# and user provided values should override +_type_cast+ or +_cast_value+
|
69
|
+
# instead.
|
70
|
+
def _type_cast_from_user(value)
|
71
|
+
_type_cast(value)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Cast a value from the ruby type to a type that the json knows how
|
75
|
+
# to understand. The returned value from this method should be a
|
76
|
+
# +String+, +Numeric+, +Symbol+, +true+, +false+, or +nil+
|
77
|
+
def _type_cast_for_json(value)
|
78
|
+
value
|
79
|
+
end
|
80
|
+
|
81
|
+
def _type_cast(value)
|
82
|
+
_cast_value(value) unless value.nil?
|
83
|
+
end
|
84
|
+
|
85
|
+
# Convenience method for types which do not need separate type casting
|
86
|
+
# behavior for user and database inputs. Called by
|
87
|
+
# `_type_cast_from_json` and `_type_cast_from_user` for all values except
|
88
|
+
# `nil`.
|
89
|
+
#
|
90
|
+
# If you wish to catch the nil case use the `_type_cast` function
|
91
|
+
def _cast_value(value) # :doc:
|
92
|
+
value
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/sunstone.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "sunstone"
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.authors = ["Jon Bracy"]
|
5
|
+
s.email = ["jonbracy@gmail.com"]
|
6
|
+
s.homepage = "http://sunstonerb.com"
|
7
|
+
s.summary = %q{A library for interacting with REST APIs}
|
8
|
+
s.description = %q{A library for interacting with REST APIs. Similar to ActiveResource}
|
9
|
+
|
10
|
+
s.files = `git ls-files`.split("\n")
|
11
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
12
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
|
+
s.require_paths = ["lib"]
|
14
|
+
|
15
|
+
# Developoment
|
16
|
+
s.add_development_dependency 'rake'
|
17
|
+
s.add_development_dependency 'rdoc'
|
18
|
+
s.add_development_dependency 'sdoc'
|
19
|
+
s.add_development_dependency 'bundler'
|
20
|
+
s.add_development_dependency 'minitest'
|
21
|
+
s.add_development_dependency 'minitest-reporters'
|
22
|
+
s.add_development_dependency 'mocha'
|
23
|
+
s.add_development_dependency 'faker'
|
24
|
+
s.add_development_dependency 'factory_girl'
|
25
|
+
s.add_development_dependency 'webmock'
|
26
|
+
s.add_development_dependency 'sdoc-templates-42floors'
|
27
|
+
|
28
|
+
# Runtime
|
29
|
+
s.add_runtime_dependency 'wankel'
|
30
|
+
s.add_runtime_dependency 'cookie_store'
|
31
|
+
s.add_runtime_dependency 'activesupport'
|
32
|
+
s.add_runtime_dependency 'activemodel'
|
33
|
+
s.add_runtime_dependency 'connection_pool'
|
34
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BelongsToModel < Sunstone::Model
|
4
|
+
end
|
5
|
+
|
6
|
+
|
7
|
+
class Sunstone::Model::AssociationsTest < Minitest::Test
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@klass = Class.new(Sunstone::Model)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "inherited models get a schema setup with id" do
|
14
|
+
assert_equal({}, @klass.reflect_on_associations)
|
15
|
+
end
|
16
|
+
|
17
|
+
test "::belongs_to adds association" do
|
18
|
+
@klass.belongs_to :belongs_to_model
|
19
|
+
|
20
|
+
assert_equal({
|
21
|
+
:name=>:belongs_to_model,
|
22
|
+
:macro=>:belongs_to,
|
23
|
+
:klass=>BelongsToModel,
|
24
|
+
:foreign_key=>:belongs_to_model_id
|
25
|
+
}, @klass.reflect_on_associations[:belongs_to_model])
|
26
|
+
end
|
27
|
+
|
28
|
+
test "::belongs_to addes foreign_key attribute to class" do
|
29
|
+
@klass.belongs_to :belongs_to_model
|
30
|
+
|
31
|
+
assert_kind_of Sunstone::Type::Integer, @klass.schema[:belongs_to_model_id]
|
32
|
+
end
|
33
|
+
|
34
|
+
test "::belongs_to setter and getter" do
|
35
|
+
@klass.belongs_to :belongs_to_model
|
36
|
+
|
37
|
+
model = @klass.new
|
38
|
+
omodel = BelongsToModel.new(:id => 10)
|
39
|
+
assert_nil model.belongs_to_model
|
40
|
+
model.belongs_to_model = omodel
|
41
|
+
assert_equal omodel, model.belongs_to_model
|
42
|
+
assert_equal 10, model.belongs_to_model_id
|
43
|
+
end
|
44
|
+
|
45
|
+
test "::has_many adds association" do
|
46
|
+
@klass.has_many :belongs_to_models
|
47
|
+
|
48
|
+
assert_equal({
|
49
|
+
:name => :belongs_to_models,
|
50
|
+
:macro => :has_many,
|
51
|
+
:klass => BelongsToModel
|
52
|
+
}, @klass.reflect_on_associations[:belongs_to_models])
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Sunstone::Model::AttributesTest < Minitest::Test
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@klass = Class.new(Sunstone::Model)
|
7
|
+
end
|
8
|
+
|
9
|
+
test "inherited models get a schema setup with id" do
|
10
|
+
assert_kind_of Sunstone::Schema, @klass.schema
|
11
|
+
assert_kind_of Sunstone::Type::Integer, @klass.schema[:id]
|
12
|
+
end
|
13
|
+
|
14
|
+
test "::attribute" do
|
15
|
+
@klass.attribute :name, :string
|
16
|
+
|
17
|
+
assert_kind_of Sunstone::Type::String, @klass.schema[:name]
|
18
|
+
end
|
19
|
+
|
20
|
+
test "::attribute sets up readers" do
|
21
|
+
@klass.attribute :name, :string
|
22
|
+
model = @klass.new
|
23
|
+
|
24
|
+
model.attributes[:name] = "my name"
|
25
|
+
assert_equal "my name", model.name
|
26
|
+
end
|
27
|
+
|
28
|
+
test "::attributes sets up writer" do
|
29
|
+
@klass.attribute :name, :string
|
30
|
+
model = @klass.new
|
31
|
+
|
32
|
+
model.schema[:name].expects(:type_cast_from_user).with("my name").returns("value")
|
33
|
+
model.name = "my name"
|
34
|
+
|
35
|
+
assert_equal "value", model.name
|
36
|
+
assert_equal "value", model.attributes[:name]
|
37
|
+
end
|
38
|
+
|
39
|
+
test "::define_schema" do
|
40
|
+
@klass.define_schema do
|
41
|
+
attribute :name, :string
|
42
|
+
integer :size
|
43
|
+
end
|
44
|
+
|
45
|
+
assert_kind_of Sunstone::Type::String, @klass.schema[:name]
|
46
|
+
assert_kind_of Sunstone::Type::Integer, @klass.schema[:size]
|
47
|
+
end
|
48
|
+
|
49
|
+
test '#has?' do
|
50
|
+
@klass.define_schema do
|
51
|
+
attribute :name, :string
|
52
|
+
integer :size
|
53
|
+
end
|
54
|
+
model = @klass.new(:size => 20)
|
55
|
+
|
56
|
+
assert_equal false, model.has?(:name)
|
57
|
+
assert_equal true, model.has?(:size)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Sunstone::Model::PersistenceTest < Minitest::Test
|
4
|
+
|
5
|
+
class TestModel < Sunstone::Model
|
6
|
+
define_schema do
|
7
|
+
attribute :name, :string
|
8
|
+
integer :size
|
9
|
+
datetime :timestamp
|
10
|
+
datetime :updated_at, :readonly => true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def setup
|
15
|
+
Sunstone.site = "http://test_api_key@testhost.com"
|
16
|
+
@klass = Class.new(Sunstone::Model)
|
17
|
+
end
|
18
|
+
|
19
|
+
test '#serialize' do
|
20
|
+
time = Time.now
|
21
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
22
|
+
assert_equal '{"id":null,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":null}', model.serialize
|
23
|
+
end
|
24
|
+
|
25
|
+
test '#serialize(:only => [KEYS])' do
|
26
|
+
time = Time.now
|
27
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
28
|
+
|
29
|
+
assert_equal '{"size":20}', model.serialize(:only => ['size'])
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
test '#save a new record' do
|
36
|
+
time = Time.now
|
37
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
38
|
+
|
39
|
+
stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
|
40
|
+
.with(
|
41
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
42
|
+
.to_return(
|
43
|
+
:status => 200,
|
44
|
+
:body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
45
|
+
|
46
|
+
assert_equal true, model.save
|
47
|
+
end
|
48
|
+
|
49
|
+
test '#save a new invalid record' do
|
50
|
+
time = Time.now
|
51
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
52
|
+
|
53
|
+
stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
|
54
|
+
.with(
|
55
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
56
|
+
.to_return(
|
57
|
+
:status => 400,
|
58
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
59
|
+
|
60
|
+
assert_equal false, model.save
|
61
|
+
end
|
62
|
+
|
63
|
+
test "#save a new record updates the model with the response" do
|
64
|
+
time = Time.now
|
65
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
66
|
+
|
67
|
+
stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
|
68
|
+
.with(
|
69
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
70
|
+
.to_return(
|
71
|
+
:status => 200,
|
72
|
+
:body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
73
|
+
|
74
|
+
model.save
|
75
|
+
assert_equal 20, model.id
|
76
|
+
assert_equal time.iso8601(3), model.updated_at.iso8601(3)
|
77
|
+
end
|
78
|
+
|
79
|
+
test "#save on an new record will set new_record? is false" do
|
80
|
+
time = Time.now
|
81
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
82
|
+
|
83
|
+
stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
|
84
|
+
.with(
|
85
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
86
|
+
.to_return(
|
87
|
+
:status => 200,
|
88
|
+
:body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
89
|
+
|
90
|
+
model.save
|
91
|
+
assert_equal false, model.new_record?
|
92
|
+
end
|
93
|
+
|
94
|
+
test '#save on a persisted record' do
|
95
|
+
time = Time.now
|
96
|
+
model = TestModel.new(:id => 13, :size => 20, :timestamp => time)
|
97
|
+
model.instance_variable_set(:@new_record, false)
|
98
|
+
|
99
|
+
stub_request(:put, "http://testhost.com/sunstone_model_persistence_test_test_models/13")
|
100
|
+
.with(
|
101
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
102
|
+
.to_return(
|
103
|
+
:status => 200,
|
104
|
+
:body => '{"id":13,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
105
|
+
|
106
|
+
assert_equal true, model.save
|
107
|
+
end
|
108
|
+
|
109
|
+
test '#save on a persisted record updates the model with the response' do
|
110
|
+
time = Time.now
|
111
|
+
model = TestModel.new(:id => 13, :size => 20, :timestamp => time)
|
112
|
+
model.instance_variable_set(:@new_record, false)
|
113
|
+
|
114
|
+
stub_request(:put, "http://testhost.com/sunstone_model_persistence_test_test_models/13")
|
115
|
+
.with(
|
116
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
117
|
+
.to_return(
|
118
|
+
:status => 200,
|
119
|
+
:body => '{"id":13,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
120
|
+
|
121
|
+
model.save
|
122
|
+
assert_equal 13, model.id
|
123
|
+
assert_equal time.iso8601(3), model.updated_at.iso8601(3)
|
124
|
+
end
|
125
|
+
|
126
|
+
test '#save! a new record' do
|
127
|
+
time = Time.now
|
128
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
129
|
+
|
130
|
+
stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
|
131
|
+
.with(
|
132
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
133
|
+
.to_return(
|
134
|
+
:status => 200,
|
135
|
+
:body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
136
|
+
|
137
|
+
assert_equal true, model.save!
|
138
|
+
end
|
139
|
+
|
140
|
+
test '#save! a new invalid record' do
|
141
|
+
time = Time.now
|
142
|
+
model = TestModel.new(:size => 20, :timestamp => time)
|
143
|
+
|
144
|
+
stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
|
145
|
+
.with(
|
146
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
|
147
|
+
.to_return(
|
148
|
+
:status => 400,
|
149
|
+
:body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
|
150
|
+
|
151
|
+
assert_raises Sunstone::RecordInvalid do
|
152
|
+
model.save!
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
test '::find(id)' do
|
158
|
+
stub_request(:get, "http://testhost.com/sunstone_model_persistence_test_test_models/324").to_return(:body => '{"size": 40}')
|
159
|
+
|
160
|
+
model = TestModel.find('324')
|
161
|
+
assert_kind_of TestModel, model
|
162
|
+
assert_equal 40, model.size
|
163
|
+
end
|
164
|
+
|
165
|
+
test '::find(id) with 404' do
|
166
|
+
stub_request(:get, "http://testhost.com/sunstone_model_persistence_test_test_models/324").to_return(:status => 404)
|
167
|
+
|
168
|
+
assert_raises Sunstone::Exception::NotFound do
|
169
|
+
TestModel.find('324')
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|