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.
		
		
		
		
		
			
		
			
				
					
					
						
							198 lines
						
					
					
						
							6.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							198 lines
						
					
					
						
							6.0 KiB
						
					
					
				| package schema | |
| 
 | |
| import ( | |
| 	"testing" | |
| 
 | |
| 	"github.com/stretchr/testify/assert" | |
| 	"github.com/stretchr/testify/require" | |
| ) | |
| 
 | |
| func TestEncodeDecodeVarint(t *testing.T) { | |
| 	testCases := []struct { | |
| 		name  string | |
| 		value uint64 | |
| 	}{ | |
| 		{"zero", 0}, | |
| 		{"small", 1}, | |
| 		{"medium", 127}, | |
| 		{"large", 128}, | |
| 		{"very_large", 16384}, | |
| 		{"max_uint32", 4294967295}, | |
| 	} | |
| 
 | |
| 	for _, tc := range testCases { | |
| 		t.Run(tc.name, func(t *testing.T) { | |
| 			// Encode the value | |
| 			encoded := encodeVarint(tc.value) | |
| 			require.NotEmpty(t, encoded) | |
| 
 | |
| 			// Decode it back | |
| 			decoded, bytesRead := readVarint(encoded) | |
| 			require.Equal(t, len(encoded), bytesRead, "Should consume all encoded bytes") | |
| 			assert.Equal(t, tc.value, decoded, "Decoded value should match original") | |
| 		}) | |
| 	} | |
| } | |
| 
 | |
| func TestCreateConfluentEnvelopeWithProtobufIndexes(t *testing.T) { | |
| 	testCases := []struct { | |
| 		name     string | |
| 		format   Format | |
| 		schemaID uint32 | |
| 		indexes  []int | |
| 		payload  []byte | |
| 	}{ | |
| 		{ | |
| 			name:     "avro_no_indexes", | |
| 			format:   FormatAvro, | |
| 			schemaID: 123, | |
| 			indexes:  nil, | |
| 			payload:  []byte("avro payload"), | |
| 		}, | |
| 		{ | |
| 			name:     "protobuf_no_indexes", | |
| 			format:   FormatProtobuf, | |
| 			schemaID: 456, | |
| 			indexes:  nil, | |
| 			payload:  []byte("protobuf payload"), | |
| 		}, | |
| 		{ | |
| 			name:     "protobuf_single_index", | |
| 			format:   FormatProtobuf, | |
| 			schemaID: 789, | |
| 			indexes:  []int{1}, | |
| 			payload:  []byte("protobuf with index"), | |
| 		}, | |
| 		{ | |
| 			name:     "protobuf_multiple_indexes", | |
| 			format:   FormatProtobuf, | |
| 			schemaID: 101112, | |
| 			indexes:  []int{0, 1, 2, 3}, | |
| 			payload:  []byte("protobuf with multiple indexes"), | |
| 		}, | |
| 	} | |
| 
 | |
| 	for _, tc := range testCases { | |
| 		t.Run(tc.name, func(t *testing.T) { | |
| 			// Create the envelope | |
| 			envelope := CreateConfluentEnvelope(tc.format, tc.schemaID, tc.indexes, tc.payload) | |
| 
 | |
| 			// Verify basic structure | |
| 			require.True(t, len(envelope) >= 5, "Envelope should be at least 5 bytes") | |
| 			assert.Equal(t, byte(0x00), envelope[0], "Magic byte should be 0x00") | |
| 
 | |
| 			// Extract and verify schema ID | |
| 			extractedSchemaID, ok := ExtractSchemaID(envelope) | |
| 			require.True(t, ok, "Should be able to extract schema ID") | |
| 			assert.Equal(t, tc.schemaID, extractedSchemaID, "Schema ID should match") | |
| 
 | |
| 			// Parse the envelope based on format | |
| 			if tc.format == FormatProtobuf && len(tc.indexes) > 0 { | |
| 				// Use Protobuf-specific parser with known index count | |
| 				parsed, ok := ParseConfluentProtobufEnvelopeWithIndexCount(envelope, len(tc.indexes)) | |
| 				require.True(t, ok, "Should be able to parse Protobuf envelope") | |
| 				assert.Equal(t, tc.format, parsed.Format) | |
| 				assert.Equal(t, tc.schemaID, parsed.SchemaID) | |
| 				assert.Equal(t, tc.indexes, parsed.Indexes, "Indexes should match") | |
| 				assert.Equal(t, tc.payload, parsed.Payload, "Payload should match") | |
| 			} else { | |
| 				// Use generic parser | |
| 				parsed, ok := ParseConfluentEnvelope(envelope) | |
| 				require.True(t, ok, "Should be able to parse envelope") | |
| 				assert.Equal(t, tc.schemaID, parsed.SchemaID) | |
| 				 | |
| 				if tc.format == FormatProtobuf && len(tc.indexes) == 0 { | |
| 					// For Protobuf without indexes, payload should match | |
| 					assert.Equal(t, tc.payload, parsed.Payload, "Payload should match") | |
| 				} else if tc.format == FormatAvro { | |
| 					// For Avro, payload should match (no indexes) | |
| 					assert.Equal(t, tc.payload, parsed.Payload, "Payload should match") | |
| 				} | |
| 			} | |
| 		}) | |
| 	} | |
| } | |
| 
 | |
