1+ /*
2+ Copyright 2024 API Testing Authors.
3+
4+ Licensed under the Apache License, Version 2.0 (the "License");
5+ you may not use this file except in compliance with the License.
6+ You may obtain a copy of the License at
7+
8+ http://www.apache.org/licenses/LICENSE-2.0
9+
10+ Unless required by applicable law or agreed to in writing, software
11+ distributed under the License is distributed on an "AS IS" BASIS,
12+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ See the License for the specific language governing permissions and
14+ limitations under the License.
15+ */
16+ package server
17+
18+ import (
19+ "context"
20+ "strings"
21+ "testing"
22+
23+ "github.com/stretchr/testify/assert"
24+ "github.com/stretchr/testify/require"
25+ )
26+
27+ // formatSQL provides basic SQL formatting for testing
28+ func formatSQL (sql string ) string {
29+ formatted := strings .ReplaceAll (sql , " FROM " , "\n FROM " )
30+ formatted = strings .ReplaceAll (formatted , " WHERE " , "\n WHERE " )
31+ formatted = strings .ReplaceAll (formatted , " ORDER BY " , "\n ORDER BY " )
32+ formatted = strings .ReplaceAll (formatted , " GROUP BY " , "\n GROUP BY " )
33+ formatted = strings .ReplaceAll (formatted , " HAVING " , "\n HAVING " )
34+ return strings .TrimSpace (formatted )
35+ }
36+
37+ func TestAIPluginBridge_BasicFunctionality (t * testing.T ) {
38+ bridge := NewAIPluginBridge ()
39+
40+ // Test default client works
41+ client := bridge .GetPlugin ("generate_sql" )
42+ assert .NotNil (t , client )
43+
44+ // Test plugin registration
45+ mockClient := NewExtendedMockAIPluginClient (true )
46+ bridge .RegisterPlugin ("test-plugin" , mockClient )
47+
48+ plugins := bridge .GetAllPlugins ()
49+ assert .Len (t , plugins , 1 )
50+ assert .Equal (t , "test-plugin" , plugins [0 ].ID )
51+ }
52+
53+ func TestMessageTransformer_DataQueryTransformations (t * testing.T ) {
54+ transformer := & MessageTransformer {}
55+
56+ t .Run ("Transform to GenerateSQLRequest" , func (t * testing.T ) {
57+ query := & DataQuery {
58+ Type : "ai" ,
59+ NaturalLanguage : "Find all users" ,
60+ DatabaseType : "postgresql" ,
61+ ExplainQuery : true ,
62+ AiContext : map [string ]string {
63+ "table" : "users" ,
64+ },
65+ }
66+
67+ req := transformer .TransformDataQueryToGenerateSQL (query )
68+
69+ assert .Equal (t , "Find all users" , req .NaturalLanguage )
70+ assert .Equal (t , "postgresql" , req .DatabaseTarget .Type )
71+ assert .True (t , req .Options .IncludeExplanation )
72+ assert .True (t , req .Options .FormatOutput )
73+ assert .Equal (t , "users" , req .Context ["table" ])
74+ })
75+
76+ t .Run ("Transform to ValidateSQLRequest" , func (t * testing.T ) {
77+ query := & DataQuery {
78+ Type : "ai" ,
79+ Sql : "SELECT * FROM users" ,
80+ DatabaseType : "mysql" ,
81+ AiContext : map [string ]string {
82+ "version" : "8.0" ,
83+ },
84+ }
85+
86+ req := transformer .TransformDataQueryToValidateSQL (query )
87+
88+ assert .Equal (t , "SELECT * FROM users" , req .Sql )
89+ assert .Equal (t , "mysql" , req .DatabaseType )
90+ assert .Equal (t , "8.0" , req .Context ["version" ])
91+ })
92+ }
93+
94+ func TestMessageTransformer_ResponseTransformations (t * testing.T ) {
95+ transformer := & MessageTransformer {}
96+
97+ t .Run ("Transform GenerateSQLResponse" , func (t * testing.T ) {
98+ resp := & GenerateSQLResponse {
99+ GeneratedSql : "SELECT * FROM users WHERE active = 1" ,
100+ ConfidenceScore : 0.95 ,
101+ Explanation : "Query to find active users" ,
102+ Suggestions : []string {"Add LIMIT" , "Add INDEX" },
103+ }
104+
105+ result := transformer .TransformGenerateSQLToDataQueryResult (resp )
106+
107+ require .NotNil (t , result )
108+ require .NotEmpty (t , result .Data )
109+
110+ dataMap := make (map [string ]string )
111+ for _ , pair := range result .Data {
112+ dataMap [pair .Key ] = pair .Value
113+ }
114+
115+ assert .Equal (t , "SELECT * FROM users WHERE active = 1" , dataMap ["generated_sql" ])
116+ assert .Equal (t , "0.95" , dataMap ["confidence_score" ])
117+ assert .Equal (t , "Query to find active users" , dataMap ["explanation" ])
118+
119+ // Check suggestions are in items
120+ assert .Len (t , result .Items , 2 )
121+ })
122+
123+ t .Run ("Transform ValidateSQLResponse" , func (t * testing.T ) {
124+ resp := & ValidateSQLResponse {
125+ IsValid : true ,
126+ FormattedSql : "SELECT *\n FROM users" ,
127+ Warnings : []string {"Consider adding LIMIT" },
128+ }
129+
130+ result := transformer .TransformValidateSQLToDataQueryResult (resp )
131+
132+ require .NotNil (t , result )
133+ require .NotEmpty (t , result .Data )
134+
135+ dataMap := make (map [string ]string )
136+ for _ , pair := range result .Data {
137+ dataMap [pair .Key ] = pair .Value
138+ }
139+
140+ assert .Equal (t , "true" , dataMap ["is_valid" ])
141+ assert .Equal (t , "SELECT *\n FROM users" , dataMap ["formatted_sql" ])
142+
143+ // Check warning is in items
144+ assert .Len (t , result .Items , 1 )
145+ })
146+ }
147+
148+ func TestMessageTransformer_Validation (t * testing.T ) {
149+ transformer := & MessageTransformer {}
150+
151+ tests := []struct {
152+ name string
153+ query * DataQuery
154+ expectError bool
155+ errorContains string
156+ }{
157+ {
158+ name : "valid AI query with natural language" ,
159+ query : & DataQuery {
160+ Type : "ai" ,
161+ NaturalLanguage : "Find users" ,
162+ DatabaseType : "postgresql" ,
163+ },
164+ expectError : false ,
165+ },
166+ {
167+ name : "valid AI query with SQL" ,
168+ query : & DataQuery {
169+ Type : "ai" ,
170+ Sql : "SELECT * FROM users" ,
171+ },
172+ expectError : false ,
173+ },
174+ {
175+ name : "invalid - empty query" ,
176+ query : & DataQuery {
177+ Type : "ai" ,
178+ },
179+ expectError : true ,
180+ errorContains : "must have either natural_language or sql field" ,
181+ },
182+ {
183+ name : "invalid database type" ,
184+ query : & DataQuery {
185+ Type : "ai" ,
186+ NaturalLanguage : "Find users" ,
187+ DatabaseType : "unsupported_db" ,
188+ },
189+ expectError : true ,
190+ errorContains : "unsupported database type" ,
191+ },
192+ }
193+
194+ for _ , tt := range tests {
195+ t .Run (tt .name , func (t * testing.T ) {
196+ err := transformer .ValidateAIQuery (tt .query )
197+
198+ if tt .expectError {
199+ assert .Error (t , err )
200+ if tt .errorContains != "" {
201+ assert .Contains (t , err .Error (), tt .errorContains )
202+ }
203+ } else {
204+ assert .NoError (t , err )
205+ }
206+ })
207+ }
208+ }
209+
210+ func TestExtendedMockAIPluginClient_Operations (t * testing.T ) {
211+ client := NewExtendedMockAIPluginClient (true )
212+ ctx := context .Background ()
213+
214+ t .Run ("GenerateSQL" , func (t * testing.T ) {
215+ req := & GenerateSQLRequest {
216+ NaturalLanguage : "Find all users" ,
217+ }
218+
219+ resp , err := client .GenerateSQL (ctx , req )
220+
221+ require .NoError (t , err )
222+ require .NotNil (t , resp )
223+ assert .NotEmpty (t , resp .GeneratedSql )
224+ assert .Greater (t , resp .ConfidenceScore , float32 (0 ))
225+ assert .NotEmpty (t , resp .Explanation )
226+ })
227+
228+ t .Run ("ValidateSQL" , func (t * testing.T ) {
229+ req := & ValidateSQLRequest {
230+ Sql : "SELECT * FROM users" ,
231+ }
232+
233+ resp , err := client .ValidateSQL (ctx , req )
234+
235+ require .NoError (t , err )
236+ require .NotNil (t , resp )
237+ assert .True (t , resp .IsValid )
238+ assert .NotEmpty (t , resp .FormattedSql )
239+ })
240+
241+ t .Run ("GetCapabilities" , func (t * testing.T ) {
242+ resp , err := client .GetCapabilities (ctx )
243+
244+ require .NoError (t , err )
245+ require .NotNil (t , resp )
246+ assert .NotEmpty (t , resp .SupportedDatabases )
247+ assert .NotEmpty (t , resp .Features )
248+ assert .Equal (t , HealthStatus_HEALTHY , resp .Status )
249+ })
250+
251+ t .Run ("IsHealthy" , func (t * testing.T ) {
252+ healthy := client .IsHealthy (ctx )
253+ assert .True (t , healthy )
254+ })
255+ }
256+
257+ func TestAIPluginBridge_ErrorSimulation (t * testing.T ) {
258+ bridge := NewAIPluginBridge ()
259+ client := NewExtendedMockAIPluginClient (true )
260+
261+ // Test error simulation
262+ client .SetSimulateErrors (true , false )
263+ bridge .RegisterPlugin ("error-test" , client )
264+
265+ ctx := context .Background ()
266+ req := & GenerateSQLRequest {
267+ NaturalLanguage : "Find users" ,
268+ }
269+
270+ _ , err := bridge .GenerateSQL (ctx , req )
271+ assert .Error (t , err )
272+ assert .Contains (t , err .Error (), "simulated generation error" )
273+ }
274+
275+ func TestAIQueryRouter_IsAIQuery_Logic (t * testing.T ) {
276+ // Create a minimal server-like struct for testing
277+ router := NewAIQueryRouter (nil )
278+
279+ tests := []struct {
280+ name string
281+ query * DataQuery
282+ expected bool
283+ }{
284+ {
285+ name : "AI type query" ,
286+ query : & DataQuery {
287+ Type : "ai" ,
288+ Sql : "SELECT * FROM users" ,
289+ },
290+ expected : true ,
291+ },
292+ {
293+ name : "Natural language query" ,
294+ query : & DataQuery {
295+ Type : "sql" ,
296+ NaturalLanguage : "Find users" ,
297+ },
298+ expected : true ,
299+ },
300+ {
301+ name : "Database type specified" ,
302+ query : & DataQuery {
303+ Type : "sql" ,
304+ Sql : "SELECT * FROM users" ,
305+ DatabaseType : "postgresql" ,
306+ },
307+ expected : true ,
308+ },
309+ {
310+ name : "Traditional SQL query" ,
311+ query : & DataQuery {
312+ Type : "sql" ,
313+ Sql : "SELECT * FROM users" ,
314+ },
315+ expected : false ,
316+ },
317+ {
318+ name : "Nil query" ,
319+ query : nil ,
320+ expected : false ,
321+ },
322+ }
323+
324+ for _ , tt := range tests {
325+ t .Run (tt .name , func (t * testing.T ) {
326+ result := router .IsAIQuery (tt .query )
327+ assert .Equal (t , tt .expected , result )
328+ })
329+ }
330+ }
331+
332+ func TestAIPluginBridge_Integration (t * testing.T ) {
333+ // Test full integration flow
334+ bridge := NewAIPluginBridge ()
335+ transformer := & MessageTransformer {}
336+
337+ // Test SQL generation flow
338+ query := & DataQuery {
339+ Type : "ai" ,
340+ NaturalLanguage : "Count all users" ,
341+ DatabaseType : "postgresql" ,
342+ ExplainQuery : true ,
343+ }
344+
345+ // Transform query
346+ req := transformer .TransformDataQueryToGenerateSQL (query )
347+ assert .NotNil (t , req )
348+
349+ // Call bridge
350+ ctx := context .Background ()
351+ resp , err := bridge .GenerateSQL (ctx , req )
352+ require .NoError (t , err )
353+ require .NotNil (t , resp )
354+
355+ // Transform response
356+ result := transformer .TransformGenerateSQLToDataQueryResult (resp )
357+ require .NotNil (t , result )
358+ require .NotEmpty (t , result .Data )
359+
360+ // Verify result structure
361+ dataMap := make (map [string ]string )
362+ for _ , pair := range result .Data {
363+ dataMap [pair .Key ] = pair .Value
364+ }
365+
366+ assert .Contains (t , dataMap , "generated_sql" )
367+ assert .Contains (t , dataMap , "confidence_score" )
368+ assert .Contains (t , dataMap , "explanation" )
369+ }
0 commit comments