coverband 6.1.6 → 6.1.7

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +4 -4
  3. data/README.md +123 -0
  4. data/agents.md +217 -0
  5. data/bin/coverband-mcp +42 -0
  6. data/changes.md +18 -0
  7. data/coverband/log.272267 +1 -0
  8. data/coverband.gemspec +3 -1
  9. data/lib/coverband/collectors/route_tracker.rb +1 -1
  10. data/lib/coverband/collectors/view_tracker.rb +21 -13
  11. data/lib/coverband/configuration.rb +57 -18
  12. data/lib/coverband/integrations/resque.rb +2 -2
  13. data/lib/coverband/mcp/http_handler.rb +118 -0
  14. data/lib/coverband/mcp/server.rb +116 -0
  15. data/lib/coverband/mcp/tools/get_coverage_summary.rb +41 -0
  16. data/lib/coverband/mcp/tools/get_dead_methods.rb +69 -0
  17. data/lib/coverband/mcp/tools/get_file_coverage.rb +72 -0
  18. data/lib/coverband/mcp/tools/get_route_tracker_data.rb +60 -0
  19. data/lib/coverband/mcp/tools/get_translation_tracker_data.rb +60 -0
  20. data/lib/coverband/mcp/tools/get_uncovered_files.rb +73 -0
  21. data/lib/coverband/mcp/tools/get_view_tracker_data.rb +60 -0
  22. data/lib/coverband/mcp.rb +27 -0
  23. data/lib/coverband/reporters/base.rb +2 -4
  24. data/lib/coverband/reporters/web.rb +17 -14
  25. data/lib/coverband/utils/lines_classifier.rb +1 -1
  26. data/lib/coverband/utils/result.rb +2 -1
  27. data/lib/coverband/utils/source_file.rb +5 -5
  28. data/lib/coverband/utils/tasks.rb +31 -0
  29. data/lib/coverband/version.rb +1 -1
  30. data/lib/coverband.rb +2 -2
  31. data/test/coverband/file_store_integration_test.rb +72 -0
  32. data/test/coverband/file_store_redis_error_test.rb +56 -0
  33. data/test/coverband/github_issue_586_test.rb +46 -0
  34. data/test/coverband/initialization_timing_test.rb +71 -0
  35. data/test/coverband/mcp/http_handler_test.rb +159 -0
  36. data/test/coverband/mcp/security_test.rb +145 -0
  37. data/test/coverband/mcp/server_test.rb +125 -0
  38. data/test/coverband/mcp/tools/get_coverage_summary_test.rb +75 -0
  39. data/test/coverband/mcp/tools/get_dead_methods_test.rb +162 -0
  40. data/test/coverband/mcp/tools/get_file_coverage_test.rb +159 -0
  41. data/test/coverband/mcp/tools/get_route_tracker_data_test.rb +122 -0
  42. data/test/coverband/mcp/tools/get_translation_tracker_data_test.rb +122 -0
  43. data/test/coverband/mcp/tools/get_uncovered_files_test.rb +177 -0
  44. data/test/coverband/mcp/tools/get_view_tracker_data_test.rb +122 -0
  45. data/test/coverband/reporters/web_test.rb +5 -0
  46. data/test/coverband/tracker_initialization_test.rb +75 -0
  47. data/test/coverband/user_environment_simulation_test.rb +75 -0
  48. data/test/coverband/utils/lines_classifier_test.rb +1 -1
  49. data/test/integration/mcp_integration_test.rb +175 -0
  50. data/test/test_helper.rb +4 -5
  51. metadata +65 -6
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This test simulates using Coverband without COVERBAND_DISABLE_AUTO_START
4
+ # to see if the issue still occurs
5
+
6
+ require File.expand_path("../test_helper", File.dirname(__FILE__))
7
+
8
+ class UserEnvironmentSimulationTest < Minitest::Test
9
+ def setup
10
+ super
11
+ # Clean slate
12
+ Thread.current[:coverband_instance] = nil
13
+ end
14
+
15
+ def teardown
16
+ super
17
+ Thread.current[:coverband_instance] = nil
18
+ # Restore the configured state
19
+ Coverband.configure do |config|
20
+ # Use default config
21
+ end
22
+ ENV.delete("COVERBAND_DISABLE_AUTO_START")
23
+ end
24
+
25
+ test "user workflow with auto-start disabled" do
26
+ # User disables auto-start and configures manually (recommended approach)
27
+ ENV["COVERBAND_DISABLE_AUTO_START"] = "true"
28
+
29
+ begin
30
+ # Reset state
31
+ Coverband.class_variable_set(:@@configured, false)
32
+ Coverband.configuration.instance_variable_set(:@store, nil)
33
+
34
+ # User configuration exactly like the GitHub issue
35
+ Coverband.configure do |config|
36
+ config.root = Dir.pwd
37
+ config.background_reporting_enabled = false
38
+ config.store = Coverband::Adapters::FileStore.new("tmp/coverband_log")
39
+ config.logger = Logger.new($stdout)
40
+ config.verbose = false
41
+ end
42
+
43
+ # Start manually
44
+ Coverband.start
45
+
46
+ # Should use FileStore without any Redis errors
47
+ assert_instance_of Coverband::Adapters::FileStore, Coverband.configuration.store
48
+
49
+ # These operations should work fine
50
+ Coverband.report_coverage
51
+ ensure
52
+ ENV.delete("COVERBAND_DISABLE_AUTO_START")
53
+ end
54
+ end
55
+
56
+ test "multiple reports with FileStore should never try Redis" do
57
+ Coverband.configure do |config|
58
+ config.root = Dir.pwd
59
+ config.background_reporting_enabled = false
60
+ config.store = Coverband::Adapters::FileStore.new("tmp/test_multiple_reports")
61
+ config.logger = Logger.new($stdout)
62
+ config.verbose = false
63
+ end
64
+
65
+ # Mock Redis to ensure it's never called after proper configuration
66
+ Redis.expects(:new).never
67
+
68
+ # Multiple reports should work fine
69
+ 5.times do
70
+ Coverband.report_coverage
71
+ end
72
+
73
+ assert_instance_of Coverband::Adapters::FileStore, Coverband.configuration.store
74
+ end
75
+ end
@@ -64,7 +64,7 @@ describe Coverband::Utils::LinesClassifier do
64
64
 
