magic-admin 0.0.0 → 0.1.0

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.
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicAdmin
4
+
5
+ module Util
6
+
7
+ # Description:
8
+ # Method provides you platform information hash
9
+ #
10
+ # Returns:
11
+ # hash with following keys.
12
+ # platform:
13
+ # language:
14
+ # language_version:
15
+ # user_name:
16
+ def self.platform_info
17
+ {
18
+ platform: Config.platform,
19
+ language: Config.language,
20
+ language_version: Config.language_version,
21
+ user_name: Config.user_name
22
+ }
23
+ end
24
+
25
+ # Description:
26
+ # Method provides you user agent hash
27
+ #
28
+ # Returns:
29
+ # hash with following keys.
30
+ # sdk_version:
31
+ # publisher:
32
+ # platform:
33
+ def self.user_agent
34
+ {
35
+ sdk_version: MagicAdmin::VERSION,
36
+ publisher: Config.publisher,
37
+ platform: platform_info
38
+ }
39
+ end
40
+
41
+ # Description:
42
+ # Method provides you request headers hash
43
+ #
44
+ # Arguments:
45
+ # secret_key: API Secret Key.
46
+ #
47
+ # Returns:
48
+ # hash with following keys.
49
+ # content-type:
50
+ # X-Magic-Secret-Key:
51
+ # User-Agent:
52
+ def self.headers(secret_key)
53
+ {
54
+ "content-type": "application/json",
55
+ "X-Magic-Secret-Key": secret_key,
56
+ "User-Agent": Util.user_agent
57
+ }
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MagicAdmin
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift(::File.join(::File.dirname(__FILE__), "lib"))
4
+
5
+ require "magic-admin/version"
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "magic-admin"
9
+ s.version = MagicAdmin::VERSION
10
+ s.required_ruby_version = ">= 2.5.0"
11
+ s.summary = "Ruby bindings for the Magic Admin API"
12
+
13
+ s.description = "The Magic Admin Ruby provides convenient ways " \
14
+ "for developers to interact with Magic API endpoints" \
15
+ "and an array of utilities to handle DID Token."
16
+ s.author = "Magic Labs Inc."
17
+ s.email = "support@magic.link"
18
+ s.homepage = "https://docs.magic.link/admin-sdk/ruby"
19
+ s.license = "MIT"
20
+
21
+ s.metadata = {
22
+ }
23
+
24
+ s.add_dependency "eth", "~> 0.4"
25
+ s.add_development_dependency "byebug", "~> 11.0"
26
+ s.add_development_dependency "rspec", "~> 3.9"
27
+ s.add_development_dependency "rubocop", "~> 0.80"
28
+ s.add_development_dependency "webmock", "~> 3.8"
29
+ s.add_development_dependency "simplecov", "~> 0.19"
30
+
31
+ s.files = `git ls-files`.split("\n")
32
+ s.test_files = `git ls-files -- test/*`.split("\n")
33
+ s.executables = `git ls-files -- bin/*`.split("\n")
34
+ .map { |f| ::File.basename(f) }
35
+ s.require_paths = ["lib"]
36
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe MagicAdmin::Http::Client do
6
+ let(:api_base) { MagicAdmin::Config.api_base }
7
+ let(:retries) { 3 }
8
+ let(:backoff) { 0.02 }
9
+ let(:timeout) { 5 }
10
+ let(:stub_response_body) do
11
+ { "data" => {}, "error_code" => "", "message" => "", "status" => "ok" }
12
+ end
13
+
14
+ subject { described_class.new(api_base, retries, timeout, backoff) }
15
+
16
+ it "present attr_reader" do
17
+ expect(subject).to respond_to(:retries)
18
+ expect(subject).to respond_to(:backoff)
19
+ expect(subject).to respond_to(:timeout)
20
+ expect(subject).to respond_to(:base_url)
21
+ expect(subject).to respond_to(:http_request)
22
+ expect(subject).to respond_to(:http_response)
23
+ end
24
+
25
+ context "#call" do
26
+ it "calling methods" do
27
+ stub_request(:get, "https://api.magic.link//v1/admin/auth/user/get")
28
+ .to_return(status: 200, body: stub_response_body.to_json, headers: {})
29
+ expect(subject).to receive(:backoff_retries)
30
+ .with(subject.retries, subject.backoff)
31
+ expect(subject.http_response).to receive(:from_net_http)
32
+
33
+ subject.call(:get, "/v1/admin/auth/user/get", {})
34
+ end
35
+ end
36
+
37
+ describe "private methods" do
38
+ context "#backoff_retries" do
39
+ describe "when raise StandardError error" do
40
+ it "retries until attempts >= max_retries" do
41
+ block = proc {}
42
+ max_retries = 3
43
+
44
+ expect(block).to receive(:call)
45
+ .and_raise(StandardError)
46
+ .exactly(max_retries)
47
+ .times
48
+
49
+ expect do
50
+ subject.send(:backoff_retries,
51
+ max_retries,
52
+ backoff,
53
+ &block)
54
+ end .to raise_error(StandardError)
55
+ end
56
+ end
57
+ end
58
+
59
+ context "#use_ssl?" do
60
+ it "return true when url schema is https" do
61
+ url_with_scheme = double("url", scheme: "https")
62
+ expect(subject.send(:use_ssl?, url_with_scheme)).to be_truthy
63
+ end
64
+ end
65
+
66
+ context "#base_client" do
67
+ it "calling http request with arguments" do
68
+ url = double("url", scheme: "https", host: "localhost", port: 3000)
69
+ request = double("request")
70
+ read_timeout = double("read_timeout")
71
+
72
+ expect(Net::HTTP).to receive(:start)
73
+ .with(url.host, url.port, use_ssl: true)
74
+
75
+ subject.send(:base_client, url, request, read_timeout)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe MagicAdmin::Http::Request do
6
+ let(:url) { URI("https://api.magic.link/v1/admin/auth/user/get") }
7
+ let(:options) { {} }
8
+ describe "class methods" do
9
+ context ".request" do
10
+ it "raise error when method is not [GET POST]" do
11
+ expect do
12
+ described_class.request(:put,
13
+ url,
14
+ options)
15
+ end .to raise_error(MagicAdmin::APIError,
16
+ "Request method not supported.")
17
+ end
18
+
19
+ it "when method is GET" do
20
+ expect_any_instance_of(described_class).to receive(:get)
21
+ .with(url, options)
22
+
23
+ described_class.request(:get, url, options)
24
+ end
25
+
26
+ it "when method is POST" do
27
+ expect_any_instance_of(described_class).to receive(:post)
28
+ .with(url, options)
29
+
30
+ described_class.request(:post, url, options)
31
+ end
32
+ end
33
+ end
34
+
35
+ context "#get" do
36
+ it "return response" do
37
+ expect(subject.get(url, options)).to be_instance_of(Net::HTTP::Get)
38
+
39
+ expected = "https://api.magic.link/v1/admin/auth/user/get?"
40
+ expect(subject.get(url, options).uri.to_s).to eq(expected)
41
+ end
42
+ end
43
+
44
+ context "#post" do
45
+ it "return response" do
46
+ expect(subject.post(url, options)).to be_instance_of(Net::HTTP::Post)
47
+
48
+ expected = "https://api.magic.link/v1/admin/auth/user/get"
49
+ expect(subject.post(url, options).uri.to_s).to eq(expected)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe MagicAdmin::Http::Response do
6
+ let(:stub_response_body) do
7
+ { "data" => {}, "error_code" => "", "message" => "", "status" => "ok" }
8
+ end
9
+
10
+ let(:http_resp) do
11
+ double(
12
+ "http_resp",
13
+ body: stub_response_body.to_json,
14
+ code: 200,
15
+ message: "ok"
16
+ )
17
+ end
18
+
19
+ let(:url) { URI("https://api.magic.link//v1/admin/auth/user/get") }
20
+ let(:request) { MagicAdmin::Http::Request.request(:get, url, {}) }
21
+
22
+ subject { described_class.new(http_resp) }
23
+
24
+ it "present attr_reader" do
25
+ expect(subject).to respond_to(:data)
26
+ expect(subject).to respond_to(:content)
27
+ expect(subject).to respond_to(:status_code)
28
+ end
29
+
30
+ context "#error_opt" do
31
+ it "return response" do
32
+ expect(subject.error_opt(request)).to include(
33
+ :http_status,
34
+ :http_code,
35
+ :http_response,
36
+ :http_message,
37
+ :http_error_code,
38
+ :http_request_params,
39
+ :http_method
40
+ )
41
+ end
42
+ end
43
+
44
+ describe "class_methods" do
45
+ context ".from_net_http" do
46
+ it "with valid request" do
47
+ reps = described_class.from_net_http(http_resp, request)
48
+ expect(reps).to be_instance_of(MagicAdmin::Http::Response)
49
+
50
+ expect(reps.status_code).to eq(200)
51
+ end
52
+
53
+ context "with invalid request" do
54
+ it "raise error BadRequestError" do
55
+ error_resp = instance_double(
56
+ Net::HTTPBadRequest,
57
+ body: stub_response_body.to_json,
58
+ code: 400,
59
+ message: "HTTP Bad Request"
60
+ )
61
+
62
+ allow(Net::HTTPBadRequest).to receive(:===)
63
+ .with(error_resp)
64
+ .and_return(true)
65
+
66
+ expect do
67
+ described_class.from_net_http(error_resp, request)
68
+ end .to raise_error(MagicAdmin::BadRequestError)
69
+ end
70
+
71
+ it "raise error HTTPUnauthorized" do
72
+ error_resp = instance_double(
73
+ Net::HTTPUnauthorized,
74
+ body: stub_response_body.to_json,
75
+ code: 401,
76
+ message: "HTTP Unauthorized Request Error"
77
+ )
78
+
79
+ allow(Net::HTTPUnauthorized).to receive(:===)
80
+ .with(error_resp)
81
+ .and_return(true)
82
+
83
+ expect do
84
+ described_class.from_net_http(error_resp, request)
85
+ end .to raise_error(MagicAdmin::AuthenticationError)
86
+ end
87
+
88
+ it "raise error HTTPForbidden" do
89
+ error_resp = instance_double(
90
+ Net::HTTPForbidden,
91
+ body: stub_response_body.to_json,
92
+ code: 403,
93
+ message: "HTTP Forbidden Request Error"
94
+ )
95
+
96
+ allow(Net::HTTPForbidden).to receive(:===)
97
+ .with(error_resp)
98
+ .and_return(true)
99
+
100
+ expect do
101
+ described_class.from_net_http(error_resp, request)
102
+ end .to raise_error(MagicAdmin::ForbiddenError)
103
+ end
104
+
105
+ it "raise error HTTPTooManyRequests" do
106
+ error_resp = instance_double(
107
+ Net::HTTPTooManyRequests,
108
+ body: stub_response_body.to_json,
109
+ code: 429,
110
+ message: "HTTP Many Request Error"
111
+ )
112
+
113
+ allow(Net::HTTPTooManyRequests).to receive(:===)
114
+ .with(error_resp)
115
+ .and_return(true)
116
+
117
+ expect do
118
+ described_class.from_net_http(error_resp, request)
119
+ end .to raise_error(MagicAdmin::RateLimitingError)
120
+ end
121
+
122
+ it "raise error HTTPServerError" do
123
+ error_resp = instance_double(
124
+ Net::HTTPServerError,
125
+ body: stub_response_body.to_json,
126
+ code: 500,
127
+ message: "HTTP Internal Server Error"
128
+ )
129
+
130
+ allow(Net::HTTPServerError).to receive(:===)
131
+ .with(error_resp)
132
+ .and_return(true)
133
+
134
+ expect do
135
+ described_class.from_net_http(error_resp, request)
136
+ end .to raise_error(MagicAdmin::APIError)
137
+ end
138
+
139
+ it "raise error HTTPGatewayTimeout" do
140
+ error_resp = instance_double(
141
+ Net::HTTPGatewayTimeout,
142
+ body: stub_response_body.to_json,
143
+ code: 504,
144
+ message: "HTTP Gateway Timeoutr"
145
+ )
146
+
147
+ allow(Net::HTTPGatewayTimeout).to receive(:===)
148
+ .with(error_resp)
149
+ .and_return(true)
150
+
151
+ expect do
152
+ described_class.from_net_http(error_resp, request)
153
+ end .to raise_error(MagicAdmin::APIError)
154
+ end
155
+
156
+ it "raise error HTTPServiceUnavailable" do
157
+ error_resp = instance_double(
158
+ Net::HTTPServiceUnavailable,
159
+ body: stub_response_body.to_json,
160
+ code: 503,
161
+ message: "HTTP Service Unavailable"
162
+ )
163
+
164
+ allow(Net::HTTPServiceUnavailable).to receive(:===)
165
+ .with(error_resp)
166
+ .and_return(true)
167
+
168
+ expect do
169
+ described_class.from_net_http(error_resp, request)
170
+ end .to raise_error(MagicAdmin::APIError)
171
+ end
172
+
173
+ it "raise error HTTPBadGateway" do
174
+ error_resp = instance_double(
175
+ Net::HTTPBadGateway,
176
+ body: stub_response_body.to_json,
177
+ code: 502,
178
+ message: "HTTP Bad Gateway"
179
+ )
180
+
181
+ allow(Net::HTTPBadGateway).to receive(:===)
182
+ .with(error_resp)
183
+ .and_return(true)
184
+
185
+ expect do
186
+ described_class.from_net_http(error_resp, request)
187
+ end .to raise_error(MagicAdmin::APIError)
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Magic do
6
+ let(:env_secret_key) { "<ENV_MAGIC_API_SECRET_KEY>" }
7
+ let(:agr_secret_key) { "<ARG_MAGIC_API_SECRET_KEY>" }
8
+
9
+ describe "magic object without arguments and environment variables" do
10
+ it "should raise an error" do
11
+ expect { Magic.new }.to raise_exception MagicAdmin::MagicError
12
+ end
13
+ end
14
+
15
+ describe "magic object set secret_key" do
16
+ it "should be set with environment variable" do
17
+ ENV["MAGIC_API_SECRET_KEY"] = env_secret_key
18
+ magic = Magic.new
19
+ expect(magic.secret_key).to eq(env_secret_key)
20
+ end
21
+
22
+ it "should be set with arguments" do
23
+ magic = Magic.new(api_secret_key: agr_secret_key)
24
+ expect(magic.secret_key).to eq(agr_secret_key)
25
+ end
26
+
27
+ it "should be set with arguments ignore environment variable" do
28
+ ENV["MAGIC_API_SECRET_KEY"] = env_secret_key
29
+ magic = Magic.new(api_secret_key: agr_secret_key)
30
+ expect(magic.secret_key).to eq(agr_secret_key)
31
+ expect(magic.secret_key).not_to eq(env_secret_key)
32
+ end
33
+ end
34
+
35
+ describe "magic object network strategy" do
36
+ before(:each) do
37
+ ENV["MAGIC_API_SECRET_KEY"] = spec_api_secret_key
38
+ end
39
+
40
+ describe "set retries" do
41
+ let(:default_retries) { 3 }
42
+ let(:env_retries) { "4" }
43
+ let(:arg_retries) { 5 }
44
+
45
+ it "should be set with default values" do
46
+ http_client = Magic.new.http_client
47
+ expect(http_client.retries).to eq(default_retries)
48
+ end
49
+
50
+ it "should be set with environment variable" do
51
+ ENV["MAGIC_API_RETRIES"] = env_retries
52
+ http_client = Magic.new.http_client
53
+ expect(http_client.retries).to eq(env_retries.to_f)
54
+ end
55
+
56
+ it "should be set with argument" do
57
+ http_client = Magic.new(retries: arg_retries).http_client
58
+ expect(http_client.retries).to eq(arg_retries)
59
+ end
60
+
61
+ it "should be set with argument ignore environment variable" do
62
+ ENV["MAGIC_API_RETRIES"] = env_retries
63
+ http_client = Magic.new(retries: arg_retries).http_client
64
+ expect(http_client.retries).to eq(arg_retries)
65
+ end
66
+ end
67
+
68
+ describe "set timeout" do
69
+ let(:default_timeout) { 5 }
70
+ let(:env_timeout) { "6" }
71
+ let(:arg_timeout) { 7 }
72
+
73
+ it "should be set with default values" do
74
+ http_client = Magic.new.http_client
75
+ expect(http_client.timeout).to eq(default_timeout)
76
+ end
77
+
78
+ it "should be set with environment variable" do
79
+ ENV["MAGIC_API_TIMEOUT"] = env_timeout
80
+ http_client = Magic.new.http_client
81
+ expect(http_client.timeout).to eq(env_timeout.to_f)
82
+ end
83
+
84
+ it "should be set with argument" do
85
+ http_client = Magic.new(timeout: arg_timeout).http_client
86
+ expect(http_client.timeout).to eq(arg_timeout)
87
+ end
88
+
89
+ it "should be set with argument ignore environment variable" do
90
+ ENV["MAGIC_API_TIMEOUT"] = env_timeout
91
+ http_client = Magic.new(timeout: arg_timeout).http_client
92
+ expect(http_client.timeout).to eq(arg_timeout)
93
+ end
94
+ end
95
+
96
+ describe "set backoff" do
97
+ let(:default_backoff) { 0.02 }
98
+ let(:env_backoff) { "0.03" }
99
+ let(:arg_backoff) { 0.04 }
100
+
101
+ it "should be set with default values" do
102
+ http_client = Magic.new.http_client
103
+ expect(http_client.backoff).to eq(default_backoff)
104
+ end
105
+
106
+ it "should be set with environment variable" do
107
+ ENV["MAGIC_API_BACKOFF"] = env_backoff
108
+ http_client = Magic.new.http_client
109
+ expect(http_client.backoff).to eq(env_backoff.to_f)
110
+ end
111
+
112
+ it "should be set with argument" do
113
+ http_client = Magic.new(backoff: arg_backoff).http_client
114
+ expect(http_client.backoff).to eq(arg_backoff)
115
+ end
116
+
117
+ it "should be set with argument ignore environment variable" do
118
+ ENV["MAGIC_API_BACKOFF"] = env_backoff
119
+ http_client = Magic.new(backoff: arg_backoff).http_client
120
+ expect(http_client.backoff).to eq(arg_backoff)
121
+ end
122
+ end
123
+ end
124
+ end