Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
543 lines
13 KiB
Go
543 lines
13 KiB
Go
package schema
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/linkedin/goavro/v2"
|
|
"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
|
|
)
|
|
|
|
func TestNewAvroDecoder(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
schema string
|
|
expectErr bool
|
|
}{
|
|
{
|
|
name: "valid record schema",
|
|
schema: `{
|
|
"type": "record",
|
|
"name": "User",
|
|
"fields": [
|
|
{"name": "id", "type": "int"},
|
|
{"name": "name", "type": "string"}
|
|
]
|
|
}`,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "valid enum schema",
|
|
schema: `{
|
|
"type": "enum",
|
|
"name": "Color",
|
|
"symbols": ["RED", "GREEN", "BLUE"]
|
|
}`,
|
|
expectErr: false,
|
|
},
|
|
{
|
|
name: "invalid schema",
|
|
schema: `{"invalid": "schema"}`,
|
|
expectErr: true,
|
|
},
|
|
{
|
|
name: "empty schema",
|
|
schema: "",
|
|
expectErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
decoder, err := NewAvroDecoder(tt.schema)
|
|
|
|
if (err != nil) != tt.expectErr {
|
|
t.Errorf("NewAvroDecoder() error = %v, expectErr %v", err, tt.expectErr)
|
|
return
|
|
}
|
|
|
|
if !tt.expectErr && decoder == nil {
|
|
t.Error("Expected non-nil decoder for valid schema")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAvroDecoder_Decode(t *testing.T) {
|
|
schema := `{
|
|
"type": "record",
|
|
"name": "User",
|
|
"fields": [
|
|
{"name": "id", "type": "int"},
|
|
{"name": "name", "type": "string"},
|
|
{"name": "email", "type": ["null", "string"], "default": null}
|
|
]
|
|
}`
|
|
|
|
decoder, err := NewAvroDecoder(schema)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create decoder: %v", err)
|
|
}
|
|
|
|
// Create test data
|
|
codec, _ := goavro.NewCodec(schema)
|
|
testRecord := map[string]interface{}{
|
|
"id": int32(123),
|
|
"name": "John Doe",
|
|
"email": map[string]interface{}{
|
|
"string": "john@example.com", // Avro union format
|
|
},
|
|
}
|
|
|
|
// Encode to binary
|
|
binary, err := codec.BinaryFromNative(nil, testRecord)
|
|
if err != nil {
|
|
t.Fatalf("Failed to encode test data: %v", err)
|
|
}
|
|
|
|
// Test decoding
|
|
result, err := decoder.Decode(binary)
|
|
if err != nil {
|
|
t.Fatalf("Failed to decode: %v", err)
|
|
}
|
|
|
|
// Verify results
|
|
if result["id"] != int32(123) {
|
|
t.Errorf("Expected id=123, got %v", result["id"])
|
|
}
|
|
|
|
if result["name"] != "John Doe" {
|
|
t.Errorf("Expected name='John Doe', got %v", result["name"])
|
|
}
|
|
|
|
// For union types, Avro returns a map with the type name as key
|
|
if emailMap, ok := result["email"].(map[string]interface{}); ok {
|
|
if emailMap["string"] != "john@example.com" {
|
|
t.Errorf("Expected email='john@example.com', got %v", emailMap["string"])
|
|
}
|
|
} else {
|
|
t.Errorf("Expected email to be a union map, got %v", result["email"])
|
|
}
|
|
}
|
|
|
|
func TestAvroDecoder_DecodeToRecordValue(t *testing.T) {
|
|
schema := `{
|
|
"type": "record",
|
|
"name": "SimpleRecord",
|
|
"fields": [
|
|
{"name": "id", "type": "int"},
|
|
{"name": "name", "type": "string"}
|
|
]
|
|
}`
|
|
|
|
decoder, err := NewAvroDecoder(schema)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create decoder: %v", err)
|
|
}
|
|
|
|
// Create and encode test data
|
|
codec, _ := goavro.NewCodec(schema)
|
|
testRecord := map[string]interface{}{
|
|
"id": int32(456),
|
|
"name": "Jane Smith",
|
|
}
|
|
|
|
binary, err := codec.BinaryFromNative(nil, testRecord)
|
|
if err != nil {
|
|
t.Fatalf("Failed to encode test data: %v", err)
|
|
}
|
|
|
|
// Test decoding to RecordValue
|
|
recordValue, err := decoder.DecodeToRecordValue(binary)
|
|
if err != nil {
|
|
t.Fatalf("Failed to decode to RecordValue: %v", err)
|
|
}
|
|
|
|
// Verify RecordValue structure
|
|
if recordValue.Fields == nil {
|
|
t.Fatal("Expected non-nil fields")
|
|
}
|
|
|
|
idValue := recordValue.Fields["id"]
|
|
if idValue == nil {
|
|
t.Fatal("Expected id field")
|
|
}
|
|
|
|
if idValue.GetInt32Value() != 456 {
|
|
t.Errorf("Expected id=456, got %v", idValue.GetInt32Value())
|
|
}
|
|
|
|
nameValue := recordValue.Fields["name"]
|
|
if nameValue == nil {
|
|
t.Fatal("Expected name field")
|
|
}
|
|
|
|
if nameValue.GetStringValue() != "Jane Smith" {
|
|
t.Errorf("Expected name='Jane Smith', got %v", nameValue.GetStringValue())
|
|
}
|
|
}
|
|
|
|
func TestMapToRecordValue(t *testing.T) {
|
|
testMap := map[string]interface{}{
|
|
"bool_field": true,
|
|
"int32_field": int32(123),
|
|
"int64_field": int64(456),
|
|
"float_field": float32(1.23),
|
|
"double_field": float64(4.56),
|
|
"string_field": "hello",
|
|
"bytes_field": []byte("world"),
|
|
"null_field": nil,
|
|
"array_field": []interface{}{"a", "b", "c"},
|
|
"nested_field": map[string]interface{}{
|
|
"inner": "value",
|
|
},
|
|
}
|
|
|
|
recordValue := MapToRecordValue(testMap)
|
|
|
|
// Test each field type
|
|
if !recordValue.Fields["bool_field"].GetBoolValue() {
|
|
t.Error("Expected bool_field=true")
|
|
}
|
|
|
|
if recordValue.Fields["int32_field"].GetInt32Value() != 123 {
|
|
t.Error("Expected int32_field=123")
|
|
}
|
|
|
|
if recordValue.Fields["int64_field"].GetInt64Value() != 456 {
|
|
t.Error("Expected int64_field=456")
|
|
}
|
|
|
|
if recordValue.Fields["float_field"].GetFloatValue() != 1.23 {
|
|
t.Error("Expected float_field=1.23")
|
|
}
|
|
|
|
if recordValue.Fields["double_field"].GetDoubleValue() != 4.56 {
|
|
t.Error("Expected double_field=4.56")
|
|
}
|
|
|
|
if recordValue.Fields["string_field"].GetStringValue() != "hello" {
|
|
t.Error("Expected string_field='hello'")
|
|
}
|
|
|
|
if string(recordValue.Fields["bytes_field"].GetBytesValue()) != "world" {
|
|
t.Error("Expected bytes_field='world'")
|
|
}
|
|
|
|
// Test null value (converted to empty string)
|
|
if recordValue.Fields["null_field"].GetStringValue() != "" {
|
|
t.Error("Expected null_field to be empty string")
|
|
}
|
|
|
|
// Test array
|
|
arrayValue := recordValue.Fields["array_field"].GetListValue()
|
|
if arrayValue == nil || len(arrayValue.Values) != 3 {
|
|
t.Error("Expected array with 3 elements")
|
|
}
|
|
|
|
// Test nested record
|
|
nestedValue := recordValue.Fields["nested_field"].GetRecordValue()
|
|
if nestedValue == nil {
|
|
t.Fatal("Expected nested record")
|
|
}
|
|
|
|
if nestedValue.Fields["inner"].GetStringValue() != "value" {
|
|
t.Error("Expected nested inner='value'")
|
|
}
|
|
}
|
|
|
|
func TestGoValueToSchemaValue(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input interface{}
|
|
expected func(*schema_pb.Value) bool
|
|
}{
|
|
{
|
|
name: "nil value",
|
|
input: nil,
|
|
expected: func(v *schema_pb.Value) bool {
|
|
return v.GetStringValue() == ""
|
|
},
|
|
},
|
|
{
|
|
name: "bool value",
|
|
input: true,
|
|
expected: func(v *schema_pb.Value) bool {
|
|
return v.GetBoolValue() == true
|
|
},
|
|
},
|
|
{
|
|
name: "int32 value",
|
|
input: int32(123),
|
|
expected: func(v *schema_pb.Value) bool {
|
|
return v.GetInt32Value() == 123
|
|
},
|
|
},
|
|
{
|
|
name: "int64 value",
|
|
input: int64(456),
|
|
expected: func(v *schema_pb.Value) bool {
|
|
return v.GetInt64Value() == 456
|
|
},
|
|
},
|
|
{
|
|
name: "string value",
|
|
input: "test",
|
|
expected: func(v *schema_pb.Value) bool {
|
|
return v.GetStringValue() == "test"
|
|
},
|
|
},
|
|
{
|
|
name: "bytes value",
|
|
input: []byte("data"),
|
|
expected: func(v *schema_pb.Value) bool {
|
|
return string(v.GetBytesValue()) == "data"
|
|
},
|
|
},
|
|
{
|
|
name: "time value",
|
|
input: time.Unix(1234567890, 0),
|
|
expected: func(v *schema_pb.Value) bool {
|
|
return v.GetTimestampValue() != nil
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := goValueToSchemaValue(tt.input)
|
|
if !tt.expected(result) {
|
|
t.Errorf("goValueToSchemaValue() failed for %v", tt.input)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestInferRecordTypeFromMap(t *testing.T) {
|
|
testMap := map[string]interface{}{
|
|
"id": int64(123),
|
|
"name": "test",
|
|
"active": true,
|
|
"score": float64(95.5),
|
|
"tags": []interface{}{"tag1", "tag2"},
|
|
"metadata": map[string]interface{}{"key": "value"},
|
|
}
|
|
|
|
recordType := InferRecordTypeFromMap(testMap)
|
|
|
|
if len(recordType.Fields) != 6 {
|
|
t.Errorf("Expected 6 fields, got %d", len(recordType.Fields))
|
|
}
|
|
|
|
// Create a map for easier field lookup
|
|
fieldMap := make(map[string]*schema_pb.Field)
|
|
for _, field := range recordType.Fields {
|
|
fieldMap[field.Name] = field
|
|
}
|
|
|
|
// Test field types
|
|
if fieldMap["id"].Type.GetScalarType() != schema_pb.ScalarType_INT64 {
|
|
t.Error("Expected id field to be INT64")
|
|
}
|
|
|
|
if fieldMap["name"].Type.GetScalarType() != schema_pb.ScalarType_STRING {
|
|
t.Error("Expected name field to be STRING")
|
|
}
|
|
|
|
if fieldMap["active"].Type.GetScalarType() != schema_pb.ScalarType_BOOL {
|
|
t.Error("Expected active field to be BOOL")
|
|
}
|
|
|
|
if fieldMap["score"].Type.GetScalarType() != schema_pb.ScalarType_DOUBLE {
|
|
t.Error("Expected score field to be DOUBLE")
|
|
}
|
|
|
|
// Test array field
|
|
if fieldMap["tags"].Type.GetListType() == nil {
|
|
t.Error("Expected tags field to be LIST")
|
|
}
|
|
|
|
// Test nested record field
|
|
if fieldMap["metadata"].Type.GetRecordType() == nil {
|
|
t.Error("Expected metadata field to be RECORD")
|
|
}
|
|
}
|
|
|
|
func TestInferTypeFromValue(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input interface{}
|
|
expected schema_pb.ScalarType
|
|
}{
|
|
{"nil", nil, schema_pb.ScalarType_STRING}, // Default for nil
|
|
{"bool", true, schema_pb.ScalarType_BOOL},
|
|
{"int32", int32(123), schema_pb.ScalarType_INT32},
|
|
{"int64", int64(456), schema_pb.ScalarType_INT64},
|
|
{"int", int(789), schema_pb.ScalarType_INT64},
|
|
{"float32", float32(1.23), schema_pb.ScalarType_FLOAT},
|
|
{"float64", float64(4.56), schema_pb.ScalarType_DOUBLE},
|
|
{"string", "test", schema_pb.ScalarType_STRING},
|
|
{"bytes", []byte("data"), schema_pb.ScalarType_BYTES},
|
|
{"time", time.Now(), schema_pb.ScalarType_TIMESTAMP},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := inferTypeFromValue(tt.input)
|
|
|
|
// Handle special cases
|
|
if tt.input == nil || reflect.TypeOf(tt.input).Kind() == reflect.Slice ||
|
|
reflect.TypeOf(tt.input).Kind() == reflect.Map {
|
|
// Skip scalar type check for complex types
|
|
return
|
|
}
|
|
|
|
if result.GetScalarType() != tt.expected {
|
|
t.Errorf("inferTypeFromValue() = %v, want %v", result.GetScalarType(), tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Integration test with real Avro data
|
|
func TestAvroDecoder_Integration(t *testing.T) {
|
|
// Complex Avro schema with nested records and arrays
|
|
schema := `{
|
|
"type": "record",
|
|
"name": "Order",
|
|
"fields": [
|
|
{"name": "id", "type": "string"},
|
|
{"name": "customer_id", "type": "int"},
|
|
{"name": "total", "type": "double"},
|
|
{"name": "items", "type": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "record",
|
|
"name": "Item",
|
|
"fields": [
|
|
{"name": "product_id", "type": "string"},
|
|
{"name": "quantity", "type": "int"},
|
|
{"name": "price", "type": "double"}
|
|
]
|
|
}
|
|
}},
|
|
{"name": "metadata", "type": {
|
|
"type": "record",
|
|
"name": "Metadata",
|
|
"fields": [
|
|
{"name": "source", "type": "string"},
|
|
{"name": "timestamp", "type": "long"}
|
|
]
|
|
}}
|
|
]
|
|
}`
|
|
|
|
decoder, err := NewAvroDecoder(schema)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create decoder: %v", err)
|
|
}
|
|
|
|
// Create complex test data
|
|
codec, _ := goavro.NewCodec(schema)
|
|
testOrder := map[string]interface{}{
|
|
"id": "order-123",
|
|
"customer_id": int32(456),
|
|
"total": float64(99.99),
|
|
"items": []interface{}{
|
|
map[string]interface{}{
|
|
"product_id": "prod-1",
|
|
"quantity": int32(2),
|
|
"price": float64(29.99),
|
|
},
|
|
map[string]interface{}{
|
|
"product_id": "prod-2",
|
|
"quantity": int32(1),
|
|
"price": float64(39.99),
|
|
},
|
|
},
|
|
"metadata": map[string]interface{}{
|
|
"source": "web",
|
|
"timestamp": int64(1234567890),
|
|
},
|
|
}
|
|
|
|
// Encode to binary
|
|
binary, err := codec.BinaryFromNative(nil, testOrder)
|
|
if err != nil {
|
|
t.Fatalf("Failed to encode test data: %v", err)
|
|
}
|
|
|
|
// Decode to RecordValue
|
|
recordValue, err := decoder.DecodeToRecordValue(binary)
|
|
if err != nil {
|
|
t.Fatalf("Failed to decode to RecordValue: %v", err)
|
|
}
|
|
|
|
// Verify complex structure
|
|
if recordValue.Fields["id"].GetStringValue() != "order-123" {
|
|
t.Error("Expected order ID to be preserved")
|
|
}
|
|
|
|
if recordValue.Fields["customer_id"].GetInt32Value() != 456 {
|
|
t.Error("Expected customer ID to be preserved")
|
|
}
|
|
|
|
// Check array handling
|
|
itemsArray := recordValue.Fields["items"].GetListValue()
|
|
if itemsArray == nil || len(itemsArray.Values) != 2 {
|
|
t.Fatal("Expected items array with 2 elements")
|
|
}
|
|
|
|
// Check nested record handling
|
|
metadataRecord := recordValue.Fields["metadata"].GetRecordValue()
|
|
if metadataRecord == nil {
|
|
t.Fatal("Expected metadata record")
|
|
}
|
|
|
|
if metadataRecord.Fields["source"].GetStringValue() != "web" {
|
|
t.Error("Expected metadata source to be preserved")
|
|
}
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkAvroDecoder_Decode(b *testing.B) {
|
|
schema := `{
|
|
"type": "record",
|
|
"name": "User",
|
|
"fields": [
|
|
{"name": "id", "type": "int"},
|
|
{"name": "name", "type": "string"}
|
|
]
|
|
}`
|
|
|
|
decoder, _ := NewAvroDecoder(schema)
|
|
codec, _ := goavro.NewCodec(schema)
|
|
|
|
testRecord := map[string]interface{}{
|
|
"id": int32(123),
|
|
"name": "John Doe",
|
|
}
|
|
|
|
binary, _ := codec.BinaryFromNative(nil, testRecord)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, _ = decoder.Decode(binary)
|
|
}
|
|
}
|
|
|
|
func BenchmarkMapToRecordValue(b *testing.B) {
|
|
testMap := map[string]interface{}{
|
|
"id": int64(123),
|
|
"name": "test",
|
|
"active": true,
|
|
"score": float64(95.5),
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = MapToRecordValue(testMap)
|
|
}
|
|
}
|