You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							643 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							643 lines
						
					
					
						
							17 KiB
						
					
					
				| package schema | |
| 
 | |
| import ( | |
| 	"encoding/json" | |
| 	"net/http" | |
| 	"net/http/httptest" | |
| 	"testing" | |
| 	"time" | |
| 
 | |
| 	"github.com/linkedin/goavro/v2" | |
| ) | |
| 
 | |
| // TestFullIntegration_AvroWorkflow tests the complete Avro workflow | |
| func TestFullIntegration_AvroWorkflow(t *testing.T) { | |
| 	// Create comprehensive mock schema registry | |
| 	server := createMockSchemaRegistry(t) | |
| 	defer server.Close() | |
| 
 | |
| 	// Create manager with realistic configuration | |
| 	config := ManagerConfig{ | |
| 		RegistryURL:     server.URL, | |
| 		ValidationMode:  ValidationPermissive, | |
| 		EnableMirroring: false, | |
| 		CacheTTL:        "5m", | |
| 	} | |
| 
 | |
| 	manager, err := NewManager(config) | |
| 	if err != nil { | |
| 		t.Fatalf("Failed to create manager: %v", err) | |
| 	} | |
| 
 | |
| 	// Test 1: Producer workflow - encode schematized message | |
| 	t.Run("Producer_Workflow", func(t *testing.T) { | |
| 		// Create realistic user data (with proper Avro union handling) | |
| 		userData := map[string]interface{}{ | |
| 			"id":    int32(12345), | |
| 			"name":  "Alice Johnson", | |
| 			"email": map[string]interface{}{"string": "alice@example.com"}, // Avro union | |
| 			"age":   map[string]interface{}{"int": int32(28)},              // Avro union | |
| 			"preferences": map[string]interface{}{ | |
| 				"Preferences": map[string]interface{}{ // Avro union with record type | |
| 					"notifications": true, | |
| 					"theme":         "dark", | |
| 				}, | |
| 			}, | |
| 		} | |
| 
 | |
| 		// Create Avro message (simulate what a Kafka producer would send) | |
| 		avroSchema := getUserAvroSchema() | |
| 		codec, err := goavro.NewCodec(avroSchema) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to create Avro codec: %v", err) | |
| 		} | |
| 
 | |
| 		avroBinary, err := codec.BinaryFromNative(nil, userData) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to encode Avro data: %v", err) | |
| 		} | |
| 
 | |
| 		// Create Confluent envelope (what Kafka Gateway receives) | |
| 		confluentMsg := CreateConfluentEnvelope(FormatAvro, 1, nil, avroBinary) | |
| 
 | |
| 		// Decode message (Produce path processing) | |
| 		decodedMsg, err := manager.DecodeMessage(confluentMsg) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to decode message: %v", err) | |
| 		} | |
| 
 | |
| 		// Verify decoded data | |
| 		if decodedMsg.SchemaID != 1 { | |
| 			t.Errorf("Expected schema ID 1, got %d", decodedMsg.SchemaID) | |
| 		} | |
| 
 | |
| 		if decodedMsg.SchemaFormat != FormatAvro { | |
| 			t.Errorf("Expected Avro format, got %v", decodedMsg.SchemaFormat) | |
| 		} | |
| 
 | |
| 		// Verify field values | |
| 		fields := decodedMsg.RecordValue.Fields | |
| 		if fields["id"].GetInt32Value() != 12345 { | |
| 			t.Errorf("Expected id=12345, got %v", fields["id"].GetInt32Value()) | |
| 		} | |
| 
 | |
| 		if fields["name"].GetStringValue() != "Alice Johnson" { | |
| 			t.Errorf("Expected name='Alice Johnson', got %v", fields["name"].GetStringValue()) | |
| 		} | |
| 
 | |
| 		t.Logf("Successfully processed producer message with %d fields", len(fields)) | |
| 	}) | |
| 
 | |
