|
| 1 | +classdef tresponseStreamer < matlab.unittest.TestCase |
| 2 | +% Tests for llms.stream.reponseStreamer |
| 3 | +% |
| 4 | +% This test file contains unit tests, with a specific focus on edge cases that |
| 5 | +% are hard to trigger in end-to-end tests. |
| 6 | + |
| 7 | +% Copyright 2024 The MathWorks, Inc. |
| 8 | + |
| 9 | + methods (Test) |
| 10 | + function singleResponse(testCase) |
| 11 | + s = tracingStreamer; |
| 12 | + inp = 'data: {"choices":[{"content_filter_results":{},"delta":{"content":"foo","role":"assistant"}}]}'; |
| 13 | + inp = [inp newline 'data: [DONE]']; |
| 14 | + inp = unicode2native(inp,"UTF-8").'; |
| 15 | + testCase.verifyTrue(s.doPutData(inp,false)); |
| 16 | + testCase.verifyEqual(s.StreamFun(),"foo"); |
| 17 | + end |
| 18 | + |
| 19 | + function skipEmpty(testCase) |
| 20 | + s = tracingStreamer; |
| 21 | + inp = [... |
| 22 | + 'data: {"choices":[{"content_filter_results":{},"delta":{"content":"foo","role":"assistant"}}]}' newline ... |
| 23 | + 'data: {"choices":[]}' newline ... |
| 24 | + 'data: [DONE]']; |
| 25 | + inp = unicode2native(inp,"UTF-8").'; |
| 26 | + testCase.verifyTrue(s.doPutData(inp,false)); |
| 27 | + testCase.verifyEqual(s.StreamFun(),"foo"); |
| 28 | + end |
| 29 | + |
| 30 | + function splitResponse(testCase) |
| 31 | + % it can happen that the server sends packets split in the |
| 32 | + % middle of a JSON object. Hard to trigger on purpose. |
| 33 | + s = tracingStreamer; |
| 34 | + inp = 'data: {"choices":[{"content_filter_results":{},"delta":{"content":"foo","role":"assistant"}}]}'; |
| 35 | + inp = unicode2native(inp,"UTF-8").'; |
| 36 | + testCase.verifyFalse(s.doPutData(inp(1:42),false)); |
| 37 | + testCase.verifyFalse(s.doPutData(inp(43:end),false)); |
| 38 | + testCase.verifyEqual(s.StreamFun(),"foo"); |
| 39 | + end |
| 40 | + |
| 41 | + function ollamaFormat(testCase) |
| 42 | + s = tracingStreamer; |
| 43 | + inp = '{"model":"mistral","created_at":"2024-06-07T07:43:30.658793Z","message":{"role":"assistant","content":" Hello"},"done":false}'; |
| 44 | + inp = unicode2native(inp,"UTF-8").'; |
| 45 | + testCase.verifyFalse(s.doPutData(inp,false)); |
| 46 | + inp = '{"model":"mistral","created_at":"2024-06-07T07:43:30.658793Z","message":{"role":"assistant","content":" World"},"done":true}'; |
| 47 | + inp = unicode2native(inp,"UTF-8").'; |
| 48 | + testCase.verifyTrue(s.doPutData(inp,false)); |
| 49 | + testCase.verifyEqual(s.StreamFun(),[" Hello"," World"]); |
| 50 | + end |
| 51 | + |
| 52 | + function badJSON(testCase) |
| 53 | + s = tracingStreamer; |
| 54 | + inp = 'data: {"choices":[{"content_filter_results":{};"delta":{"content":"foo","role":"assistant"}}]}'; |
| 55 | + inp = [inp newline inp]; |
| 56 | + inp = unicode2native(inp,"UTF-8").'; |
| 57 | + testCase.verifyError(@() s.doPutData(inp,false),'llms:stream:responseStreamer:InvalidInput'); |
| 58 | + testCase.verifyEmpty(s.StreamFun()); |
| 59 | + end |
| 60 | + end |
| 61 | +end |
| 62 | + |
| 63 | +function s = tracingStreamer |
| 64 | + data = strings(1, 0); |
| 65 | + function seen = sf(str) |
| 66 | + % Append streamed text to an empty string array of length 1 |
| 67 | + if nargin > 0 |
| 68 | + data = [data, str]; |
| 69 | + end |
| 70 | + seen = data; |
| 71 | + end |
| 72 | + s = llms.stream.responseStreamer(@sf); |
| 73 | +end |
0 commit comments