test(agentcompat): add protocol clients

Co-authored-by: naiba/CloudCode <hi+cloudcode@nai.ba>
This commit is contained in:
naiba
2026-07-20 04:48:15 +00:00
co-authored by naiba/CloudCode
parent 8a0e84b214
commit 1c3e926819
23 changed files with 3329 additions and 0 deletions
@@ -0,0 +1,90 @@
package client
import (
"context"
"encoding/base64"
"errors"
"net/http"
)
var ErrInvalidSQLiteHoldReceipt = errors.New("client: invalid sqlite hold receipt")
type SQLiteHoldState string
const (
SQLiteHoldStateArmed SQLiteHoldState = "armed"
SQLiteHoldStateSelected SQLiteHoldState = "selected"
SQLiteHoldStateFinalizing SQLiteHoldState = "finalizing"
SQLiteHoldStateReleased SQLiteHoldState = "released"
SQLiteHoldStateAborted SQLiteHoldState = "aborted"
)
type SQLiteHoldReceipt struct {
ID string `json:"id"`
State SQLiteHoldState `json:"state,omitempty"`
}
func (client *Client) ArmSQLiteHold(ctx context.Context) (SQLiteHoldReceipt, error) {
receipt, err := DoREST[struct{}, SQLiteHoldReceipt](ctx, client, RESTRequest[struct{}]{Method: http.MethodPost, Path: "/agentcompat/sqlite-hold/arm", Body: &struct{}{}})
return validateSQLiteHoldReceipt(receipt, SQLiteHoldStateArmed, err)
}
func (client *Client) WaitForSQLiteHold(ctx context.Context, receipt SQLiteHoldReceipt, target SQLiteHoldState) (SQLiteHoldReceipt, error) {
if err := validateSQLiteHoldRequest(receipt, target); err != nil {
return SQLiteHoldReceipt{}, err
}
request := SQLiteHoldReceipt{ID: receipt.ID, State: target}
result, err := DoREST[SQLiteHoldReceipt, SQLiteHoldReceipt](ctx, client, RESTRequest[SQLiteHoldReceipt]{Method: http.MethodPost, Path: "/agentcompat/sqlite-hold/wait", Body: &request})
return validateSQLiteHoldReceipt(result, target, err)
}
func (client *Client) SnapshotSQLiteHold(ctx context.Context, receipt SQLiteHoldReceipt) (SQLiteHoldReceipt, error) {
return client.sqliteHoldAction(ctx, receipt, "snapshot", "")
}
func (client *Client) ReleaseSQLiteHold(ctx context.Context, receipt SQLiteHoldReceipt) (SQLiteHoldReceipt, error) {
return client.sqliteHoldAction(ctx, receipt, "release", SQLiteHoldStateReleased)
}
func (client *Client) AbortSQLiteHold(ctx context.Context, receipt SQLiteHoldReceipt) (SQLiteHoldReceipt, error) {
return client.sqliteHoldAction(ctx, receipt, "abort", SQLiteHoldStateAborted)
}
func (client *Client) sqliteHoldAction(ctx context.Context, receipt SQLiteHoldReceipt, action string, expected SQLiteHoldState) (SQLiteHoldReceipt, error) {
if err := validateSQLiteHoldRequest(receipt, ""); err != nil {
return SQLiteHoldReceipt{}, err
}
request := SQLiteHoldReceipt{ID: receipt.ID}
result, err := DoREST[SQLiteHoldReceipt, SQLiteHoldReceipt](ctx, client, RESTRequest[SQLiteHoldReceipt]{Method: http.MethodPost, Path: "/agentcompat/sqlite-hold/" + action, Body: &request})
return validateSQLiteHoldReceipt(result, expected, err)
}
func validateSQLiteHoldRequest(receipt SQLiteHoldReceipt, target SQLiteHoldState) error {
decoded, err := base64.RawURLEncoding.DecodeString(receipt.ID)
if err != nil || len(receipt.ID) != 43 || len(decoded) != 32 {
return ErrInvalidSQLiteHoldReceipt
}
if target != "" && target != SQLiteHoldStateSelected && target != SQLiteHoldStateFinalizing {
return ErrInvalidSQLiteHoldReceipt
}
return nil
}
func validateSQLiteHoldReceipt(receipt SQLiteHoldReceipt, expected SQLiteHoldState, err error) (SQLiteHoldReceipt, error) {
if err != nil {
return SQLiteHoldReceipt{}, err
}
if err := validateSQLiteHoldRequest(receipt, ""); err != nil || !validSQLiteHoldState(receipt.State) || expected != "" && receipt.State != expected {
return SQLiteHoldReceipt{}, ErrInvalidSQLiteHoldReceipt
}
return receipt, nil
}
func validSQLiteHoldState(state SQLiteHoldState) bool {
switch state {
case SQLiteHoldStateArmed, SQLiteHoldStateSelected, SQLiteHoldStateFinalizing, SQLiteHoldStateReleased, SQLiteHoldStateAborted:
return true
default:
return false
}
}