| 	// Test 2: Consumer workflow - reconstruct original message | |
| 	t.Run("Consumer_Workflow", func(t *testing.T) { | |
| 		// Create test RecordValue (simulate what's stored in SeaweedMQ) | |
| 		testData := map[string]interface{}{ | |
| 			"id":    int32(67890), | |
| 			"name":  "Bob Smith", | |
| 			"email": map[string]interface{}{"string": "bob@example.com"}, | |
| 			"age":   map[string]interface{}{"int": int32(35)}, // Avro union | |
| 		} | |
| 		recordValue := MapToRecordValue(testData) | |
| 
 | |
| 		// Reconstruct message (Fetch path processing) | |
| 		reconstructedMsg, err := manager.EncodeMessage(recordValue, 1, FormatAvro) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to reconstruct message: %v", err) | |
| 		} | |
| 
 | |
| 		// Verify reconstructed message can be parsed | |
| 		envelope, ok := ParseConfluentEnvelope(reconstructedMsg) | |
| 		if !ok { | |
| 			t.Fatal("Failed to parse reconstructed envelope") | |
| 		} | |
| 
 | |
| 		if envelope.SchemaID != 1 { | |
| 			t.Errorf("Expected schema ID 1, got %d", envelope.SchemaID) | |
| 		} | |
| 
 | |
| 		// Verify the payload can be decoded by Avro | |
| 		avroSchema := getUserAvroSchema() | |
| 		codec, err := goavro.NewCodec(avroSchema) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to create Avro codec: %v", err) | |
| 		} | |
| 
 | |
| 		decodedData, _, err := codec.NativeFromBinary(envelope.Payload) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to decode reconstructed Avro data: %v", err) | |
| 		} | |
| 
 | |
| 		// Verify data integrity | |
| 		decodedMap := decodedData.(map[string]interface{}) | |
| 		if decodedMap["id"] != int32(67890) { | |
| 			t.Errorf("Expected id=67890, got %v", decodedMap["id"]) | |
| 		} | |
| 
 | |
| 		if decodedMap["name"] != "Bob Smith" { | |
| 			t.Errorf("Expected name='Bob Smith', got %v", decodedMap["name"]) | |
| 		} | |
| 
 | |
| 		t.Logf("Successfully reconstructed consumer message: %d bytes", len(reconstructedMsg)) | |
| 	}) | |
| 
 | |
