neeto-monitor-ruby 1.0.42
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +288 -0
- data/Rakefile +14 -0
- data/lib/neeto-monitor-ruby.rb +7 -0
- data/lib/neeto_monitor_ruby/configuration.rb +92 -0
- data/lib/neeto_monitor_ruby/heartbeat_runner_job.rb +22 -0
- data/lib/neeto_monitor_ruby/init/common.rb +13 -0
- data/lib/neeto_monitor_ruby/init/rails.rb +27 -0
- data/lib/neeto_monitor_ruby/init/ruby.rb +10 -0
- data/lib/neeto_monitor_ruby/monitor.rb +158 -0
- data/lib/neeto_monitor_ruby/monitor_utils.rb +47 -0
- data/lib/neeto_monitor_ruby/neeto_monitor.rb +28 -0
- data/lib/neeto_monitor_ruby/plugin.rb +86 -0
- data/lib/neeto_monitor_ruby/plugins/sidekiq.rb +90 -0
- data/lib/neeto_monitor_ruby/version.rb +5 -0
- data/test/dummy/failure_worker.rb +14 -0
- data/test/dummy/monitor_disabled_worker.rb +14 -0
- data/test/dummy/success_worker.rb +13 -0
- data/test/neeto_monitor/configuration_test.rb +97 -0
- data/test/neeto_monitor/heartbeat_runner_job_test.rb +36 -0
- data/test/neeto_monitor/monitor_test.rb +164 -0
- data/test/neeto_monitor/neeto_monitor_test.rb +10 -0
- data/test/neeto_monitor/plugin_test.rb +78 -0
- data/test/neeto_monitor/plugins/sidekiq_test.rb +75 -0
- data/test/test_helper.rb +15 -0
- metadata +155 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NeetoMonitorRuby
|
4
|
+
module MonitorUtils
|
5
|
+
MONITOR_TYPES = {
|
6
|
+
check: "check",
|
7
|
+
job: "job",
|
8
|
+
heartbeat: "heartbeat"
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
JOB_STATES = {
|
12
|
+
run: "run",
|
13
|
+
complete: "complete",
|
14
|
+
fail: "fail"
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
def self.included(klass)
|
18
|
+
klass.extend(ClassMethods)
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
def job(monitor_key, &block)
|
23
|
+
monitor = Monitor.new(monitor_key)
|
24
|
+
series = monitor.generate_stamp
|
25
|
+
monitor.job_ping(state: JOB_STATES[:run], series:)
|
26
|
+
|
27
|
+
block.call
|
28
|
+
monitor.job_ping(state: JOB_STATES[:complete], series:)
|
29
|
+
rescue StandardError => exception
|
30
|
+
monitor.job_ping(state: JOB_STATES[:fail], message: exception.message, series:)
|
31
|
+
raise exception
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def generate_stamp
|
36
|
+
Time.now.utc.to_f
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_series
|
40
|
+
"#{generate_stamp}-#{random_string}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def random_string
|
44
|
+
rand(2**256).to_s(36)[0..7]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
require_relative "configuration"
|
5
|
+
require_relative "plugin"
|
6
|
+
|
7
|
+
module NeetoMonitorRuby
|
8
|
+
extend Forwardable
|
9
|
+
extend self
|
10
|
+
|
11
|
+
attr_accessor :config, :logger
|
12
|
+
|
13
|
+
def_delegator "NeetoMonitorRuby::Monitor", :load_monitors!
|
14
|
+
|
15
|
+
def init!(options = {})
|
16
|
+
self.config = Configuration.configure!(options, true)
|
17
|
+
self.logger = self.config.logger
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_plugins!
|
21
|
+
Dir[File.expand_path("../plugins/*.rb", __FILE__)].each do |plugin|
|
22
|
+
require plugin
|
23
|
+
end
|
24
|
+
Plugin.load!(self.config)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
NeetoMonitor = NeetoMonitorRuby
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NeetoMonitorRuby
|
4
|
+
class Plugin
|
5
|
+
class << self
|
6
|
+
@@instances = {}
|
7
|
+
|
8
|
+
def instances
|
9
|
+
@@instances
|
10
|
+
end
|
11
|
+
|
12
|
+
def register(name = nil, &block)
|
13
|
+
raise(ArgumentError, "Plugin name is required, but was nil.") unless name
|
14
|
+
|
15
|
+
key = name.to_sym
|
16
|
+
raise("Already registered: #{name}") if instances[key]
|
17
|
+
|
18
|
+
instances[key] = new(name).tap { |d| d.instance_eval(&block) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def load!(config)
|
22
|
+
instances.each_pair do |name, plugin|
|
23
|
+
if config.public_send("#{name}_enabled")
|
24
|
+
plugin.load!
|
25
|
+
else
|
26
|
+
NeetoMonitorRuby.logger.debug("skipped plugin #{name} load because it's disabled")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :name, :requirements, :executions, :config
|
33
|
+
|
34
|
+
def initialize(name)
|
35
|
+
@name = name
|
36
|
+
@loaded = false
|
37
|
+
@requirements = []
|
38
|
+
@executions = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def requirement(&block)
|
42
|
+
@requirements << block
|
43
|
+
end
|
44
|
+
|
45
|
+
def execution(&block)
|
46
|
+
@executions << block
|
47
|
+
end
|
48
|
+
|
49
|
+
def load!
|
50
|
+
if loaded?
|
51
|
+
NeetoMonitorRuby.logger.debug("skip plugin #{name} as already loaded")
|
52
|
+
return false
|
53
|
+
elsif fulfilled?
|
54
|
+
NeetoMonitorRuby.logger.debug("load plugin #{name}")
|
55
|
+
@executions.each { |block| instance_eval(&block) }
|
56
|
+
@loaded = true
|
57
|
+
else
|
58
|
+
NeetoMonitorRuby.logger.debug("skip plugin load #{name} requirement not fulfilled")
|
59
|
+
end
|
60
|
+
|
61
|
+
@loaded
|
62
|
+
rescue => exception
|
63
|
+
log_plugin_exception(exception)
|
64
|
+
@loaded = true
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
def fulfilled?
|
69
|
+
@requirements.all? { |block| instance_eval(&block) }
|
70
|
+
rescue => exception
|
71
|
+
log_plugin_exception(exception)
|
72
|
+
false
|
73
|
+
end
|
74
|
+
|
75
|
+
def loaded?
|
76
|
+
@loaded
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def log_plugin_exception(exception)
|
82
|
+
NeetoMonitorRuby.logger.error("plugin error name=#{name} class=#{exception.class} #{exception.message}")
|
83
|
+
NeetoMonitorRuby.logger.error e.backtrace
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../monitor_utils"
|
4
|
+
|
5
|
+
module NeetoMonitorRuby
|
6
|
+
module Plugins
|
7
|
+
module Sidekiq
|
8
|
+
class ServerMiddleware
|
9
|
+
SKIPPED_WORKERS = %w(ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper).freeze
|
10
|
+
|
11
|
+
attr_reader :sidekiq_worker
|
12
|
+
|
13
|
+
def call(worker, _message, _queue)
|
14
|
+
@sidekiq_worker = worker
|
15
|
+
|
16
|
+
job_ping(state: MonitorUtils::JOB_STATES[:run])
|
17
|
+
|
18
|
+
worker_result = yield
|
19
|
+
|
20
|
+
job_ping(state: MonitorUtils::JOB_STATES[:complete])
|
21
|
+
|
22
|
+
worker_result
|
23
|
+
rescue => exception
|
24
|
+
job_ping(state: MonitorUtils::JOB_STATES[:fail], message: exception.message)
|
25
|
+
|
26
|
+
raise exception
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def job_ping(state:, message: nil)
|
32
|
+
return unless can_monitor?
|
33
|
+
|
34
|
+
::Sidekiq.logger.debug("neetoMonitor pinging key: #{monitor_key} state: #{state} message: #{message}")
|
35
|
+
|
36
|
+
neeto_monitor.job_ping(state:, message:, series:)
|
37
|
+
|
38
|
+
rescue => exception
|
39
|
+
::Sidekiq.logger.error("Error: neetoMonitor ping #{monitor_key} - #{exception.message}")
|
40
|
+
::Sidekiq.logger.error(exception.backtrace)
|
41
|
+
end
|
42
|
+
|
43
|
+
def series
|
44
|
+
@_series ||= neeto_monitor.generate_series
|
45
|
+
end
|
46
|
+
|
47
|
+
def neeto_monitor
|
48
|
+
@_neeto_monitor ||= NeetoMonitorRuby::Monitor.new(monitor_key)
|
49
|
+
end
|
50
|
+
|
51
|
+
def monitor_key
|
52
|
+
return @_monitor_key if @_monitor_key
|
53
|
+
|
54
|
+
@_monitor_key = fetch_sidekiq_option("neeto_monitor_key", sidekiq_worker.class.name)
|
55
|
+
return @_monitor_key unless NeetoMonitorRuby.config.key_prefix_enabled && NeetoMonitorRuby.config.key_prefix
|
56
|
+
|
57
|
+
@_monitor_key = [NeetoMonitorRuby.config.key_prefix, @_monitor_key].join("::")
|
58
|
+
end
|
59
|
+
|
60
|
+
def neeto_monitor_disabled?
|
61
|
+
fetch_sidekiq_option("neeto_monitor_disabled", false)
|
62
|
+
end
|
63
|
+
|
64
|
+
def fetch_sidekiq_option(key, default = nil)
|
65
|
+
sidekiq_worker.class.sidekiq_options.fetch(key, default)
|
66
|
+
end
|
67
|
+
|
68
|
+
def can_monitor?
|
69
|
+
@_can_monitor ||= !neeto_monitor.api_key.nil? && !neeto_monitor_disabled? && !skip?
|
70
|
+
end
|
71
|
+
|
72
|
+
def skip?
|
73
|
+
SKIPPED_WORKERS.include?(monitor_key) || SKIPPED_WORKERS.include?(monitor_key.split("::", 2).last)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Plugin.register "sidekiq" do
|
78
|
+
requirement { defined?(::Sidekiq) }
|
79
|
+
|
80
|
+
execution do
|
81
|
+
::Sidekiq.configure_server do |sidekiq|
|
82
|
+
sidekiq.server_middleware do |chain|
|
83
|
+
chain.prepend ServerMiddleware
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../test_helper"
|
4
|
+
|
5
|
+
module NeetoMonitor
|
6
|
+
class ConfigurationTest < Minitest::Test
|
7
|
+
attr_reader :yaml_file_path
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@yaml_file_path = "./test/config.yml"
|
11
|
+
NeetoMonitor::Configuration.reset!
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_configure_with_options
|
15
|
+
config = NeetoMonitor::Configuration.configure!({ api_key: "api_key", environment: "test" }, true)
|
16
|
+
|
17
|
+
assert_equal "api_key", config.api_key
|
18
|
+
assert_equal "test", config.environment
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_configure_with_default_values
|
22
|
+
config = NeetoMonitor::Configuration.configure!
|
23
|
+
|
24
|
+
assert_equal NeetoMonitor::Configuration::BASE_URL, config.base_url
|
25
|
+
assert_equal NeetoMonitor::Configuration::DEFAULT_PING_TIMEOUT, config.ping_timeout
|
26
|
+
assert_equal true, config.sidekiq_enabled
|
27
|
+
assert_nil config.config_path
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_load_config_with_valid_file
|
31
|
+
config_file = File.new(yaml_file_path, "w")
|
32
|
+
config_file.write(YAML.dump(api_key: "dgs56sds7d", environment: "test"))
|
33
|
+
config_file.close
|
34
|
+
|
35
|
+
config = NeetoMonitor::Configuration.configure!({ config_path: config_file.path }, true)
|
36
|
+
|
37
|
+
assert_equal "dgs56sds7d", config.api_key
|
38
|
+
assert_equal "test", config.environment
|
39
|
+
assert_equal "https://neetomonitor.com", config.base_url
|
40
|
+
|
41
|
+
File.delete(yaml_file_path)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_load_config_with_invalid_file
|
45
|
+
config_file = File.new(yaml_file_path, "w")
|
46
|
+
config_file.write("api_key kbkj'api_key'\" \n}environment: 'test'")
|
47
|
+
config_file.close
|
48
|
+
|
49
|
+
assert_raises NeetoMonitor::ConfigurationError do
|
50
|
+
NeetoMonitor::Configuration.load_config(config_file.path)
|
51
|
+
end
|
52
|
+
|
53
|
+
File.delete(yaml_file_path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_reset
|
57
|
+
config = NeetoMonitor::Configuration.configure!({ api_key: "api_key", config_path: "no-config.yml" }, true)
|
58
|
+
|
59
|
+
assert_equal "https://neetomonitor.com", config.base_url
|
60
|
+
|
61
|
+
NeetoMonitor::Configuration.reset!
|
62
|
+
|
63
|
+
assert_equal "3d6d07b40ac6", NeetoMonitor::Configuration.config.api_key
|
64
|
+
assert_nil NeetoMonitor::Configuration.config.config_path
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_load_config_with_file_not_found
|
68
|
+
assert_raises NeetoMonitor::ConfigurationError do
|
69
|
+
NeetoMonitor::Configuration.load_config("./test/not_found.yml")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_fetch_or_set_value_with_environment_variable
|
74
|
+
original_value = ENV["NEETO_MONITOR_API_KEY"]
|
75
|
+
ENV["NEETO_MONITOR_API_KEY"] = "env_api_key"
|
76
|
+
|
77
|
+
config = NeetoMonitor::Configuration.new
|
78
|
+
|
79
|
+
assert_equal "env_api_key", config.api_key
|
80
|
+
|
81
|
+
ENV["NEETO_MONITOR_API_KEY"] = original_value
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_fetch_or_set_value_with_options
|
85
|
+
config = NeetoMonitor::Configuration.new(api_key: "options_api_key")
|
86
|
+
|
87
|
+
assert_equal "options_api_key", config.api_key
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_fetch_or_set_value_with_default_value
|
91
|
+
config = NeetoMonitor::Configuration.new
|
92
|
+
|
93
|
+
assert_equal 8, config.ping_timeout
|
94
|
+
assert_equal true, config.sidekiq_enabled
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
class NeetoMonitor::HeartbeatRunnerJobTest < ActiveJob::TestCase
|
6
|
+
def test_job_pings_heartbeat_and_enqueues_another_job
|
7
|
+
heartbeat_name = "neeto-heartbeat"
|
8
|
+
schedule = "* * * * *"
|
9
|
+
stub_ping_request
|
10
|
+
|
11
|
+
NeetoMonitorRuby::HeartbeatRunnerJob.perform_now(heartbeat_name, schedule)
|
12
|
+
|
13
|
+
assert_enqueued_with(
|
14
|
+
job: NeetoMonitorRuby::HeartbeatRunnerJob,
|
15
|
+
args: [heartbeat_name, schedule],
|
16
|
+
at: ->(t) { t > Time.now }
|
17
|
+
) do
|
18
|
+
NeetoMonitorRuby::HeartbeatRunnerJob.perform_now(heartbeat_name, schedule)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def stub_ping_request(monitor_key = "neeto-heartbeat", params = {}, status_code = 200)
|
25
|
+
stub_request(:get, "https://neetomonitor.com/tm/3d6d07b40ac6/#{monitor_key}")
|
26
|
+
.with(
|
27
|
+
query: hash_including({ "env" => "test" }.merge(params)),
|
28
|
+
headers: {
|
29
|
+
"Accept" => "application/json",
|
30
|
+
"Content-Type" => "application/json",
|
31
|
+
"User-Agent" => "neeto-monitor-ruby"
|
32
|
+
}
|
33
|
+
)
|
34
|
+
.to_return(status: status_code, body: "", headers: {})
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../test_helper"
|
4
|
+
|
5
|
+
class NeetoMonitor::MonitorTest < Minitest::Test
|
6
|
+
include ActiveJob::TestHelper
|
7
|
+
|
8
|
+
def test_monitor_sends_telemetry_event
|
9
|
+
stub_ping_request
|
10
|
+
monitor = NeetoMonitor::Monitor.new("website-check")
|
11
|
+
|
12
|
+
assert monitor.ping
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_monitor_sends_telemetry_event_with_params
|
16
|
+
params = { state: "run", series: "job101" }
|
17
|
+
job_monitor_key = "night-job-check"
|
18
|
+
|
19
|
+
stub_ping_request(job_monitor_key, params)
|
20
|
+
monitor = NeetoMonitor::Monitor.new(job_monitor_key)
|
21
|
+
|
22
|
+
assert monitor.ping(params)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_monitor_job_sends_complete_event
|
26
|
+
job_monitor_key = "night-job-check"
|
27
|
+
|
28
|
+
stub_ping_request(job_monitor_key, { state: "run", kind: "job" })
|
29
|
+
stub_ping_request(job_monitor_key, { state: "complete", kind: "job" })
|
30
|
+
|
31
|
+
response = NeetoMonitor::Monitor.job job_monitor_key do
|
32
|
+
perform_addition_work(100, 200)
|
33
|
+
end
|
34
|
+
|
35
|
+
assert response
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_monitor_job_sends_fail_event
|
39
|
+
job_monitor_key = "night-job-check"
|
40
|
+
|
41
|
+
stub_ping_request(job_monitor_key, { state: "run", kind: "job" })
|
42
|
+
stub_ping_request(job_monitor_key, { state: "fail", kind: "job" })
|
43
|
+
|
44
|
+
assert_raises(StandardError) do
|
45
|
+
NeetoMonitor::Monitor.job job_monitor_key { raise StandardError.new }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_load_monitors!
|
50
|
+
yaml_file_path = "./test/config.yml"
|
51
|
+
reset = true
|
52
|
+
stub_bulk_create_request
|
53
|
+
stub_ping_request("neeto-heartbeat")
|
54
|
+
|
55
|
+
assert_no_enqueued_jobs
|
56
|
+
|
57
|
+
NeetoMonitorRuby::HeartbeatRunnerJob.perform_later("neeto-heartbeat", "* * * * *")
|
58
|
+
|
59
|
+
assert_enqueued_jobs 1
|
60
|
+
|
61
|
+
config_file = File.new(yaml_file_path, "w")
|
62
|
+
config_file.write(YAML.dump(config_hash))
|
63
|
+
config_file.close
|
64
|
+
|
65
|
+
NeetoMonitor.init!({ config_path: config_file.path })
|
66
|
+
NeetoMonitor::Monitor.load_monitors!
|
67
|
+
|
68
|
+
assert_enqueued_jobs 1
|
69
|
+
|
70
|
+
NeetoMonitor.init!
|
71
|
+
File.delete(yaml_file_path)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def stub_ping_request(monitor_key = "website-check", params = {}, status_code = 200)
|
77
|
+
stub_request(:get, "https://neetomonitor.com/tm/3d6d07b40ac6/#{monitor_key}")
|
78
|
+
.with(
|
79
|
+
query: hash_including({ "env" => "test" }.merge(params)),
|
80
|
+
headers: {
|
81
|
+
"Accept" => "application/json",
|
82
|
+
"Content-Type" => "application/json",
|
83
|
+
"User-Agent" => "neeto-monitor-ruby"
|
84
|
+
}
|
85
|
+
)
|
86
|
+
.to_return(status: status_code, body: "", headers: {})
|
87
|
+
end
|
88
|
+
|
89
|
+
def perform_addition_work(param1, param2)
|
90
|
+
param1 + param2
|
91
|
+
end
|
92
|
+
|
93
|
+
def stub_bulk_create_request
|
94
|
+
stub_request(:post, "https://neetomonitor.com/api/v1/clients/bulk_checks")
|
95
|
+
.with(
|
96
|
+
body: bulk_create_params.to_json,
|
97
|
+
headers: {
|
98
|
+
"Accept" => "application/json",
|
99
|
+
"Content-Type" => "application/json",
|
100
|
+
"User-Agent" => "neeto-monitor-ruby"
|
101
|
+
}
|
102
|
+
)
|
103
|
+
.to_return(status: 200, body: "", headers: {})
|
104
|
+
end
|
105
|
+
|
106
|
+
def config_hash
|
107
|
+
{
|
108
|
+
api_key: "3d6d07b40ac6",
|
109
|
+
environment: "test",
|
110
|
+
monitors: {
|
111
|
+
jobs: [
|
112
|
+
{
|
113
|
+
name: "neeto-job",
|
114
|
+
schedule: "0 0 * * *"
|
115
|
+
}
|
116
|
+
],
|
117
|
+
checks: [
|
118
|
+
{
|
119
|
+
name: "neeto-monitor",
|
120
|
+
request_attributes: {
|
121
|
+
endpoint: "http://app.neetomonitor.test/health_check/",
|
122
|
+
kind: "http",
|
123
|
+
verb: "get",
|
124
|
+
interval: 10,
|
125
|
+
timeout: 20
|
126
|
+
}
|
127
|
+
}
|
128
|
+
],
|
129
|
+
heartbeats: [
|
130
|
+
{
|
131
|
+
name: "neeto-heartbeat",
|
132
|
+
schedule: "* * * * *"
|
133
|
+
}
|
134
|
+
]
|
135
|
+
}
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
def bulk_create_params
|
140
|
+
{
|
141
|
+
checks: [
|
142
|
+
{
|
143
|
+
name: "neeto-job",
|
144
|
+
schedule: "0 0 * * *",
|
145
|
+
kind: "job",
|
146
|
+
environment: "test"
|
147
|
+
},
|
148
|
+
{
|
149
|
+
name: "neeto-monitor",
|
150
|
+
request_attributes: {
|
151
|
+
endpoint: "http://app.neetomonitor.test/health_check/",
|
152
|
+
kind: "http",
|
153
|
+
verb: "get",
|
154
|
+
interval: 10,
|
155
|
+
timeout: 20
|
156
|
+
},
|
157
|
+
kind: "check",
|
158
|
+
environment: "test"
|
159
|
+
}
|
160
|
+
],
|
161
|
+
api_key: "3d6d07b40ac6"
|
162
|
+
}
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../test_helper"
|
4
|
+
|
5
|
+
module NeetoMonitor
|
6
|
+
class PluginTest < Minitest::Test
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
def setup
|
10
|
+
NeetoMonitor::Plugin.instances.clear
|
11
|
+
@config = Configuration.new({ sidekiq_enabled: true })
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_register
|
15
|
+
NeetoMonitor::Plugin.register("sidekiq", &requirement_block)
|
16
|
+
instances = NeetoMonitor::Plugin.instances
|
17
|
+
|
18
|
+
assert_equal 1, instances.size
|
19
|
+
assert_equal "sidekiq", instances[:sidekiq].name
|
20
|
+
assert_instance_of NeetoMonitor::Plugin, instances[:sidekiq]
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_register_without_name
|
24
|
+
assert_raises(ArgumentError) { NeetoMonitor::Plugin.register }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_register_with_duplicate_name
|
28
|
+
NeetoMonitor::Plugin.register("sidekiq", &requirement_block)
|
29
|
+
|
30
|
+
assert_raises(RuntimeError) { NeetoMonitor::Plugin.register("sidekiq", &requirement_block) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_load_enabled_plugins
|
34
|
+
@@executed = false
|
35
|
+
|
36
|
+
NeetoMonitor::Plugin.register("sidekiq") do
|
37
|
+
requirement { true }
|
38
|
+
execution { @@executed = true }
|
39
|
+
end
|
40
|
+
|
41
|
+
NeetoMonitor::Plugin.load!(config)
|
42
|
+
|
43
|
+
sidekiq_instance = NeetoMonitor::Plugin.instances[:sidekiq]
|
44
|
+
|
45
|
+
assert sidekiq_instance.loaded?
|
46
|
+
assert @@executed
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_skip_disabled_plugins
|
50
|
+
NeetoMonitor::Plugin.register("sidekiq", &requirement_block)
|
51
|
+
|
52
|
+
new_config = Configuration.new({ sidekiq_enabled: false })
|
53
|
+
NeetoMonitor::Plugin.load!(new_config)
|
54
|
+
|
55
|
+
instances = NeetoMonitor::Plugin.instances
|
56
|
+
refute instances[:sidekiq].loaded?
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_skip_plugins_with_unfulfilled_requirements
|
60
|
+
NeetoMonitor::Plugin.register("sidekiq", &requirement_unfulfilled_block)
|
61
|
+
|
62
|
+
NeetoMonitor::Plugin.load!(config)
|
63
|
+
|
64
|
+
instances = NeetoMonitor::Plugin.instances
|
65
|
+
refute instances[:sidekiq].loaded?
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def requirement_block
|
71
|
+
proc { requirement { true } }
|
72
|
+
end
|
73
|
+
|
74
|
+
def requirement_unfulfilled_block
|
75
|
+
proc { requirement { false } }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|