mode-sdk 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +109 -0
- data/Rakefile +6 -0
- data/lib/mode/sdk.rb +70 -0
- data/lib/mode/sdk/client.rb +87 -0
- data/lib/mode/sdk/client/request.rb +133 -0
- data/lib/mode/sdk/client/response.rb +83 -0
- data/lib/mode/sdk/column.rb +95 -0
- data/lib/mode/sdk/column_set.rb +56 -0
- data/lib/mode/sdk/configuration.rb +21 -0
- data/lib/mode/sdk/hash_util.rb +21 -0
- data/lib/mode/sdk/table.rb +168 -0
- data/lib/mode/sdk/table_import.rb +52 -0
- data/lib/mode/sdk/upload.rb +57 -0
- data/lib/mode/sdk/version.rb +9 -0
- data/lib/mode/sdk/warehouse_util.rb +35 -0
- data/mode-sdk.gemspec +27 -0
- data/spec/lib/mode/sdk/client/request_spec.rb +105 -0
- data/spec/lib/mode/sdk/client/response_spec.rb +65 -0
- data/spec/lib/mode/sdk/client_spec.rb +71 -0
- data/spec/lib/mode/sdk/column_set_spec.rb +53 -0
- data/spec/lib/mode/sdk/column_spec.rb +101 -0
- data/spec/lib/mode/sdk/hash_util_spec.rb +18 -0
- data/spec/lib/mode/sdk/table_import_spec.rb +33 -0
- data/spec/lib/mode/sdk/table_spec.rb +191 -0
- data/spec/lib/mode/sdk/upload_spec.rb +37 -0
- data/spec/lib/mode/sdk/warehouse_util_spec.rb +40 -0
- data/spec/lib/mode/sdk_spec.rb +50 -0
- data/spec/spec_helper.rb +17 -0
- metadata +145 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mode::Sdk::Column do
|
6
|
+
describe '#validate!' do
|
7
|
+
it 'returns true if no exceptions are raised' do
|
8
|
+
column = Mode::Sdk::Column.new({})
|
9
|
+
|
10
|
+
expect(column).to receive(:validate_keys!)
|
11
|
+
expect(column).to receive(:validate_name!)
|
12
|
+
expect(column).to receive(:validate_type!)
|
13
|
+
|
14
|
+
expect(column.validate!).to eq(true)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#validate_keys!' do
|
19
|
+
it 'raises error if column is missing name key' do
|
20
|
+
column = Mode::Sdk::Column.new(type: 'text')
|
21
|
+
|
22
|
+
expect {
|
23
|
+
column.send(:validate_keys!)
|
24
|
+
}.to raise_error(Mode::Sdk::Column::InvalidError) do |exception|
|
25
|
+
expect(exception.message).to match(/missing required key 'name'/i)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'raises error if column is missing type key' do
|
30
|
+
column = Mode::Sdk::Column.new(name: 'name')
|
31
|
+
|
32
|
+
expect {
|
33
|
+
column.send(:validate_keys!)
|
34
|
+
}.to raise_error(Mode::Sdk::Column::InvalidError) do |exception|
|
35
|
+
expect(exception.message).to match(/missing required key 'type'/i)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'raises error if column has extra keys' do
|
40
|
+
column = Mode::Sdk::Column.new(name: 'name', type: 'text', foo: 'bar')
|
41
|
+
|
42
|
+
expect {
|
43
|
+
column.send(:validate_keys!)
|
44
|
+
}.to raise_error(Mode::Sdk::Column::InvalidError) do |exception|
|
45
|
+
expect(exception.message).to match(/has unexpected keys/i)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'returns true for valid keys' do
|
50
|
+
column = Mode::Sdk::Column.new(name: nil, type: nil)
|
51
|
+
|
52
|
+
expect(column.send(:validate_keys!)).to eq(true)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#validate_name!' do
|
57
|
+
it 'raises error if column name is too short' do
|
58
|
+
column = Mode::Sdk::Column.new(name: 'n')
|
59
|
+
|
60
|
+
expect {
|
61
|
+
column.send(:validate_name!)
|
62
|
+
}.to raise_error(Mode::Sdk::Column::InvalidError) do |exception|
|
63
|
+
expect(exception.message).to match(/name is invalid/i)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'raises error if column name is too long' do
|
68
|
+
column = Mode::Sdk::Column.new(name: 'no' * 50)
|
69
|
+
|
70
|
+
expect {
|
71
|
+
column.send(:validate_name!)
|
72
|
+
}.to raise_error(Mode::Sdk::Column::InvalidError) do |exception|
|
73
|
+
expect(exception.message).to match(/name is invalid/i)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns true for valid name' do
|
78
|
+
column = Mode::Sdk::Column.new(name: 'name')
|
79
|
+
|
80
|
+
expect(column.send(:validate_name!)).to eq(true)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#validate_type!' do
|
85
|
+
it 'raises error if column type is not recognized' do
|
86
|
+
column = Mode::Sdk::Column.new(type: 'nope')
|
87
|
+
|
88
|
+
expect {
|
89
|
+
column.send(:validate_type!)
|
90
|
+
}.to raise_error(Mode::Sdk::Column::InvalidError) do |exception|
|
91
|
+
expect(exception.message).to match(/type is invalid/i)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns true for valid type' do
|
96
|
+
column = Mode::Sdk::Column.new(type: 'integer')
|
97
|
+
|
98
|
+
expect(column.send(:validate_type!)).to eq(true)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mode::Sdk::HashUtil do
|
6
|
+
let :util do
|
7
|
+
Object.new.extend(Mode::Sdk::HashUtil)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#stringify_keys' do
|
11
|
+
it 'stringifies keys' do
|
12
|
+
hash = { foo1: 'bar1', foo2: 'bar2' }
|
13
|
+
|
14
|
+
expect(util.stringify_keys(hash)).to eq(
|
15
|
+
'foo1' => 'bar1', 'foo2' => 'bar2')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mode::Sdk::TableImport do
|
6
|
+
describe '#poll' do
|
7
|
+
it 'polls state until completed' do
|
8
|
+
import = Mode::Sdk::TableImport.new('/some/path')
|
9
|
+
|
10
|
+
reprs = %w(new enqueued running running failed).map do |state|
|
11
|
+
{ 'state' => state }
|
12
|
+
end
|
13
|
+
|
14
|
+
expect(import).to receive(:fetch_repr).and_return(*reprs)
|
15
|
+
|
16
|
+
expect { |b|
|
17
|
+
import.poll(0, &b)
|
18
|
+
}.to yield_successive_args(*reprs)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#fetch_repr' do
|
23
|
+
it 'performs get request' do
|
24
|
+
import = Mode::Sdk::TableImport.new('/some/path')
|
25
|
+
|
26
|
+
response = double(:response, body: { 'state' => 'enqueued' })
|
27
|
+
|
28
|
+
expect(Mode::Sdk::Client).to receive(:get).and_return(response)
|
29
|
+
|
30
|
+
expect(import.send(:fetch_repr)).to eq('state' => 'enqueued')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mode::Sdk::Table do
|
6
|
+
describe '#owner' do
|
7
|
+
it 'defaults to authenticated username' do
|
8
|
+
expect(Mode::Sdk).to receive(:username).and_return('sally')
|
9
|
+
table = Mode::Sdk::Table.new('name')
|
10
|
+
expect(table.send(:owner)).to eq('sally')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'uses owner option if present' do
|
14
|
+
expect(Mode::Sdk).to receive(:username).never
|
15
|
+
table = Mode::Sdk::Table.new('name', owner: 'earl')
|
16
|
+
expect(table.send(:owner)).to eq('earl')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#resource_path' do
|
21
|
+
it 'forms path correctly' do
|
22
|
+
table = Mode::Sdk::Table.new('name', owner: 'sally')
|
23
|
+
expect(table.send(:resource_path)).to eq('/api/sally/tables/name')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#exists?' do
|
28
|
+
it 'is true if table exists' do
|
29
|
+
response = Mode::Sdk::Client::Response.new(nil)
|
30
|
+
expect(response).to receive(:code).and_return(200)
|
31
|
+
expect(Mode::Sdk::Client).to receive(:head).and_return(response)
|
32
|
+
|
33
|
+
table = Mode::Sdk::Table.new('name', owner: 'sally')
|
34
|
+
expect(table.send(:exists?)).to eq(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'is false if table does not exist' do
|
38
|
+
response = Mode::Sdk::Client::Response.new(nil)
|
39
|
+
expect(response).to receive(:code).and_return(404)
|
40
|
+
expect(Mode::Sdk::Client).to receive(:head).and_return(response)
|
41
|
+
|
42
|
+
table = Mode::Sdk::Table.new('name', owner: 'sally')
|
43
|
+
expect(table.send(:exists?)).to eq(false)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#create' do
|
48
|
+
it 'creates table' do
|
49
|
+
table = Mode::Sdk::Table.new('name')
|
50
|
+
|
51
|
+
expect(table).to receive(:upsert) do |*args|
|
52
|
+
expect(args.first).to eq(:create)
|
53
|
+
end
|
54
|
+
|
55
|
+
expect(table.create).to eq(true)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#replace' do
|
60
|
+
it 'creates table' do
|
61
|
+
table = Mode::Sdk::Table.new('name')
|
62
|
+
|
63
|
+
expect(table).to receive(:upsert) do |*args|
|
64
|
+
expect(args.first).to eq(:replace)
|
65
|
+
end
|
66
|
+
|
67
|
+
expect(table.replace).to eq(true)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#validate!' do
|
72
|
+
it 'raises exception if upload token is missing' do
|
73
|
+
table = Mode::Sdk::Table.new('no')
|
74
|
+
|
75
|
+
expect {
|
76
|
+
table.send(:validate!)
|
77
|
+
}.to raise_error(Mode::Sdk::Table::InvalidError) do |exception|
|
78
|
+
expect(exception.message).to match(/missing required attribute/i)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'raises exception if table name is invalid' do
|
83
|
+
table = Mode::Sdk::Table.new('no')
|
84
|
+
table.upload_token = 'token'
|
85
|
+
|
86
|
+
expect {
|
87
|
+
table.send(:validate!)
|
88
|
+
}.to raise_error(Mode::Sdk::Table::InvalidError) do |exception|
|
89
|
+
expect(exception.message).to match(/invalid name/i)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns true if no exceptions are raised' do
|
94
|
+
table = Mode::Sdk::Table.new('name')
|
95
|
+
table.upload_token = 'token'
|
96
|
+
|
97
|
+
expect_any_instance_of(Mode::Sdk::ColumnSet).to(
|
98
|
+
receive(:validate!).at_least(:once).and_return(true))
|
99
|
+
|
100
|
+
expect(table.send(:validate!)).to eq(true)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '#upsert' do
|
105
|
+
let :response do
|
106
|
+
Mode::Sdk::Client::Response.new(nil)
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'for create' do
|
110
|
+
it 'creates table' do
|
111
|
+
table = Mode::Sdk::Table.new('name', owner: 'owner')
|
112
|
+
|
113
|
+
expect(table).to receive(:validate!)
|
114
|
+
expect(response).to receive(:code).and_return(200)
|
115
|
+
expect(Mode::Sdk::Client).to receive(:post).and_return(response)
|
116
|
+
|
117
|
+
expect(table.send(:upsert, :create)).to be_an_instance_of(
|
118
|
+
Mode::Sdk::Client::Response)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'raises exception for bad request' do
|
122
|
+
table = Mode::Sdk::Table.new('name', owner: 'owner')
|
123
|
+
|
124
|
+
expect(table).to receive(:validate!)
|
125
|
+
expect(response).to receive(:code).and_return(400)
|
126
|
+
expect(response).to receive(:body)
|
127
|
+
expect(Mode::Sdk::Client).to receive(:post).and_return(response)
|
128
|
+
|
129
|
+
expect {
|
130
|
+
table.send(:upsert, :create)
|
131
|
+
}.to raise_error(Mode::Sdk::Table::InvalidError)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe 'for replace' do
|
136
|
+
it 'replaces table' do
|
137
|
+
table = Mode::Sdk::Table.new('name', owner: 'owner')
|
138
|
+
|
139
|
+
expect(table).to receive(:validate!)
|
140
|
+
expect(response).to receive(:code).and_return(200)
|
141
|
+
expect(Mode::Sdk::Client).to receive(:put).and_return(response)
|
142
|
+
|
143
|
+
expect(table.send(:upsert, :replace)).to be_an_instance_of(
|
144
|
+
Mode::Sdk::Client::Response)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe '#full_name' do
|
150
|
+
it 'forms full name with schema' do
|
151
|
+
table = Mode::Sdk::Table.new('name', owner: 'owner')
|
152
|
+
|
153
|
+
expect(table.full_name).to eq('owner.name')
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe '#upsert_data' do
|
158
|
+
it 'is formed correctly' do
|
159
|
+
table = Mode::Sdk::Table.new('name', owner: 'owner')
|
160
|
+
table.columns = [{ name: 'name', type: 'string' }]
|
161
|
+
table.upload_token = 'token'
|
162
|
+
|
163
|
+
result = table.send(:upsert_data)
|
164
|
+
|
165
|
+
expected = {
|
166
|
+
upload_token: 'token',
|
167
|
+
table: {
|
168
|
+
name: 'name',
|
169
|
+
description: nil,
|
170
|
+
columns: [{ 'name' => 'name', 'type' => 'string' }]
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
expect(result).to eq(expected)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe '#columns=' do
|
179
|
+
it 'unmemoizes column set' do
|
180
|
+
table = Mode::Sdk::Table.new('name', owner: 'owner')
|
181
|
+
table.columns = [{ name: 'name', type: 'string' }]
|
182
|
+
table.send(:column_set)
|
183
|
+
|
184
|
+
expect(table.instance_variable_defined?(:@column_set)).to eq(true)
|
185
|
+
|
186
|
+
table.columns = [{ name: 'name', type: 'string' }]
|
187
|
+
|
188
|
+
expect(table.instance_variable_defined?(:@column_set)).to eq(false)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mode::Sdk::Upload do
|
6
|
+
describe '#create' do
|
7
|
+
it 'performs http post' do
|
8
|
+
upload = Mode::Sdk::Upload.new('content')
|
9
|
+
|
10
|
+
expect(Mode::Sdk::Client).to receive(:post) do |*args|
|
11
|
+
expect(args[0]).to eq('/api/uploads')
|
12
|
+
|
13
|
+
expect(args[1]).to eq('content')
|
14
|
+
|
15
|
+
options = args[2]
|
16
|
+
|
17
|
+
expect(options[:content_type]).to eq('application/csv')
|
18
|
+
expect(options[:content_length]).to eq(7)
|
19
|
+
expect(options[:expect]).to eq([201])
|
20
|
+
end
|
21
|
+
|
22
|
+
upload.create
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#token' do
|
27
|
+
it 'retrieves the token' do
|
28
|
+
upload = Mode::Sdk::Upload.new('content')
|
29
|
+
|
30
|
+
response = Mode::Sdk::Client::Response.new(nil)
|
31
|
+
expect(response).to receive(:body).and_return('token' => 'sometoken')
|
32
|
+
expect(upload).to receive(:create).and_return(response)
|
33
|
+
|
34
|
+
expect(upload.token).to eq('sometoken')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mode::Sdk::WarehouseUtil do
|
6
|
+
let :util do
|
7
|
+
Object.new.extend(Mode::Sdk::WarehouseUtil)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#normalize_name' do
|
11
|
+
it 'preserves short name' do
|
12
|
+
expect(util.normalize_name('foo_bar')).to eq('foo_bar')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'truncates long name' do
|
16
|
+
expect(util.normalize_name('a' * 100).size).to eq(64)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#normalize_string' do
|
21
|
+
it 'preserves simple strings' do
|
22
|
+
%w(foo foo_bar foo_bar_baz).each do |string|
|
23
|
+
expect(util.send(:normalize_string, string)).to eq(string)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'normalizes messy strings' do
|
28
|
+
expected = {
|
29
|
+
' fOO_' => 'foo',
|
30
|
+
'_ foo___' => 'foo',
|
31
|
+
'fo*(*o__BaR ! ?' => 'foo_bar',
|
32
|
+
'fo__o- _!bar_b _ - az ' => 'fo_o_bar_b_az'
|
33
|
+
}
|
34
|
+
|
35
|
+
expected.each do |input, output|
|
36
|
+
expect(util.send(:normalize_string, input)).to eq(output)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mode::Sdk do
|
6
|
+
after :each do
|
7
|
+
Mode::Sdk.reset
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.configure' do
|
11
|
+
it 'sets configuration variables' do
|
12
|
+
expect_any_instance_of(
|
13
|
+
Mode::Sdk::Configuration).to receive(:setting=).once
|
14
|
+
|
15
|
+
Mode::Sdk.configure do |config|
|
16
|
+
config.setting = 'value'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.config' do
|
22
|
+
it 'instantiates and memoizes configuration instance' do
|
23
|
+
expect(Mode::Sdk.instance_variable_get(:@config)).to be_nil
|
24
|
+
|
25
|
+
expect(Mode::Sdk.config).to be_an_instance_of(Mode::Sdk::Configuration)
|
26
|
+
|
27
|
+
config = Mode::Sdk.instance_variable_get(:@config)
|
28
|
+
|
29
|
+
expect(config).to be_an_instance_of(Mode::Sdk::Configuration)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '.account' do
|
34
|
+
it 'returns account from client' do
|
35
|
+
expect(Mode::Sdk::Client).to receive(:account).and_return(
|
36
|
+
'username' => 'someone')
|
37
|
+
|
38
|
+
expect(Mode::Sdk.account).to eq('username' => 'someone')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '.username' do
|
43
|
+
it 'returns username from client' do
|
44
|
+
expect(Mode::Sdk::Client).to receive(:account).and_return(
|
45
|
+
'username' => 'someone')
|
46
|
+
|
47
|
+
expect(Mode::Sdk.username).to eq('someone')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|