Skip to content

Commit

Permalink
Handle redirects and add bearer token authenticator
Browse files Browse the repository at this point in the history
  • Loading branch information
sferik committed Sep 18, 2023
1 parent 56245db commit 5fe21fe
Show file tree
Hide file tree
Showing 15 changed files with 501 additions and 248 deletions.
96 changes: 62 additions & 34 deletions spec/client_spec.cr
Original file line number Diff line number Diff line change
@@ -1,45 +1,73 @@
require "./spec_helper"

module X
describe Client do
client = Client.new(api_key: "api_key", api_key_secret: "api_key_secret", access_token: "access_token", access_token_secret: "access_token_secret")

describe "#get" do
it "sends a GET request" do
endpoint = "test_endpoint"
stub_request(:get, endpoint, 200)
response = client.get(endpoint)
response.should eq({} of String => String)
end
describe X::Client do
describe "Initialization" do
it "sets up a default client" do
client = client()
client.should_not be_nil
end

describe "#post" do
it "sends a POST request with body" do
endpoint = "test_endpoint"
body = "{\"data\":\"test\"}"
stub_request(:post, endpoint, 200)
response = client.post(endpoint, body)
response.should eq({} of String => String)
end
it "sets up a client with a bearer token" do
client = X::Client.new(bearer_token: "TEST_BEARER_TOKEN")
client.should_not be_nil
end
end

describe "#put" do
it "sends a PUT request with body" do
endpoint = "test_endpoint"
body = "{\"data\":\"test\"}"
stub_request(:put, endpoint, 200)
response = client.put(endpoint, body)
response.should eq({} of String => String)
end
{% for http_method in X::RequestBuilder::HTTP_METHODS %}
it "test_{{http_method.downcase.id}}_oauth_request_success" do
client = client()
WebMock.stub({{http_method.downcase}}, "https://api.twitter.com/2/tweets").
to_return(status: 200, body: "{}", headers: {"Content-Type" => "application/json"})
response = client.{{http_method.downcase.id}}("tweets")
response.should eq({} of String => String)
end

describe "#delete" do
it "sends a DELETE request" do
endpoint = "test_endpoint"
stub_request(:delete, endpoint, 200)
response = client.delete(endpoint)
response.should eq({} of String => String)
end
it "test_{{http_method.downcase.id}}_bearer_token_request_success" do
client = X::Client.new(bearer_token: "TEST_BEARER_TOKEN")
WebMock.stub({{http_method.downcase}}, "https://api.twitter.com/2/tweets").
to_return(status: 200, body: "{}", headers: {"Content-Type" => "application/json"})
response = client.{{http_method.downcase.id}}("tweets")
response.should eq({} of String => String)
end
{% end %}

it "checks default base uri" do
client = client()
client.base_uri.should eq(X::Connection::DEFAULT_BASE_URL)
end

it "allows setting base uri" do
client = client()
client.base_uri = URI.parse("https://example.com")
client.base_uri.to_s.should eq("https://example.com")
end

it "checks default user agent" do
client = client()
client.user_agent.should eq(X::RequestBuilder::DEFAULT_USER_AGENT)
end

it "allows setting user agent" do
client = client()
client.user_agent = "Custom User Agent"
client.user_agent.should eq("Custom User Agent")
end

it "checks default timeouts" do
client = client()
client.connect_timeout.should eq(X::Connection::DEFAULT_CONNECT_TIMEOUT)
client.read_timeout.should eq(X::Connection::DEFAULT_READ_TIMEOUT)
client.write_timeout.should eq(X::Connection::DEFAULT_WRITE_TIMEOUT)
end

it "allows setting timeouts" do
client = client()
client.connect_timeout = 10.seconds
client.read_timeout = 10.seconds
client.write_timeout = 10.seconds

client.connect_timeout.should eq(10.seconds)
client.read_timeout.should eq(10.seconds)
client.write_timeout.should eq(10.seconds)
end
end
41 changes: 41 additions & 0 deletions spec/connection_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require "./spec_helper"

