xively-rb 0.2.09
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.
- data/.gitignore +13 -0
- data/.rbenv-version +1 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +91 -0
- data/CONTRIBUTING.md +95 -0
- data/Gemfile +15 -0
- data/LICENSE.md +13 -0
- data/README.md +10 -0
- data/Rakefile +25 -0
- data/ci/build_hudson.sh +24 -0
- data/init.rb +2 -0
- data/lib/xively-rb.rb +44 -0
- data/lib/xively-rb/array_extensions.rb +6 -0
- data/lib/xively-rb/base.rb +52 -0
- data/lib/xively-rb/base/instance_methods.rb +28 -0
- data/lib/xively-rb/client.rb +43 -0
- data/lib/xively-rb/datapoint.rb +72 -0
- data/lib/xively-rb/datastream.rb +127 -0
- data/lib/xively-rb/exceptions.rb +5 -0
- data/lib/xively-rb/feed.rb +109 -0
- data/lib/xively-rb/hash_extensions.rb +16 -0
- data/lib/xively-rb/helpers.rb +41 -0
- data/lib/xively-rb/key.rb +99 -0
- data/lib/xively-rb/nil_content.rb +15 -0
- data/lib/xively-rb/object_extensions.rb +6 -0
- data/lib/xively-rb/parsers/csv/datastream_defaults.rb +50 -0
- data/lib/xively-rb/parsers/csv/feed_defaults.rb +97 -0
- data/lib/xively-rb/parsers/defaults.rb +15 -0
- data/lib/xively-rb/parsers/json/datapoint_defaults.rb +16 -0
- data/lib/xively-rb/parsers/json/datastream_defaults.rb +58 -0
- data/lib/xively-rb/parsers/json/feed_defaults.rb +114 -0
- data/lib/xively-rb/parsers/json/key_defaults.rb +20 -0
- data/lib/xively-rb/parsers/json/search_result_defaults.rb +24 -0
- data/lib/xively-rb/parsers/json/trigger_defaults.rb +16 -0
- data/lib/xively-rb/parsers/xml/datapoint_defaults.rb +27 -0
- data/lib/xively-rb/parsers/xml/datastream_defaults.rb +53 -0
- data/lib/xively-rb/parsers/xml/errors.rb +7 -0
- data/lib/xively-rb/parsers/xml/feed_defaults.rb +83 -0
- data/lib/xively-rb/parsers/xml/helpers.rb +116 -0
- data/lib/xively-rb/parsers/xml/key_defaults.rb +46 -0
- data/lib/xively-rb/parsers/xml/trigger_defaults.rb +28 -0
- data/lib/xively-rb/permission.rb +67 -0
- data/lib/xively-rb/resource.rb +43 -0
- data/lib/xively-rb/search_result.rb +68 -0
- data/lib/xively-rb/string_extensions.rb +6 -0
- data/lib/xively-rb/templates/csv/datapoint_defaults.rb +22 -0
- data/lib/xively-rb/templates/csv/datastream_defaults.rb +43 -0
- data/lib/xively-rb/templates/csv/feed_defaults.rb +47 -0
- data/lib/xively-rb/templates/defaults.rb +14 -0
- data/lib/xively-rb/templates/json/datapoint_defaults.rb +15 -0
- data/lib/xively-rb/templates/json/datastream_defaults.rb +61 -0
- data/lib/xively-rb/templates/json/feed_defaults.rb +90 -0
- data/lib/xively-rb/templates/json/key_defaults.rb +39 -0
- data/lib/xively-rb/templates/json/search_result_defaults.rb +42 -0
- data/lib/xively-rb/templates/json/trigger_defaults.rb +21 -0
- data/lib/xively-rb/templates/xml/datapoint_defaults.rb +25 -0
- data/lib/xively-rb/templates/xml/datastream_defaults.rb +66 -0
- data/lib/xively-rb/templates/xml/feed_defaults.rb +112 -0
- data/lib/xively-rb/templates/xml/search_result_defaults.rb +118 -0
- data/lib/xively-rb/templates/xml_headers.rb +17 -0
- data/lib/xively-rb/trigger.rb +66 -0
- data/lib/xively-rb/validations.rb +9 -0
- data/lib/xively-rb/version.rb +3 -0
- data/spec/fixtures/models.rb +81 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/contain_datapoint_eeml_matcher.rb +16 -0
- data/spec/support/contain_datastream_eeml_matcher.rb +60 -0
- data/spec/support/contain_feed_eeml_matcher.rb +98 -0
- data/spec/support/datapoint_helper.rb +53 -0
- data/spec/support/datastream_helper.rb +324 -0
- data/spec/support/describe_eeml_matcher.rb +23 -0
- data/spec/support/feed_helper.rb +783 -0
- data/spec/support/fully_represent_datapoint_matcher.rb +30 -0
- data/spec/support/fully_represent_datastream_matcher.rb +96 -0
- data/spec/support/fully_represent_feed_matcher.rb +234 -0
- data/spec/support/fully_represent_key_matcher.rb +74 -0
- data/spec/support/fully_represent_search_result_matcher.rb +67 -0
- data/spec/support/fully_represent_trigger_matcher.rb +29 -0
- data/spec/support/key_helper.rb +74 -0
- data/spec/support/search_result_helper.rb +252 -0
- data/spec/support/trigger_helper.rb +51 -0
- data/spec/xively-rb/array_extensions_spec.rb +9 -0
- data/spec/xively-rb/base/instance_methods_spec.rb +109 -0
- data/spec/xively-rb/base_spec.rb +56 -0
- data/spec/xively-rb/client_spec.rb +51 -0
- data/spec/xively-rb/datapoint_spec.rb +187 -0
- data/spec/xively-rb/datastream_spec.rb +344 -0
- data/spec/xively-rb/feed_spec.rb +341 -0
- data/spec/xively-rb/hash_extensions_spec.rb +20 -0
- data/spec/xively-rb/helpers_spec.rb +56 -0
- data/spec/xively-rb/key_spec.rb +198 -0
- data/spec/xively-rb/parsers/csv/datastream_defaults_spec.rb +110 -0
- data/spec/xively-rb/parsers/csv/feed_defaults_spec.rb +234 -0
- data/spec/xively-rb/parsers/json/datapoint_defaults_spec.rb +21 -0
- data/spec/xively-rb/parsers/json/datastream_defaults_spec.rb +105 -0
- data/spec/xively-rb/parsers/json/feed_defaults_spec.rb +45 -0
- data/spec/xively-rb/parsers/json/key_defaults_spec.rb +14 -0
- data/spec/xively-rb/parsers/json/search_result_defaults_spec.rb +18 -0
- data/spec/xively-rb/parsers/json/trigger_defaults_spec.rb +22 -0
- data/spec/xively-rb/parsers/xml/datapoint_defaults_spec.rb +19 -0
- data/spec/xively-rb/parsers/xml/datastream_defaults_spec.rb +148 -0
- data/spec/xively-rb/parsers/xml/feed_defaults_spec.rb +254 -0
- data/spec/xively-rb/parsers/xml/key_defaults_spec.rb +22 -0
- data/spec/xively-rb/parsers/xml/trigger_defaults_spec.rb +22 -0
- data/spec/xively-rb/search_result_spec.rb +257 -0
- data/spec/xively-rb/string_extensions_spec.rb +12 -0
- data/spec/xively-rb/templates/csv/datapoint_defaults_spec.rb +41 -0
- data/spec/xively-rb/templates/csv/datastream_defaults_spec.rb +131 -0
- data/spec/xively-rb/templates/csv/feed_defaults_spec.rb +78 -0
- data/spec/xively-rb/templates/json/datapoint_defaults_spec.rb +14 -0
- data/spec/xively-rb/templates/json/datastream_defaults_spec.rb +170 -0
- data/spec/xively-rb/templates/json/feed_defaults_spec.rb +399 -0
- data/spec/xively-rb/templates/json/key_defaults_spec.rb +29 -0
- data/spec/xively-rb/templates/json/search_result_defaults_spec.rb +37 -0
- data/spec/xively-rb/templates/json/trigger_defaults_spec.rb +19 -0
- data/spec/xively-rb/templates/xml/datapoint_defaults_spec.rb +14 -0
- data/spec/xively-rb/templates/xml/datastream_defaults_spec.rb +113 -0
- data/spec/xively-rb/templates/xml/feed_defaults_spec.rb +131 -0
- data/spec/xively-rb/templates/xml/search_result_defaults_spec.rb +44 -0
- data/spec/xively-rb/trigger_spec.rb +157 -0
- data/xively-rb.gemspec +41 -0
- metadata +333 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "default datastream csv parser" do
|
|
4
|
+
describe "csv" do
|
|
5
|
+
it "should convert Pachube CSV into attributes hash" do
|
|
6
|
+
csv = datastream_as_(:csv)
|
|
7
|
+
datastream = Xively::Datastream.new(csv, :v2)
|
|
8
|
+
datastream.should fully_represent_datastream(:csv, csv)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should capture timestamp if present" do
|
|
12
|
+
csv = datastream_as_(:csv, :version => "timestamped")
|
|
13
|
+
datastream = Xively::Datastream.new(csv, :v2, :csv)
|
|
14
|
+
datastream.updated.should == "2011-02-16T16:21:01.834174Z"
|
|
15
|
+
datastream.current_value.should == "14"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should raise error if passed more than a single row" do
|
|
19
|
+
csv = "12\n13"
|
|
20
|
+
expect {
|
|
21
|
+
Xively::Datastream.new(csv)
|
|
22
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should raise error passed more than three values in a row" do
|
|
26
|
+
csv = "#{Time.now.iso8601(6)},123,456"
|
|
27
|
+
expect {
|
|
28
|
+
Xively::Datastream.new(csv)
|
|
29
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should raise error if passed more than a single value as v1" do
|
|
33
|
+
csv = "192,2"
|
|
34
|
+
expect {
|
|
35
|
+
Xively::Datastream.new(csv, :v1)
|
|
36
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should raise exception if passed garbage csv" do
|
|
40
|
+
expect {
|
|
41
|
+
Xively::Datastream.new("badly, \"quoted", :csv)
|
|
42
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should not raise exception if passed data with nil value" do
|
|
46
|
+
expect {
|
|
47
|
+
datastream = Xively::Datastream.new("2012-08-12T00:00:00Z,", :v2)
|
|
48
|
+
datastream.current_value.should be_empty
|
|
49
|
+
}.to_not raise_error
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should parse multiline csv" do
|
|
53
|
+
csv = <<-CSV
|
|
54
|
+
2012-02-08T00:00:00Z,123
|
|
55
|
+
2012-02-08T00:00:10Z,124
|
|
56
|
+
2012-02-08T00:00:20Z,125
|
|
57
|
+
2012-02-08T00:00:30Z,126
|
|
58
|
+
CSV
|
|
59
|
+
datastream = Xively::Datastream.new(csv, :v2)
|
|
60
|
+
datastream.updated.should be_nil
|
|
61
|
+
datastream.current_value.should be_nil
|
|
62
|
+
datastream.datapoints.size.should == 4
|
|
63
|
+
datastream.datapoints.collect { |d| [d.at, d.value].join(",") }.join("\n").should == csv.strip
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "should not parse multiline csv passed to the v1 api" do
|
|
67
|
+
csv = <<-CSV
|
|
68
|
+
2012-02-08T00:00:00Z,123
|
|
69
|
+
2012-02-08T00:00:10Z,124
|
|
70
|
+
2012-02-08T00:00:20Z,125
|
|
71
|
+
2012-02-08T00:00:30Z,126
|
|
72
|
+
CSV
|
|
73
|
+
expect {
|
|
74
|
+
datastream = Xively::Datastream.new(csv, :v1)
|
|
75
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should not accept multiline csv with just single values" do
|
|
79
|
+
csv = <<-CSV
|
|
80
|
+
123
|
|
81
|
+
124
|
|
82
|
+
125
|
|
83
|
+
126
|
|
84
|
+
CSV
|
|
85
|
+
|
|
86
|
+
expect {
|
|
87
|
+
datastream = Xively::Datastream.new(csv, :v2)
|
|
88
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "should strip whitespace from multiline values" do
|
|
92
|
+
csv = <<-CSV
|
|
93
|
+
2012-02-08T00:00:00Z , 123
|
|
94
|
+
2012-02-08T00:00:10Z , 124
|
|
95
|
+
2012-02-08T00:00:20Z , 125
|
|
96
|
+
2012-02-08T00:00:30Z , 126
|
|
97
|
+
CSV
|
|
98
|
+
|
|
99
|
+
datastream = Xively::Datastream.new(csv, :v2)
|
|
100
|
+
datastream.updated.should be_nil
|
|
101
|
+
datastream.current_value.should be_nil
|
|
102
|
+
datastream.datapoints.size.should == 4
|
|
103
|
+
datastream.datapoints.sort { |a, b| a.at <=> b.at }.collect { |d| [d.at, d.value] }.should == [["2012-02-08T00:00:00Z","123"],
|
|
104
|
+
["2012-02-08T00:00:10Z","124"],
|
|
105
|
+
["2012-02-08T00:00:20Z","125"],
|
|
106
|
+
["2012-02-08T00:00:30Z","126"]]
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "default feed csv parser" do
|
|
4
|
+
describe "csv" do
|
|
5
|
+
it "should convert Pachube CSV v2 into attributes hash" do
|
|
6
|
+
csv = feed_as_(:csv, :version => 'v2')
|
|
7
|
+
feed = Xively::Feed.new(csv)
|
|
8
|
+
feed.should fully_represent_feed(:csv_v2, csv)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should convert no timestamp v2 CSV into attributes hash" do
|
|
12
|
+
csv = feed_as_(:csv, :version => 'v2_notimestamp')
|
|
13
|
+
feed = Xively::Feed.new(csv)
|
|
14
|
+
feed.should fully_represent_feed(:csv_v2, csv)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should convert Pachube CSV v1 into attributes hash" do
|
|
18
|
+
csv = feed_as_(:csv, :version => 'v1')
|
|
19
|
+
feed = Xively::Feed.new(csv)
|
|
20
|
+
feed.should fully_represent_feed(:csv_v1, csv)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should raise an exception if Pachube CSV cannot be detected" do
|
|
24
|
+
csv = feed_as_(:csv, :version => 'unknown')
|
|
25
|
+
lambda {Xively::Feed.new(csv)}.should raise_exception(Xively::Parsers::CSV::UnknownVersionError)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should accept manually determining csv version to be v2" do
|
|
29
|
+
csv = feed_as_(:csv, :version => 'unknown')
|
|
30
|
+
feed = Xively::Feed.new(csv, :v2)
|
|
31
|
+
feed.should fully_represent_feed(:csv_v2, csv)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should accept manually determining csv version to be v1" do
|
|
35
|
+
csv = feed_as_(:csv, :version => 'unknown')
|
|
36
|
+
feed = Xively::Feed.new(csv, :v1)
|
|
37
|
+
feed.should fully_represent_feed(:csv_v1, csv)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should accept explicit blank values for v2 csv" do
|
|
41
|
+
expect {
|
|
42
|
+
Xively::Feed.new("stream_id,''", :v2)
|
|
43
|
+
}.to_not raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should raise an error if passed some v2 csv that does not contain a value" do
|
|
47
|
+
expect {
|
|
48
|
+
Xively::Feed.new("stream_id", :v2)
|
|
49
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should raise an error if passed empty content as v2" do
|
|
53
|
+
expect {
|
|
54
|
+
Xively::Feed.new("", :v2)
|
|
55
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should raise an error if passed empty content as v1" do
|
|
59
|
+
expect {
|
|
60
|
+
Xively::Feed.new("", :v1)
|
|
61
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should raise an error if passed some wild csv with more than max permitted three columns" do
|
|
65
|
+
csv =<<-CSV
|
|
66
|
+
Date-Time, System HOA,Jockey Pump HOA,VFD Pump HOA,Lag Pump HOA,Lag Pump 2 HOA,Power Monitor,Water Level Relay,High Discharge Pressure,Reset Function,Jockey Running,VFD Run,Lag Pump Run,VFD Fault,Filter In Auto,Filter In Hand,Differential Press 1,Filter 1 Running,High Limit Switch,Low Limit Switch,Lag Pump Running,VFD Run Output Auto,VFD Pump On,Lag Pump,Lag Pump 1 On,System Auto Mode,Fault,Lag Pump 2 Run,Jockey On,Jockey Pump Run,Lag Pump 2,Filter Forward,Filter Reverse,Filter Solenoid,Pressure,Flow,Unknown?,VFD Input,VFD Output,
|
|
67
|
+
2009;Apr;19;12;44;15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
|
|
68
|
+
2009;Apr;19;12;44;30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
|
|
69
|
+
2009;Apr;19;12;48;52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
|
|
70
|
+
CSV
|
|
71
|
+
expect {
|
|
72
|
+
Xively::Feed.new(csv)
|
|
73
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should raise an error if passed more than one row when we state it's v1" do
|
|
77
|
+
csv =<<-CSV
|
|
78
|
+
This,2
|
|
79
|
+
Wrong,3
|
|
80
|
+
Is,4
|
|
81
|
+
CSV
|
|
82
|
+
|
|
83
|
+
expect {
|
|
84
|
+
Xively::Feed.new(csv, :v1)
|
|
85
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError, /3 rows/)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context "nil attribute csv" do
|
|
89
|
+
before(:each) do
|
|
90
|
+
@csv = "0,,"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "should not raise exception if csv has nil values as v1" do
|
|
94
|
+
expect {
|
|
95
|
+
feed = Xively::Feed.new(@csv, :v1)
|
|
96
|
+
feed.datastreams.size.should == 3
|
|
97
|
+
}.to_not raise_error
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should not raise exception if csv has nil attributes as v2" do
|
|
101
|
+
expect {
|
|
102
|
+
feed = Xively::Feed.new(@csv, :v2)
|
|
103
|
+
feed.datastreams.size.should == 1
|
|
104
|
+
}.to_not raise_error
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
context "unwanted whitespace" do
|
|
109
|
+
it "should strip whitespace from v2" do
|
|
110
|
+
dodgy_csv = <<-CSV
|
|
111
|
+
0, 00035
|
|
112
|
+
stream1, 0012
|
|
113
|
+
2, 2012-08-02T14:11:14Z ," red car "
|
|
114
|
+
CSV
|
|
115
|
+
good_csv = <<-CSV
|
|
116
|
+
0,00035
|
|
117
|
+
stream1,0012
|
|
118
|
+
2,2012-08-02T14:11:14Z,red car
|
|
119
|
+
CSV
|
|
120
|
+
feed = Xively::Feed.new(dodgy_csv)
|
|
121
|
+
feed.should fully_represent_feed(:csv_v2, good_csv)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
it "should strip whitespace from v1" do
|
|
125
|
+
dodgy_csv = %Q{ 00035 , 0012," red car"}
|
|
126
|
+
good_csv = "00035,0012,red car"
|
|
127
|
+
feed = Xively::Feed.new(dodgy_csv)
|
|
128
|
+
feed.should fully_represent_feed(:csv_v1, good_csv)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
context "multivalue csv" do
|
|
133
|
+
def check_multiline_csv(csv)
|
|
134
|
+
feed = Xively::Feed.new(csv)
|
|
135
|
+
|
|
136
|
+
feed.datastreams.size.should == 2
|
|
137
|
+
feed.datastreams.each do |datastream|
|
|
138
|
+
datastream.updated.should be_nil
|
|
139
|
+
datastream.current_value.should be_nil
|
|
140
|
+
datastream.datapoints.size.should == 3
|
|
141
|
+
datastream.datapoints.sort { |a,b| a.at <=> b.at }.collect { |d| [d.at, d.value] }.should == [["2012-08-12T00:00:00Z", "1"],
|
|
142
|
+
["2012-08-12T00:00:05Z", "2"],
|
|
143
|
+
["2012-08-12T00:00:10Z", "3"]]
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "should capture multivalue csv with timestamps" do
|
|
148
|
+
csv = <<-CSV
|
|
149
|
+
stream0,2012-08-12T00:00:00Z,1
|
|
150
|
+
stream1,2012-08-12T00:00:00Z,1
|
|
151
|
+
stream0,2012-08-12T00:00:05Z,2
|
|
152
|
+
stream1,2012-08-12T00:00:05Z,2
|
|
153
|
+
stream0,2012-08-12T00:00:10Z,3
|
|
154
|
+
stream1,2012-08-12T00:00:10Z,3
|
|
155
|
+
CSV
|
|
156
|
+
|
|
157
|
+
check_multiline_csv(csv)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it "should capture multivalue csv with timestamps no matter the grouping" do
|
|
161
|
+
csv = <<-CSV
|
|
162
|
+
stream0,2012-08-12T00:00:00Z,1
|
|
163
|
+
stream0,2012-08-12T00:00:05Z,2
|
|
164
|
+
stream0,2012-08-12T00:00:10Z,3
|
|
165
|
+
stream1,2012-08-12T00:00:00Z,1
|
|
166
|
+
stream1,2012-08-12T00:00:05Z,2
|
|
167
|
+
stream1,2012-08-12T00:00:10Z,3
|
|
168
|
+
CSV
|
|
169
|
+
|
|
170
|
+
check_multiline_csv(csv)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "should strip whitespace from multiline csv" do
|
|
174
|
+
csv = <<-CSV
|
|
175
|
+
stream0, 2012-08-12T00:00:00Z, 1
|
|
176
|
+
stream0, 2012-08-12T00:00:05Z, 2
|
|
177
|
+
stream0, 2012-08-12T00:00:10Z, 3
|
|
178
|
+
stream1, 2012-08-12T00:00:00Z, 1
|
|
179
|
+
stream1, 2012-08-12T00:00:05Z, 2
|
|
180
|
+
stream1, 2012-08-12T00:00:10Z, 3
|
|
181
|
+
CSV
|
|
182
|
+
|
|
183
|
+
check_multiline_csv(csv)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "should reject multivalue csv without timestamps" do
|
|
187
|
+
csv = <<-CSV
|
|
188
|
+
stream0,1
|
|
189
|
+
stream1,1
|
|
190
|
+
stream0,2
|
|
191
|
+
stream1,2
|
|
192
|
+
stream0,3
|
|
193
|
+
stream1,3
|
|
194
|
+
CSV
|
|
195
|
+
expect {
|
|
196
|
+
Xively::Feed.new(csv)
|
|
197
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
it "should reject multivalue csv if we tell it its v1" do
|
|
201
|
+
csv = <<-CSV
|
|
202
|
+
stream0,2012-08-12T00:00:00Z,1
|
|
203
|
+
stream1,2012-08-12T00:00:00Z,1
|
|
204
|
+
CSV
|
|
205
|
+
|
|
206
|
+
expect {
|
|
207
|
+
Xively::Feed.new(csv, :v1)
|
|
208
|
+
}.to raise_error(Xively::Parsers::CSV::InvalidCSVError)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
it "should permit an individual value within a larger update to not have a timestamp" do
|
|
212
|
+
csv = <<-CSV
|
|
213
|
+
stream0,2012-08-12T00:00:00Z,1
|
|
214
|
+
stream1,2012-08-12T00:00:00Z,1
|
|
215
|
+
stream0,2012-08-12T00:00:05Z,2
|
|
216
|
+
stream1,2012-08-12T00:00:05Z,2
|
|
217
|
+
stream0,2012-08-12T00:00:10Z,3
|
|
218
|
+
stream1,2012-08-12T00:00:10Z,3
|
|
219
|
+
stream2,4
|
|
220
|
+
CSV
|
|
221
|
+
feed = Xively::Feed.new(csv)
|
|
222
|
+
feed.datastreams.size.should == 3
|
|
223
|
+
sorted_datastreams = feed.datastreams.sort { |a, b| a.id <=> b.id }
|
|
224
|
+
[0,1].each do |i|
|
|
225
|
+
sorted_datastreams[i].current_value.should be_nil
|
|
226
|
+
sorted_datastreams[i].updated.should be_nil
|
|
227
|
+
sorted_datastreams[i].datapoints.size.should == 3
|
|
228
|
+
end
|
|
229
|
+
sorted_datastreams[2].current_value.should == "4"
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "default datapoint json parser" do
|
|
4
|
+
before(:each) do
|
|
5
|
+
@datapoint = Xively::Datapoint.new(datapoint_as_(:json))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should convert into attributes hash" do
|
|
9
|
+
@json = datapoint_as_(:json)
|
|
10
|
+
attributes = @datapoint.from_json(@json)
|
|
11
|
+
json = MultiJson.load(@json)
|
|
12
|
+
attributes["at"].should == json["at"]
|
|
13
|
+
attributes["value"].should == json["value"]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should raise known exeception if passed garbage as json" do
|
|
17
|
+
expect {
|
|
18
|
+
Xively::Datapoint.new("This is not\nJSON", :json)
|
|
19
|
+
}.to raise_error(Xively::Parsers::JSON::InvalidJSONError)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "default datastream json parser" do
|
|
4
|
+
include Xively::Helpers
|
|
5
|
+
|
|
6
|
+
before(:each) do
|
|
7
|
+
@datastream = Xively::Datastream.new(datastream_as_(:json))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should default to v2 if no version is present" do
|
|
11
|
+
@json = datastream_as_(:json, :version => "1.0.0", :except => [:version])
|
|
12
|
+
attributes = @datastream.from_json(@json)
|
|
13
|
+
json = MultiJson.load(@json)
|
|
14
|
+
attributes["id"].should == json["id"]
|
|
15
|
+
attributes["updated"].should == json["at"]
|
|
16
|
+
attributes["current_value"].should == json["current_value"]
|
|
17
|
+
attributes["max_value"].should == json["max_value"]
|
|
18
|
+
attributes["min_value"].should == json["min_value"]
|
|
19
|
+
attributes["tags"].should == join_tags(json["tags"])
|
|
20
|
+
attributes["unit_type"].should == json["unit"]["type"]
|
|
21
|
+
attributes["unit_label"].should == json["unit"]["label"]
|
|
22
|
+
attributes["unit_symbol"].should == json["unit"]["symbol"]
|
|
23
|
+
at_least_one_datapoint = false
|
|
24
|
+
attributes["datapoints"].each do |point|
|
|
25
|
+
at_least_one_datapoint = true
|
|
26
|
+
dp = json["datapoints"].detect {|dp| dp["at"] == point["at"]}
|
|
27
|
+
point["value"].should == dp["value"]
|
|
28
|
+
point["at"].should == dp["at"]
|
|
29
|
+
end
|
|
30
|
+
at_least_one_datapoint.should be_true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should raise known exception if passed garbage as JSON" do
|
|
34
|
+
expect {
|
|
35
|
+
Xively::Datastream.new("This is not json", :v2, :json)
|
|
36
|
+
}.to raise_error(Xively::Parsers::JSON::InvalidJSONError)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "1.0.0 (used by API v2)" do
|
|
40
|
+
it "should convert into attributes hash" do
|
|
41
|
+
@json = datastream_as_(:json)
|
|
42
|
+
attributes = @datastream.from_json(@json)
|
|
43
|
+
json = MultiJson.load(@json)
|
|
44
|
+
attributes["id"].should == json["id"]
|
|
45
|
+
attributes["updated"].should == json["at"]
|
|
46
|
+
attributes["current_value"].should == json["current_value"]
|
|
47
|
+
attributes["max_value"].should == json["max_value"]
|
|
48
|
+
attributes["min_value"].should == json["min_value"]
|
|
49
|
+
attributes["tags"].should == join_tags(json["tags"])
|
|
50
|
+
attributes["unit_type"].should == json["unit"]["type"]
|
|
51
|
+
attributes["unit_label"].should == json["unit"]["label"]
|
|
52
|
+
attributes["unit_symbol"].should == json["unit"]["symbol"]
|
|
53
|
+
at_least_one_datapoint = false
|
|
54
|
+
attributes["datapoints"].each do |point|
|
|
55
|
+
at_least_one_datapoint = true
|
|
56
|
+
dp = json["datapoints"].detect {|dp| dp["at"] == point["at"]}
|
|
57
|
+
point["value"].should == dp["value"]
|
|
58
|
+
point["at"].should == dp["at"]
|
|
59
|
+
end
|
|
60
|
+
at_least_one_datapoint.should be_true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should handle blank tags" do
|
|
64
|
+
@json = datastream_as_(:json, :except => [:tags])
|
|
65
|
+
lambda {@datastream.from_json(@json)}.should_not raise_error
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should capture timestamp" do
|
|
69
|
+
@json = datastream_as_(:json, :version => "1.0.0-minimal_timestamp")
|
|
70
|
+
attributes = @datastream.from_json(@json)
|
|
71
|
+
json = MultiJson.load(@json)
|
|
72
|
+
attributes["updated"].should_not be_nil
|
|
73
|
+
attributes["updated"].should == json["at"]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context "0.6-alpha (used by API v1)" do
|
|
78
|
+
|
|
79
|
+
it "should convert into attributes hash" do
|
|
80
|
+
@json = datastream_as_(:json, :version => "0.6-alpha")
|
|
81
|
+
attributes = @datastream.from_json(@json)
|
|
82
|
+
json = MultiJson.load(@json)
|
|
83
|
+
attributes["id"].should == json["id"]
|
|
84
|
+
attributes["updated"].should == json["values"].first["recorded_at"]
|
|
85
|
+
attributes["current_value"].should == json["values"].first["value"]
|
|
86
|
+
attributes["max_value"].should == json["values"].first["max_value"]
|
|
87
|
+
attributes["min_value"].should == json["values"].first["min_value"]
|
|
88
|
+
attributes["tags"].should == json["tags"].join(',')
|
|
89
|
+
attributes["unit_type"].should == json["unit"]["type"]
|
|
90
|
+
attributes["unit_label"].should == json["unit"]["label"]
|
|
91
|
+
attributes["unit_symbol"].should == json["unit"]["symbol"]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "should handle blank tags" do
|
|
95
|
+
@json = datastream_as_(:json, :version => "0.6-alpha", :except => [:tags])
|
|
96
|
+
lambda {@datastream.from_json(@json)}.should_not raise_error
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "should handle blank values" do
|
|
100
|
+
@json = datastream_as_(:json, :version => "0.6-alpha", :except => [:values])
|
|
101
|
+
lambda {@datastream.from_json(@json)}.should_not raise_error
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|