hephaestus 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +63 -21
- data/README.md +169 -6
- data/bin/hephaestus +20 -3
- data/lib/Rakefile +10 -0
- data/lib/hephaestus/engine.rb +72 -0
- data/lib/hephaestus/http.rb +36 -0
- data/lib/hephaestus/middleware/malformed_request.rb +100 -0
- data/lib/hephaestus/middleware/openapi_validation.rb +89 -0
- data/lib/hephaestus/middleware/tracing_attributes.rb +50 -0
- data/lib/hephaestus/middleware.rb +7 -0
- data/lib/hephaestus/support/hephaestus/api.rb +105 -0
- data/lib/hephaestus/support/hephaestus/webmocks/browser_webmock.rb +21 -0
- data/lib/hephaestus/support/hephaestus/webmocks/slack_webmock.rb +21 -0
- data/lib/hephaestus/support/hephaestus/webmocks/yetto_webmock.rb +195 -0
- data/lib/hephaestus/support/rails.rb +35 -0
- data/lib/hephaestus/test_helper.rb +45 -0
- data/lib/hephaestus/version.rb +2 -2
- data/lib/hephaestus.rb +1 -0
- data/lib/tasks/hephaestus_tasks.rake +7 -0
- data/lib/tasks/package.rake +9 -0
- data/lib/tasks/rubocop.rake +6 -0
- data/lib/version.rb +6 -0
- data/templates/app/controllers/app_controller.rb +1 -0
- data/templates/app/controllers/application_controller.rb +2 -101
- data/templates/app/jobs/update_yetto_job.rb +1 -1
- data/templates/app/lib/plug_app/middleware/openapi_validation.rb +3 -3
- data/templates/app/services/yetto_service.rb +2 -2
- data/templates/script/hmac_text +1 -1
- data/templates/test/jobs/update_yetto_job_test.rb +1 -1
- data/templates/test/support/webmocks/yetto_webmock.rb +5 -5
- metadata +330 -12
@@ -0,0 +1,89 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "openapi_first"
|
5
|
+
|
6
|
+
module Hephaestus
|
7
|
+
module Middleware
|
8
|
+
class OpenapiValidation
|
9
|
+
API_PATH_PREFIX = "/api/"
|
10
|
+
API_SPEC_PATH = Rails.root.join("lib/schemas/api/2023-03-06/openapi.json")
|
11
|
+
|
12
|
+
def initialize(app, ignore_path: "/settings", match_path: API_PATH_PREFIX, limit_methods_to: nil, spec: API_SPEC_PATH)
|
13
|
+
@app = app
|
14
|
+
@ignore_path = ignore_path
|
15
|
+
@match_path = match_path
|
16
|
+
@limit_methods_to = limit_methods_to
|
17
|
+
@spec = OpenapiFirst.load(spec)
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
request = Rack::Request.new(env)
|
22
|
+
|
23
|
+
return @app.call(env) if request.path.include?(@ignore_path)
|
24
|
+
return @app.call(env) unless request.path.starts_with?(@match_path)
|
25
|
+
|
26
|
+
return @app.call(env) if @limit_methods_to.present? && @limit_methods_to.exclude?(request.request_method)
|
27
|
+
|
28
|
+
begin
|
29
|
+
# force content-type to JSON
|
30
|
+
env["CONTENT_TYPE"] = "application/json" if env["CONTENT_TYPE"] != "application/json"
|
31
|
+
|
32
|
+
validated_request = @spec.validate_request(request)
|
33
|
+
|
34
|
+
return @app.call(env) if validated_request.valid?
|
35
|
+
|
36
|
+
case validated_request.error
|
37
|
+
when OpenapiFirst::Schema::ValidationError
|
38
|
+
error_arr = format_arr(validated_request.error.errors.map(&:message))
|
39
|
+
Rails.logger.error(error_arr) if print_user_api_errors?
|
40
|
+
[Hephaestus::HTTP::BAD_REQUEST_I, { "Content-Type" => "application/json" }, [error_arr]]
|
41
|
+
else
|
42
|
+
case validated_request.error.type
|
43
|
+
when :not_found
|
44
|
+
[Hephaestus::HTTP::NOT_FOUND_I, { "Content-Type" => "application/json" }, [format_str("Not Found")]]
|
45
|
+
else
|
46
|
+
error_message = if validated_request.error.errors.present?
|
47
|
+
format_arr(validated_request.error.errors.map(&:message))
|
48
|
+
else
|
49
|
+
format_str(validated_request.error.message)
|
50
|
+
end
|
51
|
+
|
52
|
+
Rails.logger.error(error_message) if print_user_api_errors?
|
53
|
+
[Hephaestus::HTTP::BAD_REQUEST_I, { "Content-Type" => "application/json" }, [error_message]]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue StandardError => e
|
57
|
+
raise e unless Rails.env.production?
|
58
|
+
|
59
|
+
Rails.logger.error(
|
60
|
+
"openapi.request_validation.error",
|
61
|
+
path: request.path,
|
62
|
+
method: request.env["REQUEST_METHOD"],
|
63
|
+
error_message: e.message,
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private def format_str(error)
|
69
|
+
{
|
70
|
+
errors: [
|
71
|
+
{
|
72
|
+
message: error,
|
73
|
+
},
|
74
|
+
],
|
75
|
+
}.to_json
|
76
|
+
end
|
77
|
+
|
78
|
+
private def format_arr(errors)
|
79
|
+
{
|
80
|
+
errors: errors.each_with_object([]) do |error, arr|
|
81
|
+
arr << {
|
82
|
+
message: error,
|
83
|
+
}
|
84
|
+
end,
|
85
|
+
}.to_json
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "opentelemetry"
|
5
|
+
require "active_support/parameter_filter"
|
6
|
+
|
7
|
+
module Hephaestus
|
8
|
+
module Middleware
|
9
|
+
class TracingAttributes
|
10
|
+
attr_reader :app
|
11
|
+
|
12
|
+
HTTP_REQUEST_CONTENT_LENGTH = "http.request_content_length"
|
13
|
+
HTTP_REQUEST_BODY = "http.request.body"
|
14
|
+
|
15
|
+
def initialize(app)
|
16
|
+
@app = app
|
17
|
+
@filterer = ActiveSupport::ParameterFilter.new(Rails.application.config.filter_parameters)
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
request = ActionDispatch::Request.new(env.dup)
|
22
|
+
|
23
|
+
OpenTelemetry::Trace.current_span.add_attributes({
|
24
|
+
"version" => Hephaestus::Engine::GIT_SHA,
|
25
|
+
HTTP_REQUEST_CONTENT_LENGTH => env["CONTENT_LENGTH"].to_i,
|
26
|
+
HTTP_REQUEST_BODY => process_tracing_body(request),
|
27
|
+
})
|
28
|
+
|
29
|
+
app.call(env)
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_tracing_body(request)
|
33
|
+
if Rails.configuration.respond_to?(:tracing_body_filters)
|
34
|
+
Rails.configuration.tracing_body_filters.each do |path, filter|
|
35
|
+
next unless request.path.starts_with?(path)
|
36
|
+
|
37
|
+
result = filter.call(request)
|
38
|
+
|
39
|
+
return result if result.is_a?(String)
|
40
|
+
|
41
|
+
return result.to_json
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
params = request.params
|
46
|
+
@filterer.filter(params).to_json
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
module API
|
6
|
+
module TestHelpers
|
7
|
+
include Rack::Test::Methods
|
8
|
+
|
9
|
+
def plug(method, path, headers: {}, version: Rails.configuration.yetto_api_version, body: {}, parse: true)
|
10
|
+
prepended_path = prepend_plug_path(version, path)
|
11
|
+
|
12
|
+
http_call(method, prepended_path, headers: headers, version: version, body: body, parse: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def api(method, path, headers: {}, version: Rails.configuration.yetto_api_version, body: {}, parse: true)
|
16
|
+
prepended_path = prepend_api_path(version, path)
|
17
|
+
|
18
|
+
http_call(method, prepended_path, headers: headers, version: version, body: body, parse: true)
|
19
|
+
end
|
20
|
+
|
21
|
+
def http_call(method, path, headers: {}, version: nil, body: {}, parse: true)
|
22
|
+
# explicitly assert headers cannot be nil
|
23
|
+
if headers.nil?
|
24
|
+
send(method, path, body.to_json)
|
25
|
+
else
|
26
|
+
headers["HTTP_ACCEPT"] ||= headers.fetch("HTTP_ACCEPT", "application/json")
|
27
|
+
headers["CONTENT_TYPE"] ||= headers.fetch("CONTENT_TYPE", "application/json")
|
28
|
+
body = body.to_json if headers["CONTENT_TYPE"] == "application/json"
|
29
|
+
send(method, path, body, headers)
|
30
|
+
end
|
31
|
+
|
32
|
+
JSON.parse(last_response.body) if last_response.body.present? && parse
|
33
|
+
end
|
34
|
+
|
35
|
+
def assert_response(expected_status, expected_body = nil)
|
36
|
+
expected_status = case expected_status
|
37
|
+
when :ok, :okay
|
38
|
+
Hephaestus::HTTP::OK_I
|
39
|
+
when :created
|
40
|
+
Hephaestus::HTTP::CREATED_I
|
41
|
+
when :no_content
|
42
|
+
Hephaestus::HTTP::NO_CONTENT_I
|
43
|
+
when :redirect
|
44
|
+
Hephaestus::HTTP::FOUND_I
|
45
|
+
when :bad_request
|
46
|
+
Hephaestus::HTTP::BAD_REQUEST_I
|
47
|
+
when :unauthorized
|
48
|
+
Hephaestus::HTTP::UNAUTHORIZED_I
|
49
|
+
when :forbidden
|
50
|
+
Hephaestus::HTTP::FORBIDDEN_I
|
51
|
+
when :not_found
|
52
|
+
Hephaestus::HTTP::NOT_FOUND_I
|
53
|
+
when :not_acceptable
|
54
|
+
Hephaestus::HTTP::NOT_ACCEPTABLE_I
|
55
|
+
when :service_unavailable
|
56
|
+
Hephaestus::HTTP::SERVICE_UNAVAILABLE_I
|
57
|
+
else
|
58
|
+
raise ArgumentError, "Unknown status: #{expected_status}"
|
59
|
+
end
|
60
|
+
|
61
|
+
assert_equal(expected_status, last_response.status)
|
62
|
+
end
|
63
|
+
|
64
|
+
def prepend_plug_path(version, path)
|
65
|
+
"/#{plug_shortname}/#{version}#{path}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def prepend_api_path(version, path)
|
69
|
+
"/api/#{version}#{path}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def headers(event, body)
|
73
|
+
case event
|
74
|
+
when :after_create
|
75
|
+
{
|
76
|
+
Hephaestus::Headers::HEADER_EVENT => "after_create",
|
77
|
+
Hephaestus::Headers::HEADER_RECORD_TYPE => "plug_installation",
|
78
|
+
}
|
79
|
+
when :after_update_plug_installation
|
80
|
+
{
|
81
|
+
Hephaestus::Headers::HEADER_EVENT => "after_update",
|
82
|
+
Hephaestus::Headers::HEADER_RECORD_TYPE => "plug_installation",
|
83
|
+
}
|
84
|
+
when :after_update_inbox
|
85
|
+
{
|
86
|
+
Hephaestus::Headers::HEADER_EVENT => "after_update",
|
87
|
+
Hephaestus::Headers::HEADER_RECORD_TYPE => "inbox",
|
88
|
+
}
|
89
|
+
when :after_update_organization
|
90
|
+
{
|
91
|
+
Hephaestus::Headers::HEADER_EVENT => "after_update",
|
92
|
+
Hephaestus::Headers::HEADER_RECORD_TYPE => "organization",
|
93
|
+
}
|
94
|
+
when :after_destroy_plug_installation
|
95
|
+
{
|
96
|
+
Hephaestus::Headers::HEADER_EVENT => "after_destroy",
|
97
|
+
Hephaestus::Headers::HEADER_RECORD_TYPE => "plug_installation",
|
98
|
+
}
|
99
|
+
else
|
100
|
+
{}
|
101
|
+
end.merge(Hephaestus::Headers::HEADER_SIGNATURE => yetto_auth_header(body))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
module Webmocks
|
6
|
+
module BrowserWebmock
|
7
|
+
def browser_mock(status: 200)
|
8
|
+
browser_mock = Object.new
|
9
|
+
Ferrum::Browser.stubs(:new).returns(browser_mock)
|
10
|
+
browser_mock.stubs(:go_to)
|
11
|
+
browser_mock.stubs(:quit)
|
12
|
+
response_mock = Ferrum::Network::Response.new("", "")
|
13
|
+
response_mock.stubs(:wait_for_idle).returns(true)
|
14
|
+
network_response_mock = Object.new
|
15
|
+
browser_mock.stubs(:network).returns(network_response_mock)
|
16
|
+
network_response_mock.stubs(:response).returns(response_mock)
|
17
|
+
response_mock.stubs(:status).returns(status)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
module Webmocks
|
6
|
+
module SlackWebmock
|
7
|
+
def assert_requested_send_to_slack_log
|
8
|
+
assert_requested(:post, "https://slack.com/the_log_room")
|
9
|
+
end
|
10
|
+
|
11
|
+
def stub_send_to_slack_log
|
12
|
+
stub_request(:post, "https://slack.com/the_log_room")
|
13
|
+
.to_return(
|
14
|
+
status: 200,
|
15
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
16
|
+
body: {}.to_json,
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hephaestus
|
5
|
+
module Webmocks
|
6
|
+
module YettoWebmock
|
7
|
+
def yetto_auth_header(payload, signing_secret = SIGNING_SECRET)
|
8
|
+
"sha256=#{OpenSSL::HMAC.hexdigest(Hephaestus::ValidatesFromYetto::SHA256_DIGEST, signing_secret, payload.to_json)}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert_requested_post_access_token(plug_installation_id, times: 1)
|
12
|
+
assert_requested(:post, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/plug/installations/#{plug_installation_id}/access_tokens", times: times)
|
13
|
+
end
|
14
|
+
|
15
|
+
def stub_post_access_token(plug_installation_id)
|
16
|
+
response = {
|
17
|
+
token: Faker::Alphanumeric.alphanumeric(number: 26).upcase,
|
18
|
+
}
|
19
|
+
|
20
|
+
stub_request(:post, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/plug/installations/#{plug_installation_id}/access_tokens")
|
21
|
+
.to_return(
|
22
|
+
body: response.to_json,
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def assert_requested_get_plug_installation(plug_installation_id, times: 1)
|
27
|
+
assert_requested(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}", times:)
|
28
|
+
end
|
29
|
+
|
30
|
+
def stub_get_plug_installation(plug_installation_id, response: {}, status: 200)
|
31
|
+
stub_request(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
|
32
|
+
.to_return(
|
33
|
+
status: status,
|
34
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
35
|
+
body: response.to_json,
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def assert_requested_update_plug_installation(plug_installation_id)
|
40
|
+
assert_requested(:patch, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def assert_not_requested_update_plug_installation(plug_installation_id)
|
44
|
+
assert_requested(:patch, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}", times: 0)
|
45
|
+
end
|
46
|
+
|
47
|
+
def stub_update_plug_installation(plug_installation_id, params, response: {}, status: 200)
|
48
|
+
stub_post_access_token(plug_installation_id)
|
49
|
+
|
50
|
+
response[:plug_installation] = { id: plug_installation_id }
|
51
|
+
|
52
|
+
stub_request(:patch, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/installations/#{plug_installation_id}")
|
53
|
+
.with(
|
54
|
+
body: params,
|
55
|
+
)
|
56
|
+
.to_return(
|
57
|
+
status: status,
|
58
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
59
|
+
body: response.to_json,
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def assert_requested_create_conversation(plug_installation_id, inbox_id)
|
64
|
+
assert_requested(:post, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/conversations")
|
65
|
+
end
|
66
|
+
|
67
|
+
def stub_create_conversation(plug_installation_id, inbox_id, payload, response: {})
|
68
|
+
stub_post_access_token(plug_installation_id)
|
69
|
+
|
70
|
+
response[:plug_installation] = { id: plug_installation_id }
|
71
|
+
|
72
|
+
stub_request(:post, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/conversations")
|
73
|
+
.with(
|
74
|
+
body: payload,
|
75
|
+
)
|
76
|
+
.to_return(
|
77
|
+
status: 200,
|
78
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
79
|
+
body: response.to_json,
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def assert_requested_get_plug_installations(filter: "")
|
84
|
+
assert_requested(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/plug/installations?#{filter}")
|
85
|
+
end
|
86
|
+
|
87
|
+
def stub_get_plug_installations(response, status: 200, filter: "")
|
88
|
+
stub_request(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/plug/installations?#{filter}")
|
89
|
+
.to_return(
|
90
|
+
status: status,
|
91
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
92
|
+
body: response.to_json,
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def assert_requested_get_messages_in_inbox(plug_installation_id, inbox_id, filter: "")
|
97
|
+
assert_requested(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/messages?#{filter}")
|
98
|
+
end
|
99
|
+
|
100
|
+
def stub_get_messages_in_inbox(plug_installation_id, inbox_id, response, filter: "")
|
101
|
+
stub_post_access_token(plug_installation_id)
|
102
|
+
stub_request(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/inboxes/#{inbox_id}/messages?#{filter}")
|
103
|
+
.to_return(
|
104
|
+
status: 200,
|
105
|
+
body: response.to_json,
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
def assert_requested_get_messages_in_conversation(plug_installation_id, conversation_id, filter: "")
|
110
|
+
assert_requested(:get, "#{::Hephaestus::YettoService::YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages?#{filter}")
|
111
|
+
end
|
112
|
+
|
113
|
+
def stub_get_messages_in_conversation(plug_installation_id, conversation_id, response, status: 200, filter: "")
|
114
|
+
stub_post_access_token(plug_installation_id)
|
115
|
+
|
116
|
+
stub_request(:get, "#{::Hephaestus::YettoService::YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages?#{filter}")
|
117
|
+
.to_return(
|
118
|
+
status: status,
|
119
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
120
|
+
body: response.to_json,
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
def stub_add_message_to_conversation(plug_installation_id, conversation_id, payload, response: {}, status: 200)
|
125
|
+
stub_post_access_token(plug_installation_id)
|
126
|
+
|
127
|
+
response[:plug_installation] = { id: plug_installation_id }
|
128
|
+
|
129
|
+
stub_request(:post, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages")
|
130
|
+
.with(
|
131
|
+
body: payload,
|
132
|
+
)
|
133
|
+
.to_return(
|
134
|
+
status: status,
|
135
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
136
|
+
body: response.to_json,
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
def assert_requested_add_message_to_conversation(plug_installation_id, conversation_id)
|
141
|
+
assert_requested(:post, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages")
|
142
|
+
end
|
143
|
+
|
144
|
+
def assert_requested_create_message(plug_installation_id, message_id)
|
145
|
+
assert_requested(:post, "#{::Hephaestus::YettoService::YETTO_API_VERSION_TLD}/messages/#{message_id}/replies")
|
146
|
+
end
|
147
|
+
|
148
|
+
def stub_create_message(plug_installation_id, message_id, payload)
|
149
|
+
stub_post_access_token(plug_installation_id)
|
150
|
+
|
151
|
+
stub_request(:post, "#{::Hephaestus::YettoService::YETTO_API_VERSION_TLD}/messages/#{message_id}/replies")
|
152
|
+
.with(
|
153
|
+
body: payload,
|
154
|
+
)
|
155
|
+
.to_return(
|
156
|
+
status: 200,
|
157
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
158
|
+
body: {}.to_json,
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
def assert_requested_update_message(plug_installation_id, message_id)
|
163
|
+
assert_requested(:patch, "#{::Hephaestus::YettoService::YETTO_API_VERSION_TLD}/messages/#{message_id}")
|
164
|
+
end
|
165
|
+
|
166
|
+
def stub_update_message(plug_installation_id, message_id, payload)
|
167
|
+
stub_post_access_token(plug_installation_id)
|
168
|
+
stub_request(:patch, "#{::Hephaestus::YettoService::YETTO_API_VERSION_TLD}/messages/#{message_id}")
|
169
|
+
.with(
|
170
|
+
body: payload,
|
171
|
+
)
|
172
|
+
.to_return(
|
173
|
+
status: 200,
|
174
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
175
|
+
body: {}.to_json,
|
176
|
+
)
|
177
|
+
end
|
178
|
+
|
179
|
+
def assert_requested_find_message_in_conversation_by_metadata(plug_installation_id, conversation_id)
|
180
|
+
assert_requested(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages?#{filter}")
|
181
|
+
end
|
182
|
+
|
183
|
+
def stub_find_message_in_conversation(plug_installation_id, conversation_id, response, status: 200, filter: "")
|
184
|
+
stub_post_access_token(plug_installation_id)
|
185
|
+
|
186
|
+
stub_request(:get, "#{Hephaestus::YettoService::YETTO_API_VERSION_TLD}/conversations/#{conversation_id}/messages?#{filter}")
|
187
|
+
.to_return(
|
188
|
+
status: status,
|
189
|
+
headers: { content_type: "application/json; charset=utf-8" },
|
190
|
+
body: response.to_json,
|
191
|
+
)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module ActiveSupport
|
5
|
+
class TestCase
|
6
|
+
# Run tests in parallel with specified workers
|
7
|
+
parallelize(workers: :number_of_processors)
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@organization_id ||= "org_#{Faker::Alphanumeric.alphanumeric(number: 26).upcase}"
|
11
|
+
@plug_installation_id ||= "pli_#{Faker::Alphanumeric.alphanumeric(number: 26).upcase}"
|
12
|
+
@inbox_id ||= "ibx_#{Faker::Alphanumeric.alphanumeric(number: 26).upcase}"
|
13
|
+
@plug_id ||= "plg_#{Faker::Alphanumeric.alphanumeric(number: 26).upcase}"
|
14
|
+
@message_id ||= "msg_#{Faker::Alphanumeric.alphanumeric(number: 26).upcase}"
|
15
|
+
@conversation_id ||= "cnv_#{Faker::Alphanumeric.alphanumeric(number: 26).upcase}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def file_fixture_path(dir, name)
|
19
|
+
Rails.root.join("test", "fixtures", "files", dir, name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_expected_args(expected_args)
|
23
|
+
lambda do |job_args_arr|
|
24
|
+
job_args_arr.first.each do |actual_args|
|
25
|
+
actual_key = actual_args.first
|
26
|
+
actual_value = actual_args.second
|
27
|
+
|
28
|
+
expected_value = expected_args[actual_key]
|
29
|
+
|
30
|
+
assert_equal(expected_value, actual_value, "Expected `#{actual_key}` to be `#{expected_value.nil? ? "nil" : expected_value}`, but was `#{actual_value.nil? ? "nil" : actual_value}`")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
ENV["RAILS_ENV"] ||= "test"
|
5
|
+
|
6
|
+
require_relative File.join($LOAD_PATH.last, "..", "config", "environment.rb")
|
7
|
+
|
8
|
+
module Hephaestus
|
9
|
+
module TestHelper
|
10
|
+
require "minitest/autorun"
|
11
|
+
require "minitest/pride"
|
12
|
+
|
13
|
+
require "debug" if ENV.fetch("DEBUG", false)
|
14
|
+
|
15
|
+
if ENV["COVERAGE"] == "1"
|
16
|
+
require "simplecov"
|
17
|
+
require "simplecov-console"
|
18
|
+
|
19
|
+
SimpleCov.start("rails")
|
20
|
+
|
21
|
+
# do not crash on failure; we want a distinct job to report the coverage error
|
22
|
+
module SimpleCov
|
23
|
+
class << self
|
24
|
+
def result_exit_status(_)
|
25
|
+
SimpleCov::ExitCodes::SUCCESS
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require "webmock"
|
32
|
+
require "httpx/adapters/webmock"
|
33
|
+
require "webmock/minitest"
|
34
|
+
WebMock.enable!
|
35
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
36
|
+
|
37
|
+
require_relative "support/rails"
|
38
|
+
|
39
|
+
# Load everything else from engine's test/support
|
40
|
+
Dir[File.expand_path("support/hephaestus/**/*.rb", __dir__)].each { |rb| require(rb) }
|
41
|
+
|
42
|
+
# https://github.com/freerange/mocha#rails
|
43
|
+
require "mocha/minitest"
|
44
|
+
end
|
45
|
+
end
|
data/lib/hephaestus/version.rb
CHANGED
data/lib/hephaestus.rb
CHANGED
@@ -0,0 +1,9 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "rubygems/package_task"
|
5
|
+
|
6
|
+
GEMSPEC = Bundler.load_gemspec(File.join(__dir__, "..", "..", "hephaestus.gemspec")) unless defined?(GEMSPEC)
|
7
|
+
gem_path = Gem::PackageTask.new(GEMSPEC).define
|
8
|
+
desc "Package the ruby gem"
|
9
|
+
task "package" => [gem_path]
|
data/lib/version.rb
ADDED