amee 2.6.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/Gemfile +18 -0
  2. data/README +2 -2
  3. data/Rakefile +31 -0
  4. data/VERSION +1 -0
  5. data/amee-ruby.gemspec +147 -0
  6. data/examples/view_profile_item.rb +32 -0
  7. data/lib/amee.rb +0 -1
  8. data/lib/amee/profile_item.rb +27 -6
  9. data/spec/amee_spec.rb +25 -0
  10. data/spec/cache_spec.rb +152 -0
  11. data/spec/connection_spec.rb +295 -0
  12. data/spec/data_category_spec.rb +259 -0
  13. data/spec/data_item_spec.rb +224 -0
  14. data/spec/data_item_value_history_spec.rb +311 -0
  15. data/spec/data_item_value_spec.rb +231 -0
  16. data/spec/data_object_spec.rb +9 -0
  17. data/spec/drill_down_spec.rb +163 -0
  18. data/spec/fixtures/AD63A83B4D41.json +1 -0
  19. data/spec/fixtures/AD63A83B4D41.xml +1 -0
  20. data/spec/fixtures/create_item.json +1 -0
  21. data/spec/fixtures/create_item.xml +1 -0
  22. data/spec/fixtures/data.json +1 -0
  23. data/spec/fixtures/data.xml +1 -0
  24. data/spec/fixtures/data_home_energy_quantity.xml +146 -0
  25. data/spec/fixtures/data_home_energy_quantity_biodiesel.xml +177 -0
  26. data/spec/fixtures/data_transport_car_generic_drill_fuel_diesel.xml +33 -0
  27. data/spec/fixtures/empty.json +1 -0
  28. data/spec/fixtures/empty.xml +1 -0
  29. data/spec/fixtures/parse_test.xml +22 -0
  30. data/spec/fixtures/v0_data_transport_transport_drill_transportType_Car1.xml +20 -0
  31. data/spec/item_definition_spec.rb +313 -0
  32. data/spec/item_value_definition_spec.rb +253 -0
  33. data/spec/logger_spec.rb +16 -0
  34. data/spec/object_spec.rb +44 -0
  35. data/spec/parse_helper_spec.rb +72 -0
  36. data/spec/profile_category_spec.rb +565 -0
  37. data/spec/profile_item_spec.rb +451 -0
  38. data/spec/profile_item_value_spec.rb +196 -0
  39. data/spec/profile_object_spec.rb +24 -0
  40. data/spec/profile_spec.rb +88 -0
  41. data/spec/rails_spec.rb +48 -0
  42. data/spec/spec.opts +2 -0
  43. data/spec/spec_helper.rb +56 -0
  44. data/spec/user_spec.rb +249 -0
  45. metadata +189 -55
  46. data/lib/amee/version.rb +0 -10