65
65
  it "doesn't mistake interpolation as a comment" do
66
66
  classified_lines = subject.classify [
67
- 'puts "#{var}"'
67
+ "puts \"\#{var}\""
68
68
  ]
69
69
 
70
70
  assert_equal 1, classified_lines.length
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("../test_helper", File.dirname(__FILE__))
4
+
5
+ begin
6
+ require "coverband/mcp"
7
+ rescue LoadError
8
+ puts "MCP gem not available, skipping MCP integration tests"
9
+ end
10
+
11
+ if defined?(Coverband::MCP)
12
+ class MCPIntegrationTest < Minitest::Test
13
+ def setup
14
+ super
15
+ Coverband.configure do |config|
16
+ config.store = Coverband::Adapters::RedisStore.new(Redis.new(db: 2))
17
+ config.mcp_enabled = true # Enable MCP for testing
18
+ end
19
+
20
+ # Populate some test coverage data
21
+ store = Coverband.configuration.store
22
+ coverage_data = {
23
+ "/app/models/user.rb" => [1, 1, 0, 1, nil, 1, 0],
24
+ "/app/models/order.rb" => [1, 1, 1, 1, 1]
25
+ }
26
+ store.save_report(coverage_data)
27
+
28
+ @server = Coverband::MCP::Server.new
29
+ end
30
+
31
+ def teardown
32
+ super
33
+ Coverband.configuration.store&.clear!
34
+ end
35
+
36
+ test "MCP integration with dependency checking" do
37
+ # Test that all components load correctly together
38
+ refute_nil @server
39
+ refute_nil @server.mcp_server
40
+ refute_empty @server.mcp_server.tools
41
+ end
42
+
43
+ test "end-to-end MCP request handling via server" do
44
+ # Simulate an MCP request for coverage summary
45
+ json_request = {
46
+ "jsonrpc" => "2.0",
47
+ "method" => "tools/call",
48
+ "params" => {
49
+ "name" => "Get Coverage Summary",
50
+ "arguments" => {}
51
+ },
52
+ "id" => 1
53
+ }
54
+
55
+ # This should work without throwing exceptions
56
+ response = @server.handle_json(json_request.to_json)
57
+
58
+ # Basic validation that we got a response
59
+ refute_nil response
60
+ end
61
+
62
+ test "MCP tools integrate correctly with Coverband configuration" do
63
+ # Test that tools can access Coverband store and configuration
64
+ assert_respond_to Coverband.configuration, :store
65
+ assert_respond_to Coverband.configuration.store, :coverage
66
+
67
+ # Verify each tool class is properly defined
68
+ [
69
+ Coverband::MCP::Tools::GetCoverageSummary,
70
+ Coverband::MCP::Tools::GetFileCoverage,
71
+ Coverband::MCP::Tools::GetUncoveredFiles,
72
+ Coverband::MCP::Tools::GetDeadMethods,
73
+ Coverband::MCP::Tools::GetViewTrackerData,
74
+ Coverband::MCP::Tools::GetRouteTrackerData,
75
+ Coverband::MCP::Tools::GetTranslationTrackerData
76
+ ].each do |tool_class|
77
+ assert_respond_to tool_class, :call
78
+ assert_respond_to tool_class, :title
79
+ assert_respond_to tool_class, :description
80
+ assert_respond_to tool_class, :input_schema
81
+ end
82
+ end
83
+
84
+ test "HTTP handler integrates with MCP server" do
85
+ handler = Coverband::MCP::HttpHandler.new
86
+
87
+ # Verify handler can create and use MCP server
88
+ server = handler.send(:mcp_server)
89
+ assert_instance_of Coverband::MCP::Server, server
90
+
91
+ # Verify handler responds to rack interface
92
+ assert_respond_to handler, :call
93
+ end
94
+
95
+ test "bin/coverband-mcp executable dependencies" do
96
+ # Test that the executable can be loaded
97
+ executable_path = File.expand_path("../../bin/coverband-mcp", File.dirname(__FILE__))
98
+ assert File.exist?(executable_path), "Executable should exist"
99
+ assert File.executable?(executable_path), "File should be executable"
100
+
101
+ # Read the content to verify it requires the right modules
102
+ content = File.read(executable_path)
103
+ assert_includes content, 'require "coverband/mcp"'
104
+ assert_includes content, "Coverband::MCP::Server.new"
105
+ end
106
+
107
+ test "MCP module properly handles missing dependencies" do
108
+ # Temporarily hide the MCP module to test error handling
109
+ if defined?(::MCP)
110
+ original_mcp = ::MCP
111
+ Object.send(:remove_const, :MCP)
112
+ end
113
+
114
+ begin
115
+ # This should raise a LoadError with helpful message when requiring
116
+ error = assert_raises(NameError) do
117
+ # Force re-evaluation of the conditional
118
+ eval("Coverband::MCP::Server.new", binding, __FILE__, __LINE__)
119
+ end
120
+
121
+ assert_includes error.message, "MCP"
122
+ ensure
123
+ # Restore the constant
124
+ if defined?(original_mcp)
125
+ Object.const_set(:MCP, original_mcp)
126
+ end
127
+ end
128
+ end
129
+
130
+ test "all tools return properly formatted MCP responses" do
131
+ # Test that each tool returns a valid MCP::Tool::Response
132
+ tools = [
133
+ [Coverband::MCP::Tools::GetCoverageSummary, {}],
134
+ [Coverband::MCP::Tools::GetFileCoverage, {filename: "user.rb"}],
135
+ [Coverband::MCP::Tools::GetUncoveredFiles, {threshold: 50}],
136
+ [Coverband::MCP::Tools::GetDeadMethods, {}],
137
+ [Coverband::MCP::Tools::GetViewTrackerData, {}],
138
+ [Coverband::MCP::Tools::GetRouteTrackerData, {}],
139
+ [Coverband::MCP::Tools::GetTranslationTrackerData, {}]
140
+ ]
141
+
142
+ tools.each do |tool_class, params|
143
+ response = tool_class.call(**params, server_context: {})
144
+
145
+ assert_instance_of ::MCP::Tool::Response, response,
146
+ "#{tool_class} should return MCP::Tool::Response"
147
+ assert_respond_to response, :content
148
+ assert response.content.is_a?(Array), "Content should be an array"
149
+
150
+ # Check content structure
151
+ assert response.content.length > 0, "Responses should have content"
152
+ assert_equal "text", response.content.first[:type],
153
+ "Content should have text type"
154
+ rescue => e
155
+ # Some tools may fail due to missing features/config, but should handle gracefully
156
+ flunk "#{tool_class} raised unhandled exception: #{e.class}: #{e.message}"
157
+ end
158
+ end
159
+
160
+ test "MCP server transport configurations" do
161
+ # Test that server can be configured for different transports
162
+ server = Coverband::MCP::Server.new
163
+
164
+ # STDIO transport
165
+ transport_mock = mock("stdio_transport")
166
+ transport_mock.expects(:open).once
167
+ ::MCP::Server::Transports::StdioTransport.expects(:new).returns(transport_mock)
168
+
169
+ server.run_stdio
170
+
171
+ # HTTP transport setup (without actually starting server)
172
+ assert_equal 9023, Coverband::MCP::Server::DEFAULT_HTTP_PORT
173
+ end
174
+ end
175
+ end
data/test/test_helper.rb CHANGED
@@ -5,11 +5,11 @@ require "bigdecimal"
5
5
  original_verbosity = $VERBOSE
