mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
This PR is [resolving the dispatch part of Coder Inbocx](https://github.com/coder/internal/issues/403). Since the DB layer has been merged - we now want to insert notifications into Coder Inbox in parallel of the other delivery target. To do so, we push two messages instead of one using the `Enqueue` method.
123 lines
3.3 KiB
Go
123 lines
3.3 KiB
Go
package notificationstest
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"github.com/coder/coder/v2/coderd/database/dbauthz"
|
|
"github.com/coder/coder/v2/coderd/rbac"
|
|
"github.com/coder/coder/v2/coderd/rbac/policy"
|
|
)
|
|
|
|
type FakeEnqueuer struct {
|
|
authorizer rbac.Authorizer
|
|
mu sync.Mutex
|
|
sent []*FakeNotification
|
|
}
|
|
|
|
type FakeNotification struct {
|
|
UserID, TemplateID uuid.UUID
|
|
Labels map[string]string
|
|
Data map[string]any
|
|
CreatedBy string
|
|
Targets []uuid.UUID
|
|
}
|
|
|
|
// TODO: replace this with actual calls to dbauthz.
|
|
// See: https://github.com/coder/coder/issues/15481
|
|
func (f *FakeEnqueuer) assertRBACNoLock(ctx context.Context) {
|
|
if f.mu.TryLock() {
|
|
panic("Developer error: do not call assertRBACNoLock outside of a mutex lock!")
|
|
}
|
|
|
|
// If we get here, we are locked.
|
|
if f.authorizer == nil {
|
|
f.authorizer = rbac.NewStrictCachingAuthorizer(prometheus.NewRegistry())
|
|
}
|
|
|
|
act, ok := dbauthz.ActorFromContext(ctx)
|
|
if !ok {
|
|
panic("Developer error: no actor in context, you may need to use dbauthz.AsNotifier(ctx)")
|
|
}
|
|
|
|
for _, a := range []policy.Action{policy.ActionCreate, policy.ActionRead} {
|
|
err := f.authorizer.Authorize(ctx, act, a, rbac.ResourceNotificationMessage)
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
if rbac.IsUnauthorizedError(err) {
|
|
panic(fmt.Sprintf("Developer error: not authorized to %s %s. "+
|
|
"Ensure that you are using dbauthz.AsXXX with an actor that has "+
|
|
"policy.ActionCreate on rbac.ResourceNotificationMessage", a, rbac.ResourceNotificationMessage.Type))
|
|
}
|
|
panic("Developer error: failed to check auth:" + err.Error())
|
|
}
|
|
}
|
|
|
|
func (f *FakeEnqueuer) Enqueue(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) {
|
|
return f.EnqueueWithData(ctx, userID, templateID, labels, nil, createdBy, targets...)
|
|
}
|
|
|
|
func (f *FakeEnqueuer) EnqueueWithData(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) {
|
|
return f.enqueueWithDataLock(ctx, userID, templateID, labels, data, createdBy, targets...)
|
|
}
|
|
|
|
func (f *FakeEnqueuer) enqueueWithDataLock(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
f.assertRBACNoLock(ctx)
|
|
|
|
f.sent = append(f.sent, &FakeNotification{
|
|
UserID: userID,
|
|
TemplateID: templateID,
|
|
Labels: labels,
|
|
Data: data,
|
|
CreatedBy: createdBy,
|
|
Targets: targets,
|
|
})
|
|
|
|
id := uuid.New()
|
|
return []uuid.UUID{id}, nil
|
|
}
|
|
|
|
func (f *FakeEnqueuer) Clear() {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
|
|
f.sent = nil
|
|
}
|
|
|
|
func (f *FakeEnqueuer) Sent(matchers ...func(*FakeNotification) bool) []*FakeNotification {
|
|
f.mu.Lock()
|
|
defer f.mu.Unlock()
|
|
|
|
sent := []*FakeNotification{}
|
|
for _, notif := range f.sent {
|
|
// Check this notification matches all given matchers
|
|
matches := true
|
|
for _, matcher := range matchers {
|
|
if !matcher(notif) {
|
|
matches = false
|
|
break
|
|
}
|
|
}
|
|
|
|
if matches {
|
|
sent = append(sent, notif)
|
|
}
|
|
}
|
|
|
|
return sent
|
|
}
|
|
|
|
func WithTemplateID(id uuid.UUID) func(*FakeNotification) bool {
|
|
return func(n *FakeNotification) bool {
|
|
return n.TemplateID == id
|
|
}
|
|
}
|