looker-sdk 0.1.11 → 0.1.12
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/looker-sdk/authentication.rb +1 -2
- data/lib/looker-sdk/client/dynamic.rb +19 -0
- data/lib/looker-sdk/version.rb +1 -1
- data/test/helper.rb +8 -3
- data/test/looker/test_body_params.rb +150 -0
- data/test/looker/test_client.rb +36 -2
- data/test/looker/test_inline_query.rb +1 -0
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6b38ec236c26320f7fe18d8dcfb9e8020ee07aea5f65aeacc03f016d7aa12cf6
|
|
4
|
+
data.tar.gz: 717e65d319d58d044ab50656bde6b2fcdccdfff69400c5b20631bd737db7f412
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 87a1c61b1f6d4fba05c9bb31743757974ed91efb8f73cfd2e94ac2000b1b3d243c4e34b330e73319e965d477f0361e20b72d0fb196817f975bd666df79351341
|
|
7
|
+
data.tar.gz: 7f20baf26fb2d47782587e05f4867879eecc1b77552e1bc30e62fea52dd8eb053d10f272598dd0f2b5523cf293e3d875c122fb2b5550067dda20d265e984238b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.0](https://github.com/looker-open-source/looker-sdk-ruby/compare/v0.1.11...v0.2.0) (2026-03-08)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* Allow query parameters to be passed in the body for POST, PUT, and PATCH requests when no body parameter is explicitly defined. ([#156](https://github.com/looker-open-source/looker-sdk-ruby/issues/156)) ([6bb702b](https://github.com/looker-open-source/looker-sdk-ruby/commit/6bb702bd8c40bc2efdfad25df60a1a661e00e16b))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* allow tests to run against remote server ([#155](https://github.com/looker-open-source/looker-sdk-ruby/issues/155)) ([1156d52](https://github.com/looker-open-source/looker-sdk-ruby/commit/1156d52c849197176ee62e8a122d2e5bab71f4be))
|
|
14
|
+
* move query params -> body only on form ([#158](https://github.com/looker-open-source/looker-sdk-ruby/issues/158)) ([87e7280](https://github.com/looker-open-source/looker-sdk-ruby/commit/87e72805d479906ebd7d4753898d7609c9a33016))
|
|
15
|
+
* send proper content-type header at /login ([#160](https://github.com/looker-open-source/looker-sdk-ruby/issues/160)) ([36866eb](https://github.com/looker-open-source/looker-sdk-ruby/commit/36866eb7d3414c2b00a65f3ee8b3b3784416bdf8))
|
|
16
|
+
|
|
3
17
|
## [0.1.11](https://github.com/looker-open-source/looker-sdk-ruby/compare/v0.1.10...v0.1.11) (2025-01-13)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -52,8 +52,7 @@ module LookerSDK
|
|
|
52
52
|
set_access_token_from_params(nil)
|
|
53
53
|
without_authentication do
|
|
54
54
|
encoded_auth = Faraday::Utils.build_query(application_credentials)
|
|
55
|
-
post(
|
|
56
|
-
raise "login failure #{last_response.status}" unless last_response.status == 200
|
|
55
|
+
post(File.join(URI.parse(api_endpoint).path, 'login'), encoded_auth, headers: {:'Content-Type' => 'application/x-www-form-urlencoded'})
|
|
57
56
|
set_access_token_from_params(last_response.data)
|
|
58
57
|
end
|
|
59
58
|
end
|
|
@@ -144,6 +144,22 @@ module LookerSDK
|
|
|
144
144
|
b = args.length > 1 ? args[1] : {}
|
|
145
145
|
|
|
146
146
|
method = entry[:method].to_sym
|
|
147
|
+
|
|
148
|
+
if [:post, :put, :patch].include?(method) && (entry[:info][:consumes] || []).include?("application/x-www-form-urlencoded")
|
|
149
|
+
if empty_body?(a) && !empty_body?(b)
|
|
150
|
+
a = {} if empty_body?(a)
|
|
151
|
+
if b.key?(:query)
|
|
152
|
+
a.merge!(b.delete(:query))
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
b.keys.each do |k|
|
|
156
|
+
next if k == :headers
|
|
157
|
+
next if Client::CONVENIENCE_HEADERS.include?(k)
|
|
158
|
+
a[k] = b.delete(k)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
147
163
|
case method
|
|
148
164
|
when :get then get(route, a, true, &block)
|
|
149
165
|
when :post then post(route, a, merge_content_type_if_body(a, b), true, &block)
|
|
@@ -154,6 +170,9 @@ module LookerSDK
|
|
|
154
170
|
end
|
|
155
171
|
end
|
|
156
172
|
|
|
173
|
+
def empty_body?(body)
|
|
174
|
+
body.nil? || (body.respond_to?(:empty?) && body.empty?)
|
|
175
|
+
end
|
|
157
176
|
end
|
|
158
177
|
end
|
|
159
178
|
end
|
data/lib/looker-sdk/version.rb
CHANGED
data/test/helper.rb
CHANGED
|
@@ -22,9 +22,13 @@
|
|
|
22
22
|
# THE SOFTWARE.
|
|
23
23
|
############################################################################################
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
SimpleCov.
|
|
25
|
+
begin
|
|
26
|
+
require 'simplecov'
|
|
27
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new SimpleCov::Formatter::HTMLFormatter
|
|
28
|
+
SimpleCov.start
|
|
29
|
+
rescue LoadError
|
|
30
|
+
# ignore simplecov if not installed
|
|
31
|
+
end
|
|
28
32
|
|
|
29
33
|
require 'rubygems'
|
|
30
34
|
require 'bundler/setup'
|
|
@@ -94,6 +98,7 @@ def setup_sdk
|
|
|
94
98
|
else
|
|
95
99
|
c.netrc = true
|
|
96
100
|
c.netrc_file = File.join(fixture_path, '.netrc')
|
|
101
|
+
c.api_endpoint = "#{base_url}/api/#{api_version}"
|
|
97
102
|
end
|
|
98
103
|
end
|
|
99
104
|
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
require_relative '../helper'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class LookerBodyParamsTest < Minitest::Spec
|
|
5
|
+
|
|
6
|
+
def access_token
|
|
7
|
+
'87614b09dd141c22800f96f11737ade5226d7ba8'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def sdk_client(swagger, engine)
|
|
11
|
+
faraday = Faraday.new do |conn|
|
|
12
|
+
conn.use LookerSDK::Response::RaiseError
|
|
13
|
+
conn.adapter :rack, engine
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
LookerSDK.reset!
|
|
17
|
+
LookerSDK::Client.new do |config|
|
|
18
|
+
config.swagger = swagger
|
|
19
|
+
config.access_token = access_token
|
|
20
|
+
config.faraday = faraday
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def default_swagger
|
|
25
|
+
json = <<-JSON
|
|
26
|
+
{
|
|
27
|
+
"swagger": "2.0",
|
|
28
|
+
"basePath": "/api/4.0",
|
|
29
|
+
"paths": {
|
|
30
|
+
"/test_post_urlencoded": {
|
|
31
|
+
"post": {
|
|
32
|
+
"operationId": "test_post_urlencoded",
|
|
33
|
+
"consumes": ["application/x-www-form-urlencoded"],
|
|
34
|
+
"parameters": [
|
|
35
|
+
{
|
|
36
|
+
"name": "param1",
|
|
37
|
+
"in": "query",
|
|
38
|
+
"type": "string"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "param2",
|
|
42
|
+
"in": "query",
|
|
43
|
+
"type": "string"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"responses": {
|
|
47
|
+
"200": { "description": "Success" }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"/test_post_json": {
|
|
52
|
+
"post": {
|
|
53
|
+
"operationId": "test_post_json",
|
|
54
|
+
"consumes": ["application/json"],
|
|
55
|
+
"parameters": [
|
|
56
|
+
{
|
|
57
|
+
"name": "param1",
|
|
58
|
+
"in": "query",
|
|
59
|
+
"type": "string"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"responses": {
|
|
63
|
+
"200": { "description": "Success" }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"/test_post_default": {
|
|
68
|
+
"post": {
|
|
69
|
+
"operationId": "test_post_default",
|
|
70
|
+
"parameters": [
|
|
71
|
+
{
|
|
72
|
+
"name": "param1",
|
|
73
|
+
"in": "query",
|
|
74
|
+
"type": "string"
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"responses": {
|
|
78
|
+
"200": { "description": "Success" }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
JSON
|
|
85
|
+
@swagger ||= JSON.parse(json, :symbolize_names => true)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def verify(response, method, path, expected_body='', expected_query={}, content_type = nil)
|
|
89
|
+
mock = Minitest::Mock.new.expect(:call, response) do |env|
|
|
90
|
+
req = Rack::Request.new(env)
|
|
91
|
+
req_body = req.body&.gets || ''
|
|
92
|
+
|
|
93
|
+
# Parse body if it's JSON
|
|
94
|
+
begin
|
|
95
|
+
parsed_body = JSON.parse(req_body, :symbolize_names => true)
|
|
96
|
+
rescue JSON::ParserError
|
|
97
|
+
parsed_body = req_body
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Check method
|
|
101
|
+
method_match = req.request_method == method.to_s.upcase
|
|
102
|
+
|
|
103
|
+
# Check path
|
|
104
|
+
path_match = req.path_info == path
|
|
105
|
+
|
|
106
|
+
# Check query params
|
|
107
|
+
parsed_query = JSON.parse(req.params.to_json, :symbolize_names => true)
|
|
108
|
+
query_match = parsed_query == expected_query
|
|
109
|
+
|
|
110
|
+
# Check body
|
|
111
|
+
body_match = parsed_body == expected_body
|
|
112
|
+
|
|
113
|
+
if !body_match
|
|
114
|
+
puts "Body mismatch! Expected: #{expected_body.inspect}, Got: #{parsed_body.inspect}"
|
|
115
|
+
end
|
|
116
|
+
method_match && path_match && query_match && body_match
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
yield sdk_client(default_swagger, mock)
|
|
121
|
+
mock.verify
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def response
|
|
125
|
+
[200, {'Content-Type' => 'application/json'}, [{}.to_json]]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe "Body Params Refactor" do
|
|
129
|
+
it "moves query params to body for POST when consumes is x-www-form-urlencoded" do
|
|
130
|
+
# Expect body to have params, query to be empty
|
|
131
|
+
verify(response, :post, '/api/4.0/test_post_urlencoded', {param1: 'foo', param2: 'bar'}, {}) do |sdk|
|
|
132
|
+
sdk.test_post_urlencoded(nil, param1: 'foo', param2: 'bar')
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "keeps params in query for POST when consumes is application/json" do
|
|
137
|
+
# Expect body to be empty (or nil), query to have params
|
|
138
|
+
verify(response, :post, '/api/4.0/test_post_json', '', {param1: 'foo'}) do |sdk|
|
|
139
|
+
sdk.test_post_json(nil, param1: 'foo')
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "keeps params in query for POST when consumes is unspecified" do
|
|
144
|
+
# Expect body to be empty, query to have params
|
|
145
|
+
verify(response, :post, '/api/4.0/test_post_default', '', {param1: 'foo'}) do |sdk|
|
|
146
|
+
sdk.test_post_default(nil, param1: 'foo')
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
data/test/looker/test_client.rb
CHANGED
|
@@ -57,6 +57,7 @@ describe LookerSDK::Client do
|
|
|
57
57
|
opts.merge!({
|
|
58
58
|
:netrc => true,
|
|
59
59
|
:netrc_file => File.join(fixture_path, '.netrc'),
|
|
60
|
+
:api_endpoint => "#{base_url}/api/#{api_version}",
|
|
60
61
|
:connection_options => {:ssl => {:verify => false}},
|
|
61
62
|
})
|
|
62
63
|
|
|
@@ -156,12 +157,14 @@ describe LookerSDK::Client do
|
|
|
156
157
|
|
|
157
158
|
describe "with .netrc" do
|
|
158
159
|
it "can read .netrc files" do
|
|
159
|
-
|
|
160
|
+
netrc_file = File.expand_path('../../../examples/.netrc', __FILE__)
|
|
161
|
+
skip unless File.exist?(netrc_file)
|
|
160
162
|
LookerSDK.reset!
|
|
163
|
+
File.chmod(0600, netrc_file)
|
|
161
164
|
client = LookerSDK::Client.new(
|
|
162
165
|
:lazy_swagger => true,
|
|
163
166
|
:netrc => true,
|
|
164
|
-
:netrc_file =>
|
|
167
|
+
:netrc_file => netrc_file,
|
|
165
168
|
)
|
|
166
169
|
client.client_id.wont_be_nil
|
|
167
170
|
client.client_secret.wont_be_nil
|
|
@@ -373,6 +376,37 @@ describe LookerSDK::Client do
|
|
|
373
376
|
end
|
|
374
377
|
end
|
|
375
378
|
|
|
379
|
+
describe "authentication" do
|
|
380
|
+
it "sets the proper content type header on login" do
|
|
381
|
+
LookerSDK.reset!
|
|
382
|
+
client = LookerSDK::Client.new(
|
|
383
|
+
client_id: 'a',
|
|
384
|
+
client_secret: 'b',
|
|
385
|
+
api_endpoint: 'https://localhost:19999/api/4.0',
|
|
386
|
+
connection_options: {ssl: {verify: false}},
|
|
387
|
+
lazy_swagger: true
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
# login returns token info
|
|
391
|
+
token_response = OpenStruct.new(status: 200, data: {access_token: 'token', token_type: 'Bearer', expires_in: 3600})
|
|
392
|
+
|
|
393
|
+
# expect the post to have the right url, body, and headers
|
|
394
|
+
mock = Minitest::Mock.new.expect(:call, token_response) do |method, path, body, options|
|
|
395
|
+
method == :post &&
|
|
396
|
+
path == '/api/4.0/login' &&
|
|
397
|
+
body == 'client_id=a&client_secret=b' &&
|
|
398
|
+
options == {headers: {:'Content-Type' => 'application/x-www-form-urlencoded'}}
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# test_client.rb uses mocha for mocking/stubbing usually:
|
|
402
|
+
Sawyer::Agent.stubs(:new).returns(mock)
|
|
403
|
+
|
|
404
|
+
client.authenticate
|
|
405
|
+
|
|
406
|
+
mock.verify
|
|
407
|
+
end
|
|
408
|
+
end
|
|
409
|
+
|
|
376
410
|
# TODO: Convert the old tests that were here to deal with swagger/dynamic way of doing things. Perhaps
|
|
377
411
|
# with a dedicated server that serves swagger customized to the test suite. Also, bring the auth tests
|
|
378
412
|
# to life here on the SDK client end.
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: looker-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Looker
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-03-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: sawyer
|
|
@@ -131,6 +131,7 @@ files:
|
|
|
131
131
|
- streaming.md
|
|
132
132
|
- test/helper.rb
|
|
133
133
|
- test/looker/swagger.json
|
|
134
|
+
- test/looker/test_body_params.rb
|
|
134
135
|
- test/looker/test_client.rb
|
|
135
136
|
- test/looker/test_dynamic_client.rb
|
|
136
137
|
- test/looker/test_dynamic_client_agent.rb
|
|
@@ -163,8 +164,9 @@ summary: Looker Ruby SDK
|
|
|
163
164
|
test_files:
|
|
164
165
|
- test/helper.rb
|
|
165
166
|
- test/looker/test_dynamic_client.rb
|
|
166
|
-
- test/looker/test_inline_query.rb
|
|
167
167
|
- test/looker/test_dynamic_client_agent.rb
|
|
168
|
-
- test/looker/
|
|
168
|
+
- test/looker/test_body_params.rb
|
|
169
169
|
- test/looker/user.json
|
|
170
|
+
- test/looker/test_inline_query.rb
|
|
170
171
|
- test/looker/swagger.json
|
|
172
|
+
- test/looker/test_client.rb
|