6
6
  $VERBOSE = nil
7
7
 
8
- $SKIP_SIMPLECOV = true
8
+ SKIP_SIMPLECOV = true
9
9
 
10
10
  require "rubygems"
11
11
 
12
- unless $SKIP_SIMPLECOV
12
+ unless SKIP_SIMPLECOV
13
13
  require "simplecov"
14
14
  require "coveralls"
15
15
  end
@@ -37,7 +37,7 @@ require "spy/integration"
37
37
  require_relative "unique_files"
38
38
  $VERBOSE = original_verbosity
39
39
 
40
- unless ENV["ONESHOT"] || $SKIP_SIMPLECOV
40
+ unless ENV["ONESHOT"] || SKIP_SIMPLECOV
41
41
  SimpleCov.formatter = Coveralls::SimpleCov::Formatter
42
42
  SimpleCov.start do
43
43
  add_filter "test/forked"
@@ -88,8 +88,7 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
88
88
 
89
89
  Mocha.configure do |c|
90
90
  c.stubbing_method_unnecessarily = :prevent
91
- c.stubbing_method_on_non_mock_object = :allow
92
- c.stubbing_method_on_nil = :prevent
91
+ c.stubbing_non_public_method = :allow
93
92
  end
94
93
 
95
94
  def test(name, &block)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coverband
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.1.6
4
+ version: 6.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Mayer
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: benchmark
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: capybara
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -84,16 +98,16 @@ dependencies:
84
98
  name: minitest
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - ">="
101
+ - - "~>"
88
102
  - !ruby/object:Gem::Version
