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.
		
		
		
		
		
			
		
			
				
					
					
						
							265 lines
						
					
					
						
							8.2 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							265 lines
						
					
					
						
							8.2 KiB
						
					
					
				
								package schema
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"reflect"
							 | 
						|
									"testing"
							 | 
						|
								
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								func TestSplitFlatSchemaToKeyValue(t *testing.T) {
							 | 
						|
									// Create a test flat schema
							 | 
						|
									flatSchema := &schema_pb.RecordType{
							 | 
						|
										Fields: []*schema_pb.Field{
							 | 
						|
											{
							 | 
						|
												Name:       "user_id",
							 | 
						|
												FieldIndex: 0,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_INT64}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "session_id",
							 | 
						|
												FieldIndex: 1,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "event_type",
							 | 
						|
												FieldIndex: 2,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "timestamp",
							 | 
						|
												FieldIndex: 3,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_INT64}},
							 | 
						|
											},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									keyColumns := []string{"user_id", "session_id"}
							 | 
						|
								
							 | 
						|
									keySchema, valueSchema, err := SplitFlatSchemaToKeyValue(flatSchema, keyColumns)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("SplitFlatSchemaToKeyValue failed: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify key schema
							 | 
						|
									if keySchema == nil {
							 | 
						|
										t.Fatal("Expected key schema, got nil")
							 | 
						|
									}
							 | 
						|
									if len(keySchema.Fields) != 2 {
							 | 
						|
										t.Errorf("Expected 2 key fields, got %d", len(keySchema.Fields))
							 | 
						|
									}
							 | 
						|
									if keySchema.Fields[0].Name != "user_id" || keySchema.Fields[1].Name != "session_id" {
							 | 
						|
										t.Errorf("Key field names incorrect: %v", []string{keySchema.Fields[0].Name, keySchema.Fields[1].Name})
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify value schema
							 | 
						|
									if valueSchema == nil {
							 | 
						|
										t.Fatal("Expected value schema, got nil")
							 | 
						|
									}
							 | 
						|
									if len(valueSchema.Fields) != 2 {
							 | 
						|
										t.Errorf("Expected 2 value fields, got %d", len(valueSchema.Fields))
							 | 
						|
									}
							 | 
						|
									if valueSchema.Fields[0].Name != "event_type" || valueSchema.Fields[1].Name != "timestamp" {
							 | 
						|
										t.Errorf("Value field names incorrect: %v", []string{valueSchema.Fields[0].Name, valueSchema.Fields[1].Name})
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify field indices are reindexed
							 | 
						|
									for i, field := range keySchema.Fields {
							 | 
						|
										if field.FieldIndex != int32(i) {
							 | 
						|
											t.Errorf("Key field %s has incorrect index %d, expected %d", field.Name, field.FieldIndex, i)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
									for i, field := range valueSchema.Fields {
							 | 
						|
										if field.FieldIndex != int32(i) {
							 | 
						|
											t.Errorf("Value field %s has incorrect index %d, expected %d", field.Name, field.FieldIndex, i)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestSplitFlatSchemaToKeyValueMissingColumns(t *testing.T) {
							 | 
						|
									flatSchema := &schema_pb.RecordType{
							 | 
						|
										Fields: []*schema_pb.Field{
							 | 
						|
											{Name: "field1", Type: &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}}},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									keyColumns := []string{"field1", "missing_field"}
							 | 
						|
								
							 | 
						|
									_, _, err := SplitFlatSchemaToKeyValue(flatSchema, keyColumns)
							 | 
						|
									if err == nil {
							 | 
						|
										t.Error("Expected error for missing key column, got nil")
							 | 
						|
									}
							 | 
						|
									if !contains(err.Error(), "missing_field") {
							 | 
						|
										t.Errorf("Error should mention missing_field: %v", err)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestCombineFlatSchemaFromKeyValue(t *testing.T) {
							 | 
						|
									keySchema := &schema_pb.RecordType{
							 | 
						|
										Fields: []*schema_pb.Field{
							 | 
						|
											{
							 | 
						|
												Name:       "user_id",
							 | 
						|
												FieldIndex: 0,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_INT64}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "session_id",
							 | 
						|
												FieldIndex: 1,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}},
							 | 
						|
											},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									valueSchema := &schema_pb.RecordType{
							 | 
						|
										Fields: []*schema_pb.Field{
							 | 
						|
											{
							 | 
						|
												Name:       "event_type",
							 | 
						|
												FieldIndex: 0,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "timestamp",
							 | 
						|
												FieldIndex: 1,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_INT64}},
							 | 
						|
											},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									flatSchema, keyColumns := CombineFlatSchemaFromKeyValue(keySchema, valueSchema)
							 | 
						|
								
							 | 
						|
									// Verify combined schema
							 | 
						|
									if flatSchema == nil {
							 | 
						|
										t.Fatal("Expected flat schema, got nil")
							 | 
						|
									}
							 | 
						|
									if len(flatSchema.Fields) != 4 {
							 | 
						|
										t.Errorf("Expected 4 fields, got %d", len(flatSchema.Fields))
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify key columns
							 | 
						|
									expectedKeyColumns := []string{"user_id", "session_id"}
							 | 
						|
									if !reflect.DeepEqual(keyColumns, expectedKeyColumns) {
							 | 
						|
										t.Errorf("Expected key columns %v, got %v", expectedKeyColumns, keyColumns)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify field order (key fields first)
							 | 
						|
									expectedNames := []string{"user_id", "session_id", "event_type", "timestamp"}
							 | 
						|
									actualNames := make([]string, len(flatSchema.Fields))
							 | 
						|
									for i, field := range flatSchema.Fields {
							 | 
						|
										actualNames[i] = field.Name
							 | 
						|
									}
							 | 
						|
									if !reflect.DeepEqual(actualNames, expectedNames) {
							 | 
						|
										t.Errorf("Expected field names %v, got %v", expectedNames, actualNames)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify field indices are sequential
							 | 
						|
									for i, field := range flatSchema.Fields {
							 | 
						|
										if field.FieldIndex != int32(i) {
							 | 
						|
											t.Errorf("Field %s has incorrect index %d, expected %d", field.Name, field.FieldIndex, i)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestExtractKeyColumnsFromCombinedSchema(t *testing.T) {
							 | 
						|
									// Create a combined schema with key_ prefixes (as created by CreateCombinedRecordType)
							 | 
						|
									combinedSchema := &schema_pb.RecordType{
							 | 
						|
										Fields: []*schema_pb.Field{
							 | 
						|
											{
							 | 
						|
												Name:       "key_user_id",
							 | 
						|
												FieldIndex: 0,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_INT64}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "key_session_id",
							 | 
						|
												FieldIndex: 1,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "event_type",
							 | 
						|
												FieldIndex: 2,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}},
							 | 
						|
											},
							 | 
						|
											{
							 | 
						|
												Name:       "timestamp",
							 | 
						|
												FieldIndex: 3,
							 | 
						|
												Type:       &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_INT64}},
							 | 
						|
											},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									flatSchema, keyColumns := ExtractKeyColumnsFromCombinedSchema(combinedSchema)
							 | 
						|
								
							 | 
						|
									// Verify flat schema
							 | 
						|
									if flatSchema == nil {
							 | 
						|
										t.Fatal("Expected flat schema, got nil")
							 | 
						|
									}
							 | 
						|
									if len(flatSchema.Fields) != 4 {
							 | 
						|
										t.Errorf("Expected 4 fields, got %d", len(flatSchema.Fields))
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify key columns (should be sorted)
							 | 
						|
									expectedKeyColumns := []string{"session_id", "user_id"}
							 | 
						|
									if !reflect.DeepEqual(keyColumns, expectedKeyColumns) {
							 | 
						|
										t.Errorf("Expected key columns %v, got %v", expectedKeyColumns, keyColumns)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify field names (key_ prefixes removed)
							 | 
						|
									expectedNames := []string{"user_id", "session_id", "event_type", "timestamp"}
							 | 
						|
									actualNames := make([]string, len(flatSchema.Fields))
							 | 
						|
									for i, field := range flatSchema.Fields {
							 | 
						|
										actualNames[i] = field.Name
							 | 
						|
									}
							 | 
						|
									if !reflect.DeepEqual(actualNames, expectedNames) {
							 | 
						|
										t.Errorf("Expected field names %v, got %v", expectedNames, actualNames)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestValidateKeyColumns(t *testing.T) {
							 | 
						|
									schema := &schema_pb.RecordType{
							 | 
						|
										Fields: []*schema_pb.Field{
							 | 
						|
											{Name: "field1", Type: &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_STRING}}},
							 | 
						|
											{Name: "field2", Type: &schema_pb.Type{Kind: &schema_pb.Type_ScalarType{ScalarType: schema_pb.ScalarType_INT64}}},
							 | 
						|
										},
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Valid key columns
							 | 
						|
									err := ValidateKeyColumns(schema, []string{"field1"})
							 | 
						|
									if err != nil {
							 | 
						|
										t.Errorf("Expected no error for valid key columns, got: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Invalid key columns
							 | 
						|
									err = ValidateKeyColumns(schema, []string{"field1", "missing_field"})
							 | 
						|
									if err == nil {
							 | 
						|
										t.Error("Expected error for invalid key columns, got nil")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Nil schema should not error
							 | 
						|
									err = ValidateKeyColumns(nil, []string{"any_field"})
							 | 
						|
									if err != nil {
							 | 
						|
										t.Errorf("Expected no error for nil schema, got: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Empty key columns should not error
							 | 
						|
									err = ValidateKeyColumns(schema, []string{})
							 | 
						|
									if err != nil {
							 | 
						|
										t.Errorf("Expected no error for empty key columns, got: %v", err)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Helper function to check if string contains substring
							 | 
						|
								func contains(str, substr string) bool {
							 | 
						|
									return len(str) >= len(substr) &&
							 | 
						|
										(len(substr) == 0 || str[len(str)-len(substr):] == substr ||
							 | 
						|
											str[:len(substr)] == substr ||
							 | 
						|
											len(str) > len(substr) && (str[len(str)-len(substr)-1:len(str)-len(substr)] == " " || str[len(str)-len(substr)-1] == ' ') && str[len(str)-len(substr):] == substr ||
							 | 
						|
											findInString(str, substr))
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func findInString(str, substr string) bool {
							 | 
						|
									for i := 0; i <= len(str)-len(substr); i++ {
							 | 
						|
										if str[i:i+len(substr)] == substr {
							 | 
						|
											return true
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
									return false
							 | 
						|
								}
							 |