3838import java .time .temporal .ChronoUnit ;
3939import java .util .Arrays ;
4040import java .util .Base64 ;
41+ import java .util .EnumSet ;
4142import java .util .List ;
4243import java .util .Random ;
4344import java .util .concurrent .CompletableFuture ;
@@ -308,15 +309,14 @@ public static Object[][] noResponseFailureProvider() {
308309 }
309310
310311 @ Test (groups = { "integration" }, dataProvider = "testServerErrorHandlingDataProvider" )
311- public void testServerErrorHandling (ClickHouseFormat format ) {
312+ public void testServerErrorHandling (ClickHouseFormat format , boolean serverCompression , boolean useHttpCompression ) {
312313 ClickHouseNode server = getServer (ClickHouseProtocol .HTTP );
313314 try (Client client = new Client .Builder ()
314315 .addEndpoint (server .getBaseUri ())
315316 .setUsername ("default" )
316317 .setPassword ("" )
317- .useNewImplementation (true )
318- // TODO: fix in old client
319- // .useNewImplementation(System.getProperty("client.tests.useNewImplementation", "false").equals("true"))
318+ .compressServerResponse (serverCompression )
319+ .useHttpCompression (useHttpCompression )
320320 .build ()) {
321321
322322 QuerySettings querySettings = new QuerySettings ().setFormat (format );
@@ -329,17 +329,62 @@ public void testServerErrorHandling(ClickHouseFormat format) {
329329 Assert .assertTrue (e .getMessage ().startsWith ("Code: 62. DB::Exception: Syntax error (Multi-statements are not allowed): failed at position 15 (end of query)" ),
330330 "Unexpected error message: " + e .getMessage ());
331331 }
332+
333+
334+ try (QueryResponse response = client .query ("CREATE TABLE table_from_csv AS SELECT * FROM file('empty.csv')" , querySettings )
335+ .get (1 , TimeUnit .SECONDS )) {
336+ Assert .fail ("Expected exception" );
337+ } catch (ServerException e ) {
338+ e .printStackTrace ();
339+ Assert .assertEquals (e .getCode (), 636 );
340+ Assert .assertTrue (e .getMessage ().startsWith ("Code: 636. DB::Exception: The table structure cannot be extracted from a CSV format file. Error: The table structure cannot be extracted from a CSV format file: the file is empty. You can specify the structure manually: (in file/uri /var/lib/clickhouse/user_files/empty.csv). (CANNOT_EXTRACT_TABLE_STRUCTURE)" ),
341+ "Unexpected error message: " + e .getMessage ());
342+ }
343+
344+
332345 } catch (Exception e ) {
333346 e .printStackTrace ();
334347 Assert .fail (e .getMessage (), e );
335348 }
349+
350+ try (Client client = new Client .Builder ()
351+ .addEndpoint (server .getBaseUri ())
352+ .setUsername ("non-existing-user" )
353+ .setPassword ("nothing" )
354+ .compressServerResponse (serverCompression )
355+ .useHttpCompression (useHttpCompression )
356+ .build ()) {
357+
358+ try (QueryResponse response = client .query ("SELECT 1" ).get (1 , TimeUnit .SECONDS )) {
359+ Assert .fail ("Expected exception" );
360+ } catch (ServerException e ) {
361+ e .printStackTrace ();
362+ Assert .assertEquals (e .getCode (), 516 );
363+ Assert .assertTrue (e .getMessage ().startsWith ("Code: 516. DB::Exception: non-existing-user: Authentication failed: password is incorrect, or there is no user with such name. (AUTHENTICATION_FAILED)" ),
364+ e .getMessage ());
365+ } catch (Exception e ) {
366+ e .printStackTrace ();
367+ Assert .fail ("Unexpected exception" , e );
368+ }
369+ }
336370 }
337371
338372 @ DataProvider (name = "testServerErrorHandlingDataProvider" )
339- public static Object [] testServerErrorHandlingDataProvider () {
340- return new Object [] { ClickHouseFormat . JSON , ClickHouseFormat .TabSeparated , ClickHouseFormat .RowBinary };
341- }
373+ public static Object [][] testServerErrorHandlingDataProvider () {
374+ EnumSet < ClickHouseFormat > formats = EnumSet . of ( ClickHouseFormat .CSV , ClickHouseFormat .TSV ,
375+ ClickHouseFormat . JSON , ClickHouseFormat . JSONCompact );
342376
377+ Object [][] result = new Object [formats .size () * 3 ][];
378+
379+ int i = 0 ;
380+ for (ClickHouseFormat format : formats ) {
381+ result [i ++] = new Object []{format , false , false };
382+ result [i ++] = new Object []{format , true , false };
383+ result [i ++] = new Object []{format , true , true };
384+ }
385+
386+ return result ;
387+ }
343388
344389 @ Test (groups = { "integration" })
345390 public void testErrorWithSuccessfulResponse () {
@@ -377,6 +422,61 @@ public void testErrorWithSuccessfulResponse() {
377422 }
378423 }
379424
425+ @ Test (groups = { "integration" }, dataProvider = "testServerErrorsUncompressedDataProvider" )
426+ public void testServerErrorsUncompressed (int code , String message , String expectedMessage ) {
427+ WireMockServer mockServer = new WireMockServer ( WireMockConfiguration
428+ .options ().port (9090 ).notifier (new ConsoleNotifier (false )));
429+ mockServer .start ();
430+
431+ mockServer .addStubMapping (WireMock .post (WireMock .anyUrl ())
432+ .willReturn (WireMock .aResponse ()
433+ .withStatus (HttpStatus .SC_OK )
434+ .withChunkedDribbleDelay (2 , 200 )
435+ .withHeader ("X-ClickHouse-Exception-Code" , String .valueOf (code ))
436+ .withHeader ("X-ClickHouse-Summary" ,
437+ "{ \" read_bytes\" : \" 10\" , \" read_rows\" : \" 1\" }" )
438+ .withBody (message ))
439+ .build ());
440+
441+ try (Client client = new Client .Builder ().addEndpoint (Protocol .HTTP , "localhost" , mockServer .port (), false )
442+ .setUsername ("default" )
443+ .setPassword ("" )
444+ .compressServerResponse (false )
445+ .build ()) {
446+
447+ try (QueryResponse response = client .query ("SELECT 1" ).get (1 , TimeUnit .SECONDS )) {
448+ Assert .fail ("Expected exception" );
449+ } catch (ServerException e ) {
450+ e .printStackTrace ();
451+ Assert .assertEquals (e .getCode (), code );
452+ Assert .assertEquals (e .getMessage (), expectedMessage );
453+ } catch (Exception e ) {
454+ e .printStackTrace ();
455+ Assert .fail ("Unexpected exception" , e );
456+ }
457+ } finally {
458+ mockServer .stop ();
459+ }
460+ }
461+
462+ @ DataProvider (name = "testServerErrorsUncompressedDataProvider" )
463+ public static Object [][] testServerErrorsUncompressedDataProvider () {
464+ return new Object [][] {
465+ { 241 , "Code: 241. DB::Exception: Memory limit (for query) exceeded: would use 97.21 MiB" ,
466+ "Code: 241. DB::Exception: Memory limit (for query) exceeded: would use 97.21 MiB" },
467+ {900 , "Code: 900. DB::Exception: \uD83D \uDCBE Floppy disk is full" ,
468+ "Code: 900. DB::Exception: \uD83D \uDCBE Floppy disk is full" },
469+ {901 , "Code: 901. DB::Exception: I write, erase, rewrite\n " +
470+ "Erase again, and then\n " +
471+ "A poppy blooms\n " +
472+ " (by Katsushika Hokusai)" ,
473+ "Code: 901. DB::Exception: I write, erase, rewrite " +
474+ "Erase again, and then " +
475+ "A poppy blooms" +
476+ " (by Katsushika Hokusai)" }
477+ };
478+ }
479+
380480 @ Test (groups = { "integration" })
381481 public void testAdditionalHeaders () {
382482 WireMockServer mockServer = new WireMockServer ( WireMockConfiguration
0 commit comments