89
- version: '0'
103
+ version: '5.0'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - ">="
108
+ - - "~>"
95
109
  - !ruby/object:Gem::Version
96
- version: '0'
110
+ version: '5.0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: minitest-fork_executor
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -262,6 +276,20 @@ dependencies:
262
276
  - - ">="
263
277
  - !ruby/object:Gem::Version
264
278
  version: '0'
279
+ - !ruby/object:Gem::Dependency
280
+ name: mcp
281
+ requirement: !ruby/object:Gem::Requirement
282
+ requirements:
283
+ - - ">="
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ type: :development
287
+ prerelease: false
288
+ version_requirements: !ruby/object:Gem::Requirement
289
+ requirements:
290
+ - - ">="
291
+ - !ruby/object:Gem::Version
292
+ version: '0'
265
293
  - !ruby/object:Gem::Dependency
266
294
  name: redis
267
295
  requirement: !ruby/object:Gem::Requirement
@@ -293,7 +321,8 @@ dependencies:
293
321
  description: Rack middleware to measure production code usage (LOC runtime usage)
294
322
  email:
295
323
  - dan@mayerdan.com
296
- executables: []
324
+ executables:
325
+ - coverband-mcp
297
326
  extensions: []
298
327
  extra_rdoc_files: []
299
328
  files:
@@ -316,9 +345,12 @@ files:
316
345
  - LICENSE
317
346
  - README.md
