@@ -185,3 +185,76 @@ async def test_consumer_idempotent_skip():
185185 await consumer .handle (_StubMessage (_envelope ()))
186186 generator .generate .assert_not_awaited ()
187187 publisher .publish .assert_not_awaited ()
188+
189+
190+ def test_format_history_formats_and_empty ():
191+ from ai_server .messaging .consumers .followup_consumer import _format_history
192+ from ai_server .model .messages .followup import HistoryItem
193+
194+ assert _format_history ([]) == "(none)"
195+ out = _format_history (
196+ [
197+ HistoryItem (role = "INTERVIEWER" , content = "Q1?" ),
198+ HistoryItem (role = "INTERVIEWEE" , content = "A1" ),
199+ ]
200+ )
201+ assert out == "면접관: Q1?\n 지원자: A1"
202+
203+
204+ def test_answer_evaluation_correctness_defaults_none_and_parses ():
205+ e1 = AnswerEvaluation (specificity = 1.0 , logic = 2.0 , structure = "NONE" )
206+ assert e1 .correctness is None
207+ e2 = AnswerEvaluation .model_validate (
208+ {"specificity" : 4 , "logic" : 4 , "structure" : "FULL_STAR" , "correctness" : 3.5 }
209+ )
210+ assert e2 .correctness == 3.5
211+
212+
213+ @pytest .mark .asyncio
214+ async def test_consumer_passes_parent_category_and_history_to_generator ():
215+ generator = MagicMock ()
216+ generator .generate = AsyncMock (
217+ return_value = FollowupResult (
218+ followup_question = "새 각도 질문" ,
219+ answer_evaluation = AnswerEvaluation (
220+ specificity = 2.0 , logic = 2.0 , structure = "NONE"
221+ ),
222+ )
223+ )
224+ publisher = MagicMock ()
225+ publisher .publish = AsyncMock ()
226+ consumer = FollowupConsumer (
227+ generator = generator ,
228+ publisher = publisher ,
229+ idempotency = LruIdempotencyStore (max_size = 10 ),
230+ callback_routing_key = "callback.questions" ,
231+ )
232+ env = {
233+ "messageId" : "m-9" ,
234+ "messageType" : "generate.followup" ,
235+ "version" : "v1" ,
236+ "traceId" : "t-9" ,
237+ "publishedAt" : "2026-05-29T00:00:00Z" ,
238+ "publisher" : "core-server" ,
239+ "payload" : {
240+ "sessionId" : 99 ,
241+ "parentMessageId" : 501 ,
242+ "answerMessageId" : 502 ,
243+ "previousQuestion" : "Q?" ,
244+ "answerText" : "A." ,
245+ "mode" : "TECHNICAL" ,
246+ "jobCategory" : "BACKEND" ,
247+ "parentCategory" : "PROJECT_DEEP_DIVE" ,
248+ "history" : [
249+ {"role" : "INTERVIEWER" , "content" : "이전 질문" },
250+ {"role" : "INTERVIEWEE" , "content" : "이전 답변" },
251+ ],
252+ },
253+ "context" : {"userId" : 42 , "sessionId" : 99 },
254+ }
255+ await consumer .handle (_StubMessage (json .dumps (env ).encode ()))
256+
257+ kwargs = generator .generate .await_args .kwargs
258+ assert kwargs ["parent_category" ] == "PROJECT_DEEP_DIVE"
259+ assert "이전 질문" in kwargs ["history" ]
260+ assert "면접관:" in kwargs ["history" ]
0 commit comments