504 lines
11 KiB
Go
504 lines
11 KiB
Go
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))
|
|
}
|
|
}
|