|
79 | 79 | import java.util.concurrent.CountDownLatch; |
80 | 80 | import java.util.concurrent.ExecutorService; |
81 | 81 | import java.util.concurrent.Executors; |
| 82 | +import java.util.function.BiFunction; |
82 | 83 | import java.util.logging.Handler; |
83 | 84 | import java.util.logging.Level; |
84 | 85 | import java.util.logging.LogRecord; |
@@ -493,7 +494,12 @@ public void onModelErrorCallback_populatesCorrectFields() throws Exception { |
493 | 494 | assertEquals("ERROR", row.get("status")); |
494 | 495 | assertEquals("model error message", row.get("error_message")); |
495 | 496 | assertNotNull(row.get("latency_ms")); |
496 | | - assertEquals(false, row.get("is_truncated")); |
| 497 | + assertFalse("Row should not contain content when it is null", row.containsKey("content")); |
| 498 | + assertFalse( |
| 499 | + "Row should not contain content_parts when it is null", row.containsKey("content_parts")); |
| 500 | + assertFalse( |
| 501 | + "Row should not contain is_truncated when content is null", |
| 502 | + row.containsKey("is_truncated")); |
497 | 503 | } |
498 | 504 |
|
499 | 505 | @Test |
@@ -649,6 +655,108 @@ protected StreamWriter createWriter() { |
649 | 655 | "attributes should not contain session_metadata", attributes.has("session_metadata")); |
650 | 656 | } |
651 | 657 |
|
| 658 | + @Test |
| 659 | + public void logEvent_usesContentFormatter_whenConfigured() throws Exception { |
| 660 | + BiFunction<Object, String, Object> formatter = |
| 661 | + (content, eventType) -> { |
| 662 | + if (Objects.equals(eventType, "USER_MESSAGE_RECEIVED") && content instanceof Content) { |
| 663 | + return "Formatted: " + content; |
| 664 | + } |
| 665 | + return content; |
| 666 | + }; |
| 667 | + |
| 668 | + BigQueryLoggerConfig formattedConfig = config.toBuilder().contentFormatter(formatter).build(); |
| 669 | + PluginState formattedState = |
| 670 | + new PluginState(formattedConfig) { |
| 671 | + @Override |
| 672 | + protected BigQueryWriteClient createWriteClient(BigQueryLoggerConfig config) { |
| 673 | + return mockWriteClient; |
| 674 | + } |
| 675 | + |
| 676 | + @Override |
| 677 | + protected StreamWriter createWriter() { |
| 678 | + return mockWriter; |
| 679 | + } |
| 680 | + }; |
| 681 | + BigQueryAgentAnalyticsPlugin formattedPlugin = |
| 682 | + new BigQueryAgentAnalyticsPlugin(formattedConfig, mockBigQuery, formattedState); |
| 683 | + |
| 684 | + Content content = Content.fromParts(Part.fromText("test message")); |
| 685 | + formattedPlugin.onUserMessageCallback(mockInvocationContext, content).blockingSubscribe(); |
| 686 | + |
| 687 | + Map<String, Object> row = formattedState.getBatchProcessor("invocation_id").queue.poll(); |
| 688 | + assertNotNull(row); |
| 689 | + assertTrue(row.get("content").toString().contains("Formatted: ")); |
| 690 | + } |
| 691 | + |
| 692 | + @Test |
| 693 | + public void logEvent_handlesNullContentFromFormatter() throws Exception { |
| 694 | + BiFunction<Object, String, Object> formatter = (content, eventType) -> null; |
| 695 | + |
| 696 | + BigQueryLoggerConfig formattedConfig = config.toBuilder().contentFormatter(formatter).build(); |
| 697 | + PluginState formattedState = |
| 698 | + new PluginState(formattedConfig) { |
| 699 | + @Override |
| 700 | + protected BigQueryWriteClient createWriteClient(BigQueryLoggerConfig config) { |
| 701 | + return mockWriteClient; |
| 702 | + } |
| 703 | + |
| 704 | + @Override |
| 705 | + protected StreamWriter createWriter() { |
| 706 | + return mockWriter; |
| 707 | + } |
| 708 | + }; |
| 709 | + BigQueryAgentAnalyticsPlugin formattedPlugin = |
| 710 | + new BigQueryAgentAnalyticsPlugin(formattedConfig, mockBigQuery, formattedState); |
| 711 | + |
| 712 | + Content content = Content.fromParts(Part.fromText("test message")); |
| 713 | + formattedPlugin.onUserMessageCallback(mockInvocationContext, content).blockingSubscribe(); |
| 714 | + |
| 715 | + Map<String, Object> row = formattedState.getBatchProcessor("invocation_id").queue.poll(); |
| 716 | + assertNotNull(row); |
| 717 | + assertFalse( |
| 718 | + "Row should not contain content when formatter returns null", row.containsKey("content")); |
| 719 | + assertFalse( |
| 720 | + "Row should not contain content_parts when formatter returns null", |
| 721 | + row.containsKey("content_parts")); |
| 722 | + } |
| 723 | + |
| 724 | + @Test |
| 725 | + public void logEvent_handlesExceptionFromFormatter() throws Exception { |
| 726 | + BiFunction<Object, String, Object> formatter = |
| 727 | + (content, eventType) -> { |
| 728 | + throw new RuntimeException("Formatter error"); |
| 729 | + }; |
| 730 | + |
| 731 | + BigQueryLoggerConfig formattedConfig = config.toBuilder().contentFormatter(formatter).build(); |
| 732 | + PluginState formattedState = |
| 733 | + new PluginState(formattedConfig) { |
| 734 | + @Override |
| 735 | + protected BigQueryWriteClient createWriteClient(BigQueryLoggerConfig config) { |
| 736 | + return mockWriteClient; |
| 737 | + } |
| 738 | + |
| 739 | + @Override |
| 740 | + protected StreamWriter createWriter() { |
| 741 | + return mockWriter; |
| 742 | + } |
| 743 | + }; |
| 744 | + BigQueryAgentAnalyticsPlugin formattedPlugin = |
| 745 | + new BigQueryAgentAnalyticsPlugin(formattedConfig, mockBigQuery, formattedState); |
| 746 | + |
| 747 | + Content content = Content.fromParts(Part.fromText("test message")); |
| 748 | + formattedPlugin.onUserMessageCallback(mockInvocationContext, content).blockingSubscribe(); |
| 749 | + |
| 750 | + Map<String, Object> row = formattedState.getBatchProcessor("invocation_id").queue.poll(); |
| 751 | + assertNotNull(row); |
| 752 | + assertFalse( |
| 753 | + "Row should not contain content when formatter throws exception", |
| 754 | + row.containsKey("content")); |
| 755 | + assertFalse( |
| 756 | + "Row should not contain content_parts when formatter throws exception", |
| 757 | + row.containsKey("content_parts")); |
| 758 | + } |
| 759 | + |
652 | 760 | @Test |
653 | 761 | public void maybeUpgradeSchema_addsNewTopLevelField() throws Exception { |
654 | 762 | Table mockTable = mock(Table.class); |
|
0 commit comments