| 	// Test 3: Round-trip integrity | |
| 	t.Run("Round_Trip_Integrity", func(t *testing.T) { | |
| 		originalData := map[string]interface{}{ | |
| 			"id":    int32(99999), | |
| 			"name":  "Charlie Brown", | |
| 			"email": map[string]interface{}{"string": "charlie@example.com"}, | |
| 			"age":   map[string]interface{}{"int": int32(42)}, // Avro union | |
| 			"preferences": map[string]interface{}{ | |
| 				"Preferences": map[string]interface{}{ // Avro union with record type | |
| 					"notifications": true, | |
| 					"theme":         "dark", | |
| 				}, | |
| 			}, | |
| 		} | |
| 
 | |
| 		// Encode -> Decode -> Encode -> Decode | |
| 		avroSchema := getUserAvroSchema() | |
| 		codec, _ := goavro.NewCodec(avroSchema) | |
| 
 | |
| 		// Step 1: Original -> Confluent | |
| 		avroBinary, _ := codec.BinaryFromNative(nil, originalData) | |
| 		confluentMsg := CreateConfluentEnvelope(FormatAvro, 1, nil, avroBinary) | |
| 
 | |
| 		// Step 2: Confluent -> RecordValue | |
| 		decodedMsg, _ := manager.DecodeMessage(confluentMsg) | |
| 
 | |
| 		// Step 3: RecordValue -> Confluent | |
| 		reconstructedMsg, encodeErr := manager.EncodeMessage(decodedMsg.RecordValue, 1, FormatAvro) | |
| 		if encodeErr != nil { | |
| 			t.Fatalf("Failed to encode message: %v", encodeErr) | |
| 		} | |
| 
 | |
| 		// Verify the reconstructed message is valid | |
| 		if len(reconstructedMsg) == 0 { | |
| 			t.Fatal("Reconstructed message is empty") | |
| 		} | |
| 
 | |
| 		// Step 4: Confluent -> Verify | |
| 		finalDecodedMsg, err := manager.DecodeMessage(reconstructedMsg) | |
| 		if err != nil { | |
| 			// Debug: Check if the reconstructed message is properly formatted | |
| 			envelope, ok := ParseConfluentEnvelope(reconstructedMsg) | |
| 			if !ok { | |
| 				t.Fatalf("Round-trip failed: reconstructed message is not a valid Confluent envelope") | |
| 			} | |
| 			t.Logf("Debug: Envelope SchemaID=%d, Format=%v, PayloadLen=%d", | |
| 				envelope.SchemaID, envelope.Format, len(envelope.Payload)) | |
| 			t.Fatalf("Round-trip failed: %v", err) | |
| 		} | |
| 
 | |
| 		// Verify data integrity through complete round-trip | |
| 		finalFields := finalDecodedMsg.RecordValue.Fields | |
| 		if finalFields["id"].GetInt32Value() != 99999 { | |
| 			t.Error("Round-trip failed for id field") | |
| 		} | |
| 
 | |
| 		if finalFields["name"].GetStringValue() != "Charlie Brown" { | |
| 			t.Error("Round-trip failed for name field") | |
| 		} | |
| 
 | |
| 		t.Log("Round-trip integrity test passed") | |
| 	}) | |
| } | |
| 
 | |
| // TestFullIntegration_MultiFormatSupport tests all schema formats together | |
| func TestFullIntegration_MultiFormatSupport(t *testing.T) { | |
| 	server := createMockSchemaRegistry(t) | |
| 	defer server.Close() | |
| 
 | |
| 	config := ManagerConfig{ | |
| 		RegistryURL:    server.URL, | |
| 		ValidationMode: ValidationPermissive, | |
| 	} | |
| 
 | |
| 	manager, err := NewManager(config) | |
| 	if err != nil { | |
| 		t.Fatalf("Failed to create manager: %v", err) | |
| 	} | |
| 
 | |
| 	testCases := []struct { | |
| 		name     string | |
| 		format   Format | |
| 		schemaID uint32 | |
| 		testData interface{} | |
| 	}{ | |
| 		{ | |
| 			name:     "Avro_Format", | |
| 			format:   FormatAvro, | |
| 			schemaID: 1, | |
| 			testData: map[string]interface{}{ | |
| 				"id":   int32(123), | |
| 				"name": "Avro User", | |
| 			}, | |
| 		}, | |
| 		{ | |
| 			name:     "JSON_Schema_Format", | |
| 			format:   FormatJSONSchema, | |
| 			schemaID: 3, | |
| 			testData: map[string]interface{}{ | |
| 				"id":     float64(456), // JSON numbers are float64 | |
| 				"name":   "JSON User", | |
| 				"active": true, | |
| 			}, | |
| 		}, | |
| 	} | |
| 
 | |
| 	for _, tc := range testCases { | |
| 		t.Run(tc.name, func(t *testing.T) { | |
| 			// Create RecordValue from test data | |
| 			recordValue := MapToRecordValue(tc.testData.(map[string]interface{})) | |
| 
 | |
| 			// Test encoding | |
| 			encoded, err := manager.EncodeMessage(recordValue, tc.schemaID, tc.format) | |
| 			if err != nil { | |
| 				if tc.format == FormatProtobuf { | |
| 					// Protobuf encoding may fail due to incomplete implementation | |
| 					t.Skipf("Protobuf encoding not fully implemented: %v", err) | |
| 				} else { | |
| 					t.Fatalf("Failed to encode %s message: %v", tc.name, err) | |
| 				} | |
| 			} | |
| 
 | |
| 			// Test decoding | |
| 			decoded, err := manager.DecodeMessage(encoded) | |
| 			if err != nil { | |
| 				t.Fatalf("Failed to decode %s message: %v", tc.name, err) | |
| 			} | |
| 
 | |
| 			// Verify format | |
| 			if decoded.SchemaFormat != tc.format { | |
| 				t.Errorf("Expected format %v, got %v", tc.format, decoded.SchemaFormat) | |
| 			} | |
| 
 | |
| 			// Verify schema ID | |
| 			if decoded.SchemaID != tc.schemaID { | |
| 				t.Errorf("Expected schema ID %d, got %d", tc.schemaID, decoded.SchemaID) | |
| 			} | |
| 
 | |
| 			t.Logf("Successfully processed %s format", tc.name) | |
| 		}) | |
| 	} | |
| } | |
| 
 | |