@@ -0,0 +1,224 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe AMEE::Data::Item do
4
+
5
+ before(:each) do
6
+ @item = AMEE::Data::Item.new
7
+ end
8
+
9
+ it "should have common AMEE object properties" do
10
+ @item.is_a?(AMEE::Data::Object).should be_true
11
+ end
12
+
13
+ it "should have values" do
14
+ @item.should respond_to(:values)
15
+ end
16
+
17
+ it "should have values" do
18
+ @item.should respond_to(:choices)
19
+ end
20
+
21
+ it "should a label" do
22
+ @item.should respond_to(:label)
23
+ end
24
+
25
+ it "should initialize AMEE::Object data on creation" do
26
+ uid = 'ABCD1234'
27
+ @item = AMEE::Data::Item.new(:uid => uid)
28
+ @item.uid.should == uid
29
+ end
30
+
31
+ it "can be created with hash of data" do
32
+ values = ["one", "two"]
33
+ choices = [{:name => "one", :value => "two"}]
34
+ label = "test"
35
+ @item = AMEE::Data::Item.new(:label => label, :values => values, :choices => choices)
36
+ @item.values.should == values
37
+ @item.choices.should == choices
38
+ @item.label.should == label
39
+ end
40
+
41
+ end
42
+
43
+ describe AMEE::Data::Item, "with an authenticated connection" do
44
+
45
+ it "should parse XML correctly" do
46
+ connection = flexmock "connection"
47
+ connection.should_receive(:retries).and_return(0)
48
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.xml')))
49
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
50
+ @data.uid.should == "AD63A83B4D41"
51
+ @data.path.should == "/transport/plane/generic/AD63A83B4D41"
52
+ @data.full_path.should == "/data/transport/plane/generic/AD63A83B4D41"
53
+ @data.category_uid.should == "FBA97B70DBDF"
54
+ @data.created.should == DateTime.new(2007,8,1,9,00,41)
55
+ @data.modified.should == DateTime.new(2007,8,1,9,00,41)
56
+ @data.label.should == "domestic"
57
+ @data.item_definition_uid.should == "441BF4BEA15B"
58
+ @data.values.size.should == 5
59
+ @data.values[0][:name].should == "kgCO2 Per Passenger Journey"
60
+ @data.values[0][:path].should == "kgCO2PerPassengerJourney"
61
+ @data.values[0][:value].should == "0"
62
+ @data.values[0][:uid].should == "127612FA4921"
63
+ end
64
+
65
+ it "should parse choices correctly from XML" do
66
+ connection = flexmock "connection"
67
+ connection.should_receive(:retries).and_return(0)
68
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.xml')))
69
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
70
+ @data.choices.size.should == 6
71
+ @data.choices[0][:name].should == "distanceKmPerYear"
72
+ @data.choices[0][:value].should be_empty
73
+ @data.choices[1][:name].should == "journeysPerYear"
74
+ @data.choices[1][:value].should be_empty
75
+ @data.choices[2][:name].should == "lat1"
76
+ @data.choices[2][:value].should == "-999"
77
+ @data.choices[3][:name].should == "lat2"
78
+ @data.choices[3][:value].should == "-999"
79
+ @data.choices[4][:name].should == "long1"
80
+ @data.choices[4][:value].should == "-999"
81
+ @data.choices[5][:name].should == "long2"
82
+ @data.choices[5][:value].should == "-999"
83
+ end
84
+
85
+ it "should parse JSON correctly" do
86
+ connection = flexmock "connection"
87
+ connection.should_receive(:retries).and_return(0)
88
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json')))
89
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
90
+ @data.uid.should == "AD63A83B4D41"
91
+ @data.path.should == "/transport/plane/generic/AD63A83B4D41"
92
+ @data.full_path.should == "/data/transport/plane/generic/AD63A83B4D41"
93
+ @data.category_uid.should == "FBA97B70DBDF"
94
+ @data.created.should == DateTime.new(2007,8,1,9,00,41)
95
+ @data.modified.should == DateTime.new(2007,8,1,9,00,41)
96
+ @data.label.should == "domestic"
97
+ @data.values.size.should == 5
98
+ @data.values[0][:name].should == "kgCO2 Per Passenger Journey"
99
+ @data.values[0][:path].should == "kgCO2PerPassengerJourney"
100
+ @data.values[0][:value].should == "0"
101
+ @data.values[0][:uid].should == "127612FA4921"
102
+ end
103
+
104
+ it "should parse choices correctly from JSON" do
105
+ connection = flexmock "connection"
106
+ connection.should_receive(:retries).and_return(0)
107
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json')))
108
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
109
+ @data.choices.size.should == 6
110
+ @data.choices[0][:name].should == "distanceKmPerYear"
111
+ @data.choices[0][:value].should be_empty
112
+ @data.choices[1][:name].should == "journeysPerYear"
113
+ @data.choices[1][:value].should be_empty
114
+ @data.choices[2][:name].should == "lat1"
115
+ @data.choices[2][:value].should == "-999"
116
+ @data.choices[3][:name].should == "lat2"
117
+ @data.choices[3][:value].should == "-999"
118
+ @data.choices[4][:name].should == "long1"
119
+ @data.choices[4][:value].should == "-999"
120
+ @data.choices[5][:name].should == "long2"
121
+ @data.choices[5][:value].should == "-999"
122
+ end
123
+
124
+ it "should fail gracefully with bad XML" do
125
+ connection = flexmock "connection"
126
+ connection.should_receive(:retries).and_return(0)
127
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.xml').first(12)))
128
+ connection.should_receive(:expire).with("/data/transport/plane/generic/AD63A83B4D41").once
129
+ lambda{AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")}.should raise_error(REXML::ParseException)
130
+ end
131
+
132
+ it "should retry if bad XML is received first time" do
133
+ connection = flexmock "connection"
134
+ connection.should_receive(:retries).and_return(2)
135
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.xml').first(12))).twice
136
+ connection.should_receive(:expire).with("/data/transport/plane/generic/AD63A83B4D41").twice
137
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.xml'))).once
138
+ lambda{AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")}.should_not raise_error
139
+ end
140
+
141
+ it "should fail gracefully with bad data in XML" do
142
+ connection = flexmock "connection"
143
+ connection.should_receive(:retries).and_return(0)
144
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('empty.xml')))
145
+ connection.should_receive(:expire).with("/data/transport/plane/generic/AD63A83B4D41").once
146
+ lambda{AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")}.should raise_error(AMEE::BadData)
147
+ end
148
+
149
+ it "should fail gracefully with bad JSON" do
150
+ connection = flexmock "connection"
151
+ connection.should_receive(:retries).and_return(0)
152
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json').first(12)))
153
+ connection.should_receive(:expire).with("/data/transport/plane/generic/AD63A83B4D41").once
154
+ lambda{AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")}.should raise_error(JSON::ParserError)
155
+ end
156
+
157
+ it "should retry if bad JSON is received first time" do
158
+ connection = flexmock "connection"
159
+ connection.should_receive(:retries).and_return(2)
160
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json').first(12))).twice
161
+ connection.should_receive(:expire).with("/data/transport/plane/generic/AD63A83B4D41").twice
162
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json'))).once
163
+ lambda{AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")}.should_not raise_error
164
+ end
165
+
166
+ it "should fail gracefully with bad data in JSON" do
167
+ connection = flexmock "connection"
168
+ connection.should_receive(:retries).and_return(0)
169
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('empty.json')))
170
+ connection.should_receive(:expire).with("/data/transport/plane/generic/AD63A83B4D41").once
171
+ lambda{AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")}.should raise_error(AMEE::BadData)
172
+ end
173
+
174
+ it "should fail gracefully on other errors" do
175
+ connection = flexmock "connection"
176
+ connection.should_receive(:retries).and_return(0)
177
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_raise(Timeout::Error)
178
+ lambda{AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")}.should raise_error(Timeout::Error)
179
+ end
180
+
181
+ end
182
+
183
+ describe "with sensible data" do
184
+
185
+ it "allows client to get a value by name" do
186
+ connection = flexmock "connection"
187
+ connection.should_receive(:retries).and_return(0)
188
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json')))
189
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
190
+ @data.value("kgCO2 Per Passenger Km").should_not be_nil
191
+ @data.value("Source").should_not be_nil
192
+ end
193
+
194
+ it "allows client to get a value by path" do
195
+ connection = flexmock "connection"
196
+ connection.should_receive(:retries).and_return(0)
197
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json')))
198
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
199
+ @data.value("kgCO2PerPassengerKm").should_not be_nil
200
+ @data.value("source").should_not be_nil
201
+ end
202
+
203
+ it "allows update" do
204
+ connection = flexmock "connection"
205
+ connection.should_receive(:retries).and_return(0)
206
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json')))
207
+ connection.should_receive(:put).with("/data/transport/plane/generic/AD63A83B4D41", :kgCO2PerPassengerKm => 0.159).and_return(flexmock(:body => '{"amountPerMonth":0,"userValueChoices":{"choices":[{"value":"","name":"distanceKmPerYear"},{"value":"","name":"journeysPerYear"},{"value":"-999","name":"lat1"},{"value":"-999","name":"lat2"},{"value":"-999","name":"long1"},{"value":"-999","name":"long2"}],"name":"userValueChoices"},"path":"/transport/plane/generic/AD63A83B4D41","dataItem":{"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","itemDefinition":{"uid":"441BF4BEA15B"},"itemValues":[{"value":"0","uid":"127612FA4921","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}},{"value":"0.159","uid":"7F27A5707101","path":"kgCO2PerPassengerKm","name":"kgCO2 Per Passenger Km","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"996AE5477B3F","name":"kgCO2PerKm"},"uid":"D7B4340D9404","path":"kgCO2PerPassengerKm","name":"kgCO2 Per Passenger Km"}},{"value":"-","uid":"FF50EC918A8E","path":"size","name":"Size","itemValueDefinition":{"valueDefinition":{"valueType":"TEXT","uid":"CCEB59CACE1B","name":"text"},"uid":"5D7FB5F552A5","path":"size","name":"Size"}},{"value":"domestic","uid":"FDD62D27AA15","path":"type","name":"Type","itemValueDefinition":{"valueDefinition":{"valueType":"TEXT","uid":"CCEB59CACE1B","name":"text"},"uid":"C376560CB19F","path":"type","name":"Type"}},{"value":"DfT INAS Division, 29 March 2007","uid":"9BE08FBEC54E","path":"source","name":"Source","itemValueDefinition":{"valueDefinition":{"valueType":"TEXT","uid":"CCEB59CACE1B","name":"text"},"uid":"0F0592F05AAC","path":"source","name":"Source"}}],"label":"domestic","dataCategory":{"uid":"FBA97B70DBDF","path":"generic","name":"Generic"},"uid":"AD63A83B4D41","environment":{"uid":"5F5887BCF726"},"path":"","name":"AD63A83B4D41"}}'))
208
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
209
+ @data.value("kgCO2PerPassengerKm").should == "0.158"
210
+ @data.update(:kgCO2PerPassengerKm => 0.159)
211
+ #@data.value("kgCO2PerPassengerKm").should == "0.159"
212
+ end
213
+
214
+ it "fails gracefully if update fails" do
215
+ connection = flexmock "connection"
216
+ connection.should_receive(:retries).and_return(0)
217
+ connection.should_receive(:get).with("/data/transport/plane/generic/AD63A83B4D41", {}).and_return(flexmock(:body => fixture('AD63A83B4D41.json')))
218
+ connection.should_receive(:put).with("/data/transport/plane/generic/AD63A83B4D41", :kgCO2PerPassengerKm => 0.159).and_raise("generic error")
219
+ @data = AMEE::Data::Item.get(connection, "/data/transport/plane/generic/AD63A83B4D41")
220
+ lambda{@data.update(:kgCO2PerPassengerKm => 0.159)}.should raise_error(AMEE::BadData)
221
+ end
222
+
223
+
224
+ end
@@ -0,0 +1,311 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ TestSeriesOne=[[AMEE::Epoch,1],[AMEE::Epoch+1,2],[AMEE::Epoch+3,4]]
4
+ TestSeriesTwo=[[AMEE::Epoch,2],[AMEE::Epoch+1,6],[AMEE::Epoch+5,7],[AMEE::Epoch+9,11]]
5
+
6
+ MockResourcePath="/data/transport/plane/generic/AD63A83B4D41/kgCO2PerPassengerJourney"
7
+ MockDataItemPath="/data/transport/plane/generic/AD63A83B4D41"
8
+ MockResourceXML='<Resources><DataItemValueResource><ItemValues>'+
9
+ '<ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4921"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+AMEE::Epoch.xmlschema+'</StartDate><Value>1</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/>'+
10
+ '<ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4922"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+(AMEE::Epoch+1).xmlschema+'</StartDate><Value>2</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/>'+
11
+ '<ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4923"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+(AMEE::Epoch+3).xmlschema+'</StartDate><Value>4</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/>'+
12
+ '</ItemValues></DataItemValueResource></Resources>'
13
+ MockResourceJSON='{"dataItem":{"uid":"AD63A83B4D41"},"itemValues":['+
14
+ ' {"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+AMEE::Epoch.xmlschema+'","value":"1","uid":"127612FA4921","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
15
+ ',{"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+(AMEE::Epoch+1).xmlschema+'","value":"2","uid":"127612FA4922","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
16
+ ',{"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+(AMEE::Epoch+3).xmlschema+'","value":"4","uid":"127612FA4923","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
17
+ ']}'
18
+ MockResourceXMLTwo='<Resources><DataItemValueResource><ItemValues>'+
19
+ '<ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4921"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+AMEE::Epoch.xmlschema+'</StartDate><Value>1</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/>'+
20
+ '<ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4922"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+(AMEE::Epoch+1).xmlschema+'</StartDate><Value>6</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/>'+
21
+ '<ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4924"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+(AMEE::Epoch+5).xmlschema+'</StartDate><Value>7</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/>'+
22
+ '<ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4925"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+(AMEE::Epoch+9).xmlschema+'</StartDate><Value>11</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/>'+
23
+ '</ItemValues></DataItemValueResource></Resources>'
24
+ MockResourceJSONTwo='{"dataItem":{"uid":"AD63A83B4D41"},"itemValues":['+
25
+ ' {"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+AMEE::Epoch.xmlschema+'","value":"1","uid":"127612FA4921","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
26
+ ',{"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+(AMEE::Epoch+1).xmlschema+'","value":"6","uid":"127612FA4922","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
27
+ ',{"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+(AMEE::Epoch+5).xmlschema+'","value":"7","uid":"127612FA4924","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
28
+ ',{"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+(AMEE::Epoch+9).xmlschema+'","value":"11","uid":"127612FA4925","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
29
+ ']}'
30
+ MockResourceXMLSingle='<Resources><DataItemValueResource><ItemValue Created="2007-08-01 09:00:41.0" Modified="2007-08-01 09:00:41.0" uid="127612FA4921"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><StartDate>'+AMEE::Epoch.xmlschema+'</StartDate><Value>1</Value><ItemValueDefinition uid="653828811D42"><Path>kgCO2PerPassengerJourney</Path><Name>kgCO2 Per Passenger Journey</Name><FromProfile>false</FromProfile><FromData>true</FromData><ValueDefinition uid="8CB8A1789CD6"><Name>kgCO2PerJourney</Name><ValueType>DOUBLE</ValueType></ValueDefinition></ItemValueDefinition><DataItem uid="AD63A83B4D41"/></ItemValue><DataItem uid="AD63A83B4D41"/></DataItemValueResource>'+
31
+ '</Resources>'
32
+ MockResourceJSONSingle='{"dataItem":{"uid":"AD63A83B4D41"},"itemValue":'+
33
+ ' {"item":{"uid":"AD63A83B4D41"},"modified":"2007-08-01 09:00:41.0","created":"2007-08-01 09:00:41.0","startDate":"'+AMEE::Epoch.xmlschema+'","value":"1","uid":"127612FA4921","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey","itemValueDefinition":{"valueDefinition":{"valueType":"DOUBLE","uid":"8CB8A1789CD6","name":"kgCO2PerJourney"},"uid":"653828811D42","path":"kgCO2PerPassengerJourney","name":"kgCO2 Per Passenger Journey"}}'+
34
+ '}'
35
+
36
+
37
+ describe AMEE::Data::ItemValueHistory do
38
+
39
+ before(:each) do
40
+ @history = AMEE::Data::ItemValueHistory.new
41
+ end
42
+
43
+ it "should NOT have common AMEE object properties" do
44
+ # we can't be an AMEE object, since we have a set of UIDs, not one UID
45
+ @history.is_a?(AMEE::Data::Object).should be_false
46
+ end
47
+
48
+ it "should have an array of ItemValue objects" do
49
+ @history.should respond_to(:values)
50
+ end
51
+
52
+ it "should be able to return a time series" do
53
+ @history.should respond_to(:series)
54
+ end
55
+
56
+ it "should have a type" do
57
+ @history.should respond_to(:type)
58
+ end
59
+
60
+ it "can be created with a type, and a time-value pairs array" do
61
+ series=TestSeriesOne
62
+ type = "TEXT"
63
+ @history = AMEE::Data::ItemValueHistory.new(:series => series, :type => type)
64
+ @history.series.should == series
65
+ @history.type.should == type
66
+ @history.values[0].is_a?(AMEE::Data::ItemValue).should be_true
67
+ @history.values[0].value.should == 1
68
+ @history.values[0].start_date.should == AMEE::Epoch
69
+ end
70
+
71
+ it "can be created by pushing to the array of item values" do
72
+ series=TestSeriesOne
73
+ type = "TEXT"
74
+ @history = AMEE::Data::ItemValueHistory.new(:type=>type)
75
+ @history.series.should == []
76
+ @history.type.should == type
77
+ @fstvalue = AMEE::Data::ItemValue.new(:type=>type,:value=>1,:start_date=>AMEE::Epoch)
78
+ @sndvalue = AMEE::Data::ItemValue.new(:type=>type,:value=>2,:start_date=>AMEE::Epoch+1)
79
+ @trdvalue = AMEE::Data::ItemValue.new(:type=>type,:value=>4,:start_date=>AMEE::Epoch+3)
80
+ @history.values.push @fstvalue
81
+ @history.values.push @sndvalue
82
+ @history.values.push @trdvalue
83
+ @history.values[0].is_a?(AMEE::Data::ItemValue).should be_true
84
+ @history.values[0].value.should == 1
85
+ @history.values[0].start_date.should == AMEE::Epoch
86
+ @history.series.should == series
87
+ end
88
+
89
+ it "should support DOUBLE data type" do
90
+ @history = AMEE::Data::ItemValueHistory.new(:series => TestSeriesOne, :type => "DOUBLE")
91
+ @history.series.should == TestSeriesOne
92
+ end
93
+
94
+ it "should support TEXT data type" do
95
+ @history = AMEE::Data::ItemValueHistory.new(:series => TestSeriesOne, :type => "TEXT")
96
+ @history.series.should == TestSeriesOne
97
+ end
98
+
99
+ it "allows value to be changed after creation" do
100
+ series=TestSeriesOne
101
+ type = "TEXT"
102
+ @history = AMEE::Data::ItemValueHistory.new(:series => series, :type => type)
103
+ @history.series.should == series
104
+ series = TestSeriesTwo
105
+ @history.series = series
106
+ @history.series.should == series
107
+ @history.values[1].value.should == 6
108
+ end
109
+
110
+ it "allows item values to be found by time" do
111
+ series=TestSeriesTwo
112
+ type = "TEXT"
113
+ @history = AMEE::Data::ItemValueHistory.new(:series => series, :type => type)
114
+ @value=@history.value_at(AMEE::Epoch+5)
115
+ @value.value.should == 7
116
+ lambda {
117
+ @history.value_at(AMEE::Epoch+6)
118
+ }.should raise_error
119
+ @history.values_at([AMEE::Epoch+1,AMEE::Epoch+9]).length.should eql 2
120
+ end
121
+
122
+ end
123
+
124
+ describe AMEE::Data::ItemValueHistory, "when comparing to another history" do
125
+ before(:each) do
126
+ @historyone = AMEE::Data::ItemValueHistory.new(:series=>TestSeriesOne)
127
+ @historytwo = AMEE::Data::ItemValueHistory.new(:series=>TestSeriesTwo)
128
+ @comparison=@historytwo.compare(@historyone)
129
+ end
130
+
131
+ it "should be able to compare histories" do
132
+ @comparison.should be_a Hash
133
+ @comparison[:deletions].should be_a Array
134
+ @comparison[:updates].should be_a Array
135
+ @comparison[:insertions].should be_a Array
136
+ end
137
+
138
+ it "should return an array of items to update" do
139
+ # note comparison list isnt order stable so sort here for test
140
+ @changes=@comparison[:updates].sort{|x,y| x.start_date <=> y.start_date}
141
+ @changes.length.should eql 2
142
+ @changes[1].value.should eql 6
143
+ @changes[1].start_date.should eql AMEE::Epoch+1
144
+ @changes[0].start_date.should eql AMEE::Epoch
145
+ @changes[0].value.should eql 2
146
+
147
+ end
148
+ it "should return an array of items to create" do
149
+ @changes=@comparison[:insertions].sort{|x,y| x.start_date <=> y.start_date}
150
+ @changes.length.should eql 2
151
+ @changes[0].start_date.should eql AMEE::Epoch+5
152
+ @changes[1].start_date.should eql AMEE::Epoch+9
153
+ @changes[0].value.should eql 7
154
+ @changes[1].value.should eql 11
155
+ end
156
+ it "should return an array of items to delete" do
157
+ @changes=@comparison[:deletions].sort{|x,y| x.start_date <=> y.start_date}
158
+ @changes.length.should eql 1
159
+ @changes[0].start_date.should eql AMEE::Epoch+3
160
+ end
161
+
162
+ end
163
+
164
+ describe AMEE::Data::ItemValueHistory, "with an authenticated connection" do
165
+
166
+ it "should parse XML correctly" do
167
+ connection = flexmock "connection"
168
+ connection.should_receive(:get).with(MockResourcePath,:valuesPerPage=>2).
169
+ and_return(flexmock(:body => MockResourceXML))
170
+ @history = AMEE::Data::ItemValueHistory.get(connection, MockResourcePath)
171
+ @history.series.should == TestSeriesOne
172
+ @fstvalue=@history.values[0]
173
+ @sndvalue=@history.values[1]
174
+ @fstvalue.uid.should == "127612FA4921"
175
+ @sndvalue.uid.should == "127612FA4922"
176
+ @fstvalue.name.should == "kgCO2 Per Passenger Journey"
177
+ @fstvalue.full_path.should == MockResourcePath
178
+ @fstvalue.created.should == DateTime.new(2007,8,1,9,00,41)
179
+ @fstvalue.modified.should == DateTime.new(2007,8,1,9,00,41)
180
+ @fstvalue.type.should == "DOUBLE"
181
+ @history.series.should == TestSeriesOne
182
+ @history.type.should == "DOUBLE"
183
+ end
184
+
185
+ it "should parse JSON correctly" do
186
+ connection = flexmock "connection"
187
+ connection.should_receive(:get).with(MockResourcePath,:valuesPerPage=>2).and_return(flexmock(:body => MockResourceJSON))
188
+ @history = AMEE::Data::ItemValueHistory.get(connection, MockResourcePath)
189
+ @fstvalue=@history.values[0]
190
+ @sndvalue=@history.values[1]
191
+ @fstvalue.uid.should == "127612FA4921"
192
+ @sndvalue.uid.should == "127612FA4922"
193
+ @fstvalue.name.should == "kgCO2 Per Passenger Journey"
194
+ @fstvalue.full_path.should == MockResourcePath
195
+ @fstvalue.created.should == DateTime.new(2007,8,1,9,00,41)
196
+ @fstvalue.modified.should == DateTime.new(2007,8,1,9,00,41)
197
+ @fstvalue.type.should == "DOUBLE"
198
+ @history.series.should == TestSeriesOne
199
+ @history.type.should == "DOUBLE"
200
+ end
201
+
202
+ it "should parse JSON correctly if theres only one point" do
203
+ connection = flexmock "connection"
204
+ connection.should_receive(:get).with(MockResourcePath,:valuesPerPage=>2).and_return(flexmock(:body => MockResourceJSONSingle))
205
+ @history = AMEE::Data::ItemValueHistory.get(connection, MockResourcePath)
206
+ @fstvalue=@history.values[0]
207
+ @fstvalue.uid.should == "127612FA4921"
208
+ @fstvalue.name.should == "kgCO2 Per Passenger Journey"
209
+ @fstvalue.full_path.should == MockResourcePath
210
+ @fstvalue.created.should == DateTime.new(2007,8,1,9,00,41)
211
+ @fstvalue.modified.should == DateTime.new(2007,8,1,9,00,41)
212
+ @fstvalue.type.should == "DOUBLE"
213
+ @history.series.should == [[AMEE::Epoch,1]]
214
+ @history.type.should == "DOUBLE"
215
+ end
216
+
217
+ it "should parse XML correctly if theres only one point" do
218
+ connection = flexmock "connection"
219
+ connection.should_receive(:get).with(MockResourcePath,:valuesPerPage=>2).and_return(flexmock(:body => MockResourceXMLSingle))
220
+ @history = AMEE::Data::ItemValueHistory.get(connection, MockResourcePath)
221
+ @fstvalue=@history.values[0]
222
+ @fstvalue.uid.should == "127612FA4921"
223
+ @fstvalue.name.should == "kgCO2 Per Passenger Journey"
224
+ @fstvalue.full_path.should == MockResourcePath
225
+ @fstvalue.created.should == DateTime.new(2007,8,1,9,00,41)
226
+ @fstvalue.modified.should == DateTime.new(2007,8,1,9,00,41)
227
+ @fstvalue.type.should == "DOUBLE"
228
+ @history.series.should == [[AMEE::Epoch,1]]
229
+ @history.type.should == "DOUBLE"
230
+ end
231
+
232
+ it "should fail gracefully with incorrect XML data" do
233
+ connection = flexmock "connection"
234
+ xml = '<?xml version="1.0" encoding="UTF-8"?><Resources></Resources>'
235
+ connection.should_receive(:get).with("/data",:valuesPerPage=>2).and_return(flexmock(:body => xml))
236
+ lambda{AMEE::Data::ItemValueHistory.get(connection, "/data")}.should raise_error(AMEE::BadData)
237
+ end
238
+
239
+ it "should fail gracefully with incorrect JSON data" do
240
+ connection = flexmock "connection"
241
+ json = '{}'
242
+ connection.should_receive(:get).with("/data",:valuesPerPage=>2).and_return(flexmock(:body => json))
243
+ lambda{AMEE::Data::ItemValueHistory.get(connection, "/data")}.should raise_error(AMEE::BadData)
244
+ end
245
+
246
+ it "should fail gracefully on other errors" do
247
+ connection = flexmock "connection"
248
+ connection.should_receive(:get).with("/data",:valuesPerPage=>2).and_raise("unidentified error")
249
+ lambda{AMEE::Data::ItemValueHistory.get(connection, "/data")}.should raise_error(AMEE::BadData)
250
+ end
251
+
252
+ it "should fail gracefully if create series without epoch" do
253
+ @history = AMEE::Data::ItemValueHistory.new()
254
+ lambda{@history.series=[[AMEE::Epoch+1,5]]}.should raise_error(AMEE::BadData)
255
+ end
256
+
257
+ end
258
+
259
+ describe AMEE::Data::ItemValueHistory, "after loading" do
260
+
261
+ before(:each) do
262
+ @path = MockResourcePath
263
+ @connection = flexmock "connection"
264
+ @connection.should_receive(:get).with(@path,:valuesPerPage=>2).and_return(flexmock(:body => MockResourceJSON))
265
+ @val = AMEE::Data::ItemValueHistory.get(@connection, @path)
266
+ end
267
+
268
+ it "can have series changed and saved back to server" do
269
+ @connection.should_receive(:put).with(MockDataItemPath+"/127612FA4921", :value => 2).once.and_return(flexmock(:body => ''))
270
+ # note this one shouldn't include a start date as it is the epoch point
271
+ @connection.should_receive(:put).with(MockDataItemPath+"/127612FA4922", :value => 6, :startDate => AMEE::Epoch+1).once.and_return(flexmock(:body => ''))
272
+ @connection.should_receive(:delete).with(MockDataItemPath+"/127612FA4923").once.and_return(flexmock(:body => ''))
273
+ @connection.should_receive(:post).with(MockDataItemPath,
274
+ :kgCO2PerPassengerJourney => 7, :startDate => AMEE::Epoch+5).once.and_return({'Location'=>'http://foo.com/'})
275
+ @connection.should_receive(:post).with(MockDataItemPath,
276
+ :kgCO2PerPassengerJourney => 11, :startDate => AMEE::Epoch+9).once.and_return({'Location'=>'http://foo.com/'})
277
+ lambda {
278
+ @val.series = TestSeriesTwo
279
+ @val.save!
280
+ }.should_not raise_error
281
+ end
282
+
283
+ it "can have series changed and saved back to server (using SSL)" do
284
+ @connection.should_receive(:put).with(MockDataItemPath+"/127612FA4921", :value => 2).once.and_return(flexmock(:body => ''))
285
+ # note this one shouldn't include a start date as it is the epoch point
286
+ @connection.should_receive(:put).with(MockDataItemPath+"/127612FA4922", :value => 6, :startDate => AMEE::Epoch+1).once.and_return(flexmock(:body => ''))
287
+ @connection.should_receive(:delete).with(MockDataItemPath+"/127612FA4923").once.and_return(flexmock(:body => ''))
288
+ @connection.should_receive(:post).with(MockDataItemPath,
289
+ :kgCO2PerPassengerJourney => 7, :startDate => AMEE::Epoch+5).once.and_return({'Location'=>'https://foo.com/'})
290
+ @connection.should_receive(:post).with(MockDataItemPath,
291
+ :kgCO2PerPassengerJourney => 11, :startDate => AMEE::Epoch+9).once.and_return({'Location'=>'https://foo.com/'})
292
+ lambda {
293
+ @val.series = TestSeriesTwo
294
+ @val.save!
295
+ }.should_not raise_error
296
+ end
297
+
298
+ it "cannot create a new series (unsupported by platform)" do
299
+ lambda {
300
+ @val.series = TestSeriesTwo
301
+ @val.create!
302
+ }.should raise_error(AMEE::NotSupported,"Cannot create a Data Item Value History from scratch: at least one data point must exist when the DI is created")
303
+ end
304
+
305
+ it "cannot delete an entire series (unsupported by platform)" do
306
+ lambda {
307
+ @val.delete!
308
+ }.should raise_error(AMEE::NotSupported,"Cannot delete all of history: at least one data point must always exist.")
309
+ end
310
+
311
+ end