mirror of
https://github.com/Buriburizaem0n/nezha_domains.git
synced 2026-09-20 18:20:12 +00:00
test(agentcompat): add agent runtime harness
Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
//go:build linux
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/nezhahq/nezha/integration/agentcompat/internal/workspace"
|
||||
)
|
||||
|
||||
type PreparedBinaryUsageError struct {
|
||||
Operation string
|
||||
Reason string
|
||||
}
|
||||
|
||||
func (err *PreparedBinaryUsageError) Error() string {
|
||||
return fmt.Sprintf("prepared agent binary %s: %s", err.Operation, err.Reason)
|
||||
}
|
||||
|
||||
// PreparedBinary owns a build-only workspace. Each successful Start lease keeps
|
||||
// that workspace alive; Agent workspaces own their own config, logs, and process tracking.
|
||||
type PreparedBinary struct {
|
||||
workspace *workspace.Workspace
|
||||
binaryPath string
|
||||
mu sync.Mutex
|
||||
consumers int
|
||||
closed bool
|
||||
}
|
||||
|
||||
func PrepareBinary(ctx context.Context, sourceDir string) (*PreparedBinary, error) {
|
||||
if err := validateSourceDir(sourceDir); err != nil {
|
||||
return nil, &PreparedBinaryUsageError{Operation: "prepare", Reason: err.Error()}
|
||||
}
|
||||
workspaceRoot, err := workspace.New(context.WithoutCancel(ctx))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create prepared agent workspace: %w", err)
|
||||
}
|
||||
binaryPath, err := workspaceRoot.Build(ctx, agentBuildSpec(sourceDir))
|
||||
if err != nil {
|
||||
return nil, closePreparedWorkspace(workspaceRoot, err)
|
||||
}
|
||||
if err := exposePreparedBinary(workspaceRoot.Root(), binaryPath); err != nil {
|
||||
return nil, closePreparedWorkspace(workspaceRoot, err)
|
||||
}
|
||||
return &PreparedBinary{workspace: workspaceRoot, binaryPath: binaryPath}, nil
|
||||
}
|
||||
|
||||
func closePreparedWorkspace(workspaceRoot *workspace.Workspace, cause error) error {
|
||||
return fmt.Errorf("prepare agent binary: %w", closeError(cause, workspaceRoot.Close()))
|
||||
}
|
||||
|
||||
func exposePreparedBinary(root, binaryPath string) error {
|
||||
for _, path := range []string{root, filepath.Dir(binaryPath)} {
|
||||
if err := os.Chmod(path, 0o755); err != nil {
|
||||
return fmt.Errorf("make prepared agent binary executable: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (prepared *PreparedBinary) BinaryPath() string {
|
||||
if prepared == nil {
|
||||
return ""
|
||||
}
|
||||
prepared.mu.Lock()
|
||||
defer prepared.mu.Unlock()
|
||||
return prepared.binaryPath
|
||||
}
|
||||
|
||||
func (prepared *PreparedBinary) WorkspaceRoot() string {
|
||||
if prepared == nil {
|
||||
return ""
|
||||
}
|
||||
prepared.mu.Lock()
|
||||
defer prepared.mu.Unlock()
|
||||
return prepared.workspace.Root()
|
||||
}
|
||||
|
||||
func (prepared *PreparedBinary) acquire() (string, func(), error) {
|
||||
if prepared == nil {
|
||||
return "", nil, &PreparedBinaryUsageError{Operation: "start", Reason: "is nil"}
|
||||
}
|
||||
prepared.mu.Lock()
|
||||
defer prepared.mu.Unlock()
|
||||
if prepared.workspace == nil || prepared.binaryPath == "" {
|
||||
return "", nil, &PreparedBinaryUsageError{Operation: "start", Reason: "is uninitialized"}
|
||||
}
|
||||
if prepared.closed {
|
||||
return "", nil, &PreparedBinaryUsageError{Operation: "start", Reason: "is closed"}
|
||||
}
|
||||
prepared.consumers++
|
||||
return prepared.binaryPath, prepared.release, nil
|
||||
}
|
||||
|
||||
func (prepared *PreparedBinary) release() {
|
||||
prepared.mu.Lock()
|
||||
defer prepared.mu.Unlock()
|
||||
prepared.consumers--
|
||||
}
|
||||
|
||||
func (prepared *PreparedBinary) Close() error {
|
||||
if prepared == nil {
|
||||
return &PreparedBinaryUsageError{Operation: "close", Reason: "is nil"}
|
||||
}
|
||||
prepared.mu.Lock()
|
||||
defer prepared.mu.Unlock()
|
||||
if prepared.workspace == nil || prepared.binaryPath == "" {
|
||||
return &PreparedBinaryUsageError{Operation: "close", Reason: "is uninitialized"}
|
||||
}
|
||||
if prepared.closed {
|
||||
return nil
|
||||
}
|
||||
if prepared.consumers != 0 {
|
||||
return &PreparedBinaryUsageError{Operation: "close", Reason: "has active consumers"}
|
||||
}
|
||||
if err := prepared.workspace.Close(); err != nil {
|
||||
return fmt.Errorf("close prepared agent workspace: %w", err)
|
||||
}
|
||||
prepared.closed = true
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user