| // TestIntegration_CachePerformance tests caching behavior under load | |
| func TestIntegration_CachePerformance(t *testing.T) { | |
| 	server := createMockSchemaRegistry(t) | |
| 	defer server.Close() | |
| 
 | |
| 	config := ManagerConfig{ | |
| 		RegistryURL:    server.URL, | |
| 		ValidationMode: ValidationPermissive, | |
| 	} | |
| 
 | |
| 	manager, err := NewManager(config) | |
| 	if err != nil { | |
| 		t.Fatalf("Failed to create manager: %v", err) | |
| 	} | |
| 
 | |
| 	// Create test message | |
| 	testData := map[string]interface{}{ | |
| 		"id":   int32(1), | |
| 		"name": "Cache Test", | |
| 	} | |
| 
 | |
| 	avroSchema := getUserAvroSchema() | |
| 	codec, _ := goavro.NewCodec(avroSchema) | |
| 	avroBinary, _ := codec.BinaryFromNative(nil, testData) | |
| 	testMsg := CreateConfluentEnvelope(FormatAvro, 1, nil, avroBinary) | |
| 
 | |
| 	// First decode (should hit registry) | |
| 	start := time.Now() | |
| 	_, err = manager.DecodeMessage(testMsg) | |
| 	if err != nil { | |
| 		t.Fatalf("First decode failed: %v", err) | |
| 	} | |
| 	firstDuration := time.Since(start) | |
| 
 | |
| 	// Subsequent decodes (should hit cache) | |
| 	start = time.Now() | |
| 	for i := 0; i < 100; i++ { | |
| 		_, err = manager.DecodeMessage(testMsg) | |
| 		if err != nil { | |
| 			t.Fatalf("Cached decode failed: %v", err) | |
| 		} | |
| 	} | |
| 	cachedDuration := time.Since(start) | |
| 
 | |
| 	// Verify cache performance improvement | |
| 	avgCachedTime := cachedDuration / 100 | |
| 	if avgCachedTime >= firstDuration { | |
| 		t.Logf("Warning: Cache may not be effective. First: %v, Avg Cached: %v", | |
| 			firstDuration, avgCachedTime) | |
| 	} | |
| 
 | |
| 	// Check cache stats | |
| 	decoders, schemas, subjects := manager.GetCacheStats() | |
| 	if decoders == 0 || schemas == 0 { | |
| 		t.Error("Expected non-zero cache stats") | |
| 	} | |
| 
 | |
| 	t.Logf("Cache performance: First decode: %v, Average cached: %v", | |
| 		firstDuration, avgCachedTime) | |
| 	t.Logf("Cache stats: %d decoders, %d schemas, %d subjects", | |
| 		decoders, schemas, subjects) | |
| } | |
| 
 | |