| func TestProtobufEnvelopeRoundTrip(t *testing.T) { | |
| 	// Use more realistic index values (typically small numbers for message types) | |
| 	originalIndexes := []int{0, 1, 2, 3} | |
| 	originalPayload := []byte("test protobuf message data") | |
| 	schemaID := uint32(12345) | |
| 
 | |
| 	// Create envelope | |
| 	envelope := CreateConfluentEnvelope(FormatProtobuf, schemaID, originalIndexes, originalPayload) | |
| 
 | |
| 	// Parse it back with known index count | |
| 	parsed, ok := ParseConfluentProtobufEnvelopeWithIndexCount(envelope, len(originalIndexes)) | |
| 	require.True(t, ok, "Should be able to parse created envelope") | |
| 
 | |
| 	// Verify all fields | |
| 	assert.Equal(t, FormatProtobuf, parsed.Format) | |
| 	assert.Equal(t, schemaID, parsed.SchemaID) | |
| 	assert.Equal(t, originalIndexes, parsed.Indexes) | |
| 	assert.Equal(t, originalPayload, parsed.Payload) | |
| 	assert.Equal(t, envelope, parsed.OriginalBytes) | |
| } | |
| 
 | |
| func TestVarintEdgeCases(t *testing.T) { | |
| 	t.Run("empty_data", func(t *testing.T) { | |
| 		value, bytesRead := readVarint([]byte{}) | |
| 		assert.Equal(t, uint64(0), value) | |
| 		assert.Equal(t, 0, bytesRead) | |
| 	}) | |
| 
 | |
| 	t.Run("incomplete_varint", func(t *testing.T) { | |
| 		// Create an incomplete varint (continuation bit set but no more bytes) | |
| 		incompleteVarint := []byte{0x80} // Continuation bit set, but no more bytes | |
| 		value, bytesRead := readVarint(incompleteVarint) | |
| 		assert.Equal(t, uint64(0), value) | |
| 		assert.Equal(t, 0, bytesRead) | |
| 	}) | |
| 
 | |
| 	t.Run("max_varint_length", func(t *testing.T) { | |
| 		// Create a varint that's too long (more than 10 bytes) | |
| 		tooLongVarint := make([]byte, 11) | |
| 		for i := 0; i < 10; i++ { | |
| 			tooLongVarint[i] = 0x80 // All continuation bits | |
| 		} | |
| 		tooLongVarint[10] = 0x01 // Final byte | |
|  | |
| 		value, bytesRead := readVarint(tooLongVarint) | |
| 		assert.Equal(t, uint64(0), value) | |
| 		assert.Equal(t, 0, bytesRead) | |
| 	}) | |
| } | |
| 
 | |
| func TestProtobufEnvelopeValidation(t *testing.T) { | |
| 	t.Run("valid_envelope", func(t *testing.T) { | |
| 		indexes := []int{1, 2} | |
| 		envelope := CreateConfluentEnvelope(FormatProtobuf, 123, indexes, []byte("payload")) | |
| 		parsed, ok := ParseConfluentProtobufEnvelopeWithIndexCount(envelope, len(indexes)) | |
| 		require.True(t, ok) | |
| 
 | |
| 		err := parsed.Validate() | |
| 		assert.NoError(t, err) | |
| 	}) | |
| 
 | |
| 	t.Run("zero_schema_id", func(t *testing.T) { | |
| 		indexes := []int{1} | |
| 		envelope := CreateConfluentEnvelope(FormatProtobuf, 0, indexes, []byte("payload")) | |
| 		parsed, ok := ParseConfluentProtobufEnvelopeWithIndexCount(envelope, len(indexes)) | |
| 		require.True(t, ok) | |
| 
 | |
| 		err := parsed.Validate() | |
| 		assert.Error(t, err) | |
| 		assert.Contains(t, err.Error(), "invalid schema ID: 0") | |
| 	}) | |
| 
 | |
| 	t.Run("empty_payload", func(t *testing.T) { | |
| 		indexes := []int{1} | |
| 		envelope := CreateConfluentEnvelope(FormatProtobuf, 123, indexes, []byte{}) | |
| 		parsed, ok := ParseConfluentProtobufEnvelopeWithIndexCount(envelope, len(indexes)) | |
| 		require.True(t, ok) | |
| 
 | |
| 		err := parsed.Validate() | |
| 		assert.Error(t, err) | |
| 		assert.Contains(t, err.Error(), "empty payload") | |
| 	}) | |
| }
 |