mirror of https://github.com/grafana/loki
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.
536 lines
12 KiB
536 lines
12 KiB
package delete
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/grafana/loki/v3/pkg/logcli/client"
|
|
)
|
|
|
|
func TestDeleteCreateQuery(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
query Query
|
|
expectError bool
|
|
expectParams client.DeleteRequestParams
|
|
expectOutput string
|
|
}{
|
|
{
|
|
name: "basic create request",
|
|
query: Query{
|
|
QueryString: "{job=\"test\"}",
|
|
Start: time.Unix(1000, 0),
|
|
End: time.Unix(2000, 0),
|
|
Quiet: false,
|
|
},
|
|
expectError: false,
|
|
expectParams: client.DeleteRequestParams{
|
|
Query: "{job=\"test\"}",
|
|
Start: "1000",
|
|
End: "2000",
|
|
},
|
|
expectOutput: "Delete request created successfully\n",
|
|
},
|
|
{
|
|
name: "create request with max interval",
|
|
query: Query{
|
|
QueryString: "{job=\"test\"}",
|
|
Start: time.Unix(1000, 0),
|
|
End: time.Unix(2000, 0),
|
|
MaxInterval: "1h",
|
|
Quiet: false,
|
|
},
|
|
expectError: false,
|
|
expectParams: client.DeleteRequestParams{
|
|
Query: "{job=\"test\"}",
|
|
Start: "1000",
|
|
End: "2000",
|
|
MaxInterval: "1h",
|
|
},
|
|
expectOutput: "Delete request created successfully\n",
|
|
},
|
|
{
|
|
name: "create request with zero times",
|
|
query: Query{
|
|
QueryString: "{job=\"test\"}",
|
|
Start: time.Time{},
|
|
End: time.Time{},
|
|
Quiet: false,
|
|
},
|
|
expectError: false,
|
|
expectParams: client.DeleteRequestParams{
|
|
Query: "{job=\"test\"}",
|
|
},
|
|
expectOutput: "Delete request created successfully\n",
|
|
},
|
|
{
|
|
name: "create request quiet mode",
|
|
query: Query{
|
|
QueryString: "{job=\"test\"}",
|
|
Start: time.Unix(1000, 0),
|
|
End: time.Unix(2000, 0),
|
|
Quiet: true,
|
|
},
|
|
expectError: false,
|
|
expectParams: client.DeleteRequestParams{
|
|
Query: "{job=\"test\"}",
|
|
Start: "1000",
|
|
End: "2000",
|
|
},
|
|
expectOutput: "",
|
|
},
|
|
{
|
|
name: "create request with API error",
|
|
query: Query{
|
|
QueryString: "{job=\"test\"}",
|
|
Start: time.Unix(1000, 0),
|
|
End: time.Unix(2000, 0),
|
|
Quiet: false,
|
|
},
|
|
expectError: true,
|
|
expectParams: client.DeleteRequestParams{
|
|
Query: "{job=\"test\"}",
|
|
Start: "1000",
|
|
End: "2000",
|
|
},
|
|
expectOutput: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Capture stdout
|
|
oldStdout := os.Stdout
|
|
r, w, _ := os.Pipe()
|
|
os.Stdout = w
|
|
|
|
// Create mock client
|
|
mockClient := newMockDeleteClient()
|
|
if tt.expectError {
|
|
mockClient.withCreateError(errors.New("API error"))
|
|
}
|
|
|
|
// Execute test
|
|
err := tt.query.CreateQuery(mockClient)
|
|
|
|
// Restore stdout and capture output
|
|
w.Close()
|
|
os.Stdout = oldStdout
|
|
var buf bytes.Buffer
|
|
_, _ = io.Copy(&buf, r)
|
|
output := buf.String()
|
|
|
|
// Verify results
|
|
if tt.expectError {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.expectOutput, output)
|
|
assert.Equal(t, 1, mockClient.createDeleteRequestCalls)
|
|
assert.Equal(t, tt.expectParams, mockClient.lastCreateParams)
|
|
assert.Equal(t, tt.query.Quiet, mockClient.lastCreateQuiet)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteListQuery(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
query Query
|
|
deleteRequests []client.DeleteRequest
|
|
expectError bool
|
|
expectOutput string
|
|
expectCallCount int
|
|
}{
|
|
{
|
|
name: "empty list",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
deleteRequests: []client.DeleteRequest{},
|
|
expectError: false,
|
|
expectOutput: "Found 0 delete requests:\n",
|
|
},
|
|
{
|
|
name: "single delete request",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
deleteRequests: []client.DeleteRequest{
|
|
{
|
|
StartTime: 1000,
|
|
EndTime: 2000,
|
|
Query: "{job=\"test\"}",
|
|
Status: "received",
|
|
},
|
|
},
|
|
expectError: false,
|
|
expectOutput: "Found 1 delete requests:\n" +
|
|
"Query: {job=\"test\"}\n" +
|
|
"Start Time: " + time.Unix(1000, 0).Format(time.RFC3339) + "\n" +
|
|
"End Time: " + time.Unix(2000, 0).Format(time.RFC3339) + "\n" +
|
|
"Status: received\n" +
|
|
"---\n",
|
|
},
|
|
{
|
|
name: "multiple delete requests",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
deleteRequests: []client.DeleteRequest{
|
|
{
|
|
StartTime: 1000,
|
|
EndTime: 2000,
|
|
Query: "{job=\"test1\"}",
|
|
Status: "received",
|
|
},
|
|
{
|
|
StartTime: 3000,
|
|
EndTime: 4000,
|
|
Query: "{job=\"test2\"}",
|
|
Status: "processed",
|
|
},
|
|
},
|
|
expectError: false,
|
|
expectOutput: "Found 2 delete requests:\n" +
|
|
"Query: {job=\"test1\"}\n" +
|
|
"Start Time: " + time.Unix(1000, 0).Format(time.RFC3339) + "\n" +
|
|
"End Time: " + time.Unix(2000, 0).Format(time.RFC3339) + "\n" +
|
|
"Status: received\n" +
|
|
"---\n" +
|
|
"Query: {job=\"test2\"}\n" +
|
|
"Start Time: " + time.Unix(3000, 0).Format(time.RFC3339) + "\n" +
|
|
"End Time: " + time.Unix(4000, 0).Format(time.RFC3339) + "\n" +
|
|
"Status: processed\n" +
|
|
"---\n",
|
|
},
|
|
{
|
|
name: "quiet mode",
|
|
query: Query{
|
|
Quiet: true,
|
|
},
|
|
deleteRequests: []client.DeleteRequest{
|
|
{
|
|
StartTime: 1000,
|
|
EndTime: 2000,
|
|
Query: "{job=\"test\"}",
|
|
Status: "received",
|
|
},
|
|
},
|
|
expectError: false,
|
|
expectOutput: "Query: {job=\"test\"}\n" +
|
|
"Start Time: " + time.Unix(1000, 0).Format(time.RFC3339) + "\n" +
|
|
"End Time: " + time.Unix(2000, 0).Format(time.RFC3339) + "\n" +
|
|
"Status: received\n" +
|
|
"---\n",
|
|
},
|
|
{
|
|
name: "API error",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
deleteRequests: nil,
|
|
expectError: true,
|
|
expectOutput: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Capture stdout
|
|
oldStdout := os.Stdout
|
|
r, w, _ := os.Pipe()
|
|
os.Stdout = w
|
|
|
|
// Create mock client
|
|
mockClient := newMockDeleteClient().withDeleteRequests(tt.deleteRequests)
|
|
if tt.expectError {
|
|
mockClient.withListError(errors.New("API error"))
|
|
}
|
|
|
|
// Execute test
|
|
err := tt.query.ListQuery(mockClient)
|
|
|
|
// Restore stdout and capture output
|
|
w.Close()
|
|
os.Stdout = oldStdout
|
|
var buf bytes.Buffer
|
|
_, _ = io.Copy(&buf, r)
|
|
output := buf.String()
|
|
|
|
// Verify results
|
|
if tt.expectError {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.expectOutput, output)
|
|
assert.Equal(t, 1, mockClient.listDeleteRequestsCalls)
|
|
assert.Equal(t, tt.query.Quiet, mockClient.lastListQuiet)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteListQueryJSON(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
query Query
|
|
deleteRequests []client.DeleteRequest
|
|
expectError bool
|
|
expectedJSON string
|
|
}{
|
|
{
|
|
name: "empty list JSON",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
deleteRequests: []client.DeleteRequest{},
|
|
expectError: false,
|
|
expectedJSON: "[]\n",
|
|
},
|
|
{
|
|
name: "single request JSON",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
deleteRequests: []client.DeleteRequest{
|
|
{
|
|
StartTime: 1000,
|
|
EndTime: 2000,
|
|
Query: "{job=\"test\"}",
|
|
Status: "received",
|
|
},
|
|
},
|
|
expectError: false,
|
|
expectedJSON: "[\n" +
|
|
" {\n" +
|
|
" \"start_time\": 1000,\n" +
|
|
" \"end_time\": 2000,\n" +
|
|
" \"query\": \"{job=\\\"test\\\"}\",\n" +
|
|
" \"status\": \"received\"\n" +
|
|
" }\n" +
|
|
"]\n",
|
|
},
|
|
{
|
|
name: "API error JSON",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
deleteRequests: nil,
|
|
expectError: true,
|
|
expectedJSON: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Capture stdout
|
|
oldStdout := os.Stdout
|
|
r, w, _ := os.Pipe()
|
|
os.Stdout = w
|
|
|
|
// Create mock client
|
|
mockClient := newMockDeleteClient().withDeleteRequests(tt.deleteRequests)
|
|
if tt.expectError {
|
|
mockClient.withListError(errors.New("API error"))
|
|
}
|
|
|
|
// Execute test
|
|
err := tt.query.ListQueryJSON(mockClient)
|
|
|
|
// Restore stdout and capture output
|
|
w.Close()
|
|
os.Stdout = oldStdout
|
|
var buf bytes.Buffer
|
|
_, _ = io.Copy(&buf, r)
|
|
output := buf.String()
|
|
|
|
// Verify results
|
|
if tt.expectError {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.expectedJSON, output)
|
|
assert.Equal(t, 1, mockClient.listDeleteRequestsCalls)
|
|
assert.Equal(t, tt.query.Quiet, mockClient.lastListQuiet)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteCancelQuery(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
query Query
|
|
requestID string
|
|
force bool
|
|
expectError bool
|
|
expectOutput string
|
|
}{
|
|
{
|
|
name: "basic cancel request",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
requestID: "test-request-123",
|
|
force: false,
|
|
expectError: false,
|
|
expectOutput: "Delete request test-request-123 cancelled successfully\n",
|
|
},
|
|
{
|
|
name: "cancel with force",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
requestID: "test-request-456",
|
|
force: true,
|
|
expectError: false,
|
|
expectOutput: "Delete request test-request-456 cancelled successfully\n",
|
|
},
|
|
{
|
|
name: "cancel quiet mode",
|
|
query: Query{
|
|
Quiet: true,
|
|
},
|
|
requestID: "test-request-789",
|
|
force: false,
|
|
expectError: false,
|
|
expectOutput: "",
|
|
},
|
|
{
|
|
name: "cancel with API error",
|
|
query: Query{
|
|
Quiet: false,
|
|
},
|
|
requestID: "test-request-error",
|
|
force: false,
|
|
expectError: true,
|
|
expectOutput: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Capture stdout
|
|
oldStdout := os.Stdout
|
|
r, w, _ := os.Pipe()
|
|
os.Stdout = w
|
|
|
|
// Create mock client
|
|
mockClient := newMockDeleteClient()
|
|
if tt.expectError {
|
|
mockClient.withCancelError(errors.New("API error"))
|
|
}
|
|
|
|
// Execute test
|
|
err := tt.query.CancelQuery(mockClient, tt.requestID, tt.force)
|
|
|
|
// Restore stdout and capture output
|
|
w.Close()
|
|
os.Stdout = oldStdout
|
|
var buf bytes.Buffer
|
|
_, _ = io.Copy(&buf, r)
|
|
output := buf.String()
|
|
|
|
// Verify results
|
|
if tt.expectError {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.expectOutput, output)
|
|
assert.Equal(t, 1, mockClient.cancelDeleteRequestCalls)
|
|
assert.Equal(t, tt.requestID, mockClient.lastCancelRequestID)
|
|
assert.Equal(t, tt.force, mockClient.lastCancelForce)
|
|
assert.Equal(t, tt.query.Quiet, mockClient.lastCancelQuiet)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTimeConversion(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
time time.Time
|
|
expected string
|
|
}{
|
|
{
|
|
name: "zero time",
|
|
time: time.Time{},
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "unix epoch",
|
|
time: time.Unix(0, 0),
|
|
expected: "0",
|
|
},
|
|
{
|
|
name: "specific time",
|
|
time: time.Unix(1672531200, 0), // 2023-01-01 00:00:00 UTC
|
|
expected: "1672531200",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var result string
|
|
if !tt.time.IsZero() {
|
|
result = strconv.FormatInt(tt.time.Unix(), 10)
|
|
}
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkDeleteCreateQuery(b *testing.B) {
|
|
mockClient := newMockDeleteClient()
|
|
query := Query{
|
|
QueryString: "{job=\"test\"}",
|
|
Start: time.Unix(1000, 0),
|
|
End: time.Unix(2000, 0),
|
|
Quiet: true,
|
|
}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
err := query.CreateQuery(mockClient)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkDeleteListQuery(b *testing.B) {
|
|
deleteRequests := make([]client.DeleteRequest, 100)
|
|
for i := 0; i < 100; i++ {
|
|
deleteRequests[i] = client.DeleteRequest{
|
|
StartTime: int64(1000 + i),
|
|
EndTime: int64(2000 + i),
|
|
Query: fmt.Sprintf("{job=\"test%d\"}", i),
|
|
Status: "received",
|
|
}
|
|
}
|
|
|
|
mockClient := newMockDeleteClient().withDeleteRequests(deleteRequests)
|
|
query := Query{Quiet: true}
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
err := query.ListQuery(mockClient)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|