my_john_deere_api 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/my_john_deere_api/request/create/asset.rb +16 -72
- data/lib/my_john_deere_api/request/create/asset_location.rb +113 -0
- data/lib/my_john_deere_api/request/create/base.rb +97 -0
- data/lib/my_john_deere_api/version.rb +1 -1
- data/test/lib/my_john_deere_api/request/create/asset_location_test.rb +168 -0
- data/test/lib/my_john_deere_api/request/create/asset_test.rb +1 -14
- data/test/lib/my_john_deere_api/request/create/base_test.rb +24 -0
- data/test/support/vcr/post_asset_locations.yml +95 -0
- data/test/support/vcr/post_assets.yml +5 -5
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d022fff0506123f5684e53e1365c9c72cd55225368bb7303db30f74e8c3bc651
|
4
|
+
data.tar.gz: d6ab2cabe0386168c984ddfcfbf6aa7ff1ac4a73b8cde4cd379ba9849fbe4e96
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d0815d5d7634f901741c073680769d663161cc3d959cbf914bfef8fd1f799603bb38fd2e9964700b1d421fc10929fb9ae869c763058998eff091a131ad25ae5
|
7
|
+
data.tar.gz: 496c89a2ff02d8eb0ea3edd05f03889863b6c444f4aea19d3752d69dae6904bb530ee1e6d58c1f3aab3cd9c432138f35b045d58b71eb556a74b60ecf9e69e8a7
|
@@ -2,10 +2,6 @@ require 'json'
|
|
2
2
|
|
3
3
|
module MyJohnDeereApi
|
4
4
|
class Request::Create::Asset < Request::Create::Base
|
5
|
-
attr_reader :accessor, :attributes, :errors, :response
|
6
|
-
|
7
|
-
REQUIRED_ATTRIBUTES = [:organization_id, :contribution_definition_id, :title]
|
8
|
-
|
9
5
|
VALID_CATEGORIES = {
|
10
6
|
'DEVICE' => {
|
11
7
|
'SENSOR' => ['GRAIN_BIN', 'ENVIRONMENTAL', 'IRRIGATION_PIVOT', 'OTHER']
|
@@ -17,78 +13,46 @@ module MyJohnDeereApi
|
|
17
13
|
},
|
18
14
|
}
|
19
15
|
|
20
|
-
|
21
|
-
# Accepts a valid oAuth AccessToken, and a hash of attributes.
|
22
|
-
#
|
23
|
-
# Required attributes:
|
24
|
-
# - organization_id
|
25
|
-
# - contribution_definition_id
|
26
|
-
# - title
|
27
|
-
# - asset_category
|
28
|
-
# - asset_type
|
29
|
-
# - asset_sub_type
|
30
|
-
#
|
31
|
-
# category/type/subtype must be a recognized combination as defined above.
|
32
|
-
|
33
|
-
def initialize(accessor, attributes)
|
34
|
-
@accessor = accessor
|
35
|
-
@attributes = attributes
|
36
|
-
@errors = {}
|
37
|
-
end
|
16
|
+
private
|
38
17
|
|
39
18
|
##
|
40
|
-
#
|
41
|
-
|
42
|
-
def object
|
43
|
-
return @object if defined?(@object)
|
44
|
-
|
45
|
-
request unless response
|
19
|
+
# attributes that must be specified
|
46
20
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
@object = Model::Asset.new(JSON.parse(result.body), accessor)
|
21
|
+
def required_attributes
|
22
|
+
[:organization_id, :contribution_definition_id, :title]
|
51
23
|
end
|
52
24
|
|
53
25
|
##
|
54
|
-
#
|
26
|
+
# Retrieve newly created record
|
27
|
+
|
28
|
+
def fetch_record
|
29
|
+
path = response['location'].split('/platform').last
|
30
|
+
result = accessor.get(path, headers)
|
55
31
|
|
56
|
-
|
57
|
-
validate!
|
58
|
-
@response = accessor.post(resource, request_body.to_json, headers)
|
32
|
+
JSON.parse(result.body)
|
59
33
|
end
|
60
34
|
|
61
35
|
##
|
62
|
-
#
|
63
|
-
# to the error, in order to build a useful message string.
|
36
|
+
# This is the class used to model the data
|
64
37
|
|
65
|
-
def
|
66
|
-
|
38
|
+
def model
|
39
|
+
Model::Asset
|
67
40
|
end
|
68
41
|
|
69
42
|
##
|
70
|
-
#
|
71
|
-
# if the errors hash is still empty after all validations have been run.
|
72
|
-
|
73
|
-
def valid?
|
74
|
-
return @is_valid if defined?(@is_valid)
|
75
|
-
|
76
|
-
validate_required
|
43
|
+
# Handle any custom validation for this model that may not apply to others
|
77
44
|
|
45
|
+
def validate_attributes
|
78
46
|
unless valid_categories?(attributes[:asset_category], attributes[:asset_type], attributes[:asset_sub_type])
|
79
47
|
errors[:asset_category] = 'requires valid combination of category/type/subtype'
|
80
48
|
end
|
81
|
-
|
82
|
-
@is_valid = errors.empty?
|
83
49
|
end
|
84
50
|
|
85
|
-
private
|
86
|
-
|
87
51
|
##
|
88
52
|
# Path supplied to API
|
89
53
|
|
90
54
|
def resource
|
91
|
-
@
|
55
|
+
@resource ||= "/organizations/#{attributes[:organization_id]}/assets"
|
92
56
|
end
|
93
57
|
|
94
58
|
##
|
@@ -97,7 +61,6 @@ module MyJohnDeereApi
|
|
97
61
|
def request_body
|
98
62
|
return @body if defined?(@body)
|
99
63
|
|
100
|
-
|
101
64
|
@body = {
|
102
65
|
title: attributes[:title],
|
103
66
|
assetCategory: attributes[:asset_category],
|
@@ -113,30 +76,11 @@ module MyJohnDeereApi
|
|
113
76
|
}
|
114
77
|
end
|
115
78
|
|
116
|
-
##
|
117
|
-
# Validates required attributes
|
118
|
-
|
119
|
-
def validate_required
|
120
|
-
REQUIRED_ATTRIBUTES.each do |attr|
|
121
|
-
errors[attr] = 'is required' unless attributes.keys.include?(attr)
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
79
|
##
|
126
80
|
# Returns boolean, true if this combination is valid
|
127
81
|
|
128
82
|
def valid_categories?(category, type, subtype)
|
129
83
|
VALID_CATEGORIES.dig(category, type).to_a.include?(subtype)
|
130
84
|
end
|
131
|
-
|
132
|
-
##
|
133
|
-
# Headers for POST request
|
134
|
-
|
135
|
-
def headers
|
136
|
-
@headers ||= {
|
137
|
-
'Accept' => 'application/vnd.deere.axiom.v3+json',
|
138
|
-
'Content-Type' => 'application/vnd.deere.axiom.v3+json'
|
139
|
-
}
|
140
|
-
end
|
141
85
|
end
|
142
86
|
end
|
@@ -1,5 +1,118 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
1
3
|
module MyJohnDeereApi
|
2
4
|
class Request::Create::AssetLocation < Request::Create::Base
|
5
|
+
private
|
6
|
+
|
7
|
+
##
|
8
|
+
# Request body
|
9
|
+
|
10
|
+
def request_body
|
11
|
+
return @body if defined?(@body)
|
12
|
+
|
13
|
+
@body = [
|
14
|
+
{
|
15
|
+
timestamp: timestamp,
|
16
|
+
geometry: geometry,
|
17
|
+
measurementData: attributes[:measurement_data]
|
18
|
+
}
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Parsed timestamp
|
24
|
+
|
25
|
+
def timestamp
|
26
|
+
return @timestamp if defined?(@timestamp)
|
27
|
+
|
28
|
+
@timestamp = attributes[:timestamp].is_a?(String) ?
|
29
|
+
attributes[:timestamp] :
|
30
|
+
attributes[:timestamp].strftime('%Y-%m-%dT%H:%M:%SZ')
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Parse geometry
|
35
|
+
|
36
|
+
def geometry
|
37
|
+
return @geometry if defined?(@geometry)
|
38
|
+
|
39
|
+
@geometry = attributes[:geometry].is_a?(String) ?
|
40
|
+
attributes[:geometry] :
|
41
|
+
attributes[:geometry].to_json
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Path supplied to API
|
46
|
+
|
47
|
+
def resource
|
48
|
+
@resource ||= "/assets/#{attributes[:asset_id]}/locations"
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Required attributes for this class
|
53
|
+
|
54
|
+
def required_attributes
|
55
|
+
[:asset_id, :timestamp, :geometry, :measurement_data]
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Retrieve newly created record
|
60
|
+
|
61
|
+
def fetch_record
|
62
|
+
# There is no way to fetch a single location by id, because locations
|
63
|
+
# don't have IDs. You have to fetch them in bulk via the asset, but
|
64
|
+
# there could be thousands. We limit to just the record created with
|
65
|
+
# our timestamp, which must be unique.
|
66
|
+
|
67
|
+
path = response['location'].split('/platform').last
|
68
|
+
start_date = timestamp_add(timestamp, -1)
|
69
|
+
end_date = timestamp_add(timestamp, 1)
|
70
|
+
path += "?startDate=#{start_date}&endDate=#{end_date}"
|
71
|
+
result = accessor.get(path, headers)
|
72
|
+
|
73
|
+
parsed_stamp = DateTime.parse(timestamp)
|
74
|
+
|
75
|
+
JSON.parse(result.body)['values'].detect do |record|
|
76
|
+
parsed_stamp == DateTime.parse(record['timestamp'])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Create a new timestamp adjusted by X minutes
|
82
|
+
|
83
|
+
def timestamp_add(timestamp, seconds)
|
84
|
+
stamp = DateTime.parse(timestamp).to_time + seconds
|
85
|
+
stamp.to_datetime.strftime('%Y-%m-%dT%H:%M:%SZ')
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# This is the class used to model the data
|
90
|
+
|
91
|
+
def model
|
92
|
+
Model::AssetLocation
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Custom validations for this class
|
97
|
+
|
98
|
+
def validate_attributes
|
99
|
+
validate_measurement_data
|
100
|
+
end
|
101
|
+
|
102
|
+
def validate_measurement_data
|
103
|
+
unless attributes[:measurement_data].is_a?(Array)
|
104
|
+
errors[:measurement_data] ||= 'must be an array'
|
105
|
+
return
|
106
|
+
end
|
3
107
|
|
108
|
+
attributes[:measurement_data].each do |measurement|
|
109
|
+
[:name, :value, :unit].each do |attr|
|
110
|
+
unless measurement.has_key?(attr)
|
111
|
+
errors[:measurement_data] ||= "must include #{attr}"
|
112
|
+
return
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
4
117
|
end
|
5
118
|
end
|
@@ -1,5 +1,102 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module MyJohnDeereApi
|
2
4
|
class Request::Create::Base
|
5
|
+
attr_reader :accessor, :attributes, :errors, :response
|
6
|
+
|
7
|
+
##
|
8
|
+
# Accepts a valid oAuth AccessToken, and a hash of attributes.
|
9
|
+
#
|
10
|
+
# Required attributes:
|
11
|
+
# - organization_id
|
12
|
+
# - contribution_definition_id
|
13
|
+
# - title
|
14
|
+
# - asset_category
|
15
|
+
# - asset_type
|
16
|
+
# - asset_sub_type
|
17
|
+
#
|
18
|
+
# category/type/subtype must be a recognized combination as defined above.
|
19
|
+
|
20
|
+
def initialize(accessor, attributes)
|
21
|
+
@accessor = accessor
|
22
|
+
@attributes = attributes
|
23
|
+
|
24
|
+
@errors = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Make the request, if the instance is valid
|
29
|
+
|
30
|
+
def request
|
31
|
+
validate!
|
32
|
+
@response = accessor.post(resource, request_body.to_json, headers)
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Object created by request
|
37
|
+
|
38
|
+
def object
|
39
|
+
return @object if defined?(@object)
|
40
|
+
|
41
|
+
request unless response
|
42
|
+
|
43
|
+
@object = model.new(fetch_record, accessor)
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Runs validations, adding to the errors hash as needed. Returns true
|
48
|
+
# if the errors hash is still empty after all validations have been run.
|
49
|
+
|
50
|
+
def valid?
|
51
|
+
return @is_valid if defined?(@is_valid)
|
52
|
+
|
53
|
+
validate_required
|
54
|
+
validate_attributes
|
55
|
+
|
56
|
+
@is_valid = errors.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# Run validations unique to a given model. This should be overridden
|
61
|
+
# by children where needed.
|
62
|
+
|
63
|
+
def validate_attributes
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Raises an error if the record is invalid. Passes the errors hash
|
68
|
+
# to the error, in order to build a useful message string.
|
69
|
+
|
70
|
+
def validate!
|
71
|
+
raise(InvalidRecordError, errors) unless valid?
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
##
|
77
|
+
# Attributes that must be specified, override in child class
|
78
|
+
|
79
|
+
def required_attributes
|
80
|
+
[]
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Validates required attributes
|
85
|
+
|
86
|
+
def validate_required
|
87
|
+
required_attributes.each do |attr|
|
88
|
+
errors[attr] = 'is required' unless attributes.keys.include?(attr)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Headers for POST request
|
3
94
|
|
95
|
+
def headers
|
96
|
+
@headers ||= {
|
97
|
+
'Accept' => 'application/vnd.deere.axiom.v3+json',
|
98
|
+
'Content-Type' => 'application/vnd.deere.axiom.v3+json'
|
99
|
+
}
|
100
|
+
end
|
4
101
|
end
|
5
102
|
end
|
@@ -1,10 +1,178 @@
|
|
1
1
|
require 'support/helper'
|
2
|
+
require 'date'
|
2
3
|
|
3
4
|
describe 'MyJohnDeereApi::Request::Create::AssetLocation' do
|
5
|
+
def attributes_without(*keys)
|
6
|
+
keys = keys.to_a
|
7
|
+
attributes.reject{|k,v| keys.include?(k)}
|
8
|
+
end
|
9
|
+
|
4
10
|
let(:client) { JD::Client.new(API_KEY, API_SECRET, environment: :sandbox, access: [ACCESS_TOKEN, ACCESS_SECRET]) }
|
5
11
|
let(:accessor) { VCR.use_cassette('catalog') { client.send(:accessor) } }
|
6
12
|
|
13
|
+
let(:asset_id) { ENV['ASSET_ID'] }
|
14
|
+
let(:timestamp) { DateTime.parse(timestamp_string) }
|
15
|
+
let(:timestamp_string) { '2020-01-18T00:31:00Z' }
|
16
|
+
|
17
|
+
let(:geometry) do
|
18
|
+
{
|
19
|
+
type: 'Point',
|
20
|
+
coordinates: [-103.115633, 41.670166]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:measurement_data) do
|
25
|
+
[
|
26
|
+
{
|
27
|
+
name: 'Temperature',
|
28
|
+
value: '68.0',
|
29
|
+
unit: 'F'
|
30
|
+
}
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:valid_attributes) do
|
35
|
+
{
|
36
|
+
asset_id: asset_id,
|
37
|
+
timestamp: timestamp,
|
38
|
+
geometry: geometry,
|
39
|
+
measurement_data: measurement_data
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:attributes) { valid_attributes }
|
44
|
+
|
7
45
|
describe '#initialize(access_token, attributes)' do
|
46
|
+
it 'accepts an accessor and attributes' do
|
47
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes)
|
48
|
+
|
49
|
+
assert_equal accessor, object.accessor
|
50
|
+
assert_equal attributes, object.attributes
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'creates an empty error hash' do
|
54
|
+
object = JD::Request::Create::AssetLocation.new(accessor, {})
|
55
|
+
assert_equal({}, object.errors)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#valid?' do
|
60
|
+
it 'returns true when all required attributes are present' do
|
61
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes)
|
62
|
+
|
63
|
+
assert object.valid?
|
64
|
+
assert_empty object.errors
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'requires asset_id' do
|
68
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes_without(:asset_id))
|
69
|
+
|
70
|
+
refute object.valid?
|
71
|
+
assert_equal 'is required', object.errors[:asset_id]
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'requires timestamp' do
|
75
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes_without(:timestamp))
|
76
|
+
|
77
|
+
refute object.valid?
|
78
|
+
assert_equal 'is required', object.errors[:timestamp]
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'requires geometry' do
|
82
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes_without(:geometry))
|
83
|
+
|
84
|
+
refute object.valid?
|
85
|
+
assert_equal 'is required', object.errors[:geometry]
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'requires measurement_data' do
|
89
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes_without(:measurement_data))
|
90
|
+
|
91
|
+
refute object.valid?
|
92
|
+
assert_equal 'is required', object.errors[:measurement_data]
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'validating measurement_data' do
|
96
|
+
it 'must be an array' do
|
97
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes.merge(measurement_data: 'something'))
|
98
|
+
|
99
|
+
refute object.valid?
|
100
|
+
assert_equal 'must be an array', object.errors[:measurement_data]
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'must include a name' do
|
104
|
+
without_attr = [measurement_data.first.reject{|k,v| k == :name}]
|
105
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes.merge(measurement_data: without_attr))
|
106
|
+
|
107
|
+
refute object.valid?
|
108
|
+
assert_equal 'must include name', object.errors[:measurement_data]
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'must include a value' do
|
112
|
+
without_attr = [measurement_data.first.reject{|k,v| k == :value}]
|
113
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes.merge(measurement_data: without_attr))
|
114
|
+
|
115
|
+
refute object.valid?
|
116
|
+
assert_equal 'must include value', object.errors[:measurement_data]
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'must include a unit' do
|
120
|
+
without_attr = [measurement_data.first.reject{|k,v| k == :unit}]
|
121
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes.merge(measurement_data: without_attr))
|
122
|
+
|
123
|
+
refute object.valid?
|
124
|
+
assert_equal 'must include unit', object.errors[:measurement_data]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe '#validate!' do
|
130
|
+
it 'raises an error when invalid' do
|
131
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes_without(:asset_id))
|
132
|
+
|
133
|
+
exception = assert_raises(JD::InvalidRecordError) { object.validate! }
|
134
|
+
assert_includes exception.message, 'Record is invalid'
|
135
|
+
assert_includes exception.message, 'asset_id is required'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#request_body' do
|
140
|
+
it 'properly forms the request body' do
|
141
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes)
|
142
|
+
body = object.send(:request_body)
|
143
|
+
|
144
|
+
assert_kind_of Array, body
|
145
|
+
assert_equal timestamp_string, body.first[:timestamp]
|
146
|
+
assert_equal geometry.to_json, body.first[:geometry]
|
147
|
+
assert_equal measurement_data, body.first[:measurementData]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#request' do
|
152
|
+
it 'makes the request' do
|
153
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes)
|
154
|
+
VCR.use_cassette('post_asset_locations') { object.request }
|
155
|
+
|
156
|
+
assert_kind_of Net::HTTPCreated, object.response
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#object' do
|
161
|
+
it 'returns the asset location model instance' do
|
162
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes)
|
163
|
+
result = VCR.use_cassette('post_asset_locations') { object.object }
|
164
|
+
|
165
|
+
assert_kind_of JD::Model::AssetLocation, result
|
166
|
+
|
167
|
+
# API returns seconds with decimals, even though they're always zero
|
168
|
+
integer_stamp = DateTime.parse(result.timestamp).strftime('%Y-%m-%dT%H:%M:%SZ')
|
169
|
+
|
170
|
+
# API returns string keys and an extra '@type' key
|
171
|
+
result_measurement_data = result.measurement_data.first.transform_keys{|k| k.to_sym}.slice(:name, :value, :unit)
|
8
172
|
|
173
|
+
assert_equal timestamp_string, integer_stamp
|
174
|
+
assert_equal geometry.to_json, result.geometry.to_json
|
175
|
+
assert_equal measurement_data.first, result_measurement_data
|
176
|
+
end
|
9
177
|
end
|
10
178
|
end
|
@@ -171,23 +171,10 @@ describe 'MyJohnDeereApi::Request::Create::Asset' do
|
|
171
171
|
end
|
172
172
|
end
|
173
173
|
|
174
|
-
describe '#headers' do
|
175
|
-
it 'sets the accept and content-type headers' do
|
176
|
-
object = JD::Request::Create::Asset.new(accessor, attributes)
|
177
|
-
headers = object.send(:headers)
|
178
|
-
|
179
|
-
expected = 'application/vnd.deere.axiom.v3+json'
|
180
|
-
|
181
|
-
assert_kind_of Hash, headers
|
182
|
-
assert_equal expected, headers['Accept']
|
183
|
-
assert_equal expected, headers['Content-Type']
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
174
|
describe '#request' do
|
188
175
|
it 'makes the request' do
|
189
176
|
object = JD::Request::Create::Asset.new(accessor, attributes)
|
190
|
-
|
177
|
+
VCR.use_cassette('post_assets') { object.request }
|
191
178
|
|
192
179
|
assert_kind_of Net::HTTPCreated, object.response
|
193
180
|
end
|
@@ -3,8 +3,32 @@ require 'support/helper'
|
|
3
3
|
describe 'MyJohnDeereApi::Request::Create::Base' do
|
4
4
|
let(:client) { JD::Client.new(API_KEY, API_SECRET, environment: :sandbox, access: [ACCESS_TOKEN, ACCESS_SECRET]) }
|
5
5
|
let(:accessor) { VCR.use_cassette('catalog') { client.send(:accessor) } }
|
6
|
+
let(:attributes) { {} }
|
6
7
|
|
7
8
|
describe '#initialize(access_token, attributes)' do
|
9
|
+
it 'accepts an accessor and attributes' do
|
10
|
+
object = JD::Request::Create::AssetLocation.new(accessor, attributes)
|
8
11
|
|
12
|
+
assert_equal accessor, object.accessor
|
13
|
+
assert_equal attributes, object.attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'creates an empty error hash' do
|
17
|
+
object = JD::Request::Create::AssetLocation.new(accessor, {})
|
18
|
+
assert_equal({}, object.errors)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#headers' do
|
23
|
+
it 'sets the accept and content-type headers' do
|
24
|
+
object = JD::Request::Create::Asset.new(accessor, attributes)
|
25
|
+
headers = object.send(:headers)
|
26
|
+
|
27
|
+
expected = 'application/vnd.deere.axiom.v3+json'
|
28
|
+
|
29
|
+
assert_kind_of Hash, headers
|
30
|
+
assert_equal expected, headers['Accept']
|
31
|
+
assert_equal expected, headers['Content-Type']
|
32
|
+
end
|
9
33
|
end
|
10
34
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://sandboxapi.deere.com/platform/assets/029c288a-14d9-459f-8ee6-b4e840e672a1/locations
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '[{"timestamp":"2020-01-18T00:31:00Z","geometry":"{\"type\":\"Point\",\"coordinates\":[-103.115633,41.670166]}","measurementData":[{"name":"Temperature","value":"68.0","unit":"F"}]}]'
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- application/vnd.deere.axiom.v3+json
|
12
|
+
Content-Type:
|
13
|
+
- application/vnd.deere.axiom.v3+json
|
14
|
+
Accept-Encoding:
|
15
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
16
|
+
User-Agent:
|
17
|
+
- OAuth gem v0.5.4
|
18
|
+
Content-Length:
|
19
|
+
- '181'
|
20
|
+
Authorization:
|
21
|
+
- OAuth oauth_body_hash="iiLtEEcE%2B8AM8XC5NLttAeL92i4%3D", oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
|
22
|
+
oauth_nonce="hMwIfcVWHIyjE51AQcMztDSCm0AWilBe4LTFZvuI", oauth_signature="ibSHPRsXfeazw1%2F5I%2BZlcipIZRk%3D",
|
23
|
+
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1579308624", oauth_token="47bbb9c9-41a8-4bec-8127-e3c5760af2f6",
|
24
|
+
oauth_version="1.0"
|
25
|
+
response:
|
26
|
+
status:
|
27
|
+
code: 201
|
28
|
+
message: Created
|
29
|
+
headers:
|
30
|
+
Date:
|
31
|
+
- Sat, 18 Jan 2020 00:50:24 GMT
|
32
|
+
Content-Type:
|
33
|
+
- application/vnd.deere.axiom.v3+json
|
34
|
+
X-Deere-Handling-Server:
|
35
|
+
- ip-10-214-45-182
|
36
|
+
X-Frame-Options:
|
37
|
+
- SAMEORIGIN
|
38
|
+
Location:
|
39
|
+
- https://sandboxapi.deere.com/platform/assets/029c288a-14d9-459f-8ee6-b4e840e672a1/locations
|
40
|
+
X-Deere-Elapsed-Ms:
|
41
|
+
- '59'
|
42
|
+
Transfer-Encoding:
|
43
|
+
- chunked
|
44
|
+
body:
|
45
|
+
encoding: ASCII-8BIT
|
46
|
+
string: ''
|
47
|
+
http_version:
|
48
|
+
recorded_at: Sat, 18 Jan 2020 00:50:24 GMT
|
49
|
+
- request:
|
50
|
+
method: get
|
51
|
+
uri: https://sandboxapi.deere.com/platform/assets/029c288a-14d9-459f-8ee6-b4e840e672a1/locations?endDate=2020-01-18T00:31:01Z&startDate=2020-01-18T00:30:59Z
|
52
|
+
body:
|
53
|
+
encoding: US-ASCII
|
54
|
+
string: ''
|
55
|
+
headers:
|
56
|
+
Accept:
|
57
|
+
- application/vnd.deere.axiom.v3+json
|
58
|
+
Content-Type:
|
59
|
+
- application/vnd.deere.axiom.v3+json
|
60
|
+
Accept-Encoding:
|
61
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
62
|
+
User-Agent:
|
63
|
+
- OAuth gem v0.5.4
|
64
|
+
Authorization:
|
65
|
+
- OAuth oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
|
66
|
+
oauth_nonce="hStGJCzcb5OY7HwmEsQwNX253TTZ85FurItAwDuxvdQ", oauth_signature="LEKTEGOy%2FmqrsGuEqvASGBYk7gY%3D",
|
67
|
+
oauth_signature_method="HMAC-SHA1", oauth_timestamp="1579308624", oauth_token="47bbb9c9-41a8-4bec-8127-e3c5760af2f6",
|
68
|
+
oauth_version="1.0"
|
69
|
+
response:
|
70
|
+
status:
|
71
|
+
code: 200
|
72
|
+
message: OK
|
73
|
+
headers:
|
74
|
+
Date:
|
75
|
+
- Sat, 18 Jan 2020 00:50:25 GMT
|
76
|
+
Content-Type:
|
77
|
+
- application/vnd.deere.axiom.v3+json;charset=UTF-8
|
78
|
+
X-Deere-Handling-Server:
|
79
|
+
- ip-10-214-45-182
|
80
|
+
X-Frame-Options:
|
81
|
+
- SAMEORIGIN
|
82
|
+
X-Deere-Elapsed-Ms:
|
83
|
+
- '44'
|
84
|
+
Cache-Control:
|
85
|
+
- no-store
|
86
|
+
Content-Language:
|
87
|
+
- en-US
|
88
|
+
Transfer-Encoding:
|
89
|
+
- chunked
|
90
|
+
body:
|
91
|
+
encoding: ASCII-8BIT
|
92
|
+
string: '{"links":[{"rel":"self","uri":"https://sandboxapi.deere.com/platform/assets/029c288a-14d9-459f-8ee6-b4e840e672a1/locations?startDate=2020-01-18T00:30:59Z&endDate=2020-01-18T00:31:01Z"}],"total":1,"values":[{"@type":"ContributedAssetLocation","timestamp":"2020-01-18T00:31:00.000Z","geometry":"{\"type\":\"Point\",\"coordinates\":[-103.115633,41.670166]}","measurementData":[{"@type":"BasicMeasurement","name":"Temperature","value":"68.0","unit":"F"}],"links":[]}]}'
|
93
|
+
http_version:
|
94
|
+
recorded_at: Sat, 18 Jan 2020 00:50:25 GMT
|
95
|
+
recorded_with: VCR 5.0.0
|
@@ -36,7 +36,7 @@ http_interactions:
|
|
36
36
|
X-Frame-Options:
|
37
37
|
- SAMEORIGIN
|
38
38
|
Location:
|
39
|
-
- https://sandboxapi.deere.com/platform/assets/
|
39
|
+
- https://sandboxapi.deere.com/platform/assets/029c288a-14d9-459f-8ee6-b4e840e672a1
|
40
40
|
X-Deere-Elapsed-Ms:
|
41
41
|
- '131'
|
42
42
|
Transfer-Encoding:
|
@@ -44,11 +44,11 @@ http_interactions:
|
|
44
44
|
body:
|
45
45
|
encoding: ASCII-8BIT
|
46
46
|
string: ''
|
47
|
-
http_version:
|
47
|
+
http_version:
|
48
48
|
recorded_at: Fri, 17 Jan 2020 20:05:46 GMT
|
49
49
|
- request:
|
50
50
|
method: get
|
51
|
-
uri: https://sandboxapi.deere.com/platform/assets/
|
51
|
+
uri: https://sandboxapi.deere.com/platform/assets/029c288a-14d9-459f-8ee6-b4e840e672a1
|
52
52
|
body:
|
53
53
|
encoding: US-ASCII
|
54
54
|
string: ''
|
@@ -89,7 +89,7 @@ http_interactions:
|
|
89
89
|
- chunked
|
90
90
|
body:
|
91
91
|
encoding: ASCII-8BIT
|
92
|
-
string: '{"@type":"ContributedAsset","title":"i like turtles","assetCategory":"DEVICE","assetType":"SENSOR","assetSubType":"ENVIRONMENTAL","lastModifiedDate":"2020-01-17T20:05:45.961Z","id":"
|
93
|
-
http_version:
|
92
|
+
string: '{"@type":"ContributedAsset","title":"i like turtles","assetCategory":"DEVICE","assetType":"SENSOR","assetSubType":"ENVIRONMENTAL","lastModifiedDate":"2020-01-17T20:05:45.961Z","id":"029c288a-14d9-459f-8ee6-b4e840e672a1","links":[{"@type":"Link","rel":"self","uri":"https://sandboxapi.deere.com/platform/assets/911772e9-03c5-4a02-8acf-6d7574672558"},{"@type":"Link","rel":"contributionDefinition","uri":"https://sandboxapi.deere.com/platform/contributionDefinitions/d93611c7-6f74-474f-9569-2cf88f866a32"},{"@type":"Link","rel":"organization","uri":"https://sandboxapi.deere.com/platform/organizations/444563"},{"@type":"Link","rel":"locations","uri":"https://sandboxapi.deere.com/platform/assets/911772e9-03c5-4a02-8acf-6d7574672558/locations"},{"@type":"Link","rel":"lastKnownLocation","uri":"https://sandboxapi.deere.com/platform/assets/911772e9-03c5-4a02-8acf-6d7574672558/locations?lastKnown=true"}]}'
|
93
|
+
http_version:
|
94
94
|
recorded_at: Fri, 17 Jan 2020 20:05:46 GMT
|
95
95
|
recorded_with: VCR 5.0.0
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: my_john_deere_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jaime. Bellmyer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: vcr
|
@@ -167,6 +167,7 @@ files:
|
|
167
167
|
- test/support/vcr/get_flags.yml
|
168
168
|
- test/support/vcr/get_organizations.yml
|
169
169
|
- test/support/vcr/get_request_token.yml
|
170
|
+
- test/support/vcr/post_asset_locations.yml
|
170
171
|
- test/support/vcr/post_assets.yml
|
171
172
|
- test/support/vcr/post_flag_categories.yml
|
172
173
|
homepage: https://github.com/Intellifarm/my_john_deere_api
|