|
17 | 17 | package com.google.cloud.bigquery.jdbc; |
18 | 18 |
|
19 | 19 | import static org.junit.jupiter.api.Assertions.*; |
| 20 | +import static org.mockito.ArgumentMatchers.any; |
| 21 | +import static org.mockito.ArgumentMatchers.anyBoolean; |
| 22 | +import static org.mockito.ArgumentMatchers.anyString; |
| 23 | +import static org.mockito.ArgumentMatchers.eq; |
| 24 | +import static org.mockito.ArgumentMatchers.isNull; |
| 25 | +import static org.mockito.Mockito.mock; |
| 26 | +import static org.mockito.Mockito.never; |
20 | 27 |
|
21 | 28 | import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; |
22 | 29 | import com.google.api.gax.rpc.HeaderProvider; |
23 | 30 | import com.google.api.gax.rpc.TransportChannelProvider; |
| 31 | +import com.google.auth.oauth2.GoogleCredentials; |
24 | 32 | import com.google.cloud.bigquery.BigQuery; |
25 | 33 | import com.google.cloud.bigquery.QueryJobConfiguration.JobCreationMode; |
26 | 34 | import com.google.cloud.bigquery.exception.BigQueryJdbcException; |
27 | 35 | import com.google.cloud.bigquery.storage.v1.BigQueryReadClient; |
28 | 36 | import com.google.cloud.bigquery.storage.v1.BigQueryWriteClient; |
| 37 | +import com.google.cloud.logging.Logging; |
| 38 | +import io.opentelemetry.api.OpenTelemetry; |
29 | 39 | import io.opentelemetry.api.trace.Span; |
30 | 40 | import io.opentelemetry.api.trace.Tracer; |
31 | 41 | import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension; |
|
44 | 54 | import org.junit.jupiter.api.extension.RegisterExtension; |
45 | 55 | import org.junit.jupiter.params.ParameterizedTest; |
46 | 56 | import org.junit.jupiter.params.provider.CsvSource; |
| 57 | +import org.mockito.MockedStatic; |
| 58 | +import org.mockito.Mockito; |
47 | 59 |
|
48 | 60 | public class BigQueryConnectionTest extends BigQueryJdbcLoggingBaseTest { |
49 | 61 |
|
@@ -522,4 +534,131 @@ public void testConnectionPropertiesLoggingAndMasking() throws IOException, SQLE |
522 | 534 | rootLogger.setLevel(originalLevel); |
523 | 535 | } |
524 | 536 | } |
| 537 | + |
| 538 | + @ParameterizedTest( |
| 539 | + name = |
| 540 | + "Case {index}: custom={0}, global={1}, trace={2}, log={3} -> expectTrace={4}, expectLog={5}") |
| 541 | + @CsvSource({ |
| 542 | + // hasCustom, useGlobal, enableTrace, enableLog, expectTrace, expectLog |
| 543 | + "true, true, true, true, CUSTOM, CUSTOM", |
| 544 | + "true, false, true, true, CUSTOM, CUSTOM", |
| 545 | + "false, true, true, true, GLOBAL, GLOBAL", |
| 546 | + "false, true, false, false, GLOBAL, GLOBAL", |
| 547 | + "false, false, true, false, DRIVER_MANAGED, NONE", |
| 548 | + "false, false, false, true, NONE, DRIVER_MANAGED", |
| 549 | + "false, false, true, true, DRIVER_MANAGED, DRIVER_MANAGED", |
| 550 | + "false, false, false, false, NONE, NONE" |
| 551 | + }) |
| 552 | + public void testOpenTelemetryPrecedenceHierarchy( |
| 553 | + boolean hasCustom, |
| 554 | + boolean useGlobal, |
| 555 | + boolean enableTrace, |
| 556 | + boolean enableLog, |
| 557 | + String expectTrace, |
| 558 | + String expectLog) |
| 559 | + throws Exception { |
| 560 | + |
| 561 | + DataSource ds = DataSource.fromUrl(BASE_URL); |
| 562 | + ds.setUseGlobalOpenTelemetry(useGlobal); |
| 563 | + ds.setEnableGcpTraceExporter(enableTrace); |
| 564 | + ds.setEnableGcpLogExporter(enableLog); |
| 565 | + |
| 566 | + OpenTelemetry mockCustomOtel = mock(OpenTelemetry.class); |
| 567 | + OpenTelemetry mockGlobalOtel = mock(OpenTelemetry.class); |
| 568 | + OpenTelemetry mockDriverManagedOtel = mock(OpenTelemetry.class); |
| 569 | + Logging mockLogging = mock(Logging.class); |
| 570 | + |
| 571 | + if (hasCustom) { |
| 572 | + ds.setCustomOpenTelemetry(mockCustomOtel); |
| 573 | + } |
| 574 | + |
| 575 | + try (MockedStatic<BigQueryJdbcOpenTelemetry> mockedOtel = |
| 576 | + Mockito.mockStatic(BigQueryJdbcOpenTelemetry.class); |
| 577 | + MockedStatic<BigQueryJdbcOAuthUtility> mockedAuth = |
| 578 | + Mockito.mockStatic(BigQueryJdbcOAuthUtility.class); |
| 579 | + MockedStatic<GoogleCredentials> mockedCreds = Mockito.mockStatic(GoogleCredentials.class)) { |
| 580 | + |
| 581 | + mockedCreds |
| 582 | + .when(GoogleCredentials::getApplicationDefault) |
| 583 | + .thenReturn(mock(GoogleCredentials.class)); |
| 584 | + |
| 585 | + // Mock parseOAuthProperties to always return ADC type to bypass validation |
| 586 | + mockedAuth |
| 587 | + .when(() -> BigQueryJdbcOAuthUtility.parseOAuthProperties(any(), anyString())) |
| 588 | + .thenAnswer( |
| 589 | + invocation -> { |
| 590 | + java.util.Map<String, String> props = new java.util.HashMap<>(); |
| 591 | + props.put( |
| 592 | + BigQueryJdbcUrlUtility.OAUTH_TYPE_PROPERTY_NAME, |
| 593 | + "APPLICATION_DEFAULT_CREDENTIALS"); |
| 594 | + return props; |
| 595 | + }); |
| 596 | + |
| 597 | + mockedAuth |
| 598 | + .when(() -> BigQueryJdbcOAuthUtility.getCredentials(any(), any(), any(), any())) |
| 599 | + .thenReturn(mock(GoogleCredentials.class)); |
| 600 | + |
| 601 | + mockedOtel |
| 602 | + .when( |
| 603 | + () -> |
| 604 | + BigQueryJdbcOpenTelemetry.createLoggingClient( |
| 605 | + anyBoolean(), any(), any(), any(), any())) |
| 606 | + .thenReturn(mockLogging); |
| 607 | + |
| 608 | + // Stub getOpenTelemetry to return the expected mock based on inputs |
| 609 | + mockedOtel |
| 610 | + .when( |
| 611 | + () -> |
| 612 | + BigQueryJdbcOpenTelemetry.getOpenTelemetry( |
| 613 | + eq(useGlobal), |
| 614 | + eq(enableTrace), |
| 615 | + eq(enableLog), |
| 616 | + hasCustom ? eq(mockCustomOtel) : isNull(), |
| 617 | + any(), |
| 618 | + any())) |
| 619 | + .thenAnswer( |
| 620 | + invocation -> { |
| 621 | + if (hasCustom) return mockCustomOtel; |
| 622 | + if (useGlobal) return mockGlobalOtel; |
| 623 | + if (enableTrace || enableLog) return mockDriverManagedOtel; |
| 624 | + return OpenTelemetry.noop(); |
| 625 | + }); |
| 626 | + |
| 627 | + BigQueryConnection connection = new BigQueryConnection(BASE_URL, ds); |
| 628 | + |
| 629 | + boolean shouldBeRegistered = enableLog || hasCustom || useGlobal; |
| 630 | + |
| 631 | + if (!shouldBeRegistered) { |
| 632 | + mockedOtel.verify( |
| 633 | + () -> |
| 634 | + BigQueryJdbcOpenTelemetry.registerConnection( |
| 635 | + anyString(), any(), any(), anyBoolean()), |
| 636 | + never()); |
| 637 | + } else { |
| 638 | + final OpenTelemetry expectedOtelInstance; |
| 639 | + if ("CUSTOM".equals(expectTrace) || "CUSTOM".equals(expectLog)) { |
| 640 | + expectedOtelInstance = mockCustomOtel; |
| 641 | + } else if ("GLOBAL".equals(expectTrace) || "GLOBAL".equals(expectLog)) { |
| 642 | + expectedOtelInstance = mockGlobalOtel; |
| 643 | + } else if ("DRIVER_MANAGED".equals(expectTrace) || "DRIVER_MANAGED".equals(expectLog)) { |
| 644 | + expectedOtelInstance = mockDriverManagedOtel; |
| 645 | + } else { |
| 646 | + expectedOtelInstance = OpenTelemetry.noop(); |
| 647 | + } |
| 648 | + |
| 649 | + boolean expectUseDirectGcp = "DRIVER_MANAGED".equals(expectLog); |
| 650 | + Logging expectedLogClient = expectUseDirectGcp ? mockLogging : null; |
| 651 | + |
| 652 | + mockedOtel.verify( |
| 653 | + () -> |
| 654 | + BigQueryJdbcOpenTelemetry.registerConnection( |
| 655 | + anyString(), |
| 656 | + eq(expectedOtelInstance), |
| 657 | + eq(expectedLogClient), |
| 658 | + eq(expectUseDirectGcp))); |
| 659 | + } |
| 660 | + |
| 661 | + connection.close(); |
| 662 | + } |
| 663 | + } |
525 | 664 | } |
0 commit comments