11import { describe , it , } from 'vitest' ;
2- import { ClassifierSdk , ClassifyImageOptions , ClassifyResponse , ImageFormat } from '../../src/main ' ;
2+ import { ClassificationOutput , ClassifierSdk , ClassifyImageInput , ImageFormat } from '../../src' ;
33import fs from 'fs' ;
44import { randomUUID } from 'crypto' ;
55
@@ -31,7 +31,119 @@ describe('classifierHelper', () => {
3131} ) ;
3232
3333describe ( 'classifyImage function' , ( ) => {
34- it ( 'should classify Steamboat-willie.jpg and return responses (integration smoke test)' , async ( { expect} ) => {
34+ it ( 'should classify 10 images in a single request and return responses (integration smoke test)' , async ( { expect, annotate} ) => {
35+ // This is a smoke test. You must have a running gRPC server at localhost:50051 for this to pass.
36+ // You may want to mock the gRPC client for true unit testing.
37+ const imagePath = __dirname + '/Steamboat-willie.jpg' ;
38+ const sdk = new ClassifierSdk ( {
39+ deploymentId : process . env . VITE_ATHENA_DEPLOYMENT_ID ,
40+ affiliate : process . env . VITE_ATHENA_AFFILIATE ,
41+ authentication : {
42+ issuerUrl : process . env . VITE_OAUTH_ISSUER ,
43+ clientId : process . env . VITE_ATHENA_CLIENT_ID ,
44+ clientSecret : process . env . VITE_ATHENA_CLIENT_SECRET ,
45+ scope : 'manage:classify'
46+ }
47+ } ) ;
48+
49+ // Generate 10 unique correlationIds
50+ const correlationIds =
51+ [
52+ randomUUID ( ) . toString ( ) ,
53+ randomUUID ( ) . toString ( ) ,
54+ randomUUID ( ) . toString ( )
55+ ]
56+
57+ correlationIds . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
58+
59+ annotate ( `Correlation IDs: ${ correlationIds . join ( ', ' ) } ` ) ;
60+
61+ // Create 10 input objects, each with a new stream and unique correlationId
62+ const inputs : ClassifyImageInput [ ] = correlationIds . map ( ( correlationId ) => ( {
63+ imageStream : fs . createReadStream ( imagePath ) ,
64+ format : ImageFormat . PNG ,
65+ correlationId
66+ } ) ) ;
67+
68+ // Create a promise to wrap the event emitter event 'data'
69+ const promise = new Promise < ClassificationOutput [ ] > ( ( resolve , reject ) => {
70+ const results :ClassificationOutput [ ] = [ ] ;
71+
72+ sdk . on ( 'data' , ( data ) => {
73+ if ( data . globalError )
74+ {
75+ reject ( data . globalError ) ;
76+ }
77+
78+ // Check that all correlationIds are present in the outputs
79+ for ( const result of data . outputs )
80+ {
81+ if ( correlationIds . includes ( result . correlationId ) ) {
82+ results . push ( result ) ;
83+ }
84+ }
85+ if ( results . length == correlationIds . length ) {
86+ resolve ( results ) ;
87+ }
88+ } ) ;
89+ sdk . once ( 'error' , ( err ) => {
90+ reject ( err ) ;
91+ } ) ;
92+ } ) ;
93+
94+ let error : any = undefined ;
95+
96+ await sdk . open ( ) ;
97+
98+ try {
99+ await sdk . sendClassifyRequest ( inputs ) ;
100+ } catch ( err ) {
101+ error = err ;
102+ }
103+
104+ // Wait for classifier to process some data....
105+ const outputs = await promise ;
106+ sdk . close ( ) ;
107+
108+ expect ( error ) . toBeUndefined ( ) ;
109+
110+ outputs . sort ( ( a , b ) => a . correlationId . localeCompare ( b . correlationId ) ) ;
111+
112+ expect ( outputs ) . toBeDefined ( ) ;
113+ // Check that all correlationIds are present in the outputs
114+ expect ( outputs . length ) . toBe ( correlationIds . length ) ;
115+ expect ( outputs ) . toMatchObject ( [
116+ {
117+ correlationId : correlationIds [ 0 ] ,
118+ classifications : expect . arrayContaining ( [
119+ {
120+ label : expect . any ( String ) ,
121+ weight : expect . any ( Number )
122+ }
123+ ] )
124+ } as ClassificationOutput ,
125+ {
126+ correlationId : correlationIds [ 1 ] ,
127+ classifications : expect . arrayContaining ( [
128+ {
129+ label : expect . any ( String ) ,
130+ weight : expect . any ( Number )
131+ }
132+ ] )
133+ } as ClassificationOutput ,
134+ {
135+ correlationId : correlationIds [ 2 ] ,
136+ classifications : expect . arrayContaining ( [
137+ {
138+ label : expect . any ( String ) ,
139+ weight : expect . any ( Number )
140+ }
141+ ] )
142+ } as ClassificationOutput
143+ ] ) ;
144+ } , 120000 ) ;
145+
146+ it ( 'should classify Steamboat-willie.jpg and return responses (integration smoke test)' , async ( { expect, annotate} ) => {
35147 // This is a smoke test. You must have a running gRPC server at localhost:50051 for this to pass.
36148 // You may want to mock the gRPC client for true unit testing.
37149 const imagePath = __dirname + '/Steamboat-willie.jpg' ;
@@ -48,16 +160,24 @@ describe('classifyImage function', () => {
48160
49161 const correlationId = randomUUID ( ) ;
50162
163+ annotate ( `Correlation IDs: ${ correlationId } ` ) ;
164+
51165 // Create a promise to wrap the event emitter event 'data'
52- const promise = new Promise < ClassifyResponse > ( ( resolve , reject ) => {
53- sdk . once ( 'data' , ( data ) => {
166+ const promise = new Promise < ClassificationOutput [ ] > ( ( resolve , reject ) => {
167+ // Add a timeout to reject the promise if no data is received in 30 seconds
168+ const timeout = setTimeout ( ( ) => {
169+ reject ( new Error ( 'Timeout waiting for classification response' ) ) ;
170+ } , 30000 ) ;
171+
172+ sdk . on ( 'data' , ( data ) => {
54173 const byCorrelationId = data . outputs . filter ( o => o . correlationId === correlationId ) ;
55174 if ( byCorrelationId . length > 0 ) {
56- resolve ( data ) ;
175+ clearTimeout ( timeout ) ;
176+ resolve ( byCorrelationId ) ;
57177 }
58- sdk . close ( ) ;
59178 } ) ;
60179 sdk . once ( 'error' , ( err ) => {
180+ clearTimeout ( timeout ) ;
61181 reject ( err ) ;
62182 } ) ;
63183 } ) ;
@@ -68,9 +188,8 @@ describe('classifyImage function', () => {
68188 await sdk . open ( ) ;
69189
70190 const imageStream = fs . createReadStream ( imagePath ) ;
71- const options : ClassifyImageOptions = {
191+ const options : ClassifyImageInput = {
72192 imageStream,
73- format : ImageFormat . PNG ,
74193 correlationId
75194 } ;
76195 try {
@@ -81,12 +200,20 @@ describe('classifyImage function', () => {
81200
82201 // Wait for classifier to process some data....
83202 const first = await promise ;
203+ sdk . close ( ) ;
84204
85205 expect ( first ) . toBeDefined ( ) ;
86-
87- const byCorrelationId = first . outputs . filter ( o => o . correlationId === correlationId ) ;
88-
89- expect ( byCorrelationId . length ) . toBeGreaterThan ( 0 ) ;
206+ expect ( first ) . toMatchObject ( [
207+ {
208+ correlationId,
209+ classifications : expect . arrayContaining ( [
210+ {
211+ label : expect . any ( String ) ,
212+ weight : expect . any ( Number )
213+ }
214+ ] )
215+ } as ClassificationOutput
216+ ] ) ;
90217
91218 // Accept either a successful call or a connection error (for CI/dev convenience)
92219 expect ( error ) . toBeUndefined ( ) ;
0 commit comments