nunes 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.
Files changed (83) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +11 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +150 -0
  5. data/lib/nunes.rb +39 -0
  6. data/lib/nunes/adapter.rb +56 -0
  7. data/lib/nunes/adapters/default.rb +10 -0
  8. data/lib/nunes/adapters/memory.rb +62 -0
  9. data/lib/nunes/adapters/timing_aliased.rb +17 -0
  10. data/lib/nunes/instrumentable.rb +102 -0
  11. data/lib/nunes/subscriber.rb +69 -0
  12. data/lib/nunes/subscribers/action_controller.rb +80 -0
  13. data/lib/nunes/subscribers/action_mailer.rb +33 -0
  14. data/lib/nunes/subscribers/action_view.rb +44 -0
  15. data/lib/nunes/subscribers/active_record.rb +33 -0
  16. data/lib/nunes/subscribers/active_support.rb +58 -0
  17. data/lib/nunes/subscribers/nunes.rb +24 -0
  18. data/lib/nunes/version.rb +3 -0
  19. data/nunes.gemspec +22 -0
  20. data/script/bootstrap +21 -0
  21. data/script/test +25 -0
  22. data/script/watch +30 -0
  23. data/test/adapter_test.rb +40 -0
  24. data/test/adapters/default_test.rb +26 -0
  25. data/test/adapters/timing_aliased_test.rb +26 -0
  26. data/test/cache_instrumentation_test.rb +79 -0
  27. data/test/controller_instrumentation_test.rb +88 -0
  28. data/test/fake_udp_socket_test.rb +26 -0
  29. data/test/helper.rb +25 -0
  30. data/test/instrumentable_test.rb +100 -0
  31. data/test/mailer_instrumentation_test.rb +26 -0
  32. data/test/model_instrumentation_test.rb +55 -0
  33. data/test/nunes_test.rb +20 -0
  34. data/test/rails_app/.gitignore +15 -0
  35. data/test/rails_app/Rakefile +7 -0
  36. data/test/rails_app/app/assets/images/rails.png +0 -0
  37. data/test/rails_app/app/assets/javascripts/application.js +15 -0
  38. data/test/rails_app/app/assets/stylesheets/application.css +13 -0
  39. data/test/rails_app/app/controllers/application_controller.rb +3 -0
  40. data/test/rails_app/app/controllers/posts_controller.rb +28 -0
  41. data/test/rails_app/app/helpers/application_helper.rb +2 -0
  42. data/test/rails_app/app/mailers/.gitkeep +0 -0
  43. data/test/rails_app/app/mailers/post_mailer.rb +11 -0
  44. data/test/rails_app/app/models/.gitkeep +0 -0
  45. data/test/rails_app/app/models/post.rb +2 -0
  46. data/test/rails_app/app/views/layouts/application.html.erb +14 -0
  47. data/test/rails_app/app/views/post_mailer/created.text.erb +1 -0
  48. data/test/rails_app/app/views/posts/_post.html.erb +1 -0
  49. data/test/rails_app/app/views/posts/index.html.erb +5 -0
  50. data/test/rails_app/config.ru +4 -0
  51. data/test/rails_app/config/application.rb +67 -0
  52. data/test/rails_app/config/boot.rb +6 -0
  53. data/test/rails_app/config/database.yml +6 -0
  54. data/test/rails_app/config/environment.rb +5 -0
  55. data/test/rails_app/config/environments/development.rb +31 -0
  56. data/test/rails_app/config/environments/production.rb +64 -0
  57. data/test/rails_app/config/environments/test.rb +35 -0
  58. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  59. data/test/rails_app/config/initializers/force_test_schema_load.rb +3 -0
  60. data/test/rails_app/config/initializers/inflections.rb +15 -0
  61. data/test/rails_app/config/initializers/mime_types.rb +5 -0
  62. data/test/rails_app/config/initializers/secret_token.rb +7 -0
  63. data/test/rails_app/config/initializers/session_store.rb +8 -0
  64. data/test/rails_app/config/initializers/wrap_parameters.rb +10 -0
  65. data/test/rails_app/config/locales/en.yml +5 -0
  66. data/test/rails_app/config/routes.rb +8 -0
  67. data/test/rails_app/db/migrate/20130417154459_create_posts.rb +8 -0
  68. data/test/rails_app/db/schema.rb +22 -0
  69. data/test/rails_app/db/seeds.rb +7 -0
  70. data/test/rails_app/lib/assets/.gitkeep +0 -0
  71. data/test/rails_app/lib/tasks/.gitkeep +0 -0
  72. data/test/rails_app/public/404.html +26 -0
  73. data/test/rails_app/public/422.html +26 -0
  74. data/test/rails_app/public/500.html +25 -0
  75. data/test/rails_app/public/favicon.ico +0 -0
  76. data/test/rails_app/public/index.html +241 -0
  77. data/test/rails_app/public/robots.txt +5 -0
  78. data/test/rails_app/script/rails +6 -0
  79. data/test/subscriber_test.rb +50 -0
  80. data/test/support/adapter_test_helpers.rb +33 -0
  81. data/test/support/fake_udp_socket.rb +50 -0
  82. data/test/view_instrumentation_test.rb +30 -0
  83. metadata +205 -0