| // TestIntegration_ErrorHandling tests error scenarios | |
| func TestIntegration_ErrorHandling(t *testing.T) { | |
| 	server := createMockSchemaRegistry(t) | |
| 	defer server.Close() | |
| 
 | |
| 	config := ManagerConfig{ | |
| 		RegistryURL:    server.URL, | |
| 		ValidationMode: ValidationStrict, | |
| 	} | |
| 
 | |
| 	manager, err := NewManager(config) | |
| 	if err != nil { | |
| 		t.Fatalf("Failed to create manager: %v", err) | |
| 	} | |
| 
 | |
| 	testCases := []struct { | |
| 		name        string | |
| 		message     []byte | |
| 		expectError bool | |
| 		errorType   string | |
| 	}{ | |
| 		{ | |
| 			name:        "Non_Schematized_Message", | |
| 			message:     []byte("plain text message"), | |
| 			expectError: true, | |
| 			errorType:   "not schematized", | |
| 		}, | |
| 		{ | |
| 			name:        "Invalid_Schema_ID", | |
| 			message:     CreateConfluentEnvelope(FormatAvro, 999, nil, []byte("payload")), | |
| 			expectError: true, | |
| 			errorType:   "schema not found", | |
| 		}, | |
| 		{ | |
| 			name:        "Empty_Payload", | |
| 			message:     CreateConfluentEnvelope(FormatAvro, 1, nil, []byte{}), | |
| 			expectError: true, | |
| 			errorType:   "empty payload", | |
| 		}, | |
| 		{ | |
| 			name:        "Corrupted_Avro_Data", | |
| 			message:     CreateConfluentEnvelope(FormatAvro, 1, nil, []byte("invalid avro")), | |
| 			expectError: true, | |
| 			errorType:   "decode failed", | |
| 		}, | |
| 	} | |
| 
 | |
| 	for _, tc := range testCases { | |
| 		t.Run(tc.name, func(t *testing.T) { | |
| 			_, err := manager.DecodeMessage(tc.message) | |
| 
 | |
| 			if (err != nil) != tc.expectError { | |
| 				t.Errorf("Expected error: %v, got error: %v", tc.expectError, err != nil) | |
| 			} | |
| 
 | |
| 			if tc.expectError && err != nil { | |
| 				t.Logf("Expected error occurred: %v", err) | |
| 			} | |
| 		}) | |
| 	} | |
| } | |
| 
 | |
| // TestIntegration_SchemaEvolution tests schema evolution scenarios | |
| func TestIntegration_SchemaEvolution(t *testing.T) { | |
| 	server := createMockSchemaRegistryWithEvolution(t) | |
| 	defer server.Close() | |
| 
 | |
| 	config := ManagerConfig{ | |
| 		RegistryURL:    server.URL, | |
| 		ValidationMode: ValidationPermissive, | |
| 	} | |
| 
 | |
| 	manager, err := NewManager(config) | |
| 	if err != nil { | |
| 		t.Fatalf("Failed to create manager: %v", err) | |
| 	} | |
| 
 | |
| 	// Test decoding messages with different schema versions | |
| 	t.Run("Schema_V1_Message", func(t *testing.T) { | |
| 		// Create message with schema v1 (basic user) | |
| 		userData := map[string]interface{}{ | |
| 			"id":   int32(1), | |
| 			"name": "User V1", | |
| 		} | |
| 
 | |
| 		avroSchema := getUserAvroSchemaV1() | |
| 		codec, _ := goavro.NewCodec(avroSchema) | |
| 		avroBinary, _ := codec.BinaryFromNative(nil, userData) | |
| 		msg := CreateConfluentEnvelope(FormatAvro, 1, nil, avroBinary) | |
| 
 | |
| 		decoded, err := manager.DecodeMessage(msg) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to decode v1 message: %v", err) | |
| 		} | |
| 
 | |
| 		if decoded.Version != 1 { | |
| 			t.Errorf("Expected version 1, got %d", decoded.Version) | |
| 		} | |
| 	}) | |
| 
 | |
