Очередь job получила lease и fencing, телеметрия и прогресс deploy сохраняются, ревизия пишет manifest входов. Обновление префиксов не переписывает неизменённый снимок, большие наборы идут через COPY, а устаревшая ревизия не попадает в deploy. Бандл ноды кэшируется, prune и постановка job больше не держат горячий путь. Co-authored-by: Cursor <cursoragent@cursor.com>
82 lines
2.4 KiB
Go
82 lines
2.4 KiB
Go
package nodecli
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"evobgp/internal/bundle"
|
|
)
|
|
|
|
type countingBody struct {
|
|
io.Reader
|
|
read int
|
|
}
|
|
|
|
func (b *countingBody) Read(p []byte) (int, error) {
|
|
n, e := b.Reader.Read(p)
|
|
b.read += n
|
|
return n, e
|
|
}
|
|
func (b *countingBody) Close() error { return nil }
|
|
|
|
func TestHTTPBundleBoundKnownAndChunked(t *testing.T) {
|
|
for _, length := range []int64{-1, 2048} {
|
|
body := &countingBody{Reader: bytes.NewReader(bytes.Repeat([]byte{'x'}, 2048))}
|
|
_, err := readHTTPBytes(&http.Response{Body: body, ContentLength: length}, 1024)
|
|
if !errors.Is(err, bundle.ErrLimit) {
|
|
t.Fatalf("length=%d limit=%v", length, err)
|
|
}
|
|
if body.read > 1025 || (length > 1024 && body.read != 0) {
|
|
t.Fatalf("unbounded read %d for length %d", body.read, length)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLocalBundleSizeBound(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "bundle.tar.gz")
|
|
if err := os.WriteFile(path, bytes.Repeat([]byte{'x'}, 2048), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := readBundleFile(path, bundle.Limits{MaxCompressedBytes: 1024}); !errors.Is(err, bundle.ErrLimit) {
|
|
t.Fatalf("local input cap: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestBundleHTTPMetadataAndDiagnosticsBound(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch {
|
|
case strings.Contains(r.URL.Path, "/revisions/latest"):
|
|
_, _ = io.WriteString(w, strings.Repeat(" ", 65<<10))
|
|
default:
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
_, _ = io.WriteString(w, strings.Repeat("x", 64<<10))
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
if _, err := fetchLatestRevision(server.URL, "key", "speaker"); !errors.Is(err, bundle.ErrLimit) {
|
|
t.Fatalf("metadata unbounded: %v", err)
|
|
}
|
|
if _, err := fetchBundle(server.URL, "key", "speaker", "revision"); err == nil || len(err.Error()) > 5<<10 {
|
|
t.Fatalf("diagnostic unbounded: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSyncFetchRespectsCallerCancellation(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
if _, err := fetchBundleContext(ctx, "http://127.0.0.1:1", "key", "speaker", "revision", bundle.Limits{}); !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("download ignored cancel: %v", err)
|
|
}
|
|
if _, err := fetchLatestRevisionContext(ctx, "http://127.0.0.1:1", "key", "speaker"); !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("metadata ignored cancel: %v", err)
|
|
}
|
|
}
|