@@ -0,0 +1,40 @@
1
+ require "helper"
2
+
3
+ class AdapterTest < ActiveSupport::TestCase
4
+ test "wrap for statsd" do
5
+ client_with_gauge_and_timing = Class.new do
6
+ def increment(*args); end
7
+ def gauge(*args); end
8
+ def timing(*args); end
9
+ end.new
10
+
11
+ adapter = Nunes::Adapter.wrap(client_with_gauge_and_timing)
12
+ assert_instance_of Nunes::Adapters::Default, adapter
13
+ end
14
+
15
+ test "wrap for instrumental" do
16
+ client_with_gauge_but_not_timing = Class.new do
17
+ def increment(*args); end
18
+ def gauge(*args); end
19
+ end.new
20
+
21
+ adapter = Nunes::Adapter.wrap(client_with_gauge_but_not_timing)
22
+ assert_instance_of Nunes::Adapters::TimingAliased, adapter
23
+ end
24
+
25
+ test "wrap for adapter" do
26
+ memory = Nunes::Adapters::Memory.new
27
+ adapter = Nunes::Adapter.wrap(memory)
28
+ assert_equal memory, adapter
29
+ end
30
+
31
+ test "wrap with hash" do
32
+ hash = {}
33
+ adapter = Nunes::Adapter.wrap(hash)
34
+ assert_instance_of Nunes::Adapters::Memory, adapter
35
+ end
36
+
37
+ test "wrap with nil" do
38
+ assert_raises(ArgumentError) { Nunes::Adapter.wrap(nil) }
39
+ end
40
+ end
@@ -0,0 +1,26 @@
1
+ require "helper"
2
+ require "minitest/mock"
3
+
4
+ class DefaultAdapterTest < ActiveSupport::TestCase
5
+ test "passes increment along" do
6
+ mock = MiniTest::Mock.new
7
+ mock.expect :increment, nil, ["single", 1]
8
+ mock.expect :increment, nil, ["double", 2]
9
+
10
+ client = Nunes::Adapters::Default.new(mock)
11
+ client.increment("single")
12
+ client.increment("double", 2)
13
+
14
+ mock.verify
15
+ end
16
+
17
+ test "passes timing along" do
18
+ mock = MiniTest::Mock.new
19
+ mock.expect :timing, nil, ["foo", 23]
20
+
21
+ client = Nunes::Adapters::Default.new(mock)
22
+ client.timing("foo", 23)
23
+
24
+ mock.verify
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require "helper"
2
+ require "minitest/mock"
3
+
4
+ class TimingAliasedAdapterTest < ActiveSupport::TestCase
5
+ test "passes increment along" do
6
+ mock = MiniTest::Mock.new
7
+ mock.expect :increment, nil, ["single", 1]
8
+ mock.expect :increment, nil, ["double", 2]
9
+
10
+ client = Nunes::Adapters::TimingAliased.new(mock)
11
+ client.increment("single")
12
+ client.increment("double", 2)
13
+
14
+ mock.verify
15
+ end
16
+
17
+ test "sends timing to gauge" do
18
+ mock = MiniTest::Mock.new
19
+ mock.expect :gauge, nil, ["foo", 23]
20
+
21
+ client = Nunes::Adapters::TimingAliased.new(mock)
22
+ client.timing("foo", 23)
23
+
24
+ mock.verify
25
+ end
26
+ end
@@ -0,0 +1,79 @@
1
+ require "helper"
2
+
3
+ class CacheInstrumentationTest < ActiveSupport::TestCase
4
+ attr_reader :cache
5
+
6
+ setup :setup_subscriber, :setup_cache
7
+ teardown :teardown_subscriber, :teardown_cache
8
+
9
+ def setup_subscriber
10
+ @subscriber = Nunes::Subscribers::ActiveSupport.subscribe(adapter)
11
+ end
12
+
13
+ def teardown_subscriber
14
+ ActiveSupport::Notifications.unsubscribe @subscriber if @subscriber
15
+ end
16
+
17
+ def setup_cache
18
+ ActiveSupport::Cache::MemoryStore.instrument = true
19
+ @cache = ActiveSupport::Cache::MemoryStore.new
20
+ end
21
+
22
+ def teardown_cache
23
+ ActiveSupport::Cache::MemoryStore.instrument = nil
24
+ @cache = nil
25
+ end
26
+
27
+ test "cache_read miss" do
28
+ cache.read('foo')
29
+
30
+ assert_timer "active_support.cache_read"
31
+ assert_counter "active_support.cache_miss"
32
+ end
33
+
34
+ test "cache_read hit" do
35
+ cache.write('foo', 'bar')
36
+ adapter.clear
37
+ cache.read('foo')
38
+
39
+ assert_timer "active_support.cache_read"
40
+ assert_counter "active_support.cache_hit"
41
+ end
42
+
43
+ test "cache_generate" do
44
+ cache.fetch('foo') { |key| :generate_me_please }
45
+ assert_timer "active_support.cache_generate"
46
+ end
47
+
48
+ test "cache_fetch with hit" do
49
+ cache.write('foo', 'bar')
50
+ adapter.clear
51
+ cache.fetch('foo') { |key| :never_gets_here }
52
+
53
+ assert_timer "active_support.cache_fetch"
54
+ assert_timer "active_support.cache_fetch_hit"
55
+ end
56
+
57
+ test "cache_fetch with miss" do
58
+ cache.fetch('foo') { 'foo value set here' }
59
+
60
+ assert_timer "active_support.cache_fetch"
61
+ assert_timer "active_support.cache_generate"
62
+ assert_timer "active_support.cache_write"
63
+ end
64
+
65
+ test "cache_write" do
66
+ cache.write('foo', 'bar')
67
+ assert_timer "active_support.cache_write"
68
+ end
69
+
70
+ test "cache_delete" do
71
+ cache.delete('foo')
72
+ assert_timer "active_support.cache_delete"
73
+ end
74
+
75
+ test "cache_exist?" do
76
+ cache.exist?('foo')
77
+ assert_timer "active_support.cache_exist"
78
+ end
79
+ end
@@ -0,0 +1,88 @@
1
+ require "helper"
2
+
3
+ class ControllerInstrumentationTest < ActionController::TestCase
4
+ tests PostsController
5
+
6
+ setup :setup_subscriber
7
+ teardown :teardown_subscriber
8
+
9
+ def setup_subscriber
10
+ @subscriber = Nunes::Subscribers::ActionController.subscribe(adapter)
11
+ end
12
+
13
+ def teardown_subscriber
14
+ ActiveSupport::Notifications.unsubscribe @subscriber if @subscriber
15
+ end
16
+
17
+ test "process_action" do
18
+ get :index
19
+
20
+ assert_response :success
21
+
22
+ assert_counter "action_controller.status.200"
23
+ assert_counter "action_controller.format.html"
24
+
25
+ assert_timer "action_controller.runtime"
26
+ assert_timer "action_controller.view_runtime"
27
+
28
+ assert_timer "action_controller.posts.index.runtime"
29
+ assert_timer "action_controller.posts.index.view_runtime"
30
+ end
31
+
32
+ test "send_data" do
33
+ get :some_data
34
+
35
+ assert_response :success
36
+
37
+ assert_counter "action_controller.status.200"
38
+
39
+ assert_timer "action_controller.runtime"
40
+ assert_timer "action_controller.view_runtime"
41
+
42
+ assert_timer "action_controller.posts.some_data.runtime"
43
+ assert_timer "action_controller.posts.some_data.view_runtime"
44
+ end
45
+
46
+ test "send_file" do
47
+ get :some_file
48
+
49
+ assert_response :success
50
+
51
+ assert_counter"action_controller.status.200"
52
+
53
+ assert_timer "action_controller.runtime"
54
+ assert_timer "action_controller.posts.some_file.runtime"
55
+
56
+ assert ! adapter.timer?("action_controller.view_runtime")
57
+ assert ! adapter.timer?("action_controller.posts.some_file.view_runtime")
58
+ end
59
+
60
+ test "redirect_to" do
61
+ get :some_redirect
62
+
63
+ assert_response :redirect
64
+
65
+ assert_counter "action_controller.status.302"
66
+
67
+ assert_timer "action_controller.runtime"
68
+ assert_timer "action_controller.posts.some_redirect.runtime"
69
+
70
+ assert_no_timer "action_controller.view_runtime"
71
+ assert_no_timer "action_controller.posts.some_redirect.view_runtime"
72
+ end
73
+
74
+ test "action with exception" do
75
+ get :some_boom rescue StandardError # catch the boom
76
+
77
+ assert_response :success
78
+
79
+ assert_counter "action_controller.exception.RuntimeError"
80
+ assert_counter "action_controller.format.html"
81
+
82
+ assert_timer "action_controller.runtime"
83
+ assert_timer "action_controller.posts.some_boom.runtime"
84
+
85
+ assert_no_timer "action_controller.view_runtime"
86
+ assert_no_timer "action_controller.posts.some_boom.view_runtime"
87
+ end
88
+ end
@@ -0,0 +1,26 @@
1
+ require "helper"
2
+
3
+ class FakeUdpSocketTest < ActiveSupport::TestCase
4
+ test "timer boolean" do
5
+ socket = FakeUdpSocket.new
6
+ socket.send "action_controller.posts.index.runtime:2|ms"
7
+ assert_equal true, socket.timer?("action_controller.posts.index.runtime")
8
+ assert_equal false, socket.timer?("action_controller.posts.index.faketime")
9
+ end
10
+
11
+ test "counter boolean" do
12
+ socket = FakeUdpSocket.new
13
+ socket.send "action_controller.status.200:1|c"
14
+ assert_equal true, socket.counter?("action_controller.status.200")
15
+ assert_equal false, socket.counter?("action_controller.status.400")
16
+ end
17
+
18
+ test "send, recv and clear" do
19
+ socket = FakeUdpSocket.new
20
+ socket.send "foo"
21
+ socket.send "bar"
22
+ assert_equal "foo", socket.recv
23
+ socket.clear
24
+ assert_nil socket.recv
25
+ end
26
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,25 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+
3
+ require "rails"
4
+ require "rails/test_help"
5
+ require "action_mailer"
6
+
7
+ # require everything in the support directory
8
+ root = Pathname(__FILE__).dirname.join("..").expand_path
9
+ Dir[root.join("test/support/**/*.rb")].each { |f| require f }
10
+
11
+ class ActionController::TestCase
12
+ include AdapterTestHelpers
13
+ end
14
+
15
+ class ActionMailer::TestCase
16
+ include AdapterTestHelpers
17
+ end
18
+
19
+ class ActiveSupport::TestCase
20
+ include AdapterTestHelpers
21
+ end
22
+
23
+ require "rails_app/config/environment"
24
+
25
+ require "nunes"
@@ -0,0 +1,100 @@
1
+ require "helper"
2
+
3
+ class InstrumentationTest < ActiveSupport::TestCase
4
+ attr_reader :thing_class
5
+
6
+ setup :setup_subscriber, :setup_class
7
+ teardown :teardown_subscriber, :teardown_class
8
+
9
+ def setup_subscriber
10
+ @subscriber = Nunes::Subscribers::Nunes.subscribe(adapter)
11
+ end
12
+
13
+ def teardown_subscriber
14
+ ActiveSupport::Notifications.unsubscribe @subscriber if @subscriber
15
+ end
16
+
17
+ def setup_class
18
+ @thing_class = Class.new {
19
+ extend Nunes::Instrumentable
20
+
21
+ def self.name
22
+ 'Thing'
23
+ end
24
+
25
+ def yo(args = {})
26
+ :dude
27
+ end
28
+ }
29
+ end
30
+
31
+ def teardown_class
32
+ @thing_class = nil
33
+ end
34
+
35
+ test "adds methods when extended" do
36
+ assert thing_class.respond_to?(:instrument_method_time)
37
+ end
38
+
39
+ test "attempting to instrument time for method twice" do
40
+ thing_class.instrument_method_time :yo
41
+
42
+ assert_raises(ArgumentError, "already instrumented yo for Thing") do
43
+ thing_class.instrument_method_time :yo
44
+ end
45
+ end
46
+
47
+ test "instrument_method_time" do
48
+ thing_class.instrument_method_time :yo
49
+
50
+ event = slurp_events { thing_class.new.yo(some: 'thing') }.last
51
+
52
+ assert_not_nil event, "No events were found."
53
+ assert_equal "thing.yo", event.payload[:metric]
54
+ assert_equal [{some: "thing"}], event.payload[:arguments]
55
+ assert_equal :dude, event.payload[:result]
56
+ assert_in_delta 0, event.duration, 0.1
57
+
58
+ assert_timer "thing.yo"
59
+ end
60
+
61
+ test "instrument_method_time with custom name in hash" do
62
+ thing_class.instrument_method_time :yo, name: 'Thingy.yohoho'
63
+
64
+ event = slurp_events { thing_class.new.yo(some: 'thing') }.last
65
+
66
+ assert_not_nil event, "No events were found."
67
+ assert_equal "thingy.yohoho", event.payload[:metric]
68
+
69
+ assert_timer "thingy.yohoho"
70
+ end
71
+
72
+ test "instrument_method_time with custom name as string" do
73
+ thing_class.instrument_method_time :yo, 'Thingy.yohoho'
74
+
75
+ event = slurp_events { thing_class.new.yo(some: 'thing') }.last
76
+
77
+ assert_not_nil event, "No events were found."
78
+ assert_equal "thingy.yohoho", event.payload[:metric]
79
+
80
+ assert_timer "thingy.yohoho"
81
+ end
82
+
83
+ test "instrument_method_time with custom payload" do
84
+ thing_class.instrument_method_time :yo, payload: {pay: "loadin"}
85
+
86
+ event = slurp_events { thing_class.new.yo(some: 'thing') }.last
87
+
88
+ assert_not_nil event, "No events were found."
89
+ assert_equal "loadin", event.payload[:pay]
90
+
91
+ assert_timer "thing.yo"
92
+ end
93
+
94
+ def slurp_events(&block)
95
+ events = []
96
+ callback = lambda { |*args| events << ActiveSupport::Notifications::Event.new(*args) }
97
+ ActiveSupport::Notifications.subscribed(callback, Nunes::Instrumentable::MethodTimeEventName, &block)
98
+ events
99
+ end
100
+ end
@@ -0,0 +1,26 @@
1
+ require "helper"
2
+
3
+ class MailerInstrumentationTest < ActionMailer::TestCase
4
+ tests PostMailer
5
+
6
+ setup :setup_subscriber
7
+ teardown :teardown_subscriber
8
+
9
+ def setup_subscriber
10
+ @subscriber = Nunes::Subscribers::ActionMailer.subscribe(adapter)
11
+ end
12
+
13
+ def teardown_subscriber
14
+ ActiveSupport::Notifications.unsubscribe @subscriber if @subscriber
15
+ end
16
+
17
+ test "deliver" do
18
+ PostMailer.created.deliver
19
+ assert_timer "action_mailer.deliver.post_mailer"
20
+ end
21
+
22
+ test "receive" do
23
+ PostMailer.receive PostMailer.created
24
+ assert_timer "action_mailer.receive.post_mailer"
25
+ end
26
+ end