magic-admin 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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