| package sql_test |
|
|
| import ( |
| "testing" |
|
|
| "ccLoad/internal/model" |
| sqlstore "ccLoad/internal/storage/sql" |
| ) |
|
|
| func TestWhereBuilder_ApplyLogFilter(t *testing.T) { |
| t.Parallel() |
|
|
| channelID := int64(42) |
| statusCode := 500 |
| authTokenID := int64(7) |
|
|
| tests := []struct { |
| name string |
| filter *model.LogFilter |
| expectArgsLen int |
| expectNoWhere bool |
| }{ |
| { |
| name: "nil filter", |
| filter: nil, |
| expectArgsLen: 1, |
| }, |
| { |
| name: "empty filter", |
| filter: &model.LogFilter{}, |
| expectArgsLen: 1, |
| }, |
| { |
| name: "channel_id only", |
| filter: &model.LogFilter{ |
| ChannelID: &channelID, |
| }, |
| expectArgsLen: 2, |
| }, |
| { |
| name: "model exact match", |
| filter: &model.LogFilter{ |
| Model: "gpt-4o", |
| }, |
| expectArgsLen: 2, |
| }, |
| { |
| name: "model like match", |
| filter: &model.LogFilter{ |
| ModelLike: "claude", |
| }, |
| expectArgsLen: 2, |
| }, |
| { |
| name: "status_code filter", |
| filter: &model.LogFilter{ |
| StatusCode: &statusCode, |
| }, |
| expectArgsLen: 2, |
| }, |
| { |
| name: "auth_token_id filter", |
| filter: &model.LogFilter{ |
| AuthTokenID: &authTokenID, |
| }, |
| expectArgsLen: 2, |
| }, |
| { |
| name: "all filters combined", |
| filter: &model.LogFilter{ |
| ChannelID: &channelID, |
| Model: "gpt-4o", |
| StatusCode: &statusCode, |
| AuthTokenID: &authTokenID, |
| }, |
| expectArgsLen: 5, |
| }, |
| { |
| name: "scheduled_check source", |
| filter: &model.LogFilter{ |
| LogSource: model.LogSourceScheduledCheck, |
| }, |
| expectArgsLen: 1, |
| }, |
| { |
| name: "detection source expands to two args", |
| filter: &model.LogFilter{ |
| LogSource: model.LogSourceDetection, |
| }, |
| expectArgsLen: 2, |
| }, |
| } |
|
|
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| wb := sqlstore.NewWhereBuilder() |
| wb.ApplyLogFilter(tt.filter) |
| clause, args := wb.Build() |
|
|
| if tt.expectNoWhere { |
| if clause != "" { |
| t.Errorf("expected empty clause, got %q", clause) |
| } |
| return |
| } |
|
|
| if len(args) != tt.expectArgsLen { |
| t.Errorf("expected %d args, got %d", tt.expectArgsLen, len(args)) |
| } |
|
|
| if clause == "" { |
| t.Error("expected non-empty clause") |
| } |
| if tt.filter != nil && tt.filter.LogSource == model.LogSourceDetection && clause != "log_source IN (?, ?)" { |
| t.Errorf("unexpected detection clause: %q", clause) |
| } |
| if tt.filter == nil && clause != "log_source = ?" { |
| t.Errorf("unexpected nil-filter clause: %q", clause) |
| } |
| }) |
| } |
| } |
|
|
| func TestWhereBuilder_Build_EmptyConditions(t *testing.T) { |
| t.Parallel() |
|
|
| wb := sqlstore.NewWhereBuilder() |
| clause, args := wb.Build() |
|
|
| if clause != "" { |
| t.Errorf("expected empty clause, got %q", clause) |
| } |
| if len(args) != 0 { |
| t.Errorf("expected 0 args, got %d", len(args)) |
| } |
| } |
|
|
| func TestWhereBuilder_Build_MultipleConditions(t *testing.T) { |
| t.Parallel() |
|
|
| wb := sqlstore.NewWhereBuilder() |
| wb.AddCondition("a = ?", 1) |
| wb.AddCondition("b = ?", 2) |
| wb.AddCondition("c > ?", 3) |
|
|
| clause, args := wb.Build() |
|
|
| if clause != "a = ? AND b = ? AND c > ?" { |
| t.Errorf("unexpected clause: %q", clause) |
| } |
| if len(args) != 3 { |
| t.Errorf("expected 3 args, got %d", len(args)) |
| } |
| } |
|
|
| func TestWhereBuilder_BuildWithPrefix(t *testing.T) { |
| t.Parallel() |
|
|
| t.Run("empty conditions returns empty", func(t *testing.T) { |
| wb := sqlstore.NewWhereBuilder() |
| clause, args := wb.BuildWithPrefix("WHERE") |
|
|
| if clause != "" { |
| t.Errorf("expected empty clause, got %q", clause) |
| } |
| if len(args) != 0 { |
| t.Errorf("expected 0 args, got %d", len(args)) |
| } |
| }) |
|
|
| t.Run("with conditions adds prefix", func(t *testing.T) { |
| wb := sqlstore.NewWhereBuilder() |
| wb.AddCondition("x = ?", 1) |
| clause, _ := wb.BuildWithPrefix("WHERE") |
|
|
| if clause != "WHERE x = ?" { |
| t.Errorf("unexpected clause: %q", clause) |
| } |
| }) |
|
|
| t.Run("custom prefix", func(t *testing.T) { |
| wb := sqlstore.NewWhereBuilder() |
| wb.AddCondition("x = ?", 1) |
| clause, _ := wb.BuildWithPrefix("AND") |
|
|
| if clause != "AND x = ?" { |
| t.Errorf("unexpected clause: %q", clause) |
| } |
| }) |
| } |
|
|
| func TestWhereBuilder_AddCondition_EmptyString(t *testing.T) { |
| t.Parallel() |
|
|
| wb := sqlstore.NewWhereBuilder() |
| wb.AddCondition("", 1) |
| wb.AddCondition("a = ?", 2) |
|
|
| clause, args := wb.Build() |
|
|
| if clause != "a = ?" { |
| t.Errorf("unexpected clause: %q", clause) |
| } |
| if len(args) != 1 { |
| t.Errorf("expected 1 arg, got %d", len(args)) |
| } |
| } |
|
|
| func TestWhereBuilder_Chaining(t *testing.T) { |
| t.Parallel() |
|
|
| |
| clause, args := sqlstore.NewWhereBuilder(). |
| AddCondition("a = ?", 1). |
| AddCondition("b > ?", 2). |
| Build() |
|
|
| if clause != "a = ? AND b > ?" { |
| t.Errorf("unexpected clause: %q", clause) |
| } |
| if len(args) != 2 { |
| t.Errorf("expected 2 args, got %d", len(args)) |
| } |
| } |
|
|