| 	t.Run("Schema_V2_Message", func(t *testing.T) { | |
| 		// Create message with schema v2 (user with email) | |
| 		userData := map[string]interface{}{ | |
| 			"id":    int32(2), | |
| 			"name":  "User V2", | |
| 			"email": map[string]interface{}{"string": "user@example.com"}, | |
| 		} | |
| 
 | |
| 		avroSchema := getUserAvroSchemaV2() | |
| 		codec, _ := goavro.NewCodec(avroSchema) | |
| 		avroBinary, _ := codec.BinaryFromNative(nil, userData) | |
| 		msg := CreateConfluentEnvelope(FormatAvro, 2, nil, avroBinary) | |
| 
 | |
| 		decoded, err := manager.DecodeMessage(msg) | |
| 		if err != nil { | |
| 			t.Fatalf("Failed to decode v2 message: %v", err) | |
| 		} | |
| 
 | |
| 		if decoded.Version != 2 { | |
| 			t.Errorf("Expected version 2, got %d", decoded.Version) | |
| 		} | |
| 	}) | |
| } | |
| 
 | |
| // Helper functions for creating mock schema registries | |
|  | |
| func createMockSchemaRegistry(t *testing.T) *httptest.Server { | |
| 	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| 		switch r.URL.Path { | |
| 		case "/subjects": | |
| 			// List subjects | |
| 			subjects := []string{"user-value", "product-value", "order-value"} | |
| 			json.NewEncoder(w).Encode(subjects) | |
| 
 | |
| 		case "/schemas/ids/1": | |
| 			// Avro user schema | |
| 			response := map[string]interface{}{ | |
| 				"schema":  getUserAvroSchema(), | |
| 				"subject": "user-value", | |
| 				"version": 1, | |
| 			} | |
| 			json.NewEncoder(w).Encode(response) | |
| 
 | |
| 		case "/schemas/ids/2": | |
| 			// Protobuf schema (simplified) | |
| 			response := map[string]interface{}{ | |
| 				"schema":  "syntax = \"proto3\"; message User { int32 id = 1; string name = 2; }", | |
| 				"subject": "user-value", | |
| 				"version": 2, | |
| 			} | |
| 			json.NewEncoder(w).Encode(response) | |
| 
 | |
| 		case "/schemas/ids/3": | |
| 			// JSON Schema | |
| 			response := map[string]interface{}{ | |
| 				"schema":  getUserJSONSchema(), | |
| 				"subject": "user-value", | |
| 				"version": 3, | |
| 			} | |
| 			json.NewEncoder(w).Encode(response) | |
| 
 | |
| 		default: | |
| 			w.WriteHeader(http.StatusNotFound) | |
| 		} | |
| 	})) | |
| } | |
| 
 | |
| func createMockSchemaRegistryWithEvolution(t *testing.T) *httptest.Server { | |
| 	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |
| 		switch r.URL.Path { | |
| 		case "/schemas/ids/1": | |
| 			// Schema v1 | |
| 			response := map[string]interface{}{ | |
| 				"schema":  getUserAvroSchemaV1(), | |
| 				"subject": "user-value", | |
| 				"version": 1, | |
| 			} | |
| 			json.NewEncoder(w).Encode(response) | |
| 
 | |
| 		case "/schemas/ids/2": | |
| 			// Schema v2 (evolved) | |
| 			response := map[string]interface{}{ | |
| 				"schema":  getUserAvroSchemaV2(), | |
| 				"subject": "user-value", | |
| 				"version": 2, | |
| 			} | |
| 			json.NewEncoder(w).Encode(response) | |
| 
 | |
| 		default: | |
| 			w.WriteHeader(http.StatusNotFound) | |
| 		} | |
| 	})) | |
| } | |
| 
 | |
