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
10 changes: 10 additions & 0 deletions lib/easee/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,21 @@ def raise_credentials_or_request_error(error)
raise Errors::InvalidPinCode.new("PIN code rejected", error.response)
when Errors::ChargerNotFound::CODE
raise Errors::ChargerNotFound.new("Charger not found", error.response)
when Errors::PAIRING_ERROR_CODE
raise_pairing_result_error(error)
end

raise request_failed(error)
end

def raise_pairing_result_error(error)
title = error.response&.dig(:body, "title")
error_class = Errors::PAIRING_RESULT_ERRORS.find { |klass| klass::PAIRING_RESULT_TITLES.include?(title) }
return unless error_class

raise error_class.new("Pairing rejected: #{title}", error.response)
end

def request_failed(error)
Errors::RequestFailed.new("Request returned status #{error.response_status}", error.response)
end
Expand Down
19 changes: 19 additions & 0 deletions lib/easee/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,33 @@ class Forbidden < Base; end

class InvalidPinCode < RequestFailed
CODE = 193
PAIRING_RESULT_TITLES = %w[IncorrectPIN].freeze
end

class ChargerNotFound < RequestFailed
CODE = 400
end

class TooManyAttempts < RequestFailed
PAIRING_RESULT_TITLES = %w[TooManyAttempts].freeze
end

class AlreadyPaired < RequestFailed
PAIRING_RESULT_TITLES = %w[AlreadyPairedWithPartner AlreadyPairedWithUser].freeze
end

class RateLimitExceeded < RequestFailed
def retryable? = true
end

# https://developer.easee.com/docs/enumerations — pairing result codes (0..7)
# ride on a single HTTP errorCode of 123, with the specific reason in `title`.
PAIRING_ERROR_CODE = 123

PAIRING_RESULT_ERRORS = [
InvalidPinCode,
TooManyAttempts,
AlreadyPaired,
].freeze
end
end
125 changes: 125 additions & 0 deletions spec/easee/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,131 @@
expect { client.pair(charger_id: "UNKNOWN", pin_code: "1234") }
.to raise_error(Easee::Errors::ChargerNotFound)
end

it "raises InvalidPinCode on a PairingError with title IncorrectPIN" do
token_cache = ActiveSupport::Cache::MemoryStore.new
token_cache.write(
Easee::Client::TOKENS_CACHE_KEY,
{ "accessToken" => "T123" }.to_json,
)

stub_request(:post, "https://api.easee.cloud/api/chargers/123ABC/pair?pinCode=WRONG")
.with(headers: { "Authorization" => "Bearer T123" })
.to_return(
status: 400,
body: {
errorCode: 123,
errorCodeName: "PairingError",
title: "IncorrectPIN",
}.to_json,
headers: { "Content-Type": "application/json" },
)

client = Easee::Client.new(user_name: "easee", password: "money", token_cache:)

expect { client.pair(charger_id: "123ABC", pin_code: "WRONG") }
.to raise_error(Easee::Errors::InvalidPinCode)
end

it "raises TooManyAttempts on a PairingError with title TooManyAttempts" do
token_cache = ActiveSupport::Cache::MemoryStore.new
token_cache.write(
Easee::Client::TOKENS_CACHE_KEY,
{ "accessToken" => "T123" }.to_json,
)

stub_request(:post, "https://api.easee.cloud/api/chargers/123ABC/pair?pinCode=1234")
.with(headers: { "Authorization" => "Bearer T123" })
.to_return(
status: 400,
body: {
errorCode: 123,
errorCodeName: "PairingError",
title: "TooManyAttempts",
}.to_json,
headers: { "Content-Type": "application/json" },
)

client = Easee::Client.new(user_name: "easee", password: "money", token_cache:)

expect { client.pair(charger_id: "123ABC", pin_code: "1234") }
.to raise_error(Easee::Errors::TooManyAttempts)
end

it "raises AlreadyPaired on a PairingError with title AlreadyPairedWithPartner" do
token_cache = ActiveSupport::Cache::MemoryStore.new
token_cache.write(
Easee::Client::TOKENS_CACHE_KEY,
{ "accessToken" => "T123" }.to_json,
)

stub_request(:post, "https://api.easee.cloud/api/chargers/123ABC/pair?pinCode=1234")
.with(headers: { "Authorization" => "Bearer T123" })
.to_return(
status: 400,
body: {
errorCode: 123,
errorCodeName: "PairingError",
title: "AlreadyPairedWithPartner",
}.to_json,
headers: { "Content-Type": "application/json" },
)

client = Easee::Client.new(user_name: "easee", password: "money", token_cache:)

expect { client.pair(charger_id: "123ABC", pin_code: "1234") }
.to raise_error(Easee::Errors::AlreadyPaired)
end

it "raises AlreadyPaired on a PairingError with title AlreadyPairedWithUser" do
token_cache = ActiveSupport::Cache::MemoryStore.new
token_cache.write(
Easee::Client::TOKENS_CACHE_KEY,
{ "accessToken" => "T123" }.to_json,
)

stub_request(:post, "https://api.easee.cloud/api/chargers/123ABC/pair?pinCode=1234")
.with(headers: { "Authorization" => "Bearer T123" })
.to_return(
status: 400,
body: {
errorCode: 123,
errorCodeName: "PairingError",
title: "AlreadyPairedWithUser",
}.to_json,
headers: { "Content-Type": "application/json" },
)

client = Easee::Client.new(user_name: "easee", password: "money", token_cache:)

expect { client.pair(charger_id: "123ABC", pin_code: "1234") }
.to raise_error(Easee::Errors::AlreadyPaired)
end

it "raises the generic RequestFailed on a PairingError with an unknown title" do
token_cache = ActiveSupport::Cache::MemoryStore.new
token_cache.write(
Easee::Client::TOKENS_CACHE_KEY,
{ "accessToken" => "T123" }.to_json,
)

stub_request(:post, "https://api.easee.cloud/api/chargers/123ABC/pair?pinCode=1234")
.with(headers: { "Authorization" => "Bearer T123" })
.to_return(
status: 400,
body: {
errorCode: 123,
errorCodeName: "PairingError",
title: "SomethingElse",
}.to_json,
headers: { "Content-Type": "application/json" },
)

client = Easee::Client.new(user_name: "easee", password: "money", token_cache:)

expect { client.pair(charger_id: "123ABC", pin_code: "1234") }
.to raise_error(Easee::Errors::RequestFailed)
end
end

describe "#unpair" do
Expand Down
Loading