yao/workspace/bench_test.go
Max d25bfefee0 Enhance Sandbox V2 testing and integration with Workspace
- Introduce new unit test targets for Workspace and Sandbox V2 integration in the Makefile, ensuring comprehensive testing of the new features.
- Update CI workflows to support MongoDB service for Sandbox V2 tests and improve Docker image handling.
- Implement Workspace as a first-class entity, allowing for persistent storage decoupled from container lifecycles.
- Enhance the Box struct to manage workspace IDs and update related methods for improved functionality.
- Refactor tests to accommodate new Workspace features, ensuring robust testing of the integration.

These changes significantly improve the testing framework and functionality of the Sandbox V2, enhancing the overall architecture and user experience.
2026-03-05 21:00:50 +08:00

199 lines
5 KiB
Go

package workspace_test
import (
"context"
"fmt"
"io/fs"
"testing"
"github.com/yaoapp/yao/workspace"
)
// BenchmarkWriteFile measures workspace file write latency.
func BenchmarkWriteFile(b *testing.B) {
for _, pc := range testPools() {
b.Run(pc.Name, func(b *testing.B) {
m := setupManagerForPool(b, pc)
ws := createWorkspace(b, m, pc.Name)
ctx := context.Background()
payload := []byte("package main\nfunc main() { println(\"bench\") }\n")
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := m.WriteFile(ctx, ws.ID, fmt.Sprintf("f%d.go", i), payload, 0644); err != nil {
b.Fatalf("WriteFile: %v", err)
}
}
})
}
}
// BenchmarkReadFile measures workspace file read latency.
func BenchmarkReadFile(b *testing.B) {
for _, pc := range testPools() {
b.Run(pc.Name, func(b *testing.B) {
m := setupManagerForPool(b, pc)
ws := createWorkspace(b, m, pc.Name)
ctx := context.Background()
if err := m.WriteFile(ctx, ws.ID, "bench.txt", []byte("benchmark data here"), 0644); err != nil {
b.Fatalf("setup WriteFile: %v", err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
data, err := m.ReadFile(ctx, ws.ID, "bench.txt")
if err != nil {
b.Fatalf("ReadFile: %v", err)
}
if len(data) == 0 {
b.Fatal("empty data")
}
}
})
}
}
// BenchmarkReadWriteCycle measures a full write-then-read cycle.
func BenchmarkReadWriteCycle(b *testing.B) {
for _, pc := range testPools() {
b.Run(pc.Name, func(b *testing.B) {
m := setupManagerForPool(b, pc)
ws := createWorkspace(b, m, pc.Name)
ctx := context.Background()
payload := []byte("package main\nfunc main() { println(\"cycle\") }\n")
b.ResetTimer()
for i := 0; i < b.N; i++ {
name := fmt.Sprintf("c%d.go", i)
if err := m.WriteFile(ctx, ws.ID, name, payload, 0644); err != nil {
b.Fatalf("WriteFile: %v", err)
}
data, err := m.ReadFile(ctx, ws.ID, name)
if err != nil {
b.Fatalf("ReadFile: %v", err)
}
if len(data) != len(payload) {
b.Fatalf("size mismatch: %d vs %d", len(data), len(payload))
}
}
})
}
}
// BenchmarkWriteLargeFile measures write throughput with a 1MB payload.
func BenchmarkWriteLargeFile(b *testing.B) {
for _, pc := range testPools() {
b.Run(pc.Name, func(b *testing.B) {
m := setupManagerForPool(b, pc)
ws := createWorkspace(b, m, pc.Name)
ctx := context.Background()
payload := make([]byte, 1<<20) // 1 MB
for i := range payload {
payload[i] = byte('A' + i%26)
}
b.SetBytes(int64(len(payload)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := m.WriteFile(ctx, ws.ID, fmt.Sprintf("large%d.bin", i), payload, 0644); err != nil {
b.Fatalf("WriteFile: %v", err)
}
}
})
}
}
// BenchmarkListDir measures directory listing latency (50 files).
func BenchmarkListDir(b *testing.B) {
for _, pc := range testPools() {
b.Run(pc.Name, func(b *testing.B) {
m := setupManagerForPool(b, pc)
ws := createWorkspace(b, m, pc.Name)
ctx := context.Background()
for i := 0; i < 50; i++ {
m.WriteFile(ctx, ws.ID, fmt.Sprintf("file%d.txt", i), []byte("x"), 0644)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
entries, err := m.ListDir(ctx, ws.ID, ".")
if err != nil {
b.Fatalf("ListDir: %v", err)
}
if len(entries) < 50 {
b.Fatalf("expected >= 50 entries, got %d", len(entries))
}
}
})
}
}
// BenchmarkFSWalkDir measures fs.WalkDir performance over a directory tree (45+ entries).
func BenchmarkFSWalkDir(b *testing.B) {
for _, pc := range testPools() {
b.Run(pc.Name, func(b *testing.B) {
m := setupManagerForPool(b, pc)
ws := createWorkspace(b, m, pc.Name)
ctx := context.Background()
wfs, err := m.FS(ctx, ws.ID)
if err != nil {
b.Fatalf("FS: %v", err)
}
for _, dir := range []string{"src", "src/pkg", "src/cmd", "lib"} {
wfs.MkdirAll(dir, 0755)
}
for i := 0; i < 20; i++ {
wfs.WriteFile(fmt.Sprintf("src/f%d.go", i), []byte("package src"), 0644)
}
for i := 0; i < 10; i++ {
wfs.WriteFile(fmt.Sprintf("src/pkg/p%d.go", i), []byte("package pkg"), 0644)
}
for i := 0; i < 10; i++ {
wfs.WriteFile(fmt.Sprintf("lib/l%d.go", i), []byte("package lib"), 0644)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
count := 0
fs.WalkDir(wfs, ".", func(_ string, _ fs.DirEntry, err error) error {
if err != nil {
return err
}
count++
return nil
})
if count < 40 {
b.Fatalf("walk returned only %d entries", count)
}
}
})
}
}
// BenchmarkCreateDelete measures workspace CRUD cycle.
func BenchmarkCreateDelete(b *testing.B) {
for _, pc := range testPools() {
b.Run(pc.Name, func(b *testing.B) {
m := setupManagerForPool(b, pc)
ctx := context.Background()
b.ResetTimer()
for i := 0; i < b.N; i++ {
ws, err := m.Create(ctx, workspace.CreateOptions{
Name: "bench-workspace",
Owner: "bench-user",
Node: pc.Name,
})
if err != nil {
b.Fatalf("Create: %v", err)
}
if err := m.Delete(ctx, ws.ID, true); err != nil {
b.Fatalf("Delete: %v", err)
}
}
})
}
}