Complete browser extension gRPC flow #4
@@ -50,6 +50,7 @@ type Broker struct {
|
||||
timeout time.Duration
|
||||
now func() time.Time
|
||||
nextID func() string
|
||||
notify func()
|
||||
}
|
||||
|
||||
type pendingRequest struct {
|
||||
@@ -108,6 +109,15 @@ func (b *Broker) Pending() []Request {
|
||||
return requests
|
||||
}
|
||||
|
||||
func (b *Broker) SetChangeNotifier(notify func()) {
|
||||
if b == nil {
|
||||
return
|
||||
}
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
b.notify = notify
|
||||
}
|
||||
|
||||
func (b *Broker) Request(ctx context.Context, token apitokens.Token, op apitokens.Operation, resource apitokens.Resource) (Result, error) {
|
||||
if b == nil {
|
||||
return Result{}, ErrRequestTimedOut
|
||||
@@ -128,12 +138,20 @@ func (b *Broker) Request(ctx context.Context, token apitokens.Token, op apitoken
|
||||
|
||||
b.mu.Lock()
|
||||
b.pending[pending.request.ID] = pending
|
||||
notify := b.notify
|
||||
b.mu.Unlock()
|
||||
if notify != nil {
|
||||
notify()
|
||||
}
|
||||
|
||||
defer func() {
|
||||
b.mu.Lock()
|
||||
delete(b.pending, pending.request.ID)
|
||||
notify := b.notify
|
||||
b.mu.Unlock()
|
||||
if notify != nil {
|
||||
notify()
|
||||
}
|
||||
}()
|
||||
|
||||
timer := time.NewTimer(b.timeout)
|
||||
|
||||
@@ -3,6 +3,7 @@ package apiapproval
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -120,6 +121,36 @@ func TestBrokerTimesOutPendingRequests(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBrokerNotifiesWhenPendingRequestsChange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
broker := NewBroker(time.Minute)
|
||||
changes := make(chan int, 4)
|
||||
broker.SetChangeNotifier(func() {
|
||||
changes <- len(broker.Pending())
|
||||
})
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := broker.Request(context.Background(), apitokens.Token{ID: "token-1", Name: "CLI"}, apitokens.OperationListGroups, apitokens.Resource{Kind: apitokens.ResourceGroup, Path: []string{"Root"}})
|
||||
errCh <- err
|
||||
}()
|
||||
|
||||
waitForPending(t, broker, 1)
|
||||
if _, _, err := broker.Resolve(broker.Pending()[0].ID, OutcomeAllowOnce); err != nil {
|
||||
t.Fatalf("Resolve(allow once) error = %v", err)
|
||||
}
|
||||
if err := <-errCh; err != nil {
|
||||
t.Fatalf("Request() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
got := []int{<-changes, <-changes}
|
||||
slices.Sort(got)
|
||||
if !slices.Equal(got, []int{0, 1}) {
|
||||
t.Fatalf("change notifications = %v, want [0 1]", got)
|
||||
}
|
||||
}
|
||||
|
||||
func waitForPending(t *testing.T, broker *Broker, want int) {
|
||||
t.Helper()
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ func run(w *app.Window, mode string, paths statePaths, grpcAddr string) error {
|
||||
ui.state.AuditLog = ui.auditLog
|
||||
ui.grpcAddress = host.Address()
|
||||
ui.state.Approvals = &uiApprovalManager{server: host.Server()}
|
||||
host.Server().ApprovalBroker().SetChangeNotifier(ui.invalidate)
|
||||
defer func() { _ = host.Stop() }()
|
||||
}
|
||||
for {
|
||||
|
||||
Reference in New Issue
Block a user