bug_bunny 3.0.6 → 3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +228 -4
- data/Rakefile +10 -6
- data/lib/bug_bunny/configuration.rb +13 -2
- data/lib/bug_bunny/consumer.rb +53 -25
- data/lib/bug_bunny/controller.rb +135 -91
- data/lib/bug_bunny/exception.rb +4 -0
- data/lib/bug_bunny/producer.rb +10 -3
- data/lib/bug_bunny/resource.rb +69 -150
- data/lib/bug_bunny/session.rb +65 -44
- data/lib/bug_bunny/version.rb +1 -1
- data/test/integration/fire_and_forget_test.rb +76 -0
- data/test/integration/rpc_flow_test.rb +78 -0
- data/test/test_helper.rb +24 -0
- data/test/unit/configuration_test.rb +40 -0
- data/test/unit/consumer_test.rb +44 -0
- data/test/unit/controller_headers_test.rb +38 -0
- data/test/unit/hybrid_resource_test.rb +60 -0
- data/test/unit/middleware_test.rb +61 -0
- data/test/unit/resource_test.rb +49 -0
- metadata +39 -2
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
require 'connection_pool'
|
|
5
|
+
|
|
6
|
+
# Controlador Dummy en memoria
|
|
7
|
+
module Rabbit
|
|
8
|
+
module Controllers
|
|
9
|
+
class IntegrationTest < BugBunny::Controller
|
|
10
|
+
def index
|
|
11
|
+
# CORRECCIÓN: Usar 'render' en lugar de retornar un hash implícito.
|
|
12
|
+
# Si solo retornas el valor, el Controller lo ignora y devuelve 204 (No Content).
|
|
13
|
+
render status: 200, json: { message: 'pong' }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class RpcFlowTest < Minitest::Test
|
|
20
|
+
def setup
|
|
21
|
+
skip "RabbitMQ no disponible" unless TestHelper.rabbitmq_available?
|
|
22
|
+
|
|
23
|
+
# 1. Configuración Real
|
|
24
|
+
BugBunny.configure do |c|
|
|
25
|
+
c.host = 'localhost'
|
|
26
|
+
c.username = 'wisproMQ'
|
|
27
|
+
c.password = 'wisproMQ'
|
|
28
|
+
c.port = 5672
|
|
29
|
+
c.logger = Logger.new(nil)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# 2. Pool para el Cliente
|
|
33
|
+
@pool = ConnectionPool.new(size: 1, timeout: 5) do
|
|
34
|
+
BugBunny.create_connection
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# 3. Consumer en hilo separado
|
|
38
|
+
@conn_consumer = BugBunny.create_connection
|
|
39
|
+
@queue_name = 'test_integration_queue'
|
|
40
|
+
@exchange_name = 'test_integration_exchange'
|
|
41
|
+
|
|
42
|
+
@consumer_thread = Thread.new do
|
|
43
|
+
BugBunny::Consumer.subscribe(
|
|
44
|
+
connection: @conn_consumer,
|
|
45
|
+
queue_name: @queue_name,
|
|
46
|
+
exchange_name: @exchange_name,
|
|
47
|
+
routing_key: 'test_key',
|
|
48
|
+
block: true
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
sleep 0.5 # Esperar arranque
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def teardown
|
|
55
|
+
return unless @conn_consumer
|
|
56
|
+
@conn_consumer.close
|
|
57
|
+
@consumer_thread.kill
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_rpc_request_response
|
|
61
|
+
client = BugBunny::Client.new(pool: @pool)
|
|
62
|
+
|
|
63
|
+
# Usamos request() para RPC
|
|
64
|
+
response = client.request(
|
|
65
|
+
'integration_test',
|
|
66
|
+
body: {},
|
|
67
|
+
exchange: @exchange_name,
|
|
68
|
+
routing_key: 'test_key'
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Ahora sí esperamos 200 OK
|
|
72
|
+
assert_equal 200, response['status']
|
|
73
|
+
|
|
74
|
+
body = response['body']
|
|
75
|
+
msg = body.is_a?(Hash) ? (body['message'] || body[:message]) : body
|
|
76
|
+
assert_equal 'pong', msg
|
|
77
|
+
end
|
|
78
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __dir__)
|
|
5
|
+
require 'bug_bunny'
|
|
6
|
+
|
|
7
|
+
require 'minitest/autorun'
|
|
8
|
+
require 'mocha/minitest'
|
|
9
|
+
require 'logger'
|
|
10
|
+
|
|
11
|
+
BugBunny.configure do |config|
|
|
12
|
+
config.logger = Logger.new(nil)
|
|
13
|
+
config.bunny_logger = Logger.new(nil)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module TestHelper
|
|
17
|
+
def self.rabbitmq_available?
|
|
18
|
+
socket = TCPSocket.new('localhost', 5672)
|
|
19
|
+
socket.close
|
|
20
|
+
true
|
|
21
|
+
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT
|
|
22
|
+
false
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
class ConfigurationTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
BugBunny.configuration = nil # Resetear singleton
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_default_values
|
|
11
|
+
config = BugBunny::Configuration.new
|
|
12
|
+
|
|
13
|
+
assert_equal '127.0.0.1', config.host
|
|
14
|
+
assert_equal 5672, config.port # Validamos el fix de la v3.0.6
|
|
15
|
+
assert_equal 'guest', config.username
|
|
16
|
+
assert_equal '/', config.vhost
|
|
17
|
+
assert config.automatically_recover
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_configure_block
|
|
21
|
+
BugBunny.configure do |c|
|
|
22
|
+
c.host = 'rabbit.prod'
|
|
23
|
+
c.port = 1234
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
assert_equal 'rabbit.prod', BugBunny.configuration.host
|
|
27
|
+
assert_equal 1234, BugBunny.configuration.port
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_url_generation
|
|
31
|
+
config = BugBunny::Configuration.new
|
|
32
|
+
config.host = 'host'
|
|
33
|
+
config.port = 5672
|
|
34
|
+
config.username = 'u'
|
|
35
|
+
config.password = 'p'
|
|
36
|
+
|
|
37
|
+
# CAMBIO: Agregamos el slash extra al final que genera la interpolación
|
|
38
|
+
assert_equal "amqp://u:p@host:5672//", config.url
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
class ConsumerTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
@connection = mock('Bunny::Session')
|
|
8
|
+
@channel = mock('Bunny::Channel')
|
|
9
|
+
|
|
10
|
+
# Stubs para que Consumer.new no falle
|
|
11
|
+
@connection.stubs(:open?).returns(true)
|
|
12
|
+
@connection.stubs(:create_channel).returns(@channel)
|
|
13
|
+
@connection.stubs(:close)
|
|
14
|
+
|
|
15
|
+
# Stubs para Session y Channel
|
|
16
|
+
@channel.stubs(:confirm_select)
|
|
17
|
+
@channel.stubs(:prefetch)
|
|
18
|
+
@channel.stubs(:open?).returns(true)
|
|
19
|
+
@channel.stubs(:close)
|
|
20
|
+
|
|
21
|
+
@consumer = BugBunny::Consumer.new(@connection)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_router_dispatch
|
|
25
|
+
# Probamos la lógica interna del Router (método privado router_dispatch)
|
|
26
|
+
|
|
27
|
+
# Caso 1: POST /users -> Create
|
|
28
|
+
route_post = @consumer.send(:router_dispatch, 'POST', 'users')
|
|
29
|
+
assert_equal 'users', route_post[:controller]
|
|
30
|
+
assert_equal 'create', route_post[:action]
|
|
31
|
+
|
|
32
|
+
# Caso 2: GET /users/123 -> Show
|
|
33
|
+
route_show = @consumer.send(:router_dispatch, 'GET', 'users/123')
|
|
34
|
+
assert_equal 'users', route_show[:controller]
|
|
35
|
+
assert_equal 'show', route_show[:action]
|
|
36
|
+
assert_equal '123', route_show[:id]
|
|
37
|
+
|
|
38
|
+
# Caso 3: Custom Action (POST /users/1/promote)
|
|
39
|
+
route_custom = @consumer.send(:router_dispatch, 'POST', 'users/1/promote')
|
|
40
|
+
assert_equal 'users', route_custom[:controller]
|
|
41
|
+
assert_equal 'promote', route_custom[:action]
|
|
42
|
+
assert_equal '1', route_custom[:id]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
class ControllerHeadersTest < Minitest::Test
|
|
6
|
+
# Controlador Dummy para probar headers
|
|
7
|
+
class HeadersController < BugBunny::Controller
|
|
8
|
+
def echo_headers
|
|
9
|
+
# 1. LEER del Request
|
|
10
|
+
client_token = headers['X-Client-Token']
|
|
11
|
+
|
|
12
|
+
# 2. ESCRIBIR en el Response
|
|
13
|
+
response_headers['X-Server-Time'] = '123456789'
|
|
14
|
+
response_headers['X-Received-Token'] = client_token
|
|
15
|
+
|
|
16
|
+
render status: 200, json: { message: 'ok' }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_headers_flow
|
|
21
|
+
# Simulamos los headers que enviaría el Consumer al Controller
|
|
22
|
+
request_headers = {
|
|
23
|
+
action: 'echo_headers',
|
|
24
|
+
'X-Client-Token' => 'secret_abc'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Ejecutamos el pipeline del controlador
|
|
28
|
+
response = HeadersController.call(headers: request_headers, body: {})
|
|
29
|
+
|
|
30
|
+
# Verificamos la estructura de la respuesta
|
|
31
|
+
assert_equal 200, response[:status]
|
|
32
|
+
|
|
33
|
+
# Verificamos que los headers de respuesta estén presentes
|
|
34
|
+
assert_kind_of Hash, response[:headers]
|
|
35
|
+
assert_equal '123456789', response[:headers]['X-Server-Time']
|
|
36
|
+
assert_equal 'secret_abc', response[:headers]['X-Received-Token']
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
class HybridResourceTest < Minitest::Test
|
|
6
|
+
# Definimos una clase temporal para el test
|
|
7
|
+
class Product < BugBunny::Resource
|
|
8
|
+
# Atributos explícitos (Tipados)
|
|
9
|
+
attribute :price, :decimal, default: 0.0
|
|
10
|
+
attribute :active, :boolean, default: false
|
|
11
|
+
|
|
12
|
+
# Validaciones mixtas
|
|
13
|
+
validates :price, numericality: { greater_than: 0 }
|
|
14
|
+
validates :name, presence: true # 'name' será dinámico
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_hybrid_attributes_assignment
|
|
18
|
+
# Caso: Asignación mixta en initialize
|
|
19
|
+
p = Product.new(price: "10.5", name: "Laptop", active: "1")
|
|
20
|
+
|
|
21
|
+
# 1. Atributo Tipado (:decimal) -> Coerción automática
|
|
22
|
+
assert_kind_of BigDecimal, p.price
|
|
23
|
+
assert_equal 10.5, p.price
|
|
24
|
+
|
|
25
|
+
# 2. Atributo Tipado (:boolean) -> Coerción automática
|
|
26
|
+
assert_equal true, p.active
|
|
27
|
+
|
|
28
|
+
# 3. Atributo Dinámico (method_missing) -> String directo
|
|
29
|
+
assert_equal "Laptop", p.name
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_hybrid_serialization
|
|
33
|
+
p = Product.new(price: 20.0, name: "Mouse")
|
|
34
|
+
|
|
35
|
+
# Simulamos serialización (lo que se enviaría a RabbitMQ)
|
|
36
|
+
payload = p.attributes_for_serialization
|
|
37
|
+
|
|
38
|
+
assert_equal 20.0, payload['price']
|
|
39
|
+
assert_equal "Mouse", payload['name']
|
|
40
|
+
assert_equal false, payload['active'] # Default value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_hybrid_dirty_tracking
|
|
44
|
+
p = Product.new(price: 10.0, name: "Old Name")
|
|
45
|
+
p.persisted = true
|
|
46
|
+
p.send(:clear_changes_information)
|
|
47
|
+
|
|
48
|
+
# Modificamos uno tipado y uno dinámico
|
|
49
|
+
p.price = 15.0
|
|
50
|
+
p.name = "New Name"
|
|
51
|
+
|
|
52
|
+
changes = p.changes_to_send
|
|
53
|
+
|
|
54
|
+
# Ambos deben aparecer en los cambios
|
|
55
|
+
assert_includes changes.keys, 'price'
|
|
56
|
+
assert_includes changes.keys, 'name'
|
|
57
|
+
assert_equal 15.0, changes['price']
|
|
58
|
+
assert_equal "New Name", changes['name']
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
class MiddlewareTest < Minitest::Test
|
|
6
|
+
# Middleware dummy para rastrear ejecución
|
|
7
|
+
class TrackerMiddleware < BugBunny::Middleware::Base
|
|
8
|
+
def on_request(env)
|
|
9
|
+
env[:trace] << 'req_in'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def on_complete(response)
|
|
13
|
+
response[:trace] << 'res_out'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def setup
|
|
18
|
+
@stack = BugBunny::Middleware::Stack.new
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_execution_order
|
|
22
|
+
# La "App" final (Producer)
|
|
23
|
+
final_app = ->(env) {
|
|
24
|
+
env[:trace] << 'executing'
|
|
25
|
+
{ body: 'ok', trace: env[:trace] }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@stack.use TrackerMiddleware
|
|
29
|
+
chain = @stack.build(final_app)
|
|
30
|
+
|
|
31
|
+
env = { trace: [] }
|
|
32
|
+
response = chain.call(env)
|
|
33
|
+
|
|
34
|
+
# El orden debe ser: Entrada -> Ejecución -> Salida (Cebolla)
|
|
35
|
+
expected_trace = ['req_in', 'executing', 'res_out']
|
|
36
|
+
assert_equal expected_trace, response[:trace]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_json_response_parsing
|
|
40
|
+
# Simulamos una respuesta JSON cruda
|
|
41
|
+
app = ->(_) { { 'body' => '{"foo":"bar"}', 'status' => 200 } }
|
|
42
|
+
|
|
43
|
+
middleware = BugBunny::Middleware::JsonResponse.new(app)
|
|
44
|
+
response = middleware.call({})
|
|
45
|
+
|
|
46
|
+
# Debe convertirse en Hash
|
|
47
|
+
assert_kind_of Hash, response['body']
|
|
48
|
+
assert_equal 'bar', response['body']['foo']
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_raise_error_handling
|
|
52
|
+
# Simulamos un error 404
|
|
53
|
+
app = ->(_) { { 'status' => 404, 'body' => 'Not Found' } }
|
|
54
|
+
|
|
55
|
+
middleware = BugBunny::Middleware::RaiseError.new(app)
|
|
56
|
+
|
|
57
|
+
assert_raises(BugBunny::NotFound) do
|
|
58
|
+
middleware.call({})
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../test_helper'
|
|
4
|
+
|
|
5
|
+
class ConsumerTest < Minitest::Test
|
|
6
|
+
def setup
|
|
7
|
+
# CORRECCIÓN: Asegurar que existe configuración para evitar error en Session
|
|
8
|
+
BugBunny.configure do |c|
|
|
9
|
+
c.channel_prefetch = 1
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
@connection = mock('Bunny::Session')
|
|
13
|
+
@channel = mock('Bunny::Channel')
|
|
14
|
+
|
|
15
|
+
# Stubs para que Consumer.new no falle
|
|
16
|
+
@connection.stubs(:open?).returns(true)
|
|
17
|
+
@connection.stubs(:create_channel).returns(@channel)
|
|
18
|
+
@connection.stubs(:close)
|
|
19
|
+
|
|
20
|
+
# Stubs para Session y Channel
|
|
21
|
+
@channel.stubs(:confirm_select)
|
|
22
|
+
@channel.stubs(:prefetch)
|
|
23
|
+
@channel.stubs(:open?).returns(true)
|
|
24
|
+
@channel.stubs(:close)
|
|
25
|
+
|
|
26
|
+
@consumer = BugBunny::Consumer.new(@connection)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_router_dispatch
|
|
30
|
+
# Probamos la lógica interna del Router (método privado router_dispatch)
|
|
31
|
+
|
|
32
|
+
# Caso 1: POST /users -> Create
|
|
33
|
+
route_post = @consumer.send(:router_dispatch, 'POST', 'users')
|
|
34
|
+
assert_equal 'users', route_post[:controller]
|
|
35
|
+
assert_equal 'create', route_post[:action]
|
|
36
|
+
|
|
37
|
+
# Caso 2: GET /users/123 -> Show
|
|
38
|
+
route_show = @consumer.send(:router_dispatch, 'GET', 'users/123')
|
|
39
|
+
assert_equal 'users', route_show[:controller]
|
|
40
|
+
assert_equal 'show', route_show[:action]
|
|
41
|
+
assert_equal '123', route_show[:id]
|
|
42
|
+
|
|
43
|
+
# Caso 3: Custom Action (POST /users/1/promote)
|
|
44
|
+
route_custom = @consumer.send(:router_dispatch, 'POST', 'users/1/promote')
|
|
45
|
+
assert_equal 'users', route_custom[:controller]
|
|
46
|
+
assert_equal 'promote', route_custom[:action]
|
|
47
|
+
assert_equal '1', route_custom[:id]
|
|
48
|
+
end
|
|
49
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bug_bunny
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0
|
|
4
|
+
version: 3.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- gabix
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bunny
|
|
@@ -178,6 +178,34 @@ dependencies:
|
|
|
178
178
|
- - "~>"
|
|
179
179
|
- !ruby/object:Gem::Version
|
|
180
180
|
version: '0.9'
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: minitest
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - "~>"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '5.0'
|
|
188
|
+
type: :development
|
|
189
|
+
prerelease: false
|
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - "~>"
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '5.0'
|
|
195
|
+
- !ruby/object:Gem::Dependency
|
|
196
|
+
name: mocha
|
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '2.0'
|
|
202
|
+
type: :development
|
|
203
|
+
prerelease: false
|
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
+
requirements:
|
|
206
|
+
- - "~>"
|
|
207
|
+
- !ruby/object:Gem::Version
|
|
208
|
+
version: '2.0'
|
|
181
209
|
description: BugBunny is a lightweight RPC framework for Ruby on Rails over RabbitMQ.
|
|
182
210
|
It simulates a RESTful architecture with an intelligent router, Active Record-like
|
|
183
211
|
resources, and middleware support.
|
|
@@ -213,6 +241,15 @@ files:
|
|
|
213
241
|
- lib/generators/bug_bunny/install/install_generator.rb
|
|
214
242
|
- lib/generators/bug_bunny/install/templates/initializer.rb
|
|
215
243
|
- sig/bug_bunny.rbs
|
|
244
|
+
- test/integration/fire_and_forget_test.rb
|
|
245
|
+
- test/integration/rpc_flow_test.rb
|
|
246
|
+
- test/test_helper.rb
|
|
247
|
+
- test/unit/configuration_test.rb
|
|
248
|
+
- test/unit/consumer_test.rb
|
|
249
|
+
- test/unit/controller_headers_test.rb
|
|
250
|
+
- test/unit/hybrid_resource_test.rb
|
|
251
|
+
- test/unit/middleware_test.rb
|
|
252
|
+
- test/unit/resource_test.rb
|
|
216
253
|
- test_controller.rb
|
|
217
254
|
- test_helper.rb
|
|
218
255
|
- test_resource.rb
|