Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ Obtain one from the Seam Console.
# Set the `SEAM_API_KEY` environment variable
seam = Seam.new

# Pass as the first argument to the constructor
seam = Seam.new("your-api-key")

# Pass as a keyword argument to the constructor
seam = Seam.new(api_key: "your-api-key")

Expand Down Expand Up @@ -423,6 +426,9 @@ Obtain one from the Seam Console.
# Set the `SEAM_PERSONAL_ACCESS_TOKEN` environment variable
seam = Seam::Http::WithoutWorkspace.new

# Pass as the first argument to the constructor
seam = Seam::Http::WithoutWorkspace.new("your-personal-access-token")

# Pass as a keyword argument to the constructor
seam = Seam::Http::WithoutWorkspace.new(
personal_access_token: "your-personal-access-token"
Expand Down Expand Up @@ -535,7 +541,8 @@ seam = Seam.new(
)
```

A request that exceeds the timeout raises `Faraday::TimeoutError`.
A request whose response does not arrive within the timeout raises `Faraday::TimeoutError`,
and a connection that cannot be opened within the timeout raises `Faraday::ConnectionFailed`.

#### Retry behavior

Expand Down
16 changes: 10 additions & 6 deletions lib/seam.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@
require_relative "seam/wait_for_action_attempt"

module Seam
def self.new(**args)
Seam::Http.new(**args)
def self.new(api_key = nil, **options)
Seam::Http.new(api_key, **options)
end

def self.from_api_key(api_key, endpoint: nil, wait_for_action_attempt: true, timeout: nil)
def self.from_api_key(api_key, endpoint: nil, wait_for_action_attempt: true, timeout: nil, faraday_options: {},
faraday_retry_options: {})
Seam::Http.from_api_key(api_key, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt,
timeout: timeout)
timeout: timeout, faraday_options: faraday_options, faraday_retry_options: faraday_retry_options)
end

def self.from_personal_access_token(personal_access_token, workspace_id, endpoint: nil, wait_for_action_attempt: true, timeout: nil)
Seam::Http.from_personal_access_token(personal_access_token, workspace_id, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt, timeout: timeout)
def self.from_personal_access_token(personal_access_token, workspace_id, endpoint: nil, wait_for_action_attempt: true,
timeout: nil, faraday_options: {}, faraday_retry_options: {})
Seam::Http.from_personal_access_token(personal_access_token, workspace_id, endpoint: endpoint,
wait_for_action_attempt: wait_for_action_attempt, timeout: timeout, faraday_options: faraday_options,
faraday_retry_options: faraday_retry_options)
end
end
15 changes: 9 additions & 6 deletions lib/seam/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@

module Seam
module Http
def self.new(**args)
Http::SingleWorkspace.new(**args)
def self.new(api_key = nil, **options)
Http::SingleWorkspace.new(api_key, **options)
end

def self.from_api_key(api_key, endpoint: nil, wait_for_action_attempt: true, timeout: nil)
def self.from_api_key(api_key, endpoint: nil, wait_for_action_attempt: true, timeout: nil, faraday_options: {},
faraday_retry_options: {})
Http::SingleWorkspace.from_api_key(api_key, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt,
timeout: timeout)
timeout: timeout, faraday_options: faraday_options, faraday_retry_options: faraday_retry_options)
end

def self.from_personal_access_token(personal_access_token, workspace_id, endpoint: nil, wait_for_action_attempt: true, timeout: nil)
def self.from_personal_access_token(personal_access_token, workspace_id, endpoint: nil,
wait_for_action_attempt: true, timeout: nil, faraday_options: {}, faraday_retry_options: {})
Http::SingleWorkspace.from_personal_access_token(personal_access_token, workspace_id, endpoint: endpoint,
wait_for_action_attempt: wait_for_action_attempt, timeout: timeout)
wait_for_action_attempt: wait_for_action_attempt, timeout: timeout, faraday_options: faraday_options,
faraday_retry_options: faraday_retry_options)
end

class ApiError < Seam::Error
Expand Down
14 changes: 12 additions & 2 deletions lib/seam/http_single_workspace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,20 @@ class SingleWorkspace
OPTION_NOT_PROVIDED = Object.new.freeze
private_constant :OPTION_NOT_PROVIDED

def initialize(client: nil, api_key: OPTION_NOT_PROVIDED, personal_access_token: OPTION_NOT_PROVIDED,
workspace_id: OPTION_NOT_PROVIDED, endpoint: OPTION_NOT_PROVIDED,
def initialize(token = nil, client: nil, api_key: OPTION_NOT_PROVIDED,
personal_access_token: OPTION_NOT_PROVIDED, workspace_id: OPTION_NOT_PROVIDED, endpoint: OPTION_NOT_PROVIDED,
wait_for_action_attempt: OPTION_NOT_PROVIDED, timeout: OPTION_NOT_PROVIDED,
faraday_options: OPTION_NOT_PROVIDED, faraday_retry_options: OPTION_NOT_PROVIDED)
unless token.nil?
unless api_key.equal?(OPTION_NOT_PROVIDED)
raise Http::Options::SeamInvalidOptionsError.new(
"The api_key was given both as a positional argument and as the api_key option"
)
end

api_key = token
end

supplied_options = {
api_key: api_key,
personal_access_token: personal_access_token,
Expand Down
14 changes: 12 additions & 2 deletions lib/seam/http_without_workspace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,19 @@ class WithoutWorkspace
OPTION_NOT_PROVIDED = Object.new.freeze
private_constant :OPTION_NOT_PROVIDED

def initialize(client: nil, personal_access_token: OPTION_NOT_PROVIDED, endpoint: OPTION_NOT_PROVIDED,
wait_for_action_attempt: OPTION_NOT_PROVIDED, timeout: OPTION_NOT_PROVIDED,
def initialize(token = nil, client: nil, personal_access_token: OPTION_NOT_PROVIDED,
endpoint: OPTION_NOT_PROVIDED, wait_for_action_attempt: OPTION_NOT_PROVIDED, timeout: OPTION_NOT_PROVIDED,
faraday_options: OPTION_NOT_PROVIDED, faraday_retry_options: OPTION_NOT_PROVIDED)
unless token.nil?
unless personal_access_token.equal?(OPTION_NOT_PROVIDED)
raise Http::Options::SeamInvalidOptionsError.new(
"The personal_access_token was given both as a positional argument and as the personal_access_token option"
)
end

personal_access_token = token
end

supplied_options = {
personal_access_token: personal_access_token,
endpoint: endpoint,
Expand Down
41 changes: 41 additions & 0 deletions spec/seam_client/api_key_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,43 @@
expect(device.device_id).to eq(seed["august_device_1"])
end

it "accepts the api key as the first argument" do
seam = Seam.new(seed["seam_apikey1_token"], endpoint: endpoint, wait_for_action_attempt: false)

device = seam.devices.get(device_id: seed["august_device_1"])

expect(device.device_id).to eq(seed["august_device_1"])
expect(seam.defaults.wait_for_action_attempt).to be false
end

it "accepts the api key as the first argument on every constructor" do
[Seam::Http, Seam::Http::SingleWorkspace].each do |klass|
seam = klass.new(seed["seam_apikey1_token"], endpoint: endpoint)

expect(seam.devices.get(device_id: seed["august_device_1"]).device_id).to eq(seed["august_device_1"])
end
end

it "rejects an api key given both as the first argument and as an option" do
expect { Seam.new("seam_some_api_key", api_key: "seam_other_api_key") }.to raise_error(
Seam::Http::Options::SeamInvalidOptionsError,
"Seam received invalid options: The api_key was given both as a positional argument and as the api_key option"
)
end

it "rejects an api key given as the first argument alongside a client" do
expect { Seam.new("seam_some_api_key", client: Faraday.new) }.to raise_error(
Seam::Http::Options::SeamInvalidOptionsError,
/The client option cannot be used with any other option, but received: api_key/
)
end

it "treats a nil first argument as no api key" do
seam = Seam.new(nil, api_key: seed["seam_apikey1_token"], endpoint: endpoint)

expect(seam.devices.get(device_id: seed["august_device_1"]).device_id).to eq(seed["august_device_1"])
end

it "returns resources with parsed attributes" do
devices = seam.devices.list

Expand All @@ -44,6 +81,10 @@
Seam.from_api_key("ey")
end.to raise_error(Seam::Http::Auth::SeamInvalidTokenError, /JWT/)

expect do
Seam.new("ey")
end.to raise_error(Seam::Http::Auth::SeamInvalidTokenError, /JWT/)

expect do
Seam.from_api_key("seam_cst_token")
end.to raise_error(Seam::Http::Auth::SeamInvalidTokenError, /Client Session Token/)
Expand Down
14 changes: 14 additions & 0 deletions spec/seam_client/client_without_workspace_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@
expect(seam.workspaces.list.length).to be > 0
end

it "accepts the personal access token as the first argument" do
seam = described_class.new(seed["seam_at1_token"], endpoint: endpoint)

expect(seam.workspaces.list.length).to be > 0
end

it "rejects a personal access token given both as the first argument and as an option" do
expect { described_class.new("seam_at1_token", personal_access_token: "seam_at2_token") }.to raise_error(
Seam::Http::Options::SeamInvalidOptionsError,
"Seam received invalid options: The personal_access_token was given both as a positional argument " \
"and as the personal_access_token option"
)
end

it "accepts an injected client with request defaults" do
client = Faraday.new

Expand Down
63 changes: 63 additions & 0 deletions spec/seam_client/factory_options_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# frozen_string_literal: true

RSpec.describe "the factory methods" do
let(:url) { "#{Seam::DEFAULT_ENDPOINT}/devices/list" }

def service_unavailable
{
status: 503,
body: {error: {type: "service_unavailable", message: "Down"}}.to_json,
headers: {"Content-Type" => "application/json"}
}
end

shared_examples "a factory that accepts the advanced options" do
it "passes faraday_options to the client" do
seam = build(faraday_options: {headers: {"Custom-Header" => "Test-Value"}, request: {timeout: 45}})

expect(seam.client.headers["Custom-Header"]).to eq("Test-Value")
expect(seam.client.options.timeout).to eq(45)
end

it "passes faraday_retry_options to the client" do
stub_request(:get, url).to_return(service_unavailable)

seam = build(faraday_retry_options: {max: 0, interval: 0})

expect { seam.devices.list }.to raise_error(Seam::Http::ApiError)
expect(a_request(:get, url)).to have_been_made.once
end
end

describe "Seam.from_api_key" do
def build(**options)
Seam.from_api_key("seam_some_api_key", **options)
end

include_examples "a factory that accepts the advanced options"
end

describe "Seam.from_personal_access_token" do
def build(**options)
Seam.from_personal_access_token("seam_at_token", "workspace-1", **options)
end

include_examples "a factory that accepts the advanced options"
end

describe "Seam::Http.from_api_key" do
def build(**options)
Seam::Http.from_api_key("seam_some_api_key", **options)
end

include_examples "a factory that accepts the advanced options"
end

describe "Seam::Http.from_personal_access_token" do
def build(**options)
Seam::Http.from_personal_access_token("seam_at_token", "workspace-1", **options)
end

include_examples "a factory that accepts the advanced options"
end
end
25 changes: 24 additions & 1 deletion spec/seam_client/timeout_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,35 @@
describe "a request that exceeds the timeout" do
let(:url) { "#{Seam::DEFAULT_ENDPOINT}/devices/list" }

it "raises Faraday::TimeoutError" do
it "raises Faraday::ConnectionFailed when the connection cannot be opened in time" do
stub_request(:get, url).to_timeout

seam = Seam.new(api_key: "seam_some_api_key", timeout: 1)

expect { seam.devices.list }.to raise_error(Faraday::ConnectionFailed)
end

it "raises Faraday::TimeoutError when the response does not arrive in time" do
server = TCPServer.new("127.0.0.1", 0)
thread = Thread.new do
loop do
socket = server.accept
sleep 1
socket.close
end
end

seam = Seam.new(
api_key: "seam_some_api_key",
endpoint: "http://127.0.0.1:#{server.addr[1]}",
timeout: 0.2,
faraday_retry_options: {max: 0}
)

expect { seam.devices.list }.to raise_error(Faraday::TimeoutError)
ensure
thread&.kill
server&.close
end
end
end
Loading