package index import ( "context" "encoding/json" "strings" "testing" "es-demo/client" "es-demo/config" ) // TestISMPolicyManager_PutPolicy_Validation tests policy validation func TestISMPolicyManager_PutPolicy_Validation(t *testing.T) { if testing.Short() { t.Skip("skipping integration test in short mode") } if err := config.Load(".env"); err != nil { t.Logf("warning: failed to load .env file: %v", err) } config.Init() cfg := &client.Config{ Endpoint: config.Endpoint, Region: config.Region, AccessKey: config.AccessKey, SecretKey: config.SecretKey, } c, err := client.NewClient(cfg) if err != nil { t.Fatalf("failed to create client: %v", err) } pm := NewISMPolicyManager(c) ctx := context.Background() tests := []struct { name string policyName string policy *Policy wantErr bool }{ { name: "empty policy name", policyName: "", policy: &Policy{ DefaultState: "hot", States: []State{{Name: "hot"}}, }, wantErr: true, }, { name: "invalid policy - nil", policyName: "test", policy: nil, wantErr: true, }, { name: "invalid policy - no states", policyName: "test", policy: &Policy{ Description: "Test", }, wantErr: true, }, { name: "invalid policy - missing default_state", policyName: "test", policy: &Policy{ States: []State{{Name: "hot"}}, }, wantErr: true, }, { name: "invalid policy - default_state not in states", policyName: "test", policy: &Policy{ DefaultState: "cold", States: []State{{Name: "hot"}}, }, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := pm.PutPolicy(ctx, tt.policyName, tt.policy) if (err != nil) != tt.wantErr { t.Errorf("PutPolicy() error = %v, wantErr %v", err, tt.wantErr) } }) } } // TestISMPolicyManager_GetPolicy_NotFound tests GetPolicy when policy doesn't exist func TestISMPolicyManager_GetPolicy_NotFound(t *testing.T) { if testing.Short() { t.Skip("skipping integration test in short mode") } if err := config.Load(".env"); err != nil { t.Logf("warning: failed to load .env file: %v", err) } config.Init() cfg := &client.Config{ Endpoint: config.Endpoint, Region: config.Region, AccessKey: config.AccessKey, SecretKey: config.SecretKey, } c, err := client.NewClient(cfg) if err != nil { t.Fatalf("failed to create client: %v", err) } pm := NewISMPolicyManager(c) ctx := context.Background() _, err = pm.GetPolicy(ctx, "non-existent-policy-12345") if err == nil { t.Error("GetPolicy() should return error for non-existent policy") } } // TestISMPolicyManager_DeletePolicy_NotFound tests DeletePolicy when policy doesn't exist func TestISMPolicyManager_DeletePolicy_NotFound(t *testing.T) { if testing.Short() { t.Skip("skipping integration test in short mode") } if err := config.Load(".env"); err != nil { t.Logf("warning: failed to load .env file: %v", err) } config.Init() cfg := &client.Config{ Endpoint: config.Endpoint, Region: config.Region, AccessKey: config.AccessKey, SecretKey: config.SecretKey, } c, err := client.NewClient(cfg) if err != nil { t.Fatalf("failed to create client: %v", err) } pm := NewISMPolicyManager(c) ctx := context.Background() err = pm.DeletePolicy(ctx, "non-existent-policy-12345") if err == nil { t.Error("DeletePolicy() should return error for non-existent policy") } } // TestISMPolicyManager_ListPolicies_EmptyCheck tests ListPolicies returns valid map func TestISMPolicyManager_ListPolicies_EmptyCheck(t *testing.T) { if testing.Short() { t.Skip("skipping integration test in short mode") } if err := config.Load(".env"); err != nil { t.Logf("warning: failed to load .env file: %v", err) } config.Init() cfg := &client.Config{ Endpoint: config.Endpoint, Region: config.Region, AccessKey: config.AccessKey, SecretKey: config.SecretKey, } c, err := client.NewClient(cfg) if err != nil { t.Fatalf("failed to create client: %v", err) } pm := NewISMPolicyManager(c) ctx := context.Background() policies, err := pm.ListPolicies(ctx) if err != nil { t.Fatalf("ListPolicies() error = %v", err) } if policies == nil { t.Error("ListPolicies() should not return nil map") } } // TestPolicy_ValidateEdgeCases tests additional edge cases for policy validation func TestPolicy_ValidateEdgeCases(t *testing.T) { tests := []struct { name string policy *Policy wantErr bool }{ { name: "nil policy", policy: nil, wantErr: true, }, { name: "empty states and empty phases", policy: &Policy{ Description: "Empty policy", }, wantErr: true, }, { name: "both ISM states and ILM phases", policy: &Policy{ DefaultState: "hot", States: []State{{Name: "hot"}}, Phases: map[string]Phase{ "hot": {MinAge: "0ms"}, }, }, wantErr: true, }, { name: "valid ISM policy with transitions", policy: &Policy{ Description: "Test", DefaultState: "hot", States: []State{ { Name: "hot", Transitions: []Transition{ { StateName: "warm", Conditions: &Conditions{ MinIndexAge: "1d", }, }, }, }, { Name: "warm", }, }, }, wantErr: false, }, { name: "valid ISM policy with actions", policy: &Policy{ DefaultState: "hot", States: []State{ { Name: "hot", Actions: []Action{ { Config: map[string]interface{}{ "rollover": map[string]interface{}{ "min_index_age": "1d", }, }, }, }, }, }, }, wantErr: false, }, { name: "valid ILM policy with multiple phases", policy: &Policy{ Description: "ILM policy", Phases: map[string]Phase{ "hot": { MinAge: "0ms", Actions: map[string]interface{}{ "rollover": map[string]interface{}{ "max_age": "30d", }, }, }, "delete": { MinAge: "90d", Actions: map[string]interface{}{ "delete": map[string]interface{}{}, }, }, }, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.policy.Validate() if (err != nil) != tt.wantErr { t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr) } }) } } // TestPolicy_JSONMarshaling tests policy JSON marshaling func TestPolicy_JSONMarshaling(t *testing.T) { policy := &Policy{ Description: "Test policy", DefaultState: "hot", States: []State{ { Name: "hot", Actions: []Action{ { Config: map[string]interface{}{ "rollover": map[string]interface{}{ "min_index_age": "1d", }, }, }, }, }, }, ISMTemplate: []ISMTemplate{ { IndexPatterns: []string{"test-*"}, Priority: 100, }, }, } // Marshal data, err := json.Marshal(policy) if err != nil { t.Fatalf("json.Marshal() error = %v", err) } // Unmarshal var decoded Policy if err := json.Unmarshal(data, &decoded); err != nil { t.Fatalf("json.Unmarshal() error = %v", err) } // Verify if decoded.Description != policy.Description { t.Errorf("Description = %v, want %v", decoded.Description, policy.Description) } if decoded.DefaultState != policy.DefaultState { t.Errorf("DefaultState = %v, want %v", decoded.DefaultState, policy.DefaultState) } if len(decoded.States) != len(policy.States) { t.Errorf("States length = %d, want %d", len(decoded.States), len(policy.States)) } if len(decoded.ISMTemplate) != len(policy.ISMTemplate) { t.Errorf("ISMTemplate length = %d, want %d", len(decoded.ISMTemplate), len(policy.ISMTemplate)) } } // TestPolicy_MarshalError tests error handling in policy marshaling func TestPolicy_MarshalError(t *testing.T) { if testing.Short() { t.Skip("skipping integration test in short mode") } if err := config.Load(".env"); err != nil { t.Logf("warning: failed to load .env file: %v", err) } config.Init() cfg := &client.Config{ Endpoint: config.Endpoint, Region: config.Region, AccessKey: config.AccessKey, SecretKey: config.SecretKey, } c, err := client.NewClient(cfg) if err != nil { t.Fatalf("failed to create client: %v", err) } pm := NewISMPolicyManager(c) ctx := context.Background() // 创建一个包含不可序列化数据的策略 policy := &Policy{ DefaultState: "hot", States: []State{ { Name: "hot", Actions: []Action{ { Config: map[string]interface{}{ "invalid": make(chan int), // channels 不能被 JSON 序列化 }, }, }, }, }, } err = pm.PutPolicy(ctx, "test", policy) if err == nil { t.Error("PutPolicy() should return error for invalid JSON") } if !strings.Contains(err.Error(), "marshal") { t.Errorf("Error should mention marshal, got: %v", err) } } // TestState_Transitions tests state transition logic func TestState_Transitions(t *testing.T) { state := State{ Name: "hot", Transitions: []Transition{ { StateName: "warm", Conditions: &Conditions{ MinIndexAge: "1d", }, }, { StateName: "delete", Conditions: &Conditions{ MinIndexAge: "7d", }, }, }, } if len(state.Transitions) != 2 { t.Errorf("Expected 2 transitions, got %d", len(state.Transitions)) } if state.Transitions[0].StateName != "warm" { t.Errorf("First transition state = %v, want warm", state.Transitions[0].StateName) } if state.Transitions[1].Conditions.MinIndexAge != "7d" { t.Errorf("Second transition min_index_age = %v, want 7d", state.Transitions[1].Conditions.MinIndexAge) } } // TestAction_Config tests action configuration func TestAction_Config(t *testing.T) { action := Action{ Config: map[string]interface{}{ "rollover": map[string]interface{}{ "min_index_age": "1d", "min_doc_count": 1000000, }, }, } rollover, ok := action.Config["rollover"].(map[string]interface{}) if !ok { t.Fatal("Failed to get rollover config") } if rollover["min_index_age"] != "1d" { t.Errorf("min_index_age = %v, want 1d", rollover["min_index_age"]) } if rollover["min_doc_count"] != 1000000 { t.Errorf("min_doc_count = %v, want 1000000", rollover["min_doc_count"]) } } // TestISMTemplate_Patterns tests ISM template index patterns func TestISMTemplate_Patterns(t *testing.T) { template := ISMTemplate{ IndexPatterns: []string{"logs-*", "metrics-*", "traces-*"}, Priority: 100, } if len(template.IndexPatterns) != 3 { t.Errorf("Expected 3 index patterns, got %d", len(template.IndexPatterns)) } if template.Priority != 100 { t.Errorf("Priority = %d, want 100", template.Priority) } // Test JSON marshaling data, err := json.Marshal(template) if err != nil { t.Fatalf("json.Marshal() error = %v", err) } var decoded ISMTemplate if err := json.Unmarshal(data, &decoded); err != nil { t.Fatalf("json.Unmarshal() error = %v", err) } if len(decoded.IndexPatterns) != len(template.IndexPatterns) { t.Errorf("Decoded index patterns length = %d, want %d", len(decoded.IndexPatterns), len(template.IndexPatterns)) } }