@@ -7,6 +7,9 @@ import { fromString } from 'long';
77import { HttpRequest } from '../../src' ;
88import { fromRpcTypedData } from '../../src/converters/fromRpcTypedData' ;
99import Long = require( 'long' ) ;
10+ import { RpcTypedData } from '@azure/functions-core' ;
11+ import sinon = require( 'sinon' ) ;
12+ import { ResourceFactoryResolver } from '@azure/functions-extensions-base' ;
1013
1114describe ( 'fromRpcTypedData' , ( ) => {
1215 it ( 'null' , ( ) => {
@@ -110,3 +113,160 @@ describe('fromRpcTypedData', () => {
110113 expect ( result [ 1 ] . toString ( ) ) . to . equal ( '9007199254740992' ) ;
111114 } ) ;
112115} ) ;
116+
117+ describe ( 'fromRpcTypedData - modelBindingData path' , ( ) => {
118+ // Use SinonSandbox for automatic cleanup of stubs
119+ let sandbox : sinon . SinonSandbox ;
120+
121+ // Store original ResourceFactoryResolver.getInstance to restore after tests
122+ let originalGetInstance : typeof ResourceFactoryResolver . getInstance ;
123+
124+ beforeEach ( ( ) => {
125+ sandbox = sinon . createSandbox ( ) ;
126+ // Store original method
127+ originalGetInstance = ResourceFactoryResolver . getInstance . bind ( ResourceFactoryResolver ) ;
128+ } ) ;
129+
130+ afterEach ( ( ) => {
131+ // Restore all stubs and original methods
132+ sandbox . restore ( ) ;
133+ ResourceFactoryResolver . getInstance = originalGetInstance ;
134+ } ) ;
135+
136+ it ( 'should successfully create a client when modelBindingData is valid' , ( ) => {
137+ // Arrange
138+ const mockClient = {
139+ name : 'testClient' ,
140+ download : ( ) => Promise . resolve ( { readableStreamBody : Buffer . from ( 'test' ) } ) ,
141+ } ;
142+
143+ // Create mock ResourceFactoryResolver
144+ const mockResolver = {
145+ createClient : sinon . stub ( ) . returns ( mockClient ) ,
146+ } ;
147+
148+ // Replace ResourceFactoryResolver.getInstance with our mock
149+ ResourceFactoryResolver . getInstance = sinon . stub ( ) . returns ( mockResolver ) ;
150+
151+ // Create test data
152+ const modelBindingData = {
153+ content : Buffer . from ( 'test-content' ) ,
154+ source : 'blob' ,
155+ contentType : 'application/octet-stream' ,
156+ } ;
157+
158+ const data : RpcTypedData = {
159+ modelBindingData : modelBindingData ,
160+ } ;
161+
162+ // Act
163+ const result = fromRpcTypedData ( data ) ;
164+
165+ // Assert
166+ sinon . assert . calledWith ( mockResolver . createClient , 'blob' , modelBindingData ) ;
167+ expect ( result ) . to . equal ( mockClient ) ;
168+ } ) ;
169+
170+ it ( 'should handle modelBindingData with undefined source' , ( ) => {
171+ // Arrange
172+ const mockClient = { name : 'testClient' } ;
173+
174+ const mockResolver = {
175+ createClient : sinon . stub ( ) . returns ( mockClient ) ,
176+ } ;
177+
178+ ResourceFactoryResolver . getInstance = sinon . stub ( ) . returns ( mockResolver ) ;
179+
180+ const modelBindingData = {
181+ content : Buffer . from ( 'test-content' ) ,
182+ // No source specified
183+ contentType : 'application/octet-stream' ,
184+ } ;
185+
186+ const data : RpcTypedData = {
187+ modelBindingData : modelBindingData ,
188+ } ;
189+
190+ // Act
191+ const result = fromRpcTypedData ( data ) ;
192+
193+ // Assert
194+ expect ( mockResolver . createClient . calledWith ( undefined , modelBindingData ) ) . to . be . true ;
195+ expect ( result ) . to . equal ( mockClient ) ;
196+ } ) ;
197+
198+ it ( 'should throw enhanced error when ResourceFactoryResolver.createClient throws' , ( ) => {
199+ // Arrange
200+ const originalError = new Error ( 'Factory not registered' ) ;
201+
202+ const mockResolver = {
203+ createClient : sinon . stub ( ) . throws ( originalError ) ,
204+ } ;
205+
206+ ResourceFactoryResolver . getInstance = sinon . stub ( ) . returns ( mockResolver ) ;
207+
208+ const modelBindingData = {
209+ content : Buffer . from ( 'test-content' ) ,
210+ source : 'blob' ,
211+ contentType : 'application/octet-stream' ,
212+ } ;
213+
214+ const data : RpcTypedData = {
215+ modelBindingData : modelBindingData ,
216+ } ;
217+
218+ // Act & Assert
219+ expect ( ( ) => fromRpcTypedData ( data ) ) . to . throw (
220+ 'Unable to create client. Please register the extensions library with your function app. ' +
221+ 'Error: Factory not registered'
222+ ) ;
223+ } ) ;
224+
225+ it ( 'should throw enhanced error when ResourceFactoryResolver.getInstance throws' , ( ) => {
226+ // Arrange
227+ const originalError = new Error ( 'Resolver not initialized' ) ;
228+
229+ ResourceFactoryResolver . getInstance = sinon . stub ( ) . throws ( originalError ) ;
230+
231+ const modelBindingData = {
232+ content : Buffer . from ( 'test-content' ) ,
233+ source : 'blob' ,
234+ contentType : 'application/octet-stream' ,
235+ } ;
236+
237+ const data : RpcTypedData = {
238+ modelBindingData : modelBindingData ,
239+ } ;
240+
241+ // Act & Assert
242+ expect ( ( ) => fromRpcTypedData ( data ) ) . to . throw (
243+ 'Unable to create client. Please register the extensions library with your function app. ' +
244+ 'Error: Resolver not initialized'
245+ ) ;
246+ } ) ;
247+
248+ it ( 'should handle non-Error exceptions by converting to string' , ( ) => {
249+ // Arrange
250+ const mockResolver = {
251+ createClient : sinon . stub ( ) . throws ( 'String exception' ) , // Non-Error exception
252+ } ;
253+
254+ ResourceFactoryResolver . getInstance = sinon . stub ( ) . returns ( mockResolver ) ;
255+
256+ const modelBindingData = {
257+ content : Buffer . from ( 'test-content' ) ,
258+ source : 'blob' ,
259+ contentType : 'application/octet-stream' ,
260+ } ;
261+
262+ const data : RpcTypedData = {
263+ modelBindingData : modelBindingData ,
264+ } ;
265+
266+ // Act & Assert
267+ expect ( ( ) => fromRpcTypedData ( data ) ) . to . throw (
268+ 'Unable to create client. Please register the extensions library with your function app. ' +
269+ 'Error: Sinon-provided String exception'
270+ ) ;
271+ } ) ;
272+ } ) ;
0 commit comments