describe X::Connection do
describe "Initialization" do
it "should set up with default values" do
connection = X::Connection.new
connection.base_uri.to_s.should eq "https://api.twitter.com/2/"
connection.connect_timeout.should eq 60.seconds
connection.read_timeout.should eq 60.seconds
connection.write_timeout.should eq 60.seconds
end
end

describe "base_uri changes" do
it "should affect http_client settings" do
connection = X::Connection.new(base_uri: URI.parse("https://api.twitter.com/2/"),
connect_timeout: 10.seconds,
read_timeout: 10.seconds,
write_timeout: 10.seconds)

connection.base_uri = URI.parse("http://api.x.com/2/")

connection.http_client.host.should eq "api.x.com"
connection.http_client.port.should eq 80
connection.http_client.tls?.should be_falsey
end

it "should not change other settings after base_uri change" do
connection = X::Connection.new(base_uri: URI.parse("https://api.twitter.com/2/"),
connect_timeout: 10.seconds,
read_timeout: 10.seconds,
write_timeout: 10.seconds)

connection.base_uri = URI.parse("http://api.x.com/2/")

connection.connect_timeout.should eq 10.seconds
connection.read_timeout.should eq 10.seconds
connection.write_timeout.should eq 10.seconds
end
end
end
122 changes: 60 additions & 62 deletions spec/response_handler_spec.cr
Original file line number Diff line number Diff line change
@@ -1,84 +1,82 @@
require "./spec_helper"

module X
describe ResponseHandler do
it "handles a successful response" do
response = HTTP::Client::Response.new(200, "{\"status\":\"success\"}")
handler = ResponseHandler.new
result = handler.handle(response)
result.should eq({"status" => "success"})
end
describe X::ResponseHandler do
it "handles a successful response" do
response = HTTP::Client::Response.new(200, "{\"status\":\"success\"}", HTTP::Headers{"Content-Type" => "application/json"})
handler = X::ResponseHandler.new
result = handler.handle(response)
result.should eq({"status" => "success"})
end

it "raises a BadRequestError for a 400 response" do
response = HTTP::Client::Response.new(400, "Bad Request")
handler = ResponseHandler.new
expect_raises BadRequestError, "400 Bad Request - Bad Request" do
handler.handle(response)
end
it "raises a BadRequestError for a 400 response" do
response = HTTP::Client::Response.new(400, "Bad Request")
handler = X::ResponseHandler.new
expect_raises X::BadRequestError do
handler.handle(response)
end
end

it "raises a AuthenticationError for a 401 response" do
response = HTTP::Client::Response.new(401, "Unauthorized")
handler = ResponseHandler.new
expect_raises AuthenticationError, "401 Unauthorized - Unauthorized" do
handler.handle(response)
end
it "raises a AuthenticationError for a 401 response" do
response = HTTP::Client::Response.new(401, "Unauthorized")
handler = X::ResponseHandler.new
expect_raises X::AuthenticationError do
handler.handle(response)
end
end

it "raises a ForbiddenError for a 403 response" do
response = HTTP::Client::Response.new(403, "Forbidden")
handler = ResponseHandler.new
expect_raises ForbiddenError, "403 Forbidden - Forbidden" do
handler.handle(response)
end
it "raises a ForbiddenError for a 403 response" do
response = HTTP::Client::Response.new(403, "Forbidden")
handler = X::ResponseHandler.new
expect_raises X::ForbiddenError do
handler.handle(response)
end
end

it "raises a NotFoundError for a 404 response" do
response = HTTP::Client::Response.new(404, "Not Found")
handler = ResponseHandler.new
expect_raises NotFoundError, "404 Not Found - Not Found" do
handler.handle(response)
end
it "raises a NotFoundError for a 404 response" do
response = HTTP::Client::Response.new(404, "Not Found")
handler = X::ResponseHandler.new
expect_raises X::NotFoundError do
handler.handle(response)
end
end

it "raises a TooManyRequestsError for a 429 response" do
response = HTTP::Client::Response.new(429, "Too Many Requests")
handler = ResponseHandler.new
expect_raises TooManyRequestsError, "429 Too Many Requests - Too Many Requests" do
handler.handle(response)
end
it "raises a TooManyRequestsError for a 429 response" do
response = HTTP::Client::Response.new(429, "Too Many Requests")
handler = X::ResponseHandler.new
expect_raises X::TooManyRequestsError do
handler.handle(response)
end
end

