22from unittest .mock import MagicMock
33
44import pytest
5+ from fastapi import HTTPException
56from fastapi .responses import Response
67
7- # Adjust import to real path
88from app .db .connector import DB
99
1010
11- # Fake connection and pool classes as per provided tests
11+ class DummyPool :
12+ def __init__ (self , conn = None , error = None ):
13+ self ._conn = conn
14+ self ._error = error
15+ self .got = False
16+ self .put_back = False
17+
18+ def getconn (self ):
19+ self .got = True
20+ if self ._error :
21+ raise self ._error
22+ return self ._conn
23+
24+ def putconn (self , conn ):
25+ self .put_back = True
26+
27+
28+ # Fake connection and pool classes
1229class FakeConn :
13- def __init__ (self ):
30+ def __init__ (self , rowcount = 1 ):
1431 self .cursor_obj = MagicMock ()
32+ # simulate cursor().rowcount attribute
33+ self .cursor_obj .rowcount = rowcount
1534
1635 def cursor (self ):
1736 return self .cursor_obj
@@ -25,7 +44,6 @@ def close(self):
2544
2645class FakePool :
2746 def __init__ (self , minconn , maxconn , dsn ):
28- # can assert on minconn, maxconn, dsn if desired
2947 self ._conn = FakeConn ()
3048 self .getconn = MagicMock (return_value = self ._conn )
3149 self .putconn = MagicMock ()
@@ -34,91 +52,66 @@ def __init__(self, minconn, maxconn, dsn):
3452
3553@pytest .fixture (autouse = True )
3654def fake_pool (monkeypatch ):
37- # Patch environment and pool initializer
55+ # Patch the SimpleConnectionPool to return our FakePool
3856 monkeypatch .setenv ("DATABASE_URL" , "postgres://fake" )
3957 monkeypatch .setattr (
4058 "app.db.connector.pool.SimpleConnectionPool" ,
4159 lambda minconn , maxconn , dsn : FakePool (minconn , maxconn , dsn ),
4260 )
43- # Reset singleton
61+ # Reset singleton instance
4462 DB ._instance = None
4563 yield
4664
4765
48- def test_create_table_and_store_chat ():
49- # Instantiate DB so __init__ runs create_table
50- db = DB (minconn = 2 , maxconn = 5 )
51- fake_pool = db .pool
52- conn = fake_pool .getconn ()
53- # Check that DDL for chats table was executed
54- expected_ddl = """
55- CREATE TABLE IF NOT EXISTS chats (
56- uid UUID PRIMARY KEY,
57- question TEXT NOT NULL,
58- answer TEXT NOT NULL,
59- votes INTEGER DEFAULT 0,
60- comment TEXT,
61- user_id UUID
62- );
63- """
64- conn .cursor_obj .execute .assert_any_call (expected_ddl )
65- # putconn called for initialization
66- fake_pool .putconn .assert_called_with (conn )
67-
68- # Now test store_chat
69- fake_pool .getconn .reset_mock ()
70- fake_pool .putconn .reset_mock ()
71- conn .cursor_obj .reset_mock ()
72-
73- test_uid = str (uuid .uuid4 ())
74- test_user = uuid .uuid4 ()
75- db .store_chat ("¿Hola?" , "¡Hola!" , test_uid , test_user )
76-
77- # Verify INSERT called with correct SQL and params
78- conn .cursor_obj .execute .assert_called_once_with (
79- """
80- INSERT into chats (uid, question, answer, votes, user_id) values (%s, %s, %s, %s, %s);
81- """ ,
82- (test_uid , "¿Hola?" , "¡Hola!" , 0 , str (test_user )),
83- )
84- fake_pool .putconn .assert_called_with (conn )
66+ @pytest .fixture (autouse = True )
67+ def setup_pool (monkeypatch ):
68+ # Prepare a DummyPool and assign to DB instances
69+ pool = DummyPool ()
70+ # Patch DB class to use our pool
71+ yield pool
8572
8673
87- def test_change_votes_success_up ():
88- db = DB ()
89- # Prepare inputs
90- chat_id = "11111111-1111-1111-1111-111111111111"
91- user_id = uuid .UUID (int = 0 )
92- # Call change_votes to upvote
93- response = db .change_votes (
94- chat_id = chat_id ,
95- up = True ,
96- down = False ,
97- equal = False ,
98- user_id = user_id ,
99- comment = "Comentario" ,
100- )
74+ def test_delete_chat_success ():
75+ db = DB (minconn = 1 , maxconn = 1 )
76+ conn = db .pool .getconn ()
77+ # Ensure rowcount > 0
78+ conn .cursor_obj .rowcount = 1
10179
80+ response = db .delete_chat (str (uuid .uuid4 ()))
81+ # Should return 204 response
10282 assert isinstance (response , Response )
10383 assert response .status_code == 204
84+ # Verify DELETE executed
85+ sql , params = conn .cursor_obj .execute .call_args [0 ]
86+ assert "DELETE FROM chats" in sql
87+ # Connection returned to pool
88+ assert db .pool .putconn .called
10489
105- # Inspect cursor calls
106- fake_conn = db .pool .getconn ()
107- fake_cursor = fake_conn .cursor_obj
108- calls = fake_cursor .execute .call_args_list
109- assert calls , "cursor.execute was not called"
110-
111- expected_params = (
112- 1 ,
113- "Comentario" ,
114- chat_id ,
115- str (user_id ),
116- )
117- # Find call with UPDATE chats and expected params
118- found = any (
119- "UPDATE chats" in call .args [0 ] and call .args [1 ] == expected_params
120- for call in calls
121- )
122- assert found , f"No UPDATE chats call with params { expected_params } , calls: { calls } "
123- # Ensure connection returned
90+
91+ def test_delete_chat_not_found ():
92+ db = DB (minconn = 1 , maxconn = 1 )
93+ conn = db .pool .getconn ()
94+ # Simulate no rows deleted
95+ conn .cursor_obj .rowcount = 0
96+
97+ with pytest .raises (HTTPException ) as exc :
98+ db .delete_chat (str (uuid .uuid4 ()))
99+ assert exc .value .status_code == 404
100+ assert "not found" in exc .value .detail .lower ()
101+ # Connection returned
124102 assert db .pool .putconn .called
103+
104+
105+ def test_delete_chat_db_error (setup_pool ):
106+ # Simulate generic exception during getconn
107+ setup_pool ._conn = None
108+ setup_pool ._error = Exception ("DB down" )
109+
110+ db = DB ()
111+ result = db .delete_chat ("any-id" )
112+ # On generic exception, should return a 204 Response
113+ assert isinstance (result , Response ), "Expected a Response on generic error"
114+ assert result .status_code == 204 , "Expected status code 204"
115+ # pool.getconn was attempted
116+ # No putconn since conn was never established
117+ assert not setup_pool .put_back , "Did not expect pool.putconn when getconn fails"
0 commit comments