Files
tidb/pkg/objstore/batch_test.go

123 lines
3.4 KiB
Go

// Copyright 2026 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package objstore_test
import (
"context"
"io"
"os"
"testing"
. "github.com/pingcap/tidb/pkg/objstore"
"github.com/stretchr/testify/require"
)
func TestBatched(t *testing.T) {
ctx := context.Background()
bat := Batch(nil) // Passing nil as we don't need actual storage operations
// Test operations
operations := []struct {
name string
op func() error
expected []Effect
}{
{
name: "DeleteFiles",
op: func() error {
return bat.DeleteFiles(ctx, []string{"file1.txt", "file2.txt"})
},
expected: []Effect{EffDeleteFiles{Files: []string{"file1.txt", "file2.txt"}}},
},
{
name: "DeleteFile",
op: func() error {
return bat.DeleteFile(ctx, "file3.txt")
},
expected: []Effect{EffDeleteFile("file3.txt")},
},
{
name: "WriteFile",
op: func() error {
return bat.WriteFile(ctx, "file4.txt", []byte("content"))
},
expected: []Effect{EffPut{File: "file4.txt", Content: []byte("content")}},
},
{
name: "Rename",
op: func() error {
return bat.Rename(ctx, "oldName.txt", "newName.txt")
},
expected: []Effect{EffRename{From: "oldName.txt", To: "newName.txt"}},
},
{
name: "SequenceOfOperations",
op: func() error {
if err := bat.DeleteFile(ctx, "file5.txt"); err != nil {
return err
}
if err := bat.WriteFile(ctx, "file6.txt", []byte("new content")); err != nil {
return err
}
return bat.Rename(ctx, "file6.txt", "fileRenamed.txt")
},
expected: []Effect{
EffDeleteFile("file5.txt"),
EffPut{File: "file6.txt", Content: []byte("new content")},
EffRename{From: "file6.txt", To: "fileRenamed.txt"},
}},
}
for _, op := range operations {
t.Run(op.name, func(t *testing.T) {
require.NoError(t, op.op())
effects := bat.ReadOnlyEffects()
require.Equal(t, len(op.expected), len(effects))
for i, effect := range effects {
require.Equal(t, op.expected[i], effect)
}
// Reset effects for the next test
bat.CleanEffects()
})
}
}
func TestJSONEffects(t *testing.T) {
effects := []Effect{
EffPut{File: "example.txt", Content: []byte("Hello, world")},
EffDeleteFiles{Files: []string{"old_file.txt", "temp.txt"}},
EffDeleteFile("obsolete.txt"),
EffRename{From: "old_name.txt", To: "new_name.txt"},
}
tmp, err := SaveJSONEffectsToTmp(effects)
require.NoError(t, err)
f, err := os.Open(tmp)
require.NoError(t, err)
buf, err := io.ReadAll(f)
require.NoError(t, err)
expectedJSON := `[
{"type":"objstore.EffPut","effect":{"file":"example.txt","content":"SGVsbG8sIHdvcmxk"}},
{"type":"objstore.EffDeleteFiles","effect":{"files":["old_file.txt","temp.txt"]}},
{"type":"objstore.EffDeleteFile","effect":"obsolete.txt"},
{"type":"objstore.EffRename","effect":{"from":"old_name.txt","to":"new_name.txt"}}
]`
require.JSONEq(t, expectedJSON, string(buf), "Output JSON should match expected JSON")
}