From f9831002a4241886d614d34610bb079bc15d1b31 Mon Sep 17 00:00:00 2001 From: Soulou Date: Tue, 20 Dec 2022 16:22:23 +0100 Subject: [PATCH 01/20] feat(db-api) Start adding boilerplate for database API calls --- lib/scalingo/client.rb | 17 +++++++++++ lib/scalingo/regional_database.rb | 13 +++++++++ lib/scalingo/regional_database/backups.rb | 31 +++++++++++++++++++++ lib/scalingo/regional_database/databases.rb | 18 ++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 lib/scalingo/regional_database.rb create mode 100644 lib/scalingo/regional_database/backups.rb create mode 100644 lib/scalingo/regional_database/databases.rb diff --git a/lib/scalingo/client.rb b/lib/scalingo/client.rb index 6a2ee34..7117fdd 100644 --- a/lib/scalingo/client.rb +++ b/lib/scalingo/client.rb @@ -2,6 +2,7 @@ require "scalingo/auth" require "scalingo/billing" require "scalingo/regional" +require "scalingo/regional_database" module Scalingo class Client < CoreClient @@ -26,6 +27,7 @@ def osc_fr1 scalingo: self, ) end + alias osc_fr1 apps_api_osc_fr1 def osc_secnum_fr1 @osc_secnum_fr1 ||= Regional.new( @@ -33,5 +35,20 @@ def osc_secnum_fr1 scalingo: self, ) end + alias osc_secnum_fr1 apps_api_osc_secnum_fr1 + + def db_api_osc_fr1 + @db_api_osc_fr1 ||= RegionalDatabase.new( + "https://db-api.osc-fr1.scalingo.com", + scalingo: self, + ) + end + + def db_api_osc_secnum_fr1 + @db_api_osc_secnum_fr1 ||= RegionalDatabase.new( + "https://db-api.osc-fr1.scalingo.com", + scalingo: self, + ) + end end end diff --git a/lib/scalingo/regional_database.rb b/lib/scalingo/regional_database.rb new file mode 100644 index 0000000..2e456a1 --- /dev/null +++ b/lib/scalingo/regional_database.rb @@ -0,0 +1,13 @@ +require "scalingo/api/client" + +module Scalingo + class RegionalDatabaseAPI < API::Client + require "scalingo/regional_database/databases" + require "scalingo/regional_database/backups" + + register_handlers!( + databases: Databases, + backups: Backups, + ) + end +end diff --git a/lib/scalingo/regional_database/backups.rb b/lib/scalingo/regional_database/backups.rb new file mode 100644 index 0000000..b1a246a --- /dev/null +++ b/lib/scalingo/regional_database/backups.rb @@ -0,0 +1,31 @@ +require "scalingo/api/endpoint" + +module Scalingo + class RegionalDatabase::Backups < API::Endpoint + def for(addon_id, headers = nil, &block) + data = nil + + response = connection.get( + "databases/#{addonn_id}/backups", + data, + headers, + &block + ) + + unpack(:addons) { response } + end + + def find(addon_id, backup_id, headers = nil, &block) + data = nil + + response = connection.get( + "databases/#{addon_id}/backups/#{backup_id}", + data, + headers, + &block + ) + + unpack(:backup) { response } + end + end +end diff --git a/lib/scalingo/regional_database/databases.rb b/lib/scalingo/regional_database/databases.rb new file mode 100644 index 0000000..6033331 --- /dev/null +++ b/lib/scalingo/regional_database/databases.rb @@ -0,0 +1,18 @@ +require "scalingo/api/endpoint" + +module Scalingo + class RegionalDatabase::Databases < API::Endpoint + def find(id, headers = nil, &block) + data = nil + + response = connection.get( + "databases/#{id}", + data, + headers, + &block + ) + + unpack(:database) { response } + end + end +end From 0245e4fb93dd1d5a76b163045e63a8e4d1e0a0f0 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Tue, 20 Dec 2022 17:33:34 +0100 Subject: [PATCH 02/20] Rename class RegionalDatabaseAPI into RegionalDatabase --- lib/scalingo/regional_database.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scalingo/regional_database.rb b/lib/scalingo/regional_database.rb index 2e456a1..b7887d7 100644 --- a/lib/scalingo/regional_database.rb +++ b/lib/scalingo/regional_database.rb @@ -1,7 +1,7 @@ require "scalingo/api/client" module Scalingo - class RegionalDatabaseAPI < API::Client + class RegionalDatabase < API::Client require "scalingo/regional_database/databases" require "scalingo/regional_database/backups" From d6b93da24d15529824e5d6d994eb3881377fe30b Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Tue, 20 Dec 2022 17:33:51 +0100 Subject: [PATCH 03/20] Fix aliases --- lib/scalingo/client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scalingo/client.rb b/lib/scalingo/client.rb index 7117fdd..edd6c5f 100644 --- a/lib/scalingo/client.rb +++ b/lib/scalingo/client.rb @@ -27,7 +27,7 @@ def osc_fr1 scalingo: self, ) end - alias osc_fr1 apps_api_osc_fr1 + alias apps_api_osc_fr1 osc_fr1 def osc_secnum_fr1 @osc_secnum_fr1 ||= Regional.new( @@ -35,7 +35,7 @@ def osc_secnum_fr1 scalingo: self, ) end - alias osc_secnum_fr1 apps_api_osc_secnum_fr1 + alias apps_api_osc_secnum_fr1 osc_secnum_fr1 def db_api_osc_fr1 @db_api_osc_fr1 ||= RegionalDatabase.new( From bdb8acf934769c00efccfca08004b576d6452ca6 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 12:05:40 +0100 Subject: [PATCH 04/20] Add database tokens to TokenHolder --- lib/scalingo/token_holder.rb | 60 ++++++++++++++----- spec/scalingo/regional_database_spec.rb | 11 ++++ spec/scalingo/token_holder_spec.rb | 78 +++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 spec/scalingo/regional_database_spec.rb create mode 100644 spec/scalingo/token_holder_spec.rb diff --git a/lib/scalingo/token_holder.rb b/lib/scalingo/token_holder.rb index f537273..d9dcdbd 100644 --- a/lib/scalingo/token_holder.rb +++ b/lib/scalingo/token_holder.rb @@ -4,28 +4,60 @@ module Scalingo module TokenHolder def self.included(base) base.attr_reader :token + base.attr_reader :database_tokens end def token=(input) - @token = input.is_a?(BearerToken) ? input : BearerToken.new(input.to_s, raise_on_expired: config.raise_on_expired_token) + @token = bearer_token(input) end - def authenticated? - token.present? && !token.expired? + def add_database_token(database_id, token) + @database_tokens ||= Hash.new + + @database_tokens[database_id] = bearer_token(token) + end + + def authenticated?(database_id: "") + valid?(token) + end + + def authenticated_for_database?(database_id) + return false if database_tokens.nil? + return false unless database_tokens.has_key?(database_id) + + valid?(database_tokens[database_id]) end def authenticate_with_bearer_token(bearer_token, expires_at:, raise_on_expired_token:) - self.token = if expires_at - token = bearer_token.is_a?(BearerToken) ? bearer_token.value : bearer_token.to_s - - BearerToken.new( - token, - expires_at: expires_at, - raise_on_expired: raise_on_expired_token, - ) - else - bearer_token - end + self.token = build_bearer_token(bearer_token, expires_at: expires_at, raise_on_expired_token: raise_on_expired_token) + end + + def authenticate_database_with_bearer_token(database_id, bearer_token, expires_at:, raise_on_expired_token:) + bearer_token = build_bearer_token(bearer_token, expires_at: expires_at, raise_on_expired_token: raise_on_expired_token) + + add_database_token(database_id, bearer_token) + end + + private + + def valid?(token) + token.present? && !token.expired? + end + + def bearer_token(token) + token.is_a?(BearerToken) ? token : BearerToken.new(token.to_s, raise_on_expired: config.raise_on_expired_token) + end + + def build_bearer_token(bearer_token, expires_at:, raise_on_expired_token:) + return bearer_token unless expires_at + + token = bearer_token.is_a?(BearerToken) ? bearer_token.value : bearer_token.to_s + + BearerToken.new( + token, + expires_at: expires_at, + raise_on_expired: raise_on_expired_token, + ) end end end diff --git a/spec/scalingo/regional_database_spec.rb b/spec/scalingo/regional_database_spec.rb new file mode 100644 index 0000000..2528f8d --- /dev/null +++ b/spec/scalingo/regional_database_spec.rb @@ -0,0 +1,11 @@ +require "spec_helper" + +RSpec.describe Scalingo::RegionalDatabase do + subject { described_class.new("url") } + + %w[databases backups].each do |section| + it "handles requests for #{section}" do + expect(subject.respond_to?(section)).to be true + end + end +end diff --git a/spec/scalingo/token_holder_spec.rb b/spec/scalingo/token_holder_spec.rb new file mode 100644 index 0000000..a938c00 --- /dev/null +++ b/spec/scalingo/token_holder_spec.rb @@ -0,0 +1,78 @@ +require "spec_helper" + +RSpec.describe Scalingo::TokenHolder do + subject(:token_holder_dummy_class) do + Class.new { include(Scalingo::TokenHolder); attr_accessor :config } + end + + describe "authenticate_with_bearer_token" do + subject { token_holder.authenticate_with_bearer_token(token, expires_at: expires_at, raise_on_expired_token: false) } + + let(:token_holder) do + holder = token_holder_dummy_class.new + holder.config = Scalingo::Configuration.new + + holder + end + + context "without expiration date" do + let(:token) { "1234" } + let(:expires_at) { nil } + + it "set the auth token" do + expect(token_holder.authenticated?).to be false + subject() + expect(token_holder.authenticated?).to be true + end + end + + context "with an expiration date" do + let(:token) { "1234" } + let(:expires_at) { Time.now + 1.hour } + + it "refresh the auth token" do + token_holder.authenticate_with_bearer_token(token, expires_at: 1.hour.ago, raise_on_expired_token: false) + expect(token_holder.authenticated?).to be false + + subject() + expect(token_holder.authenticated?).to be true + end + end + end + + describe "authenticate_database_with_bearer_token" do + subject { token_holder.authenticate_database_with_bearer_token(database_id, token, expires_at: expires_at, raise_on_expired_token: false) } + + let(:token_holder) do + holder = token_holder_dummy_class.new + holder.config = Scalingo::Configuration.new + + holder + end + + let(:database_id) { "db-id-1234" } + + context "without expiration date" do + let(:token) { "1234" } + let(:expires_at) { nil } + + it "set the database auth token" do + expect(token_holder.authenticated_for_database?(database_id)).to be false + subject() + expect(token_holder.authenticated_for_database?(database_id)).to be true + end + end + + context "with an expiration date" do + let(:token) { "1234" } + let(:expires_at) { Time.now + 1.hour } + + it "refresh the database token" do + token_holder.authenticate_database_with_bearer_token(database_id, token, expires_at: 1.hour.ago, raise_on_expired_token: false) + expect(token_holder.authenticated_for_database?(database_id)).to be false + subject() + expect(token_holder.authenticated_for_database?(database_id)).to be true + end + end + end +end From 399da65445cf5cde0e8d7d30b80bc54185924113 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 15:08:55 +0100 Subject: [PATCH 05/20] Add #authenticate to addons --- lib/scalingo/regional/addons.rb | 15 +++++++++++++++ lib/scalingo/token_holder.rb | 1 - spec/scalingo/regional/addons_spec.rb | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/scalingo/regional/addons.rb b/lib/scalingo/regional/addons.rb index ee38783..4241c0b 100644 --- a/lib/scalingo/regional/addons.rb +++ b/lib/scalingo/regional/addons.rb @@ -80,6 +80,21 @@ def sso(app_id, addon_id, headers = nil, &block) unpack(:addon) { response } end + def authenticate(app_id, addon_id, headers = nil, &block) + response = token(app_id, addon_id, headers, &block) + return response unless response.status == 200 + + token = response.data[:token] + client.token_holder.authenticate_database_with_bearer_token( + addon_id, + token, + expires_at: Time.now + 1.hour, + raise_on_expired_token: client.config.raise_on_expired_token + ) + + response + end + def token(app_id, addon_id, headers = nil, &block) data = nil diff --git a/lib/scalingo/token_holder.rb b/lib/scalingo/token_holder.rb index d9dcdbd..905d454 100644 --- a/lib/scalingo/token_holder.rb +++ b/lib/scalingo/token_holder.rb @@ -13,7 +13,6 @@ def token=(input) def add_database_token(database_id, token) @database_tokens ||= Hash.new - @database_tokens[database_id] = bearer_token(token) end diff --git a/spec/scalingo/regional/addons_spec.rb b/spec/scalingo/regional/addons_spec.rb index 4318958..0edc997 100644 --- a/spec/scalingo/regional/addons_spec.rb +++ b/spec/scalingo/regional/addons_spec.rb @@ -115,6 +115,26 @@ end end + describe_method "authenticate" do + context "success" do + let(:arguments) { [meta[:app_id], meta[:id]] } + let(:stub_pattern) { "token-200" } + + it_behaves_like "a singular object response" + it "authenticates" do + response + expect(scalingo.authenticated_for_database?(meta[:id])).to be true + end + end + + context "not found" do + let(:arguments) { [meta[:app_id], meta[:not_found_id]] } + let(:stub_pattern) { "token-404" } + + it_behaves_like "a not found response" + end + end + describe_method "update" do context "success" do let(:arguments) { [meta[:app_id], meta[:id], meta[:update][:valid]] } From b31802e8968bc29540220af1999f065bab526414 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 15:25:03 +0100 Subject: [PATCH 06/20] Refactor client#connection to be more ruby-ish alike --- lib/scalingo/api/client.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/scalingo/api/client.rb b/lib/scalingo/api/client.rb index 353af1b..c775c62 100644 --- a/lib/scalingo/api/client.rb +++ b/lib/scalingo/api/client.rb @@ -75,15 +75,11 @@ def connection_options # this method may return the unauthenticated connection # even with `fallback_to_guest: false` def connection(fallback_to_guest: false) - if fallback_to_guest - begin - authenticated_connection - rescue Error::Unauthenticated - unauthenticated_connection - end - else - authenticated_connection - end + authenticated_connection + rescue Error::Unauthenticated + raise unless fallback_to_guest + + unauthenticated_connection end def unauthenticated_connection From 387a4e14e448cb55502f4b1390193ade8a7e0e7f Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 15:50:39 +0100 Subject: [PATCH 07/20] Add API::Client#database_connection --- lib/scalingo/api/client.rb | 18 ++++++++++++++ spec/scalingo/api/client_spec.rb | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/lib/scalingo/api/client.rb b/lib/scalingo/api/client.rb index c775c62..c77b629 100644 --- a/lib/scalingo/api/client.rb +++ b/lib/scalingo/api/client.rb @@ -115,6 +115,24 @@ def authenticated_connection conn.adapter(config.faraday_adapter) if config.faraday_adapter } end + + def database_connection(database_id) + raise Error::Unauthenticated unless token_holder.authenticated_for_database?(database_id) + + @database_connections ||= Hash.new + @database_connections[database_id] ||= Faraday.new(connection_options) { |conn| + conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true} + conn.request :json + + bearer_token = token_holder.database_tokens[database_id]&.value + if bearer_token + auth_header = Faraday::Request::Authorization.header "Bearer", bearer_token + conn.headers[Faraday::Request::Authorization::KEY] = auth_header + end + + conn.adapter(config.faraday_adapter) if config.faraday_adapter + } + end end end end diff --git a/spec/scalingo/api/client_spec.rb b/spec/scalingo/api/client_spec.rb index cbff7f9..6cb69ef 100644 --- a/spec/scalingo/api/client_spec.rb +++ b/spec/scalingo/api/client_spec.rb @@ -170,6 +170,47 @@ end end + describe "database_connection" do + let(:database_id) { "db-id-1234" } + + context "without bearer token" do + let(:scalingo) { scalingo_guest } + + it "raises" do + expect { + subject.database_connection(database_id) + }.to raise_error(Scalingo::Error::Unauthenticated) + end + end + + context "with bearer token" do + it "has an authentication header set with a bearer scheme" do + scalingo.authenticate_database_with_bearer_token( + database_id, + "1234", + expires_at: Time.now + 1.hour, + raise_on_expired_token: false + ) + expect(subject.database_connection(database_id).headers["Authorization"]).to eq "Bearer #{subject.token_holder.database_tokens[database_id].value}" + end + end + + context "with wrong bearer token" do + it "raises" do + database_id_2 = "db-id-5678" + scalingo.authenticate_database_with_bearer_token( + database_id_2, + "1234", + expires_at: Time.now + 1.hour, + raise_on_expired_token: false + ) + expect { + subject.database_connection(database_id) + }.to raise_error(Scalingo::Error::Unauthenticated) + end + end + end + describe "connection" do context "logged" do context "no fallback to guest" do From 494c4bd5acd378f404c79fd7e4386117b89026e7 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 16:12:13 +0100 Subject: [PATCH 08/20] Use new database_connection to connect to database API --- lib/scalingo/api/endpoint.rb | 1 + lib/scalingo/client.rb | 4 ++-- lib/scalingo/regional_database/backups.rb | 14 +++++++------- lib/scalingo/regional_database/databases.rb | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/scalingo/api/endpoint.rb b/lib/scalingo/api/endpoint.rb index a2276ab..7f534e2 100644 --- a/lib/scalingo/api/endpoint.rb +++ b/lib/scalingo/api/endpoint.rb @@ -12,6 +12,7 @@ def initialize(client) end def_delegator :client, :connection + def_delegator :client, :database_connection def inspect str = %(<#{self.class}:0x#{object_id.to_s(16)} base_url:"#{@client.url}" endpoints:) diff --git a/lib/scalingo/client.rb b/lib/scalingo/client.rb index edd6c5f..7aedca8 100644 --- a/lib/scalingo/client.rb +++ b/lib/scalingo/client.rb @@ -39,14 +39,14 @@ def osc_secnum_fr1 def db_api_osc_fr1 @db_api_osc_fr1 ||= RegionalDatabase.new( - "https://db-api.osc-fr1.scalingo.com", + "https://db-api.osc-fr1.scalingo.com/api", scalingo: self, ) end def db_api_osc_secnum_fr1 @db_api_osc_secnum_fr1 ||= RegionalDatabase.new( - "https://db-api.osc-fr1.scalingo.com", + "https://db-api.osc-fr1.scalingo.com/api", scalingo: self, ) end diff --git a/lib/scalingo/regional_database/backups.rb b/lib/scalingo/regional_database/backups.rb index b1a246a..cae9f70 100644 --- a/lib/scalingo/regional_database/backups.rb +++ b/lib/scalingo/regional_database/backups.rb @@ -5,27 +5,27 @@ class RegionalDatabase::Backups < API::Endpoint def for(addon_id, headers = nil, &block) data = nil - response = connection.get( - "databases/#{addonn_id}/backups", + response = database_connection(addon_id).get( + "databases/#{addon_id}/backups", data, headers, &block ) - unpack(:addons) { response } + unpack(:database_backups) { response } end - def find(addon_id, backup_id, headers = nil, &block) + def archive(addon_id, backup_id, headers = nil, &block) data = nil - response = connection.get( - "databases/#{addon_id}/backups/#{backup_id}", + response = database_connection(addon_id).get( + "databases/#{addon_id}/backups/#{backup_id}/archive", data, headers, &block ) - unpack(:backup) { response } + unpack { response } end end end diff --git a/lib/scalingo/regional_database/databases.rb b/lib/scalingo/regional_database/databases.rb index 6033331..5cb87ac 100644 --- a/lib/scalingo/regional_database/databases.rb +++ b/lib/scalingo/regional_database/databases.rb @@ -5,7 +5,7 @@ class RegionalDatabase::Databases < API::Endpoint def find(id, headers = nil, &block) data = nil - response = connection.get( + response = database_connection(id).get( "databases/#{id}", data, headers, From eed5d23f2652b0805d485aa4f7be48e246401868 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 16:46:01 +0100 Subject: [PATCH 09/20] Add documentation regarding db-api in README --- README.md | 33 ++++++++++++++++++++++++++++++++- lib/scalingo/client.rb | 2 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02e643c..9d6e19f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A ruby wrapper for the Scalingo API ### Migration from v2 This gem is changing its name from `scalingo-ruby-api` to `scalingo`, -and the versionning does **not** reset; the first major version of `scalingo` +and the versioning does **not** reset; the first major version of `scalingo` will therefore be `3.x.x`. You can check the version 2 at [the v2 branch of this repository](https://github.com/Scalingo/scalingo-ruby-api/tree/v2) @@ -145,6 +145,37 @@ scalingo.osc_fr1.apps.all # OR scalingo.region(:osc_fr1).apps.all scalingo.apps.create(name: "my-new-app", dry_run: true) ``` +### Interacting with databases + +Requests to the [database API](https://developers.scalingo.com/databases/) requires +extra authentication for each addon you want to interact with. [Addon authentication +tokens are valid for one hour](https://developers.scalingo.com/addons#get-addon-token). + +Supported regions for database API are `db_api_osc_fr1` and `db_api_osc_secnum_fr1`. + +```ruby +require "scalingo" + +scalingo = Scalingo::Client.new +scalingo.authenticate_with(access_token: "my_access_token") + +# First, authenticate using the `addons` API +scalingo.osc_fr1.addons.authenticate(app_id, addon_id) + +# Once authenticated for that specific addon, you can interact with +# database and backup APIs. +# IDs of databases are the IDs of the corresponding addons + +# get all information for a given database +scalingo.db_api_osc_fr1.databases.find(addon_id) + +# get all backups for a given database +scalingo.db_api_osc_fr1.backups.for(addon_id) + +# get URL to download backup archive +scalingo.db_api_osc_fr1.backups.archive(addon_id, backup_id) +``` + ## Development ### Install diff --git a/lib/scalingo/client.rb b/lib/scalingo/client.rb index 7aedca8..fcc04ab 100644 --- a/lib/scalingo/client.rb +++ b/lib/scalingo/client.rb @@ -46,7 +46,7 @@ def db_api_osc_fr1 def db_api_osc_secnum_fr1 @db_api_osc_secnum_fr1 ||= RegionalDatabase.new( - "https://db-api.osc-fr1.scalingo.com/api", + "https://db-api.osc-secnum-fr1.scalingo.com/api", scalingo: self, ) end From b3074983d1d70228159b11383b1874ddf92cba8a Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 16:47:58 +0100 Subject: [PATCH 10/20] Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 003027b..5461402 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## Unreleased * Removal: `Scalingo::Client#agora_fr1` had been removed since the region no longer exists. +* New: Add `addons#authenticate` endpoint +* New API: databases API +* New API: backups API ## 3.1.0 From fb18f2c9dcc781df34dbf2722deded72451ef2d2 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 16:48:53 +0100 Subject: [PATCH 11/20] Fix changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5461402..fb4d53f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ * Removal: `Scalingo::Client#agora_fr1` had been removed since the region no longer exists. * New: Add `addons#authenticate` endpoint -* New API: databases API -* New API: backups API +* New API: database API +* New API: backup API ## 3.1.0 From 1a37f70da47f4b73467eaf8d68fe61060152ebe2 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 16:55:47 +0100 Subject: [PATCH 12/20] Fix rubocop offenses --- lib/scalingo/api/client.rb | 2 +- lib/scalingo/client.rb | 4 ++-- lib/scalingo/regional/addons.rb | 2 +- lib/scalingo/token_holder.rb | 2 +- spec/scalingo/api/client_spec.rb | 4 ++-- spec/scalingo/token_holder_spec.rb | 13 ++++++++----- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/scalingo/api/client.rb b/lib/scalingo/api/client.rb index c77b629..1b406cc 100644 --- a/lib/scalingo/api/client.rb +++ b/lib/scalingo/api/client.rb @@ -119,7 +119,7 @@ def authenticated_connection def database_connection(database_id) raise Error::Unauthenticated unless token_holder.authenticated_for_database?(database_id) - @database_connections ||= Hash.new + @database_connections ||= {} @database_connections[database_id] ||= Faraday.new(connection_options) { |conn| conn.response :json, content_type: /\bjson$/, parser_options: {symbolize_names: true} conn.request :json diff --git a/lib/scalingo/client.rb b/lib/scalingo/client.rb index fcc04ab..4f9b618 100644 --- a/lib/scalingo/client.rb +++ b/lib/scalingo/client.rb @@ -27,7 +27,7 @@ def osc_fr1 scalingo: self, ) end - alias apps_api_osc_fr1 osc_fr1 + alias_method apps_api_osc_fr1 osc_fr1 def osc_secnum_fr1 @osc_secnum_fr1 ||= Regional.new( @@ -35,7 +35,7 @@ def osc_secnum_fr1 scalingo: self, ) end - alias apps_api_osc_secnum_fr1 osc_secnum_fr1 + alias_method apps_api_osc_secnum_fr1 osc_secnum_fr1 def db_api_osc_fr1 @db_api_osc_fr1 ||= RegionalDatabase.new( diff --git a/lib/scalingo/regional/addons.rb b/lib/scalingo/regional/addons.rb index 4241c0b..7475895 100644 --- a/lib/scalingo/regional/addons.rb +++ b/lib/scalingo/regional/addons.rb @@ -89,7 +89,7 @@ def authenticate(app_id, addon_id, headers = nil, &block) addon_id, token, expires_at: Time.now + 1.hour, - raise_on_expired_token: client.config.raise_on_expired_token + raise_on_expired_token: client.config.raise_on_expired_token, ) response diff --git a/lib/scalingo/token_holder.rb b/lib/scalingo/token_holder.rb index 905d454..f00a696 100644 --- a/lib/scalingo/token_holder.rb +++ b/lib/scalingo/token_holder.rb @@ -12,7 +12,7 @@ def token=(input) end def add_database_token(database_id, token) - @database_tokens ||= Hash.new + @database_tokens ||= {} @database_tokens[database_id] = bearer_token(token) end diff --git a/spec/scalingo/api/client_spec.rb b/spec/scalingo/api/client_spec.rb index 6cb69ef..cd2d8c5 100644 --- a/spec/scalingo/api/client_spec.rb +++ b/spec/scalingo/api/client_spec.rb @@ -189,7 +189,7 @@ database_id, "1234", expires_at: Time.now + 1.hour, - raise_on_expired_token: false + raise_on_expired_token: false, ) expect(subject.database_connection(database_id).headers["Authorization"]).to eq "Bearer #{subject.token_holder.database_tokens[database_id].value}" end @@ -202,7 +202,7 @@ database_id_2, "1234", expires_at: Time.now + 1.hour, - raise_on_expired_token: false + raise_on_expired_token: false, ) expect { subject.database_connection(database_id) diff --git a/spec/scalingo/token_holder_spec.rb b/spec/scalingo/token_holder_spec.rb index a938c00..27924d7 100644 --- a/spec/scalingo/token_holder_spec.rb +++ b/spec/scalingo/token_holder_spec.rb @@ -2,7 +2,10 @@ RSpec.describe Scalingo::TokenHolder do subject(:token_holder_dummy_class) do - Class.new { include(Scalingo::TokenHolder); attr_accessor :config } + Class.new { + include(Scalingo::TokenHolder) + attr_accessor :config + } end describe "authenticate_with_bearer_token" do @@ -21,7 +24,7 @@ it "set the auth token" do expect(token_holder.authenticated?).to be false - subject() + subject expect(token_holder.authenticated?).to be true end end @@ -34,7 +37,7 @@ token_holder.authenticate_with_bearer_token(token, expires_at: 1.hour.ago, raise_on_expired_token: false) expect(token_holder.authenticated?).to be false - subject() + subject expect(token_holder.authenticated?).to be true end end @@ -58,7 +61,7 @@ it "set the database auth token" do expect(token_holder.authenticated_for_database?(database_id)).to be false - subject() + subject expect(token_holder.authenticated_for_database?(database_id)).to be true end end @@ -70,7 +73,7 @@ it "refresh the database token" do token_holder.authenticate_database_with_bearer_token(database_id, token, expires_at: 1.hour.ago, raise_on_expired_token: false) expect(token_holder.authenticated_for_database?(database_id)).to be false - subject() + subject expect(token_holder.authenticated_for_database?(database_id)).to be true end end From e44221ee10641c3563186a4f731c8e7417580b30 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Wed, 21 Dec 2022 16:58:43 +0100 Subject: [PATCH 13/20] Fix Scalingo::Client alias_methods --- lib/scalingo/client.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/scalingo/client.rb b/lib/scalingo/client.rb index 4f9b618..0c97402 100644 --- a/lib/scalingo/client.rb +++ b/lib/scalingo/client.rb @@ -27,7 +27,7 @@ def osc_fr1 scalingo: self, ) end - alias_method apps_api_osc_fr1 osc_fr1 + alias_method :apps_api_osc_fr1, :osc_fr1 def osc_secnum_fr1 @osc_secnum_fr1 ||= Regional.new( @@ -35,7 +35,7 @@ def osc_secnum_fr1 scalingo: self, ) end - alias_method apps_api_osc_secnum_fr1 osc_secnum_fr1 + alias_method :apps_api_osc_secnum_fr1, :osc_secnum_fr1 def db_api_osc_fr1 @db_api_osc_fr1 ||= RegionalDatabase.new( From 2ec543c95e0f636aa4d514dd997973cd7763ebb9 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Thu, 22 Dec 2022 11:26:46 +0100 Subject: [PATCH 14/20] Add backups#create endpoint --- lib/scalingo/regional_database/backups.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/scalingo/regional_database/backups.rb b/lib/scalingo/regional_database/backups.rb index cae9f70..1b9c361 100644 --- a/lib/scalingo/regional_database/backups.rb +++ b/lib/scalingo/regional_database/backups.rb @@ -2,6 +2,19 @@ module Scalingo class RegionalDatabase::Backups < API::Endpoint + def create(addon_id, headers = nil, &block) + data = nil + + response = database_connection(addon_id).post( + "databases/#{addon_id}/backups", + data, + headers, + &block + ) + + unpack { response } + end + def for(addon_id, headers = nil, &block) data = nil From 57508ef0b52c3af9a85ddf23b793f88e6b8e90cd Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Thu, 22 Dec 2022 11:27:10 +0100 Subject: [PATCH 15/20] Add spec for backup API --- samples/regional_database/backups/_meta.json | 3 ++ .../regional_database/backups/create-201.json | 30 +++++++++++ .../regional_database/backups/create-400.json | 24 +++++++++ .../regional_database/backups/for-200.json | 52 +++++++++++++++++++ .../regional_database/backups/for-400.json | 24 +++++++++ .../regional_database/backups_spec.rb | 41 +++++++++++++++ spec/support/scalingo.rb | 2 + 7 files changed, 176 insertions(+) create mode 100644 samples/regional_database/backups/_meta.json create mode 100644 samples/regional_database/backups/create-201.json create mode 100644 samples/regional_database/backups/create-400.json create mode 100644 samples/regional_database/backups/for-200.json create mode 100644 samples/regional_database/backups/for-400.json create mode 100644 spec/scalingo/regional_database/backups_spec.rb diff --git a/samples/regional_database/backups/_meta.json b/samples/regional_database/backups/_meta.json new file mode 100644 index 0000000..77f7355 --- /dev/null +++ b/samples/regional_database/backups/_meta.json @@ -0,0 +1,3 @@ +{ + "addon_id": "ad-5ed10967884fef000f5e4fff" +} \ No newline at end of file diff --git a/samples/regional_database/backups/create-201.json b/samples/regional_database/backups/create-201.json new file mode 100644 index 0000000..963a09f --- /dev/null +++ b/samples/regional_database/backups/create-201.json @@ -0,0 +1,30 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff/backups", + "method": "post", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 201, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "id": "5b8b36104ffb090be1ac3ce1", + "created_at": "2019-07-18T03:00:00.178+02:00", + "name": "20180902010000_kibana-3938", + "size": 0, + "status": "pending", + "database_id": "597601234ffb097af4f3099b", + "type": "postgresql" + } + } +} \ No newline at end of file diff --git a/samples/regional_database/backups/create-400.json b/samples/regional_database/backups/create-400.json new file mode 100644 index 0000000..29dd882 --- /dev/null +++ b/samples/regional_database/backups/create-400.json @@ -0,0 +1,24 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff/backups", + "method": "post", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 400, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "error": "unauthorized" + } + } +} \ No newline at end of file diff --git a/samples/regional_database/backups/for-200.json b/samples/regional_database/backups/for-200.json new file mode 100644 index 0000000..0d5eaae --- /dev/null +++ b/samples/regional_database/backups/for-200.json @@ -0,0 +1,52 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff/backups", + "method": "get", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 200, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "database_backups": [ + { + "id": "5bde44904ffb096c714be89c", + "created_at": "2018-11-04T02:00:00.154+01:00", + "name": "20181104010000_kibana-3938", + "size": 0, + "status": "pending", + "database_id": "597601234ffb097af4f3099b", + "type": "postgresql" + }, + { + "id": "5bb95a904ffb096e9a2831b8", + "created_at": "2018-10-07T03:00:00.150+02:00", + "name": "20181007010000_kibana-3938", + "size": 0, + "status": "error", + "database_id": "597601234ffb097af4f3099b", + "type": "postgresql" + }, + { + "id": "5b8b36104ffb090be1ac3ce1", + "created_at": "2018-09-02T03:00:00.178+02:00", + "name": "20180902010000_kibana-3938", + "size": 17484513608, + "status": "done", + "database_id": "597601234ffb097af4f3099b", + "type": "postgresql" + } + ] + } + } +} \ No newline at end of file diff --git a/samples/regional_database/backups/for-400.json b/samples/regional_database/backups/for-400.json new file mode 100644 index 0000000..95f1388 --- /dev/null +++ b/samples/regional_database/backups/for-400.json @@ -0,0 +1,24 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff/backups", + "method": "get", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 400, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "error": "unauthorized" + } + } +} \ No newline at end of file diff --git a/spec/scalingo/regional_database/backups_spec.rb b/spec/scalingo/regional_database/backups_spec.rb new file mode 100644 index 0000000..fe81b03 --- /dev/null +++ b/spec/scalingo/regional_database/backups_spec.rb @@ -0,0 +1,41 @@ +require "spec_helper" + +RSpec.describe Scalingo::RegionalDatabase::Backups do + before do + scalingo.add_database_token(meta[:addon_id], "the-bearer-token") + end + + describe_method "create" do + context "success" do + let(:arguments) { [meta[:addon_id]] } + let(:stub_pattern) { "create-201" } + + it_behaves_like "a singular object response", 201 + end + + context "failure" do + let(:arguments) { [meta[:addon_id]] } + let(:stub_pattern) { "create-400" } + + it_behaves_like "a client error" + end + end + + describe_method "for" do + context "success" do + let(:arguments) { [meta[:addon_id]] } + let(:stub_pattern) { "for-200" } + let(:expected_count) { 3 } + + it_behaves_like "a collection response" + it_behaves_like "a non-paginated collection" + end + + context "failure" do + let(:arguments) { [meta[:addon_id]] } + let(:stub_pattern) { "for-400" } + + it_behaves_like "a client error" + end + end +end diff --git a/spec/support/scalingo.rb b/spec/support/scalingo.rb index 680530d..45ec449 100644 --- a/spec/support/scalingo.rb +++ b/spec/support/scalingo.rb @@ -6,6 +6,7 @@ module Scalingo auth: "https://auth.scalingo.test", billing: "https://billing.scalingo.test", regional: "https://regional.scalingo.test", + regional_database: "https://regional-database.scalingo.test", } class SpecClient < CoreClient @@ -126,6 +127,7 @@ module Common let(:billing_guest) { Scalingo::Billing.new(ENDPOINTS[:billing], scalingo: scalingo_guest) } let(:regional) { Scalingo::Regional.new(ENDPOINTS[:regional], scalingo: scalingo) } let(:regional_guest) { Scalingo::Regional.new(ENDPOINTS[:regional], scalingo: scalingo_guest) } + let(:regionaldatabase) { Scalingo::RegionalDatabase.new(ENDPOINTS[:regional_database], scalingo: scalingo) } let(:meta) { @meta } let(:endpoint) do From 7f28ef59bcc5636f86345517e96fdafe15d5ca77 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Thu, 22 Dec 2022 11:33:03 +0100 Subject: [PATCH 16/20] Remove unused parameter to #authenticated? method --- lib/scalingo/token_holder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scalingo/token_holder.rb b/lib/scalingo/token_holder.rb index f00a696..db60938 100644 --- a/lib/scalingo/token_holder.rb +++ b/lib/scalingo/token_holder.rb @@ -16,7 +16,7 @@ def add_database_token(database_id, token) @database_tokens[database_id] = bearer_token(token) end - def authenticated?(database_id: "") + def authenticated? valid?(token) end From a15aa56318bf7dcfb1a1b56f2994e7d3605f63de Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Thu, 22 Dec 2022 11:35:25 +0100 Subject: [PATCH 17/20] Add missing new-lines at end of files --- samples/regional_database/backups/_meta.json | 2 +- samples/regional_database/backups/create-201.json | 2 +- samples/regional_database/backups/create-400.json | 2 +- samples/regional_database/backups/for-200.json | 2 +- samples/regional_database/backups/for-400.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/regional_database/backups/_meta.json b/samples/regional_database/backups/_meta.json index 77f7355..9c7cd6e 100644 --- a/samples/regional_database/backups/_meta.json +++ b/samples/regional_database/backups/_meta.json @@ -1,3 +1,3 @@ { "addon_id": "ad-5ed10967884fef000f5e4fff" -} \ No newline at end of file +} diff --git a/samples/regional_database/backups/create-201.json b/samples/regional_database/backups/create-201.json index 963a09f..ef43b33 100644 --- a/samples/regional_database/backups/create-201.json +++ b/samples/regional_database/backups/create-201.json @@ -27,4 +27,4 @@ "type": "postgresql" } } -} \ No newline at end of file +} diff --git a/samples/regional_database/backups/create-400.json b/samples/regional_database/backups/create-400.json index 29dd882..31143e2 100644 --- a/samples/regional_database/backups/create-400.json +++ b/samples/regional_database/backups/create-400.json @@ -21,4 +21,4 @@ "error": "unauthorized" } } -} \ No newline at end of file +} diff --git a/samples/regional_database/backups/for-200.json b/samples/regional_database/backups/for-200.json index 0d5eaae..6011c37 100644 --- a/samples/regional_database/backups/for-200.json +++ b/samples/regional_database/backups/for-200.json @@ -49,4 +49,4 @@ ] } } -} \ No newline at end of file +} diff --git a/samples/regional_database/backups/for-400.json b/samples/regional_database/backups/for-400.json index 95f1388..ce7f6a2 100644 --- a/samples/regional_database/backups/for-400.json +++ b/samples/regional_database/backups/for-400.json @@ -21,4 +21,4 @@ "error": "unauthorized" } } -} \ No newline at end of file +} From 2b2cac1507811887fcdaeb17c1657da797aaba2f Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Thu, 22 Dec 2022 14:19:27 +0100 Subject: [PATCH 18/20] Rename addons#authenticate to #authenticate! --- CHANGELOG.md | 2 +- README.md | 2 +- lib/scalingo/regional/addons.rb | 2 +- spec/scalingo/regional/addons_spec.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb4d53f..145f9e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## Unreleased * Removal: `Scalingo::Client#agora_fr1` had been removed since the region no longer exists. -* New: Add `addons#authenticate` endpoint +* New: Add `addons#authenticate!` endpoint * New API: database API * New API: backup API diff --git a/README.md b/README.md index 9d6e19f..327be83 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ scalingo = Scalingo::Client.new scalingo.authenticate_with(access_token: "my_access_token") # First, authenticate using the `addons` API -scalingo.osc_fr1.addons.authenticate(app_id, addon_id) +scalingo.osc_fr1.addons.authenticate!(app_id, addon_id) # Once authenticated for that specific addon, you can interact with # database and backup APIs. diff --git a/lib/scalingo/regional/addons.rb b/lib/scalingo/regional/addons.rb index 7475895..e6a0b52 100644 --- a/lib/scalingo/regional/addons.rb +++ b/lib/scalingo/regional/addons.rb @@ -80,7 +80,7 @@ def sso(app_id, addon_id, headers = nil, &block) unpack(:addon) { response } end - def authenticate(app_id, addon_id, headers = nil, &block) + def authenticate!(app_id, addon_id, headers = nil, &block) response = token(app_id, addon_id, headers, &block) return response unless response.status == 200 diff --git a/spec/scalingo/regional/addons_spec.rb b/spec/scalingo/regional/addons_spec.rb index 0edc997..0491c9c 100644 --- a/spec/scalingo/regional/addons_spec.rb +++ b/spec/scalingo/regional/addons_spec.rb @@ -115,7 +115,7 @@ end end - describe_method "authenticate" do + describe_method "authenticate!" do context "success" do let(:arguments) { [meta[:app_id], meta[:id]] } let(:stub_pattern) { "token-200" } From 8d462e8881dbed41d487fab69769ee00cc4bb122 Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Thu, 22 Dec 2022 14:32:34 +0100 Subject: [PATCH 19/20] Add spec for backups#archive --- samples/regional_database/backups/_meta.json | 3 ++- .../backups/archive-200.json | 24 +++++++++++++++++++ .../backups/archive-400.json | 24 +++++++++++++++++++ .../regional_database/backups_spec.rb | 17 +++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 samples/regional_database/backups/archive-200.json create mode 100644 samples/regional_database/backups/archive-400.json diff --git a/samples/regional_database/backups/_meta.json b/samples/regional_database/backups/_meta.json index 9c7cd6e..9e28296 100644 --- a/samples/regional_database/backups/_meta.json +++ b/samples/regional_database/backups/_meta.json @@ -1,3 +1,4 @@ { - "addon_id": "ad-5ed10967884fef000f5e4fff" + "addon_id": "ad-5ed10967884fef000f5e4fff", + "backup_id": "5bb95a904ffb096e9a2831b8" } diff --git a/samples/regional_database/backups/archive-200.json b/samples/regional_database/backups/archive-200.json new file mode 100644 index 0000000..c41ca39 --- /dev/null +++ b/samples/regional_database/backups/archive-200.json @@ -0,0 +1,24 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff/backups/5bb95a904ffb096e9a2831b8/archive", + "method": "get", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 200, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "download_url": "https://regional-database.scalingo.test/databases/ad-5ed10967884fef000f5e4fff/backups/5bb95a904ffb096e9a2831b8/download?token=token1234" + } + } +} diff --git a/samples/regional_database/backups/archive-400.json b/samples/regional_database/backups/archive-400.json new file mode 100644 index 0000000..23c819d --- /dev/null +++ b/samples/regional_database/backups/archive-400.json @@ -0,0 +1,24 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff/backups/5bb95a904ffb096e9a2831b8/archive", + "method": "get", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 400, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "error": "unauthorized" + } + } +} diff --git a/spec/scalingo/regional_database/backups_spec.rb b/spec/scalingo/regional_database/backups_spec.rb index fe81b03..ab88eab 100644 --- a/spec/scalingo/regional_database/backups_spec.rb +++ b/spec/scalingo/regional_database/backups_spec.rb @@ -38,4 +38,21 @@ it_behaves_like "a client error" end end + + describe_method "archive" do + context "success" do + let(:arguments) { [meta[:addon_id], meta[:backup_id]] } + let(:stub_pattern) { "archive-200" } + let(:expected_keys) { %i[download_url] } + + it_behaves_like "a singular object response" + end + + context "failure" do + let(:arguments) { [meta[:addon_id], meta[:backup_id]] } + let(:stub_pattern) { "archive-400" } + + it_behaves_like "a client error" + end + end end From 191b0bb24bfcccc5f3e39c5aa49d36e982a322ad Mon Sep 17 00:00:00 2001 From: aurelien-reeves-scalingo Date: Thu, 22 Dec 2022 14:46:31 +0100 Subject: [PATCH 20/20] Add spec for databases#find --- .../regional_database/databases/_meta.json | 3 ++ .../regional_database/databases/find-200.json | 45 +++++++++++++++++++ .../regional_database/databases/find-400.json | 24 ++++++++++ .../regional_database/databases_spec.rb | 23 ++++++++++ 4 files changed, 95 insertions(+) create mode 100644 samples/regional_database/databases/_meta.json create mode 100644 samples/regional_database/databases/find-200.json create mode 100644 samples/regional_database/databases/find-400.json create mode 100644 spec/scalingo/regional_database/databases_spec.rb diff --git a/samples/regional_database/databases/_meta.json b/samples/regional_database/databases/_meta.json new file mode 100644 index 0000000..9418729 --- /dev/null +++ b/samples/regional_database/databases/_meta.json @@ -0,0 +1,3 @@ +{ + "id": "ad-5ed10967884fef000f5e4fff" +} diff --git a/samples/regional_database/databases/find-200.json b/samples/regional_database/databases/find-200.json new file mode 100644 index 0000000..1d89912 --- /dev/null +++ b/samples/regional_database/databases/find-200.json @@ -0,0 +1,45 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff", + "method": "get", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 200, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "database": { + "id": "ad-5ed10967884fef000f5e4fff", + "resource_id": "my-db-123", + "app_name": "my-app", + "created_at": "2019-02-05T15:38:14.343+01:00", + "encryption_at_rest": true, + "features": [ + { + "name": "redis-rdb", + "status": "ACTIVATED" + } + ], + "plan": "free", + "status": "running", + "type_id": "5bf30d1104c87f000161285a", + "type_name": "redis", + "version_id": "5bf30d1104c87f000161285b", + "instances": [], + "readable_version": "3.2.9-1", + "periodic_backups_enabled": true, + "periodic_backups_scheduled_at": [0] + } + } + } +} diff --git a/samples/regional_database/databases/find-400.json b/samples/regional_database/databases/find-400.json new file mode 100644 index 0000000..70f1f13 --- /dev/null +++ b/samples/regional_database/databases/find-400.json @@ -0,0 +1,24 @@ +{ + "path": "/databases/ad-5ed10967884fef000f5e4fff", + "method": "get", + "request": { + "headers": { + "Authorization": "Bearer the-bearer-token" + } + }, + "response": { + "status": 400, + "headers": { + "Date": "Fri, 29 May 2020 13:08:59 GMT", + "Etag": "W/\"a9504bb2f6f87c65ff68074ae787831e\"", + "Content-Type": "application/json; charset=utf-8", + "Transfer-Encoding": "chunked", + "Connection": "keep-alive", + "Cache-Control": "max-age=0, private, must-revalidate", + "Referrer-Policy": "strict-origin-when-cross-origin" + }, + "json_body": { + "error": "unauthorized" + } + } +} diff --git a/spec/scalingo/regional_database/databases_spec.rb b/spec/scalingo/regional_database/databases_spec.rb new file mode 100644 index 0000000..2897cdc --- /dev/null +++ b/spec/scalingo/regional_database/databases_spec.rb @@ -0,0 +1,23 @@ +require "spec_helper" + +RSpec.describe Scalingo::RegionalDatabase::Databases do + before do + scalingo.add_database_token(meta[:id], "the-bearer-token") + end + + describe_method "find" do + context "success" do + let(:arguments) { [meta[:id]] } + let(:stub_pattern) { "find-200" } + + it_behaves_like "a singular object response" + end + + context "failure" do + let(:arguments) { [meta[:id]] } + let(:stub_pattern) { "find-400" } + + it_behaves_like "a client error" + end + end +end