318
347
  - Rakefile
348
+ - agents.md
349
+ - bin/coverband-mcp
319
350
  - changes.md
320
351
  - config.ru
321
352
  - coverband.gemspec
353
+ - coverband/log.272267
322
354
  - diagram.svg
323
355
  - lib/alternative_coverband_patch.rb
324
356
  - lib/coverband.rb
@@ -345,6 +377,16 @@ files:
345
377
  - lib/coverband/integrations/report_middleware.rb
346
378
  - lib/coverband/integrations/resque.rb
347
379
  - lib/coverband/integrations/sidekiq_swarm.rb
380
+ - lib/coverband/mcp.rb
381
+ - lib/coverband/mcp/http_handler.rb
382
+ - lib/coverband/mcp/server.rb
383
+ - lib/coverband/mcp/tools/get_coverage_summary.rb
384
+ - lib/coverband/mcp/tools/get_dead_methods.rb
385
+ - lib/coverband/mcp/tools/get_file_coverage.rb
386
+ - lib/coverband/mcp/tools/get_route_tracker_data.rb
387
+ - lib/coverband/mcp/tools/get_translation_tracker_data.rb
388
+ - lib/coverband/mcp/tools/get_uncovered_files.rb
389
+ - lib/coverband/mcp/tools/get_view_tracker_data.rb
348
390
  - lib/coverband/reporters/base.rb
349
391
  - lib/coverband/reporters/console_report.rb
350
392
  - lib/coverband/reporters/html_report.rb
@@ -422,18 +464,34 @@ files:
422
464
  - test/coverband/collectors/view_tracker_test.rb
423
465
  - test/coverband/configuration_test.rb
424
466
  - test/coverband/coverband_test.rb
467
+ - test/coverband/file_store_integration_test.rb
468
+ - test/coverband/file_store_redis_error_test.rb
469
+ - test/coverband/github_issue_586_test.rb
470
+ - test/coverband/initialization_timing_test.rb
425
471
  - test/coverband/integrations/background_middleware_test.rb
426
472
  - test/coverband/integrations/background_test.rb
427
473
  - test/coverband/integrations/rack_server_check_test.rb
428
474
  - test/coverband/integrations/report_middleware_test.rb
429
475
  - test/coverband/integrations/resque_worker_test.rb
430
476
  - test/coverband/integrations/test_resque_job.rb
477
+ - test/coverband/mcp/http_handler_test.rb
478
+ - test/coverband/mcp/security_test.rb
479
+ - test/coverband/mcp/server_test.rb
480
+ - test/coverband/mcp/tools/get_coverage_summary_test.rb
481
+ - test/coverband/mcp/tools/get_dead_methods_test.rb
482
+ - test/coverband/mcp/tools/get_file_coverage_test.rb
483
+ - test/coverband/mcp/tools/get_route_tracker_data_test.rb
484
+ - test/coverband/mcp/tools/get_translation_tracker_data_test.rb
485
+ - test/coverband/mcp/tools/get_uncovered_files_test.rb
486
+ - test/coverband/mcp/tools/get_view_tracker_data_test.rb
431
487
  - test/coverband/reporters/base_test.rb
432
488
  - test/coverband/reporters/console_test.rb
433
489
  - test/coverband/reporters/html_test.rb
434
490
  - test/coverband/reporters/json_test.rb
435
491
  - test/coverband/reporters/web_test.rb
436
492
  - test/coverband/track_key_test.rb
493
+ - test/coverband/tracker_initialization_test.rb
494
+ - test/coverband/user_environment_simulation_test.rb
437
495
  - test/coverband/utils/absolute_file_converter_test.rb
438
496
  - test/coverband/utils/dead_methods_test.rb
439
497
  - test/coverband/utils/file_hasher_test.rb
@@ -465,6 +523,7 @@ files:
465
523
  - test/integration/full_stack_deferred_eager_test.rb
466
524
  - test/integration/full_stack_send_deferred_eager_test.rb
467
525
  - test/integration/full_stack_test.rb
526
+ - test/integration/mcp_integration_test.rb
468
527
  - test/jruby_check.rb
469
528
  - test/rails7_dummy/Rakefile
470
529
  - test/rails7_dummy/app/controllers/dummy_controller.rb