it "raises a ClientError for a 499 response" do
response = HTTP::Client::Response.new(499, "Client Error")
handler = ResponseHandler.new
expect_raises ClientError, "499 Client Error - Client Error" do
handler.handle(response)
end
it "raises a ClientError for a 499 response" do
response = HTTP::Client::Response.new(499, "Client Error")
handler = X::ResponseHandler.new
expect_raises X::ClientError do
handler.handle(response)
end
end

it "raises a ServerError for a 500 response" do
response = HTTP::Client::Response.new(500, "Internal Server Error")
handler = ResponseHandler.new
expect_raises ServerError, "500 Server Error - Internal Server Error" do
handler.handle(response)
end
it "raises a ServerError for a 500 response" do
response = HTTP::Client::Response.new(500, "Internal Server Error")
handler = X::ResponseHandler.new
expect_raises X::ServerError do
handler.handle(response)
end
end

it "raises a ServerError for a 503 response" do
response = HTTP::Client::Response.new(503, "Service Unavailable")
handler = ResponseHandler.new
expect_raises ServiceUnavailableError, "503 Service Unavailable - Service Unavailable" do
handler.handle(response)
end
it "raises a ServerError for a 503 response" do
response = HTTP::Client::Response.new(503, "Service Unavailable")
handler = X::ResponseHandler.new
expect_raises X::ServiceUnavailableError do
handler.handle(response)
end
end

it "raises an Error for an unknown response" do
response = HTTP::Client::Response.new(600, "Unknown")
handler = ResponseHandler.new
expect_raises Error, "600 Unknown Response - Unknown" do
handler.handle(response)
end
it "raises an Error for an unknown response" do
response = HTTP::Client::Response.new(600, "Unknown")
handler = X::ResponseHandler.new
expect_raises X::Error do
handler.handle(response)
end
end
end
20 changes: 13 additions & 7 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@ require "../src/x"
require "spec"
require "webmock"

module SpecHelper
def stub_request(http_method : Symbol, endpoint : String, status : Int32, headers : HTTP::Headers? = nil, body : String? = "{}")
full_url = "#{X::ClientDefaults::DEFAULT_BASE_URL}#{endpoint}"
WebMock.stub(http_method, full_url).to_return(status: status, body: body, headers: headers)
end
TEST_BEARER_TOKEN = "TEST_BEARER_TOKEN"
TEST_API_KEY = "TEST_API_KEY"
TEST_API_KEY_SECRET = "TEST_API_KEY_SECRET"
TEST_ACCESS_TOKEN = "TEST_ACCESS_TOKEN"
TEST_ACCESS_TOKEN_SECRET = "TEST_ACCESS_TOKEN_SECRET"

def client
X::Client.new(
api_key: TEST_API_KEY,
api_key_secret: TEST_API_KEY_SECRET,
access_token: TEST_ACCESS_TOKEN,
access_token_secret: TEST_ACCESS_TOKEN_SECRET
)
end

Spec.before_each do
WebMock.reset
end

include SpecHelper
32 changes: 15 additions & 17 deletions spec/version_spec.cr
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
require "./spec_helper"

module X
describe VERSION do
it "has a version" do
X::VERSION.should_not be_nil
end
describe X::VERSION do
it "has a version" do
X::VERSION.should_not be_nil
end

it "has a major version" do
X::VERSION.major.should_not be_nil
end
it "has a major version" do
X::VERSION.major.should_not be_nil
end

it "has a minor version" do
X::VERSION.minor.should_not be_nil
end
it "has a minor version" do
X::VERSION.minor.should_not be_nil
end

it "has a patch version" do
X::VERSION.patch.should_not be_nil
end
it "has a patch version" do
X::VERSION.patch.should_not be_nil
end

it "converts to a string" do
X::VERSION.to_s.should be_a(String)
end
it "converts to a string" do
X::VERSION.to_s.should be_a(String)
end
end
26 changes: 0 additions & 26 deletions src/x/authenticator.cr

This file was deleted.

Loading

0 comments on commit 5fe21fe

Please sign in to comment.