| // Schema definitions for testing | |
|  | |
| func getUserAvroSchema() string { | |
| 	return `{ | |
| 		"type": "record", | |
| 		"name": "User", | |
| 		"fields": [ | |
| 			{"name": "id", "type": "int"}, | |
| 			{"name": "name", "type": "string"}, | |
| 			{"name": "email", "type": ["null", "string"], "default": null}, | |
| 			{"name": "age", "type": ["null", "int"], "default": null}, | |
| 			{"name": "preferences", "type": ["null", { | |
| 				"type": "record", | |
| 				"name": "Preferences", | |
| 				"fields": [ | |
| 					{"name": "notifications", "type": "boolean", "default": true}, | |
| 					{"name": "theme", "type": "string", "default": "light"} | |
| 				] | |
| 			}], "default": null} | |
| 		] | |
| 	}` | |
| } | |
| 
 | |
| func getUserAvroSchemaV1() string { | |
| 	return `{ | |
| 		"type": "record", | |
| 		"name": "User", | |
| 		"fields": [ | |
| 			{"name": "id", "type": "int"}, | |
| 			{"name": "name", "type": "string"} | |
| 		] | |
| 	}` | |
| } | |
| 
 | |
| func getUserAvroSchemaV2() string { | |
| 	return `{ | |
| 		"type": "record", | |
| 		"name": "User", | |
| 		"fields": [ | |
| 			{"name": "id", "type": "int"}, | |
| 			{"name": "name", "type": "string"}, | |
| 			{"name": "email", "type": ["null", "string"], "default": null} | |
| 		] | |
| 	}` | |
| } | |
| 
 | |
| func getUserJSONSchema() string { | |
| 	return `{ | |
| 		"$schema": "http://json-schema.org/draft-07/schema#", | |
| 		"type": "object", | |
| 		"properties": { | |
| 			"id": {"type": "integer"}, | |
| 			"name": {"type": "string"}, | |
| 			"active": {"type": "boolean"} | |
| 		}, | |
| 		"required": ["id", "name"] | |
| 	}` | |
| } | |
| 
 | |
| // Benchmark tests for integration scenarios | |
|  | |
| func BenchmarkIntegration_AvroDecoding(b *testing.B) { | |
| 	server := createMockSchemaRegistry(nil) | |
| 	defer server.Close() | |
| 
 | |
| 	config := ManagerConfig{RegistryURL: server.URL} | |
| 	manager, _ := NewManager(config) | |
| 
 | |
| 	// Create test message | |
| 	testData := map[string]interface{}{ | |
| 		"id":   int32(1), | |
| 		"name": "Benchmark User", | |
| 	} | |
| 
 | |
| 	avroSchema := getUserAvroSchema() | |
| 	codec, _ := goavro.NewCodec(avroSchema) | |
| 	avroBinary, _ := codec.BinaryFromNative(nil, testData) | |
| 	testMsg := CreateConfluentEnvelope(FormatAvro, 1, nil, avroBinary) | |
| 
 | |
| 	b.ResetTimer() | |
| 	for i := 0; i < b.N; i++ { | |
| 		_, _ = manager.DecodeMessage(testMsg) | |
| 	} | |
| } | |
| 
 | |
| func BenchmarkIntegration_JSONSchemaDecoding(b *testing.B) { | |
| 	server := createMockSchemaRegistry(nil) | |
| 	defer server.Close() | |
| 
 | |
| 	config := ManagerConfig{RegistryURL: server.URL} | |
| 	manager, _ := NewManager(config) | |
| 
 | |
| 	// Create test message | |
| 	jsonData := []byte(`{"id": 1, "name": "Benchmark User", "active": true}`) | |
| 	testMsg := CreateConfluentEnvelope(FormatJSONSchema, 3, nil, jsonData) | |
| 
 | |
| 	b.ResetTimer() | |
| 	for i := 0; i < b.N; i++ { | |
| 		_, _ = manager.DecodeMessage(testMsg) | |
| 	} | |
| }
 |