bug_bunny 3.0.6 → 3.1.1
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 +28 -0
- data/README.md +204 -148
- data/Rakefile +10 -6
- data/lib/bug_bunny/client.rb +26 -11
- data/lib/bug_bunny/configuration.rb +40 -3
- data/lib/bug_bunny/consumer.rb +56 -29
- data/lib/bug_bunny/controller.rb +137 -93
- data/lib/bug_bunny/exception.rb +4 -0
- data/lib/bug_bunny/producer.rb +45 -29
- data/lib/bug_bunny/request.rb +14 -2
- data/lib/bug_bunny/resource.rb +176 -138
- data/lib/bug_bunny/session.rb +97 -47
- data/lib/bug_bunny/version.rb +1 -1
- data/lib/bug_bunny.rb +1 -1
- data/test/integration/infrastructure_test.rb +61 -0
- data/test/integration/manual_client_test.rb +203 -0
- data/test/test_helper.rb +109 -0
- metadata +47 -8
- data/bin_client.rb +0 -51
- data/bin_suite.rb +0 -106
- data/bin_worker.rb +0 -26
- data/test_controller.rb +0 -49
- data/test_helper.rb +0 -20
- data/test_resource.rb +0 -19
data/bin_client.rb
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# bin_client.rb
|
|
2
|
-
require_relative 'lib/bug_bunny'
|
|
3
|
-
$stdout.sync = true # <--- Agrega esto
|
|
4
|
-
|
|
5
|
-
# 1. Configuración
|
|
6
|
-
BugBunny.configure do |config|
|
|
7
|
-
config.host = 'localhost'
|
|
8
|
-
config.username = 'wisproMQ'
|
|
9
|
-
config.password = 'wisproMQ'
|
|
10
|
-
config.vhost = 'sync.devel'
|
|
11
|
-
config.logger = Logger.new(STDOUT)
|
|
12
|
-
config.rpc_timeout = 5
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
# 2. Pool
|
|
16
|
-
POOL = ConnectionPool.new(size: 2, timeout: 5) do
|
|
17
|
-
BugBunny.create_connection
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# 3. Cliente
|
|
21
|
-
client = BugBunny.new(pool: POOL)
|
|
22
|
-
|
|
23
|
-
# --- PRUEBA 1: Publish ---
|
|
24
|
-
puts "\n[1] Enviando mensaje asíncrono (Publish)..."
|
|
25
|
-
|
|
26
|
-
# AGREGADO: exchange_type: 'topic'
|
|
27
|
-
client.publish('test/ping', exchange: 'test_exchange', exchange_type: 'topic', routing_key: 'test.ping') do |req|
|
|
28
|
-
req.body = { msg: 'Hola, soy invisible' }
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
puts " -> Enviado."
|
|
32
|
-
sleep 1
|
|
33
|
-
|
|
34
|
-
# --- PRUEBA 2: RPC ---
|
|
35
|
-
puts "\n[2] Enviando petición síncrona (Request)..."
|
|
36
|
-
|
|
37
|
-
begin
|
|
38
|
-
# AGREGADO: exchange_type: 'topic'
|
|
39
|
-
response = client.request('test/123/ping', exchange: 'test_exchange', exchange_type: 'topic', routing_key: 'test.ping') do |req|
|
|
40
|
-
req.body = { data: 'Importante' }
|
|
41
|
-
req.timeout = 3
|
|
42
|
-
req.headers['X-Source'] = 'Terminal'
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
puts " -> ✅ RESPUESTA RECIBIDA:"
|
|
46
|
-
puts " Status: #{response['status']}"
|
|
47
|
-
puts " Body: #{response['body']}"
|
|
48
|
-
|
|
49
|
-
rescue BugBunny::RequestTimeout
|
|
50
|
-
puts " -> ❌ Error: Timeout esperando respuesta."
|
|
51
|
-
end
|
data/bin_suite.rb
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
# bin_suite.rb
|
|
2
|
-
require_relative 'test_helper'
|
|
3
|
-
require_relative 'test_resource' # Cargamos la clase TestUser
|
|
4
|
-
|
|
5
|
-
# Cliente "Raw" para pruebas manuales
|
|
6
|
-
raw_client = BugBunny.new(pool: TEST_POOL)
|
|
7
|
-
|
|
8
|
-
def assert(condition, msg)
|
|
9
|
-
if condition
|
|
10
|
-
puts " ✅ PASS: #{msg}"
|
|
11
|
-
else
|
|
12
|
-
puts " ❌ FAIL: #{msg}"
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
puts "\n🔎 --- INICIANDO SUITE DE PRUEBAS BUG BUNNY ---"
|
|
17
|
-
|
|
18
|
-
# ---------------------------------------------------------
|
|
19
|
-
# TEST 1: RPC Manual (Raw Client)
|
|
20
|
-
# ---------------------------------------------------------
|
|
21
|
-
puts "\n[1] Probando RPC Manual (Client#request)..."
|
|
22
|
-
begin
|
|
23
|
-
# Notar la routing key: test_user.ping
|
|
24
|
-
response = raw_client.request('test_user/ping', exchange: 'test_exchange', exchange_type: 'topic', routing_key: 'test_user.ping')
|
|
25
|
-
assert(response['body']['message'] == 'Pong!', "Respuesta RPC recibida correctamente")
|
|
26
|
-
rescue => e
|
|
27
|
-
assert(false, "Error RPC: #{e.class} - #{e.message}")
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# ---------------------------------------------------------
|
|
31
|
-
# TEST 2: Resource Finder (ORM)
|
|
32
|
-
# ---------------------------------------------------------
|
|
33
|
-
puts "\n[2] Probando BugBunny::Resource (Estilo Rails)..."
|
|
34
|
-
|
|
35
|
-
# YA NO NECESITAS with_scope
|
|
36
|
-
puts " -> Buscando usuario ID 123..."
|
|
37
|
-
user = TestUser.find(123)
|
|
38
|
-
|
|
39
|
-
if user
|
|
40
|
-
assert(user.is_a?(TestUser), "El objeto retornado es un TestUser")
|
|
41
|
-
assert(user.name == "Gabriel", "El nombre cargó correctamente")
|
|
42
|
-
assert(user.persisted?, "El objeto figura como persistido")
|
|
43
|
-
else
|
|
44
|
-
assert(false, "No se encontró el usuario (Check worker logs)")
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# ---------------------------------------------------------
|
|
48
|
-
# TEST 3: Resource Create (ORM)
|
|
49
|
-
# ---------------------------------------------------------
|
|
50
|
-
puts "\n[3] Probando Resource Creation..."
|
|
51
|
-
puts " -> Creando usuario nuevo..."
|
|
52
|
-
new_user = TestUser.create(name: "Nuevo User", email: "new@test.com")
|
|
53
|
-
if new_user.persisted?
|
|
54
|
-
assert(new_user.persisted?, "El usuario se guardó y recibió ID")
|
|
55
|
-
assert(new_user.id.present?, "Tiene ID asignado por el worker (#{new_user.id})")
|
|
56
|
-
else
|
|
57
|
-
assert(false, "Fallo al crear usuario: #{new_user.errors.full_messages}")
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# ---------------------------------------------------------
|
|
61
|
-
# TEST 4: Validaciones Locales
|
|
62
|
-
# ---------------------------------------------------------
|
|
63
|
-
puts "\n[4] Probando Validaciones Locales..."
|
|
64
|
-
invalid_user = TestUser.new(email: "sin_nombre@test.com")
|
|
65
|
-
assert(invalid_user.valid? == false, "Usuario sin nombre es inválido")
|
|
66
|
-
assert(invalid_user.errors[:name].any?, "Tiene error en el campo :name")
|
|
67
|
-
|
|
68
|
-
# ---------------------------------------------------------
|
|
69
|
-
# TEST 5: Probando Configuración Dinámica (.with)...
|
|
70
|
-
# ---------------------------------------------------------
|
|
71
|
-
puts "\n[5] Probando Configuración Dinámica (.with)..."
|
|
72
|
-
|
|
73
|
-
# Probamos cambiar el routing key prefix temporalmente
|
|
74
|
-
begin
|
|
75
|
-
# Forzamos una routing key que no existe
|
|
76
|
-
puts " -> Intentando ruta incorrecta (esperando timeout)..."
|
|
77
|
-
TestUser.with(routing_key: 'ruta.incorrecta').find(123)
|
|
78
|
-
assert(false, "Debería haber fallado por timeout")
|
|
79
|
-
rescue BugBunny::RequestTimeout, BugBunny::ClientError
|
|
80
|
-
# Nota: Dependiendo de tu config, puede dar Timeout o 501 si llega a un worker default
|
|
81
|
-
puts " ✅ PASS: El override funcionó (timeout o error esperado en ruta incorrecta)"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Probamos que vuelve a la normalidad
|
|
85
|
-
user = TestUser.find(123)
|
|
86
|
-
assert(user.present?, " ✅ PASS: La configuración volvió a la normalidad")
|
|
87
|
-
|
|
88
|
-
# ---------------------------------------------------------
|
|
89
|
-
# TEST 6: Filtrado Complejo (Query String Nested - FIX Rack)
|
|
90
|
-
# ---------------------------------------------------------
|
|
91
|
-
puts "\n[6] Probando Resource.where con filtros anidados (Fix Rack)..."
|
|
92
|
-
|
|
93
|
-
begin
|
|
94
|
-
# Esto fallaba antes (generaba string feo en la URL: {:active=>true})
|
|
95
|
-
# Al usar Rack, esto genera: ?q[active]=true&q[roles][]=admin
|
|
96
|
-
# No necesitamos que el worker responda algo real, solo que el request SALGA sin explotar URI.
|
|
97
|
-
TestUser.where(q: { active: true, roles: ['admin'] })
|
|
98
|
-
puts " ✅ PASS: .where generó la query anidada correctamente sin errores de URI."
|
|
99
|
-
rescue URI::InvalidURIError => e
|
|
100
|
-
assert(false, "❌ FAIL: URI Inválida (El fix de Rack no funcionó): #{e.message}")
|
|
101
|
-
rescue => e
|
|
102
|
-
# Si falla por conexión o 404 está bien, lo importante es que no falle al serializar
|
|
103
|
-
puts " ✅ PASS: El request se envió correctamente (aunque el worker responda: #{e.class}). Serialización OK."
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
puts "\n🏁 SUITE FINALIZADA"
|
data/bin_worker.rb
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# bin_worker.rb
|
|
4
|
-
require 'bundler/setup'
|
|
5
|
-
require 'bug_bunny'
|
|
6
|
-
require_relative 'test_controller' # Cargamos los controladores
|
|
7
|
-
|
|
8
|
-
puts '🐰 WORKER INICIADO (Exchange: Topic)...'
|
|
9
|
-
|
|
10
|
-
# Configuración básica
|
|
11
|
-
BugBunny.configure do |config|
|
|
12
|
-
config.logger = Logger.new($stdout)
|
|
13
|
-
config.logger.level = Logger::DEBUG
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Iniciar el Consumidor
|
|
17
|
-
# Escucha en la cola 'bug_bunny_queue', atada al exchange 'test_exchange' con routing key '#' (todo)
|
|
18
|
-
connection = BugBunny.create_connection
|
|
19
|
-
|
|
20
|
-
BugBunny::Consumer.subscribe(
|
|
21
|
-
connection: connection,
|
|
22
|
-
exchange_name: 'test_exchange',
|
|
23
|
-
exchange_type: 'topic',
|
|
24
|
-
queue_name: 'bug_bunny_test_queue',
|
|
25
|
-
routing_key: '#' # Wildcard para recibir todo en este test
|
|
26
|
-
)
|
data/test_controller.rb
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# test_controller.rb
|
|
2
|
-
require 'active_support/all'
|
|
3
|
-
require 'rack'
|
|
4
|
-
require_relative 'lib/bug_bunny'
|
|
5
|
-
|
|
6
|
-
module Rabbit
|
|
7
|
-
module Controllers
|
|
8
|
-
# Nota: BugBunny buscará "TestUser" -> Rabbit::Controllers::TestUser
|
|
9
|
-
class TestUser < BugBunny::Controller
|
|
10
|
-
# GET /show (Simulado)
|
|
11
|
-
# Usado por TestUser.find(1)
|
|
12
|
-
def show
|
|
13
|
-
puts " [API] 🔍 Buscando usuario ID: #{params[:id]}"
|
|
14
|
-
if params[:id].to_i == 999
|
|
15
|
-
# Simulamos un 404
|
|
16
|
-
render status: 404, json: { error: "User not found" }
|
|
17
|
-
else
|
|
18
|
-
render status: 200, json: {
|
|
19
|
-
id: params[:id].to_i,
|
|
20
|
-
name: "Gabriel",
|
|
21
|
-
email: "gabriel@test.com",
|
|
22
|
-
persisted: true
|
|
23
|
-
}
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# POST /create
|
|
28
|
-
# Usado por TestUser.create(...)
|
|
29
|
-
def create
|
|
30
|
-
puts " [API] 💾 Creando usuario: #{params.inspect}"
|
|
31
|
-
|
|
32
|
-
# Simulamos guardado
|
|
33
|
-
new_id = rand(1000..9999)
|
|
34
|
-
|
|
35
|
-
render status: 201, json: {
|
|
36
|
-
id: new_id,
|
|
37
|
-
name: params[:name],
|
|
38
|
-
email: params[:email],
|
|
39
|
-
created_at: Time.now
|
|
40
|
-
}
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Acción custom (RPC manual)
|
|
44
|
-
def ping
|
|
45
|
-
render status: 200, json: { message: "Pong!" }
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
data/test_helper.rb
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# test_helper.rb
|
|
2
|
-
require_relative 'lib/bug_bunny'
|
|
3
|
-
|
|
4
|
-
# Forzar flush de logs
|
|
5
|
-
$stdout.sync = true
|
|
6
|
-
|
|
7
|
-
BugBunny.configure do |config|
|
|
8
|
-
config.host = 'localhost'
|
|
9
|
-
config.username = 'wisproMQ'
|
|
10
|
-
config.password = 'wisproMQ'
|
|
11
|
-
config.vhost = 'sync.devel'
|
|
12
|
-
config.logger = Logger.new(STDOUT)
|
|
13
|
-
config.logger.level = Logger::WARN # Menos ruido, solo errores importantes
|
|
14
|
-
config.rpc_timeout = 5
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# Pool compartido
|
|
18
|
-
TEST_POOL = ConnectionPool.new(size: 5, timeout: 5) do
|
|
19
|
-
BugBunny.create_connection
|
|
20
|
-
end
|
data/test_resource.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
require_relative 'test_helper'
|
|
2
|
-
|
|
3
|
-
class TestUser < BugBunny::Resource
|
|
4
|
-
# Configuración del Pool
|
|
5
|
-
self.connection_pool = -> { nil || TEST_POOL }
|
|
6
|
-
|
|
7
|
-
# Configuración del Exchange
|
|
8
|
-
self.exchange = -> { ENV['IS_STAGING'] ? 'test_exchange' : 'test_exchange' }
|
|
9
|
-
self.exchange_type = 'topic'
|
|
10
|
-
|
|
11
|
-
# ACTUALIZADO v3.0: Usamos resource_name
|
|
12
|
-
self.resource_name = 'test_users'
|
|
13
|
-
|
|
14
|
-
# ELIMINADO: attribute :id, :integer (Causa crash en v3)
|
|
15
|
-
# ELIMINADO: attribute :name, :string (Causa crash en v3)
|
|
16
|
-
|
|
17
|
-
# Las validaciones siguen funcionando igual
|
|
18
|
-
validates :name, presence: true
|
|
19
|
-
end
|