From f12b8d8e5eecc7847c2486e54e35a8410cf3851d Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 12 Dec 2024 14:53:31 +0100 Subject: [PATCH 01/22] progress --- .golangci.yaml | 1 - libs/hwutil/assert.go | 36 +++++++++++++------ libs/hwutil/errs/casts.go | 26 ++++++++++++++ libs/hwutil/errs/maps.go | 27 ++++++++++++++ .../property-value/models/propertyValue.go | 4 ++- .../property_value_postgres_projection.go | 21 ++++++++--- .../property_rules_postgres.go | 4 ++- 7 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 libs/hwutil/errs/casts.go create mode 100644 libs/hwutil/errs/maps.go diff --git a/.golangci.yaml b/.golangci.yaml index c2a6a778e..d6bba26e9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -28,7 +28,6 @@ linters: # TODOs: #865 - cyclop # TODO - dupl # TODO - - err113 # TODO - exhaustruct # TODO - gci # TODO - gocognit # TODO diff --git a/libs/hwutil/assert.go b/libs/hwutil/assert.go index 765233835..54fecf6e8 100644 --- a/libs/hwutil/assert.go +++ b/libs/hwutil/assert.go @@ -1,25 +1,39 @@ package hwutil import ( - "errors" + "fmt" "time" + + "hwutil/errs" ) // AssertTimestampToTime takes an interface and returns a time func AssertTimestampToTime(i interface{}) (*time.Time, error) { - var s float64 - var n float64 d, ok := i.(map[string]interface{}) if !ok { - return nil, errors.New("could not assert map") + return nil, fmt.Errorf("AssertTimestampToTime: %w", + errs.NewCastError("map[string]interface{}", i)) } - s, ok = d["seconds"].(float64) - if !ok { - return nil, errors.New("could not assert seconds") + + fields := []string{"seconds", "nanos"} + values := make([]float64, len(fields)) + + for i, field := range fields { + var err error + values[i], err = AssertFloat64(d[field]) + if err != nil { + return nil, fmt.Errorf("AssertTimestampToTime: %w", errs.NewInvalidMapFieldError(field, err)) + } } - n, ok = d["nanos"].(float64) - if !ok { - return nil, errors.New("could not assert nanos") + + timestamp := time.Unix(int64(values[0]), int64(values[1])) + return ×tamp, nil +} + +func AssertFloat64(i interface{}) (float64, error) { + if f, ok := i.(float64); ok { + return f, nil + } else { + return 0, errs.NewCastError("float32", i) } - return PtrTo(time.Unix(int64(s), int64(n))), nil } diff --git a/libs/hwutil/errs/casts.go b/libs/hwutil/errs/casts.go new file mode 100644 index 000000000..5ea4ef25a --- /dev/null +++ b/libs/hwutil/errs/casts.go @@ -0,0 +1,26 @@ +package errs + +import ( + "fmt" + "reflect" +) + +type CastError struct { + // Type that was provided + Got string + // Type that was Expected + Expected string +} + +// NewCastError constructs a new CastError using a provided Expected string and any value you got instead, +// it will then use refection to return the error +func NewCastError(expected string, got interface{}) CastError { + return CastError{ + Got: reflect.TypeOf(got).String(), + Expected: expected, + } +} + +func (e CastError) Error() string { + return fmt.Sprintf("CastError: expected: '%s', got: '%s'", e.Expected, e.Got) +} diff --git a/libs/hwutil/errs/maps.go b/libs/hwutil/errs/maps.go new file mode 100644 index 000000000..e5a54716a --- /dev/null +++ b/libs/hwutil/errs/maps.go @@ -0,0 +1,27 @@ +package errs + +import "fmt" + +type InvalidMapFieldError struct { + FieldName string + Cause error +} + +func NewInvalidMapFieldError(fieldName string, cause error) InvalidMapFieldError { + return InvalidMapFieldError{ + FieldName: fieldName, + Cause: cause, + } +} + +func (e InvalidMapFieldError) Unwrap() error { + return e.Cause +} + +func (e InvalidMapFieldError) Error() string { + if e.Cause != nil { + return fmt.Errorf("InvalidMapFieldError: %q is invalid: '%w'", e.FieldName, e.Cause).Error() + } else { + return fmt.Sprintf("InvalidMapFieldError: %q is invalid'", e.FieldName) + } +} diff --git a/services/property-svc/internal/property-value/models/propertyValue.go b/services/property-svc/internal/property-value/models/propertyValue.go index 69560b59f..c1d20c194 100644 --- a/services/property-svc/internal/property-value/models/propertyValue.go +++ b/services/property-svc/internal/property-value/models/propertyValue.go @@ -5,6 +5,7 @@ import ( "fmt" pb "gen/services/property_svc/v1" "hwutil" + "hwutil/errs" "time" "github.com/google/uuid" @@ -113,7 +114,8 @@ func MultiSelectChangeFromMap(m map[string]interface{}) (MultiSelectChange, erro func MultiSelectChangeFromInterface(value interface{}) (MultiSelectChange, error) { m, ok := value.(map[string]interface{}) if !ok { - return MultiSelectChange{}, errors.New("MultiSelectChangeFromInterface: value is not a map") + return MultiSelectChange{}, fmt.Errorf("MultiSelectChangeFromInterface: %w", + errs.NewCastError("map[string]interface{}", value)) } return MultiSelectChangeFromMap(m) diff --git a/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go b/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go index 8d8f74f15..36fe2b566 100644 --- a/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go +++ b/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go @@ -9,6 +9,7 @@ import ( "hwes" "hwes/eventstoredb/projections/custom" "hwutil" + "hwutil/errs" "github.com/EventStore/EventStore-Client-Go/v4/esdb" "github.com/google/uuid" @@ -348,6 +349,14 @@ func (p *Projection) onPropertyValueUpdated(ctx context.Context, evt hwes.Event) return nil, nil } +type UnknownFieldTypeError struct { + FieldType pb.FieldType +} + +func (e UnknownFieldTypeError) Error() string { + return "unknown fieldType: " + e.FieldType.String() +} + // updateBasicPropertyValue is meant to be called in onPropertyValueUpdated func updateBasicPropertyValue( ctx context.Context, @@ -366,15 +375,17 @@ func updateBasicPropertyValue( case fieldType == pb.FieldType_FIELD_TYPE_TEXT: updatePropertyValueParams.TextValue = hwutil.PtrTo(fmt.Sprintf("%v", payload.Value)) case fieldType == pb.FieldType_FIELD_TYPE_NUMBER: - val, ok := payload.Value.(float64) - if !ok { - return errors.New("could not assert number"), hwutil.PtrTo(esdb.NackActionPark) + val, err := hwutil.AssertFloat64(payload.Value) + if err != nil { + return fmt.Errorf("updateBasicPropertyValue: (FIELD_TYPE_NUMBER), parsing failed: %w", err), + hwutil.PtrTo(esdb.NackActionPark) } updatePropertyValueParams.NumberValue = &val case fieldType == pb.FieldType_FIELD_TYPE_CHECKBOX: val, ok := payload.Value.(bool) if !ok { - return errors.New("could not assert bool"), hwutil.PtrTo(esdb.NackActionPark) + return fmt.Errorf("updateBasicPropertyValue: (FIELD_TYPE_CHECKBOX), parsing failed: %w", + errs.NewCastError("bool", payload.Value)), hwutil.PtrTo(esdb.NackActionPark) } updatePropertyValueParams.BoolValue = &val case fieldType == pb.FieldType_FIELD_TYPE_DATE: @@ -390,7 +401,7 @@ func updateBasicPropertyValue( } updatePropertyValueParams.DateTimeValue = hwdb.TimeToTimestamp(*val) default: - return fmt.Errorf("updateBasicPropertyValue called with fieldType %s", fieldType.String()), + return fmt.Errorf("updateBasicPropertyValue: %w", UnknownFieldTypeError{FieldType: fieldType}), hwutil.PtrTo(esdb.NackActionPark) } diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go index 9229fc722..963c563e4 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go @@ -46,6 +46,8 @@ func NewProjection(es custom.EventStoreClient, serviceName string) *Projection { return p } +var ErrMissingRuleID = errors.New("ruleID missing") + func (p *Projection) initEventListeners() { p.RegisterEventListener(eventsV1.PropertyRuleCreated, p.onPropertyRuleCreated) p.RegisterEventListener(eventsV1.PropertyRuleListsUpdated, p.onPropertyRuleListsUpdated) @@ -61,7 +63,7 @@ func (p *Projection) onPropertyRuleCreated(ctx context.Context, evt hwes.Event) } if payload.RuleID == uuid.Nil { - return errors.New("ruleID missing"), hwutil.PtrTo(esdb.NackActionSkip) + return ErrMissingRuleID, hwutil.PtrTo(esdb.NackActionSkip) } tx, rollback, err := hwdb.BeginTx(p.db, ctx) From 00f9f56b0bc183922258e975dd90ae1ccdc7a193 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 12 Dec 2024 14:54:55 +0100 Subject: [PATCH 02/22] fix: require import --- libs/common/auth/auth_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/common/auth/auth_test.go b/libs/common/auth/auth_test.go index 0a62f48c6..c4425e8d6 100644 --- a/libs/common/auth/auth_test.go +++ b/libs/common/auth/auth_test.go @@ -1,8 +1,9 @@ package auth import ( - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/require" ) func TestIDTokenClaims_AsExpected(t *testing.T) { From fb4fee6db28daedbaeeb62f8167eb3b76cbc95eb Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 12 Dec 2024 15:34:46 +0100 Subject: [PATCH 03/22] more progress --- libs/common/hwgrpc/auth_interceptor.go | 2 +- libs/common/otel.go | 4 +- libs/hwes/aggregate.go | 2 +- libs/hwes/eventstoredb/aggregate_store.go | 9 ++- .../property-view/events/v1/events.go | 58 +++++++++++++++---- 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/libs/common/hwgrpc/auth_interceptor.go b/libs/common/hwgrpc/auth_interceptor.go index eff70f8c7..e72945c6e 100644 --- a/libs/common/hwgrpc/auth_interceptor.go +++ b/libs/common/hwgrpc/auth_interceptor.go @@ -63,7 +63,7 @@ func authInterceptor(ctx context.Context) (context.Context, error) { Msg("only fake auth is enabled! no attempt verifying token. falling back to fake token instead") claims, tokenExpires, err = auth.VerifyFakeToken(ctx, token) } else { - // verify token -> if fakeToken is used claims will be nil and we will get an error + // verify token -> if fakeToken is used claims will be nil, and we will get an error claims, tokenExpires, err = auth.VerifyIDToken(ctx, token) } diff --git a/libs/common/otel.go b/libs/common/otel.go index d1b20aa74..c24b91b7b 100644 --- a/libs/common/otel.go +++ b/libs/common/otel.go @@ -128,6 +128,8 @@ func newTraceProvider(ctx context.Context, res *resource.Resource) (*trace.Trace return traceProvider, nil } +var ErrOtelTraceExporterInvalid = errors.New("OTEL_TRACE_EXPORTER invalid") + // newTraceExporter returns a new trace.SpanExporter based on the OTEL_TRACE_EXPORTER env variable // A SpanExporter pushes traces to a tracing database. For more configuration see the corresponding documentation. func newTraceExporter(ctx context.Context) (trace.SpanExporter, error) { @@ -145,6 +147,6 @@ func newTraceExporter(ctx context.Context) (trace.SpanExporter, error) { // more info: https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp@v1.21.0 return otlptracehttp.New(ctx) default: - return nil, errors.New("OTEL_TRACE_EXPORTER invalid") + return nil, ErrOtelTraceExporterInvalid } } diff --git a/libs/hwes/aggregate.go b/libs/hwes/aggregate.go index caf7818a2..ba0f9877d 100644 --- a/libs/hwes/aggregate.go +++ b/libs/hwes/aggregate.go @@ -160,7 +160,7 @@ func (a *AggregateBase) ClearUncommittedEvents() { func (a *AggregateBase) Load(events []Event) error { for _, event := range events { if event.GetAggregateID() != a.GetID() { - return fmt.Errorf("event applied to aggregate '%s' but was targeted at aggregate '%s'", + return fmt.Errorf("AggregateBase.Load: event applied to aggregate '%s' but was targeted at aggregate '%s'", a.GetID(), event.GetAggregateID()) } diff --git a/libs/hwes/eventstoredb/aggregate_store.go b/libs/hwes/eventstoredb/aggregate_store.go index 942429fc7..13dfca272 100644 --- a/libs/hwes/eventstoredb/aggregate_store.go +++ b/libs/hwes/eventstoredb/aggregate_store.go @@ -27,6 +27,9 @@ func NewAggregateStore(es *esdb.Client) *AggregateStore { return &AggregateStore{es: es} } +var ErrNoAppliedEvents = errors.New("aggregate has no applied events. " + + "Consider to persist and load the aggregate first") + // getExpectedRevisionByPreviousRead implements a strategy for our getExpectedRevision strategy pattern. // This function resolves the version by returning the version of the last applied event of our aggregate. func (as *AggregateStore) getExpectedRevisionByPreviousRead( @@ -34,7 +37,7 @@ func (as *AggregateStore) getExpectedRevisionByPreviousRead( a hwes.Aggregate, ) (esdb.ExpectedRevision, error) { if len(a.GetAppliedEvents()) == 0 { - return nil, errors.New("aggregate has no applied events. Consider to persist and load the aggregate first") + return nil, ErrNoAppliedEvents } lastAppliedEvent := a.GetAppliedEvents()[len(a.GetAppliedEvents())-1] eventNumber := lastAppliedEvent.GetVersion() @@ -97,6 +100,8 @@ func (as *AggregateStore) doSave( return common.ConsistencyToken(r.NextExpectedVersion), nil } +var ErrAggregateWasDeleted = errors.New("aggregate has been marked as deleted") + // Implements AggregateStore interface func (as *AggregateStore) Load(ctx context.Context, aggregate hwes.Aggregate) error { @@ -131,7 +136,7 @@ func (as *AggregateStore) Load(ctx context.Context, aggregate hwes.Aggregate) er } if aggregate.IsDeleted() { - return errors.New("AggregateStore.Load: aggregate has been marked as deleted") + return fmt.Errorf("AggregateStore.Load: %w", ErrAggregateWasDeleted) } return nil diff --git a/services/property-svc/internal/property-view/events/v1/events.go b/services/property-svc/internal/property-view/events/v1/events.go index e784768ed..cc86955e2 100644 --- a/services/property-svc/internal/property-view/events/v1/events.go +++ b/services/property-svc/internal/property-view/events/v1/events.go @@ -4,8 +4,10 @@ import ( "context" "encoding/json" "errors" + "fmt" "hwes" "hwutil" + "hwutil/errs" "property-svc/internal/property-view/models" @@ -28,40 +30,65 @@ func (m *PropertyRuleCreatedEvent) ToJSON() ([]byte, error) { return json.Marshal(inter) } +var ErrNoMatcherFound = errors.New("could not find matcher in event") + func (m *PropertyRuleCreatedEvent) FromJSON(data []byte) error { var inter map[string]interface{} if err := json.Unmarshal(data, &inter); err != nil { return err } - ruleIDRaw, ok := inter["RuleID"].(string) + // + // RuleID + // + + ruleIDfieldName := "RuleID" + ruleIDRaw, ok := inter[ruleIDfieldName].(string) if !ok { - return errors.New("rule_id is not a string") + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", errs.NewInvalidMapFieldError(ruleIDfieldName, + errs.NewCastError("string", inter[ruleIDfieldName]))) } ruleID, err := uuid.Parse(ruleIDRaw) if err != nil { - return err + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", + errs.NewInvalidMapFieldError(ruleIDfieldName, err)) } - alwaysInclude, ok := hwutil.InterfaceAsStringSlice(inter["AlwaysInclude"]) + // + // AlwaysInclude + // + + alwaysIncludeFieldName := "AlwaysInclude" + alwaysInclude, ok := hwutil.InterfaceAsStringSlice(inter[alwaysIncludeFieldName]) if !ok { - return errors.New("AlwaysInclude is not a string[]") + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", + errs.NewInvalidMapFieldError(alwaysIncludeFieldName, + errs.NewCastError("string[]", inter[alwaysIncludeFieldName]))) } alwaysIncludeUUIDs, err := hwutil.StringsToUUIDs(alwaysInclude) if err != nil { - return err + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", + errs.NewInvalidMapFieldError(alwaysIncludeFieldName, err)) } - dontAlwaysInclude, ok := hwutil.InterfaceAsStringSlice(inter["DontAlwaysInclude"]) + // + // DontAlwaysInclude + // + + dontAlwaysIncludeFieldName := "DontAlwaysInclude" + dontAlwaysInclude, ok := hwutil.InterfaceAsStringSlice(inter[dontAlwaysIncludeFieldName]) if !ok { - return errors.New("DontAlwaysInclude is not a string[]") + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", + errs.NewInvalidMapFieldError(dontAlwaysIncludeFieldName, + errs.NewCastError("string[]", inter[dontAlwaysIncludeFieldName]))) } dontAlwaysIncludeUUIDs, err := hwutil.StringsToUUIDs(dontAlwaysInclude) if err != nil { - return err + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", + errs.NewInvalidMapFieldError(dontAlwaysIncludeFieldName, err)) } rule := models.PropertyViewRule{ @@ -71,9 +98,16 @@ func (m *PropertyRuleCreatedEvent) FromJSON(data []byte) error { DontAlwaysInclude: dontAlwaysIncludeUUIDs, } - matchers, ok := inter["Matchers"].(map[string]interface{}) + // + // Matchers + // + + matchersFieldName := "Matchers" + matchers, ok := inter[matchersFieldName].(map[string]interface{}) if !ok { - return errors.New("Could not assert matchers to a map") + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", + errs.NewInvalidMapFieldError(matchersFieldName, + errs.NewCastError("map[string]interface{}", inter[matchersFieldName]))) } if taskMatchers, ok := models.TaskPropertyMatchersFromMap(matchers); ok { @@ -86,7 +120,7 @@ func (m *PropertyRuleCreatedEvent) FromJSON(data []byte) error { return nil } - return errors.New("could not find matcher in event") + return ErrNoMatcherFound } func NewPropertyRuleCreatedEvent( From 12dbff54fe416609817d5707aaa890495dd4c07f Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Mon, 16 Dec 2024 21:48:38 +0100 Subject: [PATCH 04/22] more err113 --- .../common/hwgrpc/organization_interceptor.go | 4 +- libs/hwdb/errors.go | 8 +++ libs/hwes/aggregate.go | 53 +++++++++++++++---- libs/hwes/errs/errors.go | 5 ++ libs/hwes/event.go | 34 ++++++++---- libs/hwes/integration_test.go | 6 ++- .../commands/v1/create_property_set.go | 6 +-- .../property_value_postgres_projection.go | 23 +++++--- .../property-view/aggregate/aggregate.go | 4 +- .../internal/property-view/errs/errs.go | 5 ++ .../property-view/events/v1/events.go | 5 +- .../property_rules_postgres.go | 18 ++++--- .../property/commands/v1/create_property.go | 4 +- .../patient/commands/v1/create_patient.go | 4 +- .../internal/task/commands/v1/create_task.go | 4 +- .../queries/v1/get_task_with_patient_by_id.go | 3 +- .../tasks-svc/internal/tracking/tracking.go | 27 ++++------ 17 files changed, 146 insertions(+), 67 deletions(-) create mode 100644 libs/hwes/errs/errors.go create mode 100644 services/property-svc/internal/property-view/errs/errs.go diff --git a/libs/common/hwgrpc/organization_interceptor.go b/libs/common/hwgrpc/organization_interceptor.go index 1752d1453..1e02b4402 100644 --- a/libs/common/hwgrpc/organization_interceptor.go +++ b/libs/common/hwgrpc/organization_interceptor.go @@ -49,6 +49,8 @@ func StreamOrganizationInterceptor( return next(req, stream) } +var ErrOrganizationIdMissing = errors.New("organization.id missing in id token") + // organizationInterceptor parses and injects the organization id of the OIDC claims into the current context // This is a separate function to allow endpoints to not fail when an organization id is not provided func organizationInterceptor(ctx context.Context) (context.Context, error) { @@ -61,7 +63,7 @@ func organizationInterceptor(ctx context.Context) (context.Context, error) { } if len(claims.Organization.Id) == 0 { - return nil, errors.New("organization.id missing in id token") + return nil, ErrOrganizationIdMissing } // parse organizationID diff --git a/libs/hwdb/errors.go b/libs/hwdb/errors.go index 292170826..4a3d11909 100644 --- a/libs/hwdb/errors.go +++ b/libs/hwdb/errors.go @@ -4,6 +4,8 @@ import ( "common/hwerr" "context" "errors" + "fmt" + "github.com/google/uuid" "hwlocale" "reflect" "strings" @@ -261,3 +263,9 @@ func pgConnErr(ctx context.Context, connErr *pgconn.ConnectError) error { Msg("connection issue") return genericStatusError(ctx, "database connection issue") } + +type RecordNotFoundError uuid.UUID + +func (e RecordNotFoundError) Error() string { + return fmt.Sprintf("could not find record with id %q", uuid.UUID(e).String()) +} diff --git a/libs/hwes/aggregate.go b/libs/hwes/aggregate.go index ba0f9877d..ef992cba6 100644 --- a/libs/hwes/aggregate.go +++ b/libs/hwes/aggregate.go @@ -121,6 +121,12 @@ func (a *AggregateBase) RegisterEventListener(eventType string, eventHandler eve return a } +type EventTypeInvalidError string + +func (e EventTypeInvalidError) Error() string { + return fmt.Sprintf("event type '%s' is invalid", string(e)) +} + // HandleEvent finds and calls the registered event handler // based on the type of the passed event. // The executed event handler can modify the in-memory data of the aggregate. @@ -133,7 +139,7 @@ func (a *AggregateBase) HandleEvent(event Event) error { eventHandler, found := a.eventHandlers[event.EventType] if !found { - return fmt.Errorf("event type '%s' is invalid", event.EventType) + return EventTypeInvalidError(event.EventType) } if err := eventHandler(event); err != nil { @@ -155,13 +161,27 @@ func (a *AggregateBase) ClearUncommittedEvents() { a.uncommittedEvents = make([]Event, 0) } +type EventAggregateMismatchError struct { + Targeted uuid.UUID + Got uuid.UUID +} + +func (e EventAggregateMismatchError) Error() string { + return fmt.Sprintf("event applied to aggregate %q but was targeted at aggregate %q", + e.Got.String(), e.Targeted.String()) +} + +var ErrLoadDeletedAggregate = errors.New("AggregateBase.Load: aggregate has been marked as deleted") + // Load applies events to an aggregate by utilizing the registered event listeners // Currently not in use. Could be helpful for testing. func (a *AggregateBase) Load(events []Event) error { for _, event := range events { if event.GetAggregateID() != a.GetID() { - return fmt.Errorf("AggregateBase.Load: event applied to aggregate '%s' but was targeted at aggregate '%s'", - a.GetID(), event.GetAggregateID()) + return fmt.Errorf("AggregateBase.Load: %w", EventAggregateMismatchError{ + Targeted: a.GetID(), + Got: event.GetAggregateID(), + }) } if err := a.HandleEvent(event); err != nil { @@ -172,7 +192,7 @@ func (a *AggregateBase) Load(events []Event) error { a.version++ } if a.IsDeleted() { - return errors.New("AggregateBase.Load: aggregate has been marked as deleted") + return fmt.Errorf("AggregateBase.Load: %w", ErrLoadDeletedAggregate) } return nil @@ -183,8 +203,10 @@ func (a *AggregateBase) Load(events []Event) error { // Apply -> You apply a *new* event to the aggregate that could be persisted func (a *AggregateBase) Apply(event Event) error { if event.GetAggregateID() != a.GetID() { - return fmt.Errorf("event applied to aggregate '%s' but was targeted at aggregate '%s'", - a.GetID(), event.GetAggregateID()) + return fmt.Errorf("AggregateBase.Apply: %w", EventAggregateMismatchError{ + Targeted: a.GetID(), + Got: event.GetAggregateID(), + }) } if err := a.HandleEvent(event); err != nil { @@ -197,18 +219,29 @@ func (a *AggregateBase) Apply(event Event) error { return nil } +type EventOutOfDateError struct { + AggregateVersion uint64 + EventVersion uint64 +} + +func (e EventOutOfDateError) Error() string { + return fmt.Sprintf("event version (%d) is lower than aggregate version (%d)", + e.EventVersion, e.AggregateVersion) +} + // Progress should be called after all events are loaded though an aggregate store. // The passed event gets applied to an aggregate by utilizing the registered event listeners. // Progress -> You progress the state of an aggregate func (a *AggregateBase) Progress(event Event) error { if event.GetAggregateID() != a.GetID() { - return fmt.Errorf("event applied to aggregate '%s' but was targeted at aggregate '%s'", - a.GetID(), event.GetAggregateID()) + return fmt.Errorf("AggregateBase.Progress: %w", EventAggregateMismatchError{ + Targeted: a.GetID(), + Got: event.GetAggregateID(), + }) } if event.GetVersion() < a.GetVersion() { - return fmt.Errorf("event version of %d is lower then aggregate version of %d", - event.GetVersion(), a.GetVersion()) + return EventOutOfDateError{EventVersion: event.GetVersion(), AggregateVersion: a.GetVersion()} } if err := a.HandleEvent(event); err != nil { diff --git a/libs/hwes/errs/errors.go b/libs/hwes/errs/errors.go new file mode 100644 index 000000000..442ef6358 --- /dev/null +++ b/libs/hwes/errs/errors.go @@ -0,0 +1,5 @@ +package errs + +import "errors" + +var ErrAlreadyExists = errors.New("cannot create an already existing aggregate") diff --git a/libs/hwes/event.go b/libs/hwes/event.go index e51528bba..d8619d26c 100644 --- a/libs/hwes/event.go +++ b/libs/hwes/event.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "hwutil" + "hwutil/errs" "strings" "telemetry" "time" @@ -70,13 +71,16 @@ type metadata struct { func GetEventTypeOptionOfProtoMessageV1(protoMessage proto.Message) string { eventTypeOption := pbEventsV1.E_EventType - protoEventType, ok := proto.GetExtension(protoMessage.ProtoReflect().Descriptor().Options(), eventTypeOption).(string) + descriptorOptions := protoMessage.ProtoReflect().Descriptor().Options() + protoEventTypeAny := proto.GetExtension(descriptorOptions, eventTypeOption) + protoEventType, ok := protoEventTypeAny.(string) if !ok { - panic(fmt.Sprintf( - "String type assertion for eventType '%s' on protoMessage '%s' failed.", - eventTypeOption.TypeDescriptor().FullName(), - protoMessage.ProtoReflect().Descriptor().FullName(), - )) + panic( + fmt.Errorf("not a string: eventType %q on protoMessage %q: %w", + eventTypeOption.TypeDescriptor().FullName(), + protoMessage.ProtoReflect().Descriptor().FullName(), + errs.NewCastError("string", protoEventTypeAny)), + ) } if protoEventType == "" { @@ -164,6 +168,12 @@ func NewEventFromProto(aggregate Aggregate, message proto.Message, opts ...Event return event, nil } +type StreamIdMalformedError string + +func (e StreamIdMalformedError) Error() string { + return fmt.Sprintf("cannot resolve aggregateType and aggregateID from streamID %q", string(e)) +} + // resolveAggregateIDAndTypeFromStreamID extracts the aggregateID and aggregateType of a given streamID // See aggregate.GetTypeID // @@ -181,13 +191,13 @@ func resolveAggregateIDAndTypeFromStreamID(streamID string) (aID uuid.UUID, aggr aggregateTypeStr = streamIDParts[0] aggregateIDStr = streamIDParts[1] } else { - err = fmt.Errorf("cannot resolve aggregateType and aggregateID from streamID '%s'", streamID) + err = StreamIdMalformedError(streamID) return } aggregateType = AggregateType(aggregateTypeStr) if aggregateType == "" { - err = fmt.Errorf("resolved empty aggregateType from streamID '%s'", streamID) + err = StreamIdMalformedError(streamID) return } @@ -326,9 +336,11 @@ func (e *Event) SetProtoData(message proto.Message) error { return nil } +var ErrGetJsonOnProtoData = errors.New("data of event is marked as proto, use GetProtoData instead") + func (e *Event) GetJsonData(data interface{}) error { if e.DataIsProto { - return errors.New("data of this event is marked as proto, use GetProtoData instead") + return ErrGetJsonOnProtoData } if jsonable, ok := data.(hwutil.JSONAble); ok { @@ -337,9 +349,11 @@ func (e *Event) GetJsonData(data interface{}) error { return json.Unmarshal(e.Data, data) } +var ErrGetProtoOnJsonData = errors.New("data of event is not marked as proto, use GetJsonData instead") + func (e *Event) GetProtoData(message proto.Message) error { if !e.DataIsProto { - return errors.New("data of this event is not marked as proto, use GetJsonData instead") + return ErrGetProtoOnJsonData } return protojson.Unmarshal(e.Data, message) diff --git a/libs/hwes/integration_test.go b/libs/hwes/integration_test.go index 72df89a75..f246e41ab 100644 --- a/libs/hwes/integration_test.go +++ b/libs/hwes/integration_test.go @@ -151,6 +151,8 @@ func TestIntegration(t *testing.T) { } } +var ErrTest = errors.New("test error") + func TestAggregateBase_RegisterEventListener_HandleEvent(t *testing.T) { aggregate := NewUserAggregate(uuid.New()) @@ -169,7 +171,7 @@ func TestAggregateBase_RegisterEventListener_HandleEvent(t *testing.T) { } fncWithErr := func(event hwes.Event) error { - return errors.New("test error") + return ErrTest } aggregate.RegisterEventListener(UserCreated, fncWithNoErr) @@ -181,7 +183,7 @@ func TestAggregateBase_RegisterEventListener_HandleEvent(t *testing.T) { aggregate.RegisterEventListener(UserCreated, fncWithErr) if err := aggregate.HandleEvent(userCreatedEvent); err != nil { - if errors.Unwrap(err).Error() != "test error" { + if !errors.Is(err, ErrTest) { t.Error(err) } } else { diff --git a/services/property-svc/internal/property-set/commands/v1/create_property_set.go b/services/property-svc/internal/property-set/commands/v1/create_property_set.go index a352475a0..869dc44ea 100644 --- a/services/property-svc/internal/property-set/commands/v1/create_property_set.go +++ b/services/property-svc/internal/property-set/commands/v1/create_property_set.go @@ -3,11 +3,11 @@ package v1 import ( "common" "context" - "errors" "fmt" "hwauthz" "hwauthz/commonPerm" "hwes" + "hwes/errs" "property-svc/internal/property-set/perm" @@ -16,8 +16,6 @@ import ( "property-svc/internal/property-set/aggregate" ) -var ErrAlreadyExists = errors.New("cannot create an already existing aggregate") - type CreatePropertySetCommandHandler func( ctx context.Context, propertySetID uuid.UUID, @@ -42,7 +40,7 @@ func NewCreatePropertySetCommandHandler(as hwes.AggregateStore, authz hwauthz.Au } if exists { - return 0, ErrAlreadyExists + return 0, errs.ErrAlreadyExists } if err := a.CreatePropertySet(ctx, name); err != nil { diff --git a/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go b/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go index 36fe2b566..3e44645b3 100644 --- a/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go +++ b/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go @@ -103,7 +103,7 @@ func (p *Projection) onPropertyValueCreated(ctx context.Context, evt hwes.Event) if fieldType == pb.FieldType_FIELD_TYPE_SELECT { val, ok := payload.Value.(string) if !ok { - return errors.New("could not assert string"), hwutil.PtrTo(esdb.NackActionPark) + return errs.NewCastError("string", payload.Value), hwutil.PtrTo(esdb.NackActionPark) } id, err := uuid.Parse(val) if err != nil { @@ -175,13 +175,13 @@ func createBasicPropertyValue( case fieldType == pb.FieldType_FIELD_TYPE_NUMBER: val, ok := payload.Value.(float64) if !ok { - return errors.New("could not assert number"), hwutil.PtrTo(esdb.NackActionPark) + return errs.NewCastError("float64", payload.Value), hwutil.PtrTo(esdb.NackActionPark) } createPropertyValueParams.NumberValue = &val case fieldType == pb.FieldType_FIELD_TYPE_CHECKBOX: val, ok := payload.Value.(bool) if !ok { - return errors.New("could not assert bool"), hwutil.PtrTo(esdb.NackActionPark) + return errs.NewCastError("bool", payload.Value), hwutil.PtrTo(esdb.NackActionPark) } createPropertyValueParams.BoolValue = &val case fieldType == pb.FieldType_FIELD_TYPE_DATE: @@ -206,6 +206,18 @@ func createBasicPropertyValue( return nil, nil } +type PropertyValueNotFoundError uuid.UUID + +func (e PropertyValueNotFoundError) Error() string { + return fmt.Sprintf("propertyValue with id %s not found", uuid.UUID(e).String()) +} + +type PropertyNotFoundForValueError uuid.UUID + +func (e PropertyNotFoundForValueError) Error() string { + return fmt.Sprintf("property with id %s not found for propertyValue", uuid.UUID(e).String()) +} + func (p *Projection) onPropertyValueUpdated(ctx context.Context, evt hwes.Event) (error, *esdb.NackAction) { log := zlog.Ctx(ctx) @@ -218,7 +230,7 @@ func (p *Projection) onPropertyValueUpdated(ctx context.Context, evt hwes.Event) // Get Property for FieldType propertyValue, err := hwdb.Optional(p.propertyValueRepo.GetPropertyValueByID)(ctx, evt.AggregateID) if propertyValue == nil { - return fmt.Errorf("propertyValue with id %s not found", evt.AggregateID), hwutil.PtrTo(esdb.NackActionRetry) + return PropertyValueNotFoundError(evt.AggregateID), hwutil.PtrTo(esdb.NackActionRetry) } if err := hwdb.Error(ctx, err); err != nil { return err, hwutil.PtrTo(esdb.NackActionRetry) @@ -226,8 +238,7 @@ func (p *Projection) onPropertyValueUpdated(ctx context.Context, evt hwes.Event) property, err := hwdb.Optional(p.propertyRepo.GetPropertyById)(ctx, propertyValue.PropertyID) if property == nil { - return fmt.Errorf("property with id %s not found for propertyValue", propertyValue.PropertyID.String()), - hwutil.PtrTo(esdb.NackActionRetry) + return PropertyNotFoundForValueError(propertyValue.PropertyID), hwutil.PtrTo(esdb.NackActionRetry) } if err := hwdb.Error(ctx, err); err != nil { return err, hwutil.PtrTo(esdb.NackActionRetry) diff --git a/services/property-svc/internal/property-view/aggregate/aggregate.go b/services/property-svc/internal/property-view/aggregate/aggregate.go index b23c172fc..8301e4c31 100644 --- a/services/property-svc/internal/property-view/aggregate/aggregate.go +++ b/services/property-svc/internal/property-view/aggregate/aggregate.go @@ -6,6 +6,8 @@ import ( "hwes" "hwutil" + "property-svc/internal/property-view/errs" + "github.com/google/uuid" propertyViewEventsV1 "property-svc/internal/property-view/events/v1" @@ -54,7 +56,7 @@ func (a *PropertyViewRuleAggregate) onPropertyRuleCreated(event hwes.Event) erro // json unmarshaller sets uuid.Nil for missing uuids // if they are set, they have to be valid if payload.RuleID == uuid.Nil { - return errors.New("RuleID missing") + return errs.ErrMissingRuleID } if a.GetID() != payload.RuleID { return errors.New("RuleID not AggregateID") diff --git a/services/property-svc/internal/property-view/errs/errs.go b/services/property-svc/internal/property-view/errs/errs.go new file mode 100644 index 000000000..e0a342214 --- /dev/null +++ b/services/property-svc/internal/property-view/errs/errs.go @@ -0,0 +1,5 @@ +package errs + +import "errors" + +var ErrMissingRuleID = errors.New("ruleID missing") diff --git a/services/property-svc/internal/property-view/events/v1/events.go b/services/property-svc/internal/property-view/events/v1/events.go index cc86955e2..71895dc84 100644 --- a/services/property-svc/internal/property-view/events/v1/events.go +++ b/services/property-svc/internal/property-view/events/v1/events.go @@ -45,8 +45,9 @@ func (m *PropertyRuleCreatedEvent) FromJSON(data []byte) error { ruleIDfieldName := "RuleID" ruleIDRaw, ok := inter[ruleIDfieldName].(string) if !ok { - return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", errs.NewInvalidMapFieldError(ruleIDfieldName, - errs.NewCastError("string", inter[ruleIDfieldName]))) + return fmt.Errorf("PropertyRuleCreatedEvent.FromJSON: %w", + errs.NewInvalidMapFieldError(ruleIDfieldName, + errs.NewCastError("string", inter[ruleIDfieldName]))) } ruleID, err := uuid.Parse(ruleIDRaw) diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go index 963c563e4..6d1b799d2 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go @@ -2,7 +2,6 @@ package property_rules_postgres import ( "context" - "errors" "fmt" "hwdb" "hwes" @@ -10,6 +9,8 @@ import ( "hwutil" "slices" + "property-svc/internal/property-view/errs" + "github.com/EventStore/EventStore-Client-Go/v4/esdb" "github.com/google/uuid" zlog "github.com/rs/zerolog/log" @@ -46,13 +47,19 @@ func NewProjection(es custom.EventStoreClient, serviceName string) *Projection { return p } -var ErrMissingRuleID = errors.New("ruleID missing") - func (p *Projection) initEventListeners() { p.RegisterEventListener(eventsV1.PropertyRuleCreated, p.onPropertyRuleCreated) p.RegisterEventListener(eventsV1.PropertyRuleListsUpdated, p.onPropertyRuleListsUpdated) } +type UnexpectedMatchersTypeError struct { + typ interface{} +} + +func (e UnexpectedMatchersTypeError) Error() string { + return fmt.Sprintf("unexpected matchers type, got %T", e.typ) +} + func (p *Projection) onPropertyRuleCreated(ctx context.Context, evt hwes.Event) (error, *esdb.NackAction) { log := zlog.Ctx(ctx) @@ -63,7 +70,7 @@ func (p *Projection) onPropertyRuleCreated(ctx context.Context, evt hwes.Event) } if payload.RuleID == uuid.Nil { - return ErrMissingRuleID, hwutil.PtrTo(esdb.NackActionSkip) + return errs.ErrMissingRuleID, hwutil.PtrTo(esdb.NackActionSkip) } tx, rollback, err := hwdb.BeginTx(p.db, ctx) @@ -106,8 +113,7 @@ func (p *Projection) onPropertyRuleCreated(ctx context.Context, evt hwes.Event) return fmt.Errorf("could not create patient rule: %w", err), hwutil.PtrTo(esdb.NackActionRetry) } default: - return fmt.Errorf("unexpected matchers type, got %T", payload.Matchers), - hwutil.PtrTo(esdb.NackActionSkip) + return UnexpectedMatchersTypeError{typ: payload.Matchers}, hwutil.PtrTo(esdb.NackActionSkip) } // handle (dont)alwaysInclude logic diff --git a/services/property-svc/internal/property/commands/v1/create_property.go b/services/property-svc/internal/property/commands/v1/create_property.go index 405b20804..c76fc32ee 100644 --- a/services/property-svc/internal/property/commands/v1/create_property.go +++ b/services/property-svc/internal/property/commands/v1/create_property.go @@ -3,11 +3,11 @@ package v1 import ( "common" "context" - "errors" pb "gen/services/property_svc/v1" "hwauthz" "hwauthz/commonPerm" "hwes" + "hwes/errs" "github.com/google/uuid" @@ -52,7 +52,7 @@ func NewCreatePropertyCommandHandler(as hwes.AggregateStore, authz hwauthz.AuthZ } if exists { - return 0, errors.New("cannot create an already existing aggregate") + return 0, errs.ErrAlreadyExists } if err := a.CreateProperty(ctx, subjectType, fieldType, name); err != nil { diff --git a/services/tasks-svc/internal/patient/commands/v1/create_patient.go b/services/tasks-svc/internal/patient/commands/v1/create_patient.go index 41d4013ca..089e899b3 100644 --- a/services/tasks-svc/internal/patient/commands/v1/create_patient.go +++ b/services/tasks-svc/internal/patient/commands/v1/create_patient.go @@ -3,10 +3,10 @@ package v1 import ( "common" "context" - "errors" "hwauthz" "hwauthz/commonPerm" "hwes" + "hwes/errs" "tasks-svc/internal/patient/perm" @@ -45,7 +45,7 @@ func NewCreatePatientCommandHandler(as hwes.AggregateStore, authz hwauthz.AuthZ) } if exists { - return 0, errors.New("cannot create an already existing aggregate") + return 0, errs.ErrAlreadyExists } finalNotes := "" diff --git a/services/tasks-svc/internal/task/commands/v1/create_task.go b/services/tasks-svc/internal/task/commands/v1/create_task.go index e07a0c32c..ddb46f29e 100644 --- a/services/tasks-svc/internal/task/commands/v1/create_task.go +++ b/services/tasks-svc/internal/task/commands/v1/create_task.go @@ -3,11 +3,11 @@ package v1 import ( "common" "context" - "errors" pb "gen/services/tasks_svc/v1" "hwauthz" "hwauthz/commonPerm" "hwes" + "hwes/errs" patientPerm "tasks-svc/internal/patient/perm" "tasks-svc/internal/task/perm" @@ -59,7 +59,7 @@ func NewCreateTaskCommandHandler(as hwes.AggregateStore, authz hwauthz.AuthZ) Cr } if exists { - return 0, errors.New("cannot create an already existing aggregate") + return 0, errs.ErrAlreadyExists } finalStatus := pb.TaskStatus_TASK_STATUS_TODO diff --git a/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go b/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go index d0bbde2b5..12d475cdc 100644 --- a/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go +++ b/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go @@ -3,7 +3,6 @@ package v1 import ( "common" "context" - "fmt" pb "gen/services/tasks_svc/v1" "hwauthz" "hwauthz/commonPerm" @@ -36,7 +35,7 @@ func NewGetTaskWithPatientByIDQueryHandler(authz hwauthz.AuthZ) GetTaskWithPatie return nil, err } if len(rows) == 0 { - return nil, fmt.Errorf("could not find record with ID %s", taskID.String()) + return nil, hwdb.RecordNotFoundError(taskID) } // check patient permissions diff --git a/services/tasks-svc/internal/tracking/tracking.go b/services/tasks-svc/internal/tracking/tracking.go index 05e142347..6450f2cf9 100644 --- a/services/tasks-svc/internal/tracking/tracking.go +++ b/services/tasks-svc/internal/tracking/tracking.go @@ -52,10 +52,9 @@ func getUserID(ctx context.Context) string { // - SetupTracking was called earlier // - the context originates from an authenticated request func AddPatientToRecentActivity(ctx context.Context, patientID string) { - if userID := getUserID(ctx); userID != "" { - if err := lru.AddItemForUser(ctx, PatientKey, userID, patientID); err != nil { - zlog.Ctx(ctx).Error().Err(err).Msg("could not add patient to recent activity") - } + userID := getUserID(ctx) + if err := lru.AddItemForUser(ctx, PatientKey, userID, patientID); err != nil { + zlog.Ctx(ctx).Error().Err(err).Msg("could not add patient to recent activity") } } @@ -64,9 +63,8 @@ func AddPatientToRecentActivity(ctx context.Context, patientID string) { // - SetupTracking was called earlier // - the context originates from an authenticated request func RemovePatientFromRecentActivity(ctx context.Context, patientID string) { - if userID := getUserID(ctx); userID != "" { - _ = lru.RemoveItemForUser(ctx, PatientKey, userID, patientID) - } + userID := getUserID(ctx) + _ = lru.RemoveItemForUser(ctx, PatientKey, userID, patientID) } // GetRecentPatientsForUser returns patient ids from the current user's recent activity @@ -75,9 +73,6 @@ func RemovePatientFromRecentActivity(ctx context.Context, patientID string) { // - the context originates from an authenticated request func GetRecentPatientsForUser(ctx context.Context) ([]string, error) { userID := getUserID(ctx) - if userID == "" { - return nil, errors.New("GetRecentPatientsForUser called, but context has no userID") - } return lru.GetItemsForUser(ctx, PatientKey, userID) } @@ -86,10 +81,9 @@ func GetRecentPatientsForUser(ctx context.Context) ([]string, error) { // - SetupTracking was called earlier // - the context originates from an authenticated request func AddWardToRecentActivity(ctx context.Context, wardID string) { - if userID := getUserID(ctx); userID != "" { - if err := lru.AddItemForUser(ctx, WardKey, userID, wardID); err != nil { - zlog.Ctx(ctx).Error().Err(err).Msg("could not add ward to recent activity") - } + userID := getUserID(ctx) + if err := lru.AddItemForUser(ctx, WardKey, userID, wardID); err != nil { + zlog.Ctx(ctx).Error().Err(err).Msg("could not add ward to recent activity") } } @@ -98,9 +92,8 @@ func AddWardToRecentActivity(ctx context.Context, wardID string) { // - SetupTracking was called earlier // - the context originates from an authenticated request func RemoveWardFromRecentActivity(ctx context.Context, wardID string) { - if userID := getUserID(ctx); userID != "" { - _ = lru.RemoveItemForUser(ctx, WardKey, userID, wardID) - } + userID := getUserID(ctx) + _ = lru.RemoveItemForUser(ctx, WardKey, userID, wardID) } // GetRecentWardsForUser returns ward ids from the current user's recent activity From a776fc7398dc4b15abc78af6b3d5d63706f08464 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 14:59:38 +0100 Subject: [PATCH 05/22] err113 happy --- libs/common/hwerr/err.go | 10 ++++++ libs/hwauthz/spicedb/spicedb.go | 2 +- libs/hwdb/errors.go | 3 +- libs/hwes/errs/errors.go | 20 ++++++++++-- .../set_spicedb_projection.go | 4 +-- .../property-value/models/propertyValue.go | 5 ++- .../property_value_postgres_projection.go | 13 +++----- .../property-view/aggregate/aggregate.go | 6 ++-- .../internal/property-view/api/grpc.go | 4 ++- .../models/patient_property_matcher.go | 4 ++- .../models/task_property_matchers.go | 4 ++- .../internal/property/aggregate/aggregate.go | 32 +++++++++++-------- .../postgres_projection.go | 26 +++++++-------- .../property_spicedb_projection.go | 4 +-- .../property/queries/v1/get_property_by_id.go | 4 +-- .../internal/property/util/parse.go | 22 +++++++++++++ .../patient_postgres_projection.go | 4 +-- .../patient_spicedb_projection.go | 4 +-- .../internal/task/aggregate/aggregate.go | 10 +++--- .../task/commands/v1/update_subtask.go | 5 +-- services/tasks-svc/internal/task/errs/errs.go | 17 ++++++++++ .../task_postgres_projection.go | 32 +++++++++++-------- .../tasks-svc/internal/tracking/tracking.go | 7 +--- services/user-svc/internal/hwkc/client.go | 11 ++----- services/user-svc/internal/hwkc/errs.go | 26 +++++++++++++++ 25 files changed, 186 insertions(+), 93 deletions(-) create mode 100644 services/property-svc/internal/property/util/parse.go create mode 100644 services/tasks-svc/internal/task/errs/errs.go create mode 100644 services/user-svc/internal/hwkc/errs.go diff --git a/libs/common/hwerr/err.go b/libs/common/hwerr/err.go index 18aa26cdc..033c72898 100644 --- a/libs/common/hwerr/err.go +++ b/libs/common/hwerr/err.go @@ -2,6 +2,7 @@ package hwerr import ( "context" + "fmt" "hwlocale" zlog "github.com/rs/zerolog" @@ -54,3 +55,12 @@ func LocalizedMessage(ctx context.Context, locale hwlocale.Locale) *errdetails.L Message: str, } } + +type InvalidEnumError struct { + Enum string + Value string +} + +func (e InvalidEnumError) Error() string { + return fmt.Sprintf("invalid enum: %q is not a valid %q", e.Value, e.Enum) +} diff --git a/libs/hwauthz/spicedb/spicedb.go b/libs/hwauthz/spicedb/spicedb.go index 20ce1b258..647e59988 100644 --- a/libs/hwauthz/spicedb/spicedb.go +++ b/libs/hwauthz/spicedb/spicedb.go @@ -217,7 +217,7 @@ func (s *SpiceDBAuthZ) BulkCheck(ctx context.Context, checks []hwauthz.Permissio resc := req.GetResource() if pberr := pair.GetError(); pberr != nil { - err := fmt.Errorf("spicedb: error while checking permissions: %s", pberr.GetMessage()) + err := fmt.Errorf("spicedb: error while checking permissions: %s", pberr.GetMessage()) //nolint:err113 log.Error().Err(err).Msg("spicedb: error while checking permissions") return nil, err } diff --git a/libs/hwdb/errors.go b/libs/hwdb/errors.go index 4a3d11909..6bb922e42 100644 --- a/libs/hwdb/errors.go +++ b/libs/hwdb/errors.go @@ -5,12 +5,13 @@ import ( "context" "errors" "fmt" - "github.com/google/uuid" "hwlocale" "reflect" "strings" "telemetry" + "github.com/google/uuid" + "github.com/jackc/pgerrcode" "github.com/jackc/pgx/v5/pgconn" "github.com/rs/zerolog" diff --git a/libs/hwes/errs/errors.go b/libs/hwes/errs/errors.go index 442ef6358..960f16efd 100644 --- a/libs/hwes/errs/errors.go +++ b/libs/hwes/errs/errors.go @@ -1,5 +1,21 @@ package errs -import "errors" +import ( + "errors" + "fmt" -var ErrAlreadyExists = errors.New("cannot create an already existing aggregate") + "github.com/google/uuid" +) + +var ( + ErrAlreadyExists = errors.New("cannot create an already existing aggregate") + ErrOrganizationMissing = errors.New("organization is missing from event") + ErrCommitterMissing = errors.New("committer is missing from event") + ErrPayloadMissing = errors.New("payload is empty") +) + +type NotFoundError uuid.UUID + +func (e NotFoundError) Error() string { + return fmt.Sprintf("record with id %s not found", uuid.UUID(e).String()) +} diff --git a/services/property-svc/internal/property-set/projections/spiceDBProjection/set_spicedb_projection.go b/services/property-svc/internal/property-set/projections/spiceDBProjection/set_spicedb_projection.go index 75f2abc21..d6ae935c0 100644 --- a/services/property-svc/internal/property-set/projections/spiceDBProjection/set_spicedb_projection.go +++ b/services/property-svc/internal/property-set/projections/spiceDBProjection/set_spicedb_projection.go @@ -2,11 +2,11 @@ package spiceDBProjection import ( "context" - "errors" "fmt" "hwauthz" "hwauthz/commonPerm" "hwes" + "hwes/errs" "hwes/eventstoredb/projections/custom" "hwutil" @@ -59,7 +59,7 @@ func (p *Projection) onPropertySetCreated(ctx context.Context, evt hwes.Event) ( } if evt.OrganizationID == nil { - return errors.New("organization is missing from event"), hwutil.PtrTo(esdb.NackActionPark) + return errs.ErrOrganizationMissing, hwutil.PtrTo(esdb.NackActionPark) } organizationID := *evt.OrganizationID diff --git a/services/property-svc/internal/property-value/models/propertyValue.go b/services/property-svc/internal/property-value/models/propertyValue.go index c1d20c194..114135712 100644 --- a/services/property-svc/internal/property-value/models/propertyValue.go +++ b/services/property-svc/internal/property-value/models/propertyValue.go @@ -1,7 +1,6 @@ package models import ( - "errors" "fmt" pb "gen/services/property_svc/v1" "hwutil" @@ -76,12 +75,12 @@ type MultiSelectChange struct { func interfaceToStringSlice(interf interface{}) ([]string, error) { slice, ok := interf.([]interface{}) if !ok { - return nil, errors.New("value is not a slice") + return nil, errs.NewCastError("[]interface{}", interf) } strings, ok := hwutil.InterfacesToStrings(slice) if !ok { - return nil, errors.New("value is not a []string") + return nil, errs.NewCastError("[]string", slice) } return strings, nil } diff --git a/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go b/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go index 3e44645b3..66a1a8689 100644 --- a/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go +++ b/services/property-svc/internal/property-value/projections/property_value_postgres_projection/property_value_postgres_projection.go @@ -2,11 +2,11 @@ package property_value_postgres_projection import ( "context" - "errors" "fmt" pb "gen/services/property_svc/v1" "hwdb" "hwes" + esErrs "hwes/errs" "hwes/eventstoredb/projections/custom" "hwutil" "hwutil/errs" @@ -60,7 +60,7 @@ func (p *Projection) onPropertyValueCreated(ctx context.Context, evt hwes.Event) } if payload.Value == nil { - return errors.New("onPropertyValueCreated: payload is empty"), hwutil.PtrTo(esdb.NackActionPark) + return esErrs.ErrPayloadMissing, hwutil.PtrTo(esdb.NackActionPark) } propertyID, err := uuid.Parse(payload.PropertyID) @@ -76,8 +76,7 @@ func (p *Projection) onPropertyValueCreated(ctx context.Context, evt hwes.Event) // GetProperty for the fieldType property, err := hwdb.Optional(p.propertyRepo.GetPropertyById)(ctx, propertyID) if property == nil { - return fmt.Errorf("property with id %s not found for propertyValue", payload.PropertyID), - hwutil.PtrTo(esdb.NackActionRetry) + return PropertyNotFoundForValueError(propertyID), hwutil.PtrTo(esdb.NackActionRetry) } if err := hwdb.Error(ctx, err); err != nil { return err, hwutil.PtrTo(esdb.NackActionRetry) @@ -266,11 +265,7 @@ func (p *Projection) onPropertyValueUpdated(ctx context.Context, evt hwes.Event) if fieldType == pb.FieldType_FIELD_TYPE_SELECT { val, ok := payload.Value.(string) if !ok { - err = fmt.Errorf( - "onPropertyValueUpdated: could not get select value: type is %T, expected string", - payload.Value, - ) - return err, hwutil.PtrTo(esdb.NackActionPark) + return errs.NewCastError("string", payload.Value), hwutil.PtrTo(esdb.NackActionPark) } parsedID, err := uuid.Parse(val) if err != nil { diff --git a/services/property-svc/internal/property-view/aggregate/aggregate.go b/services/property-svc/internal/property-view/aggregate/aggregate.go index 8301e4c31..142179ea5 100644 --- a/services/property-svc/internal/property-view/aggregate/aggregate.go +++ b/services/property-svc/internal/property-view/aggregate/aggregate.go @@ -2,7 +2,6 @@ package aggregate import ( "context" - "errors" "hwes" "hwutil" @@ -59,7 +58,10 @@ func (a *PropertyViewRuleAggregate) onPropertyRuleCreated(event hwes.Event) erro return errs.ErrMissingRuleID } if a.GetID() != payload.RuleID { - return errors.New("RuleID not AggregateID") + return hwes.EventAggregateMismatchError{ + Targeted: a.GetID(), + Got: payload.RuleID, + } } a.PropertyViewRule = &payload.PropertyViewRule return nil diff --git a/services/property-svc/internal/property-view/api/grpc.go b/services/property-svc/internal/property-view/api/grpc.go index 69d392c28..3e3be9ab5 100644 --- a/services/property-svc/internal/property-view/api/grpc.go +++ b/services/property-svc/internal/property-view/api/grpc.go @@ -23,6 +23,8 @@ func NewPropertyViewService(aggregateStore hwes.AggregateStore, handlers *handle return &PropertyViewGrpcService{as: aggregateStore, handlers: handlers} } +var ErrNoMatcher = errors.New("no matcher provided") + func (s PropertyViewGrpcService) UpdatePropertyViewRule( ctx context.Context, req *pb.UpdatePropertyViewRuleRequest, @@ -38,7 +40,7 @@ func (s PropertyViewGrpcService) UpdatePropertyViewRule( } if matcher == nil { - return nil, errors.New("UpdatePropertyViewRule: no matcher provided") + return nil, ErrNoMatcher } appendToAlwaysInclude, err := hwutil.StringsToUUIDs(hwutil.OrEmptySlice( diff --git a/services/property-svc/internal/property-view/models/patient_property_matcher.go b/services/property-svc/internal/property-view/models/patient_property_matcher.go index 12c7c1c15..cca2acf13 100644 --- a/services/property-svc/internal/property-view/models/patient_property_matcher.go +++ b/services/property-svc/internal/property-view/models/patient_property_matcher.go @@ -68,9 +68,11 @@ func (m PatientPropertyMatchers) QueryProperties(ctx context.Context) ([]Propert return hwutil.Map(rows, cast), err } +var ErrPatientIDNotValid = errors.New("PatientID not valid") + func (m PatientPropertyMatchers) GetSubjectID() (uuid.UUID, error) { if !m.PatientID.Valid { - return uuid.UUID{}, errors.New("PatientPropertyMatchers GetSubjectID: PatientID not valid") + return uuid.UUID{}, ErrPatientIDNotValid } return m.PatientID.UUID, nil } diff --git a/services/property-svc/internal/property-view/models/task_property_matchers.go b/services/property-svc/internal/property-view/models/task_property_matchers.go index 11d1c6ff9..a034dc28c 100644 --- a/services/property-svc/internal/property-view/models/task_property_matchers.go +++ b/services/property-svc/internal/property-view/models/task_property_matchers.go @@ -67,9 +67,11 @@ func (m TaskPropertyMatchers) QueryProperties(ctx context.Context) ([]Properties return hwutil.Map(rows, cast), err } +var ErrTaskIDNotValid = errors.New("taskID not valid") + func (m TaskPropertyMatchers) GetSubjectID() (uuid.UUID, error) { if !m.TaskID.Valid { - return uuid.UUID{}, errors.New("TaskPropertyMatchers GetSubjectID: TaskID not valid") + return uuid.UUID{}, ErrTaskIDNotValid } return m.TaskID.UUID, nil } diff --git a/services/property-svc/internal/property/aggregate/aggregate.go b/services/property-svc/internal/property/aggregate/aggregate.go index 7390cbb2d..79466a8f0 100644 --- a/services/property-svc/internal/property/aggregate/aggregate.go +++ b/services/property-svc/internal/property/aggregate/aggregate.go @@ -2,11 +2,12 @@ package aggregate import ( "context" - "fmt" pb "gen/services/property_svc/v1" "hwes" "hwutil" + "property-svc/internal/property/util" + "github.com/google/uuid" propertyEventsV1 "property-svc/internal/property/events/v1" @@ -73,17 +74,15 @@ func (a *PropertyAggregate) onPropertyCreated(evt hwes.Event) error { return err } - val, found := pb.FieldType_value[payload.FieldType] - if !found { - return fmt.Errorf("invalid property fieldType: %s", payload.FieldType) + fieldType, err := util.ParseFieldType(payload.FieldType) + if err != nil { + return err } - fieldType := (pb.FieldType)(val) - val, found = pb.SubjectType_value[payload.SubjectType] - if !found { - return fmt.Errorf("invalid property subjectType: %s", payload.SubjectType) + subjectType, err := util.ParseSubjectType(payload.SubjectType) + if err != nil { + return err } - subjectType := (pb.SubjectType)(val) a.Property.SubjectType = subjectType a.Property.FieldType = fieldType @@ -139,11 +138,10 @@ func (a *PropertyAggregate) onSubjectTypeUpdated(evt hwes.Event) error { return err } - value, found := pb.SubjectType_value[payload.SubjectType] - if !found { - return fmt.Errorf("invalid subjectType: %s", payload.SubjectType) + subjectType, err := util.ParseSubjectType(payload.SubjectType) + if err != nil { + return err } - subjectType := (pb.SubjectType)(value) a.Property.SubjectType = subjectType return nil @@ -177,6 +175,12 @@ func (a *PropertyAggregate) onAllowFreetextUpdated(evt hwes.Event) error { return nil } +type SelectOptionNameMissingError uuid.UUID + +func (e SelectOptionNameMissingError) Error() string { + return "name missing for selectOption with id " + uuid.UUID(e).String() +} + func (a *PropertyAggregate) onFieldTypeDataSelectOptionsUpserted(evt hwes.Event) error { var payload propertyEventsV1.FieldTypeDataSelectOptionsUpsertedEvent if err := evt.GetJsonData(&payload); err != nil { @@ -194,7 +198,7 @@ func (a *PropertyAggregate) onFieldTypeDataSelectOptionsUpserted(evt hwes.Event) for _, option := range payload.UpsertedSelectOptions { if _, exists := selectOptions[option.ID]; !exists { if option.Name == nil { - return fmt.Errorf("name missing for selectOption with id %s", option.ID.String()) + return SelectOptionNameMissingError(option.ID) } selectOptions[option.ID] = models.SelectOption{ ID: option.ID, diff --git a/services/property-svc/internal/property/projections/postgres_projection/postgres_projection.go b/services/property-svc/internal/property/projections/postgres_projection/postgres_projection.go index 868c3fe79..a72fc5c6e 100644 --- a/services/property-svc/internal/property/projections/postgres_projection/postgres_projection.go +++ b/services/property-svc/internal/property/projections/postgres_projection/postgres_projection.go @@ -3,13 +3,14 @@ package postgres_projection import ( "context" "errors" - "fmt" pb "gen/services/property_svc/v1" "hwdb" "hwes" "hwes/eventstoredb/projections/custom" "hwutil" + "property-svc/internal/property/util" + "github.com/EventStore/EventStore-Client-Go/v4/esdb" "github.com/google/uuid" "github.com/jackc/pgx/v5" @@ -86,17 +87,15 @@ func (p *Projection) onPropertyCreated(ctx context.Context, evt hwes.Event) (err return err, hwutil.PtrTo(esdb.NackActionPark) } - value, found := pb.SubjectType_value[payload.SubjectType] - if !found { - return fmt.Errorf("subject_type %s invalid", payload.SubjectType), hwutil.PtrTo(esdb.NackActionPark) + subjectType, err := util.ParseSubjectType(payload.SubjectType) + if err != nil { + return err, hwutil.PtrTo(esdb.NackActionPark) } - subjectType := (pb.SubjectType)(value) - value, found = pb.FieldType_value[payload.FieldType] - if !found { - return fmt.Errorf("field_type %s invalid", payload.FieldType), hwutil.PtrTo(esdb.NackActionPark) + fieldType, err := util.ParseFieldType(payload.FieldType) + if err != nil { + return err, hwutil.PtrTo(esdb.NackActionPark) } - fieldType := (pb.FieldType)(value) // create query err = p.propertyRepo.CreateProperty(ctx, property_repo.CreatePropertyParams{ @@ -179,13 +178,12 @@ func (p *Projection) onSubjectTypeUpdated(ctx context.Context, evt hwes.Event) ( return err, hwutil.PtrTo(esdb.NackActionPark) } - value, found := pb.SubjectType_value[payload.SubjectType] - if !found { - return fmt.Errorf("invalid fieldType: %s", payload.SubjectType), hwutil.PtrTo(esdb.NackActionPark) + subjectType, err := util.ParseSubjectType(payload.SubjectType) + if err != nil { + return err, hwutil.PtrTo(esdb.NackActionPark) } - subjectType := (pb.SubjectType)(value) - err := p.propertyRepo.UpdateProperty(ctx, property_repo.UpdatePropertyParams{ + err = p.propertyRepo.UpdateProperty(ctx, property_repo.UpdatePropertyParams{ ID: evt.AggregateID, SubjectType: hwutil.PtrTo(int32(subjectType)), Consistency: int64(evt.GetVersion()), //nolint:gosec diff --git a/services/property-svc/internal/property/projections/spiceDBProjection/property_spicedb_projection.go b/services/property-svc/internal/property/projections/spiceDBProjection/property_spicedb_projection.go index c088f9564..e3b9da2f1 100644 --- a/services/property-svc/internal/property/projections/spiceDBProjection/property_spicedb_projection.go +++ b/services/property-svc/internal/property/projections/spiceDBProjection/property_spicedb_projection.go @@ -2,11 +2,11 @@ package spiceDBProjection import ( "context" - "errors" "fmt" "hwauthz" "hwauthz/commonPerm" "hwes" + "hwes/errs" "hwes/eventstoredb/projections/custom" "hwutil" @@ -59,7 +59,7 @@ func (p *Projection) onPropertyCreated(ctx context.Context, evt hwes.Event) (err } if evt.OrganizationID == nil { - return errors.New("organization is missing from event"), hwutil.PtrTo(esdb.NackActionPark) + return errs.ErrOrganizationMissing, hwutil.PtrTo(esdb.NackActionPark) } organizationID := *evt.OrganizationID diff --git a/services/property-svc/internal/property/queries/v1/get_property_by_id.go b/services/property-svc/internal/property/queries/v1/get_property_by_id.go index 90aaaa644..ef11ba254 100644 --- a/services/property-svc/internal/property/queries/v1/get_property_by_id.go +++ b/services/property-svc/internal/property/queries/v1/get_property_by_id.go @@ -3,11 +3,11 @@ package v1 import ( "common" "context" - "fmt" pb "gen/services/property_svc/v1" "hwauthz" "hwauthz/commonPerm" "hwdb" + "hwes/errs" "github.com/google/uuid" @@ -42,7 +42,7 @@ func NewGetPropertyByIDQueryHandler(authz hwauthz.AuthZ) GetPropertyByIDQueryHan return nil, 0, err } if len(rows) == 0 { - return nil, 0, fmt.Errorf("record with id %s not found", propertyID.String()) + return nil, 0, errs.NotFoundError(propertyID) } property := &models.Property{ diff --git a/services/property-svc/internal/property/util/parse.go b/services/property-svc/internal/property/util/parse.go new file mode 100644 index 000000000..6131e4523 --- /dev/null +++ b/services/property-svc/internal/property/util/parse.go @@ -0,0 +1,22 @@ +package util + +import ( + "common/hwerr" + pb "gen/services/property_svc/v1" +) + +func ParseFieldType(fieldType string) (pb.FieldType, error) { + val, found := pb.FieldType_value[fieldType] + if !found { + return 0, hwerr.InvalidEnumError{Enum: "FieldType", Value: fieldType} + } + return (pb.FieldType)(val), nil +} + +func ParseSubjectType(subjectType string) (pb.SubjectType, error) { + val, found := pb.SubjectType_value[subjectType] + if !found { + return 0, hwerr.InvalidEnumError{Enum: "SubjectType", Value: subjectType} + } + return (pb.SubjectType)(val), nil +} diff --git a/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go b/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go index efa4afa8e..ed1e1a89d 100644 --- a/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go +++ b/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go @@ -2,9 +2,9 @@ package patientPostgresProjection import ( "context" - "errors" "hwdb" "hwes" + "hwes/errs" "hwes/eventstoredb/projections/custom" "hwutil" @@ -63,7 +63,7 @@ func (a *Projection) onPatientCreated(ctx context.Context, evt hwes.Event) (erro } if evt.OrganizationID == nil { - return errors.New("onPatientCreated: organizationID missing"), hwutil.PtrTo(esdb.NackActionSkip) + return errs.ErrOrganizationMissing, hwutil.PtrTo(esdb.NackActionSkip) } organizationID := *evt.OrganizationID diff --git a/services/tasks-svc/internal/patient/projections/patientSpiceDBProjection/patient_spicedb_projection.go b/services/tasks-svc/internal/patient/projections/patientSpiceDBProjection/patient_spicedb_projection.go index 0423fa221..525803280 100644 --- a/services/tasks-svc/internal/patient/projections/patientSpiceDBProjection/patient_spicedb_projection.go +++ b/services/tasks-svc/internal/patient/projections/patientSpiceDBProjection/patient_spicedb_projection.go @@ -2,11 +2,11 @@ package patientSpiceDBProjection import ( "context" - "errors" "fmt" "hwauthz" "hwauthz/commonPerm" "hwes" + "hwes/errs" "hwes/eventstoredb/projections/custom" "hwutil" @@ -44,7 +44,7 @@ func (p *Projection) initEventListeners() { // Event handlers func (p *Projection) onPatientCreated(ctx context.Context, evt hwes.Event) (error, *esdb.NackAction) { if evt.OrganizationID == nil { - return errors.New("onPatientCreated: organizationID missing"), hwutil.PtrTo(esdb.NackActionSkip) + return errs.ErrOrganizationMissing, hwutil.PtrTo(esdb.NackActionSkip) } organization := commonPerm.Organization(*evt.OrganizationID) diff --git a/services/tasks-svc/internal/task/aggregate/aggregate.go b/services/tasks-svc/internal/task/aggregate/aggregate.go index e1288ee30..0eb6bbaa3 100644 --- a/services/tasks-svc/internal/task/aggregate/aggregate.go +++ b/services/tasks-svc/internal/task/aggregate/aggregate.go @@ -1,12 +1,14 @@ package aggregate import ( + "common/hwerr" "context" - "fmt" pb "gen/services/tasks_svc/v1" "hwes" "time" + "tasks-svc/internal/task/errs" + "github.com/google/uuid" taskEventsV1 "tasks-svc/internal/task/events/v1" @@ -77,7 +79,7 @@ func (a *TaskAggregate) onTaskCreated(evt hwes.Event) error { value, found := pb.TaskStatus_value[payload.Status] if !found { - return fmt.Errorf("invalid taskStatus: %s", payload.Status) + return hwerr.InvalidEnumError{Enum: "TaskStatus", Value: payload.Status} } status := (pb.TaskStatus)(value) @@ -97,7 +99,7 @@ func (a *TaskAggregate) onTaskStatusUpdated(evt hwes.Event) error { value, found := pb.TaskStatus_value[payload.Status] if !found { - return fmt.Errorf("invalid taskStatus: %s", payload.Status) + return hwerr.InvalidEnumError{Enum: "TaskStatus", Value: payload.Status} } status := (pb.TaskStatus)(value) @@ -224,7 +226,7 @@ func (a *TaskAggregate) onSubtaskNameUpdated(evt hwes.Event) error { subtask, found := a.Task.Subtasks[subtaskID] if !found { - return fmt.Errorf("Subtask '%s' not found in task '%s'", subtaskID, a.Task.ID) + return errs.SubtaskNotInTaskError{Subtask: subtaskID, Task: a.Task.ID} } subtask.Name = payload.Name diff --git a/services/tasks-svc/internal/task/commands/v1/update_subtask.go b/services/tasks-svc/internal/task/commands/v1/update_subtask.go index b5531cdf1..6d78b9661 100644 --- a/services/tasks-svc/internal/task/commands/v1/update_subtask.go +++ b/services/tasks-svc/internal/task/commands/v1/update_subtask.go @@ -3,11 +3,12 @@ package v1 import ( "common" "context" - "fmt" "hwauthz" "hwauthz/commonPerm" "hwes" + "tasks-svc/internal/task/errs" + "tasks-svc/internal/task/perm" "github.com/google/uuid" @@ -45,7 +46,7 @@ func NewUpdateSubtaskCommandHandler(as hwes.AggregateStore, authz hwauthz.AuthZ) currentSubtask, found := a.Task.Subtasks[subtaskID] if !found { - return 0, fmt.Errorf("subtask with ID: %s not found on Task with ID: %s", subtaskID, taskID) + return 0, errs.SubtaskNotInTaskError{Subtask: subtaskID, Task: taskID} } if name != nil && *name != currentSubtask.Name { diff --git a/services/tasks-svc/internal/task/errs/errs.go b/services/tasks-svc/internal/task/errs/errs.go new file mode 100644 index 000000000..eabc53ddf --- /dev/null +++ b/services/tasks-svc/internal/task/errs/errs.go @@ -0,0 +1,17 @@ +package errs + +import ( + "fmt" + + "github.com/google/uuid" +) + +type SubtaskNotInTaskError struct { + Subtask uuid.UUID + Task uuid.UUID +} + +func (e SubtaskNotInTaskError) Error() string { + return fmt.Sprintf("subtask %q not found in task %q", + e.Subtask.String(), e.Task.String()) +} diff --git a/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go b/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go index 6c81f09ec..116676f92 100644 --- a/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go +++ b/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go @@ -1,12 +1,12 @@ package task_postgres_projection import ( + "common/hwerr" "context" - "errors" - "fmt" pb "gen/services/tasks_svc/v1" "hwdb" "hwes" + esErrs "hwes/errs" "hwes/eventstoredb/projections/custom" "hwutil" @@ -57,6 +57,14 @@ func (p *Projection) initEventListeners() { p.RegisterEventListener(taskEventsV1.TaskDeleted, p.onTaskDeleted) } +func parseTaskStatus(status string) (pb.TaskStatus, error) { + value, found := pb.TaskStatus_value[status] + if !found { + return 0, hwerr.InvalidEnumError{Enum: "TaskStatus", Value: status} + } + return (pb.TaskStatus)(value), nil +} + func (p *Projection) onTaskCreated(ctx context.Context, evt hwes.Event) (error, *esdb.NackAction) { log := zlog.Ctx(ctx) @@ -76,17 +84,16 @@ func (p *Projection) onTaskCreated(ctx context.Context, evt hwes.Event) (error, return err, hwutil.PtrTo(esdb.NackActionPark) } - value, found := pb.TaskStatus_value[payload.Status] - if !found { - return fmt.Errorf("invalid taskStatus: %s", payload.Status), hwutil.PtrTo(esdb.NackActionPark) + status, err := parseTaskStatus(payload.Status) + if err != nil { + return err, hwutil.PtrTo(esdb.NackActionPark) } - status := (pb.TaskStatus)(value) var committerID uuid.UUID if evt.CommitterUserID != nil { committerID = *evt.CommitterUserID } else { - return errors.New("commiterId is not set"), hwutil.PtrTo(esdb.NackActionPark) + return esErrs.ErrCommitterMissing, hwutil.PtrTo(esdb.NackActionPark) } // Add to db @@ -115,13 +122,12 @@ func (p *Projection) onTaskStatusUpdated(ctx context.Context, evt hwes.Event) (e return err, hwutil.PtrTo(esdb.NackActionPark) } - value, found := pb.TaskStatus_value[payload.Status] - if !found { - return fmt.Errorf("invalid taskStatus: %s", payload.Status), hwutil.PtrTo(esdb.NackActionPark) + status, err := parseTaskStatus(payload.Status) + if err != nil { + return err, hwutil.PtrTo(esdb.NackActionPark) } - status := (pb.TaskStatus)(value) - err := p.taskRepo.UpdateTask(ctx, task_repo.UpdateTaskParams{ + err = p.taskRepo.UpdateTask(ctx, task_repo.UpdateTaskParams{ ID: evt.AggregateID, Status: hwutil.PtrTo(int32(status)), Consistency: int64(evt.GetVersion()), //nolint:gosec @@ -295,7 +301,7 @@ func (p *Projection) onSubtaskCreated(ctx context.Context, evt hwes.Event) (erro if evt.CommitterUserID != nil { committerID = *evt.CommitterUserID } else { - return errors.New("committerID not set"), hwutil.PtrTo(esdb.NackActionPark) + return esErrs.ErrCommitterMissing, hwutil.PtrTo(esdb.NackActionPark) } subtaskID, err := uuid.Parse(payload.SubtaskID) diff --git a/services/tasks-svc/internal/tracking/tracking.go b/services/tasks-svc/internal/tracking/tracking.go index 6450f2cf9..93195eb99 100644 --- a/services/tasks-svc/internal/tracking/tracking.go +++ b/services/tasks-svc/internal/tracking/tracking.go @@ -4,7 +4,6 @@ import ( "common/auth" "context" "decaying_lru" - "errors" "hwutil" "time" @@ -101,11 +100,7 @@ func RemoveWardFromRecentActivity(ctx context.Context, wardID string) { // - SetupTracking was called earlier // - the context originates from an authenticated request func GetRecentWardsForUser(ctx context.Context) ([]string, error) { - userID := getUserID(ctx) - if userID == "" { - return nil, errors.New("GetRecentWardsForUser called, but context has no userID") - } - return lru.GetItemsForUser(ctx, WardKey, userID) + return lru.GetItemsForUser(ctx, WardKey, getUserID(ctx)) } // SetLRU overwrites the lru, to use a custom setup, instead of SetupTracking (e.g., for testing) diff --git a/services/user-svc/internal/hwkc/client.go b/services/user-svc/internal/hwkc/client.go index e9716b9af..a72ea7beb 100644 --- a/services/user-svc/internal/hwkc/client.go +++ b/services/user-svc/internal/hwkc/client.go @@ -7,7 +7,6 @@ import ( "encoding/json" "fmt" "hwutil" - "io" "net/http" "net/url" "strconv" @@ -89,14 +88,8 @@ func (c *Client) ensureSuccessfulResponse(res *http.Response) error { if res.StatusCode >= 200 && res.StatusCode <= 299 { return nil } - body, err := io.ReadAll(res.Body) - if err != nil { - return fmt.Errorf("response status code not 2xx, cannot read response body for error message: %w", err) - } - return fmt.Errorf( - "response status for %s - %s is %d: %s", - res.Request.Method, res.Request.URL.String(), res.StatusCode, string(body), - ) + + return BadResponseError{Res: res} } func (c *Client) GetUserById(ctx context.Context, userID uuid.UUID) (*User, error) { diff --git a/services/user-svc/internal/hwkc/errs.go b/services/user-svc/internal/hwkc/errs.go new file mode 100644 index 000000000..1cd17d679 --- /dev/null +++ b/services/user-svc/internal/hwkc/errs.go @@ -0,0 +1,26 @@ +package hwkc + +import ( + "fmt" + "io" + "net/http" +) + +type BadResponseError struct { + Res *http.Response +} + +func (e BadResponseError) Error() string { + var body string + bodyBytes, err := io.ReadAll(e.Res.Body) + if err != nil { + body = "could not read body: " + err.Error() + } else { + body = string(bodyBytes) + } + + return fmt.Sprintf( + "bad response status: %s - %s is %d: %s", + e.Res.Request.Method, e.Res.Request.URL.String(), e.Res.StatusCode, body, + ) +} From af3d2ec9cf41ac7ed6233350e8804ba15c8191bf Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 17:03:29 +0100 Subject: [PATCH 06/22] cast handle nil --- libs/hwutil/errs/casts.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/hwutil/errs/casts.go b/libs/hwutil/errs/casts.go index 5ea4ef25a..575e7a78b 100644 --- a/libs/hwutil/errs/casts.go +++ b/libs/hwutil/errs/casts.go @@ -15,8 +15,13 @@ type CastError struct { // NewCastError constructs a new CastError using a provided Expected string and any value you got instead, // it will then use refection to return the error func NewCastError(expected string, got interface{}) CastError { + gotType := "nil" + if got != nil { + gotType = reflect.TypeOf(got).String() + } + return CastError{ - Got: reflect.TypeOf(got).String(), + Got: gotType, Expected: expected, } } From 94dd3930a1400bd9f1cb19db49359de765640c7c Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 16:06:04 +0100 Subject: [PATCH 07/22] feat: t.Parallel() --- .golangci.yaml | 1 - libs/common/auth/auth_test.go | 4 ++++ libs/common/hwgrpc/hwgrpc_test.go | 3 +++ libs/common/hwgrpc/locale_interceptor_test.go | 5 +++++ libs/common/hwgrpc/panic_interceptor_test.go | 1 + libs/common/test/grpc_test.go | 1 + libs/hwauthz/spicedb/spicedb_test.go | 5 +++++ libs/hwdb/helper_test.go | 6 ++++++ libs/hwes/aggregate_test.go | 2 ++ libs/hwes/event_test.go | 4 ++++ libs/hwes/integration_test.go | 4 ++++ libs/hwutil/contains_test.go | 4 ++++ libs/hwutil/parse_test.go | 18 ++++++++++++++++++ .../internal/property-view/api/grpc_test.go | 12 ++++++++++++ .../property_rules_postgres_test.go | 8 ++++++++ .../stories/GetPropertieBySubjectType_test.go | 2 ++ .../property-svc/stories/GetProperty_test.go | 4 ++++ .../stories/PropertyValueCRUD_test.go | 10 ++++++++++ .../patient/aggregate/aggregate_test.go | 12 ++++++++++++ .../internal/patient/api/grpc_test.go | 16 ++++++++++++++++ .../internal/task/aggregate/aggregate_test.go | 12 ++++++++++++ .../tasks-svc/internal/task/api/grpc_test.go | 18 ++++++++++++++++++ services/tasks-svc/stories/BedCRUD_test.go | 6 ++++++ services/tasks-svc/stories/PatientCRUD_test.go | 14 ++++++++++++++ services/tasks-svc/stories/RoomCRUD_test.go | 6 ++++++ services/tasks-svc/stories/TaskCRUD_test.go | 6 ++++++ .../tasks-svc/stories/TaskTemplateCRUD_test.go | 2 ++ services/tasks-svc/stories/WardCRUD_test.go | 10 ++++++++++ services/updates-svc/stories/updates_test.go | 6 ++++++ .../user-svc/stories/OrganizationCRUD_test.go | 2 ++ 30 files changed, 203 insertions(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 254a75c74..cda0725f1 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -35,7 +35,6 @@ linters: - godox # TODO - nestif # TODO - nlreturn # TODO - - paralleltest # TODO - protogetter # TODO - revive # TODO - stylecheck # TODO diff --git a/libs/common/auth/auth_test.go b/libs/common/auth/auth_test.go index c4425e8d6..13ac1c782 100644 --- a/libs/common/auth/auth_test.go +++ b/libs/common/auth/auth_test.go @@ -7,6 +7,8 @@ import ( ) func TestIDTokenClaims_AsExpected(t *testing.T) { + t.Parallel() + tests := []struct { name string claims IDTokenClaims @@ -95,6 +97,8 @@ func TestIDTokenClaims_AsExpected(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + t.Parallel() + err := tt.claims.AsExpected() if tt.expectedError { require.Error(t, err) diff --git a/libs/common/hwgrpc/hwgrpc_test.go b/libs/common/hwgrpc/hwgrpc_test.go index cbb427540..a07ca8e74 100644 --- a/libs/common/hwgrpc/hwgrpc_test.go +++ b/libs/common/hwgrpc/hwgrpc_test.go @@ -21,6 +21,7 @@ func arrayEq(t *testing.T, expected []language.Tag, parsed []language.Tag) { } func TestParseLocales(t *testing.T) { + t.Parallel() const mdnExample = "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5" expected := []language.Tag{language.MustParse("fr-CH"), language.French, language.English, language.German} parsed, ok := hwgrpc.ParseLocales(mdnExample) @@ -32,6 +33,7 @@ func TestParseLocales(t *testing.T) { } func TestParseLocalesReordered(t *testing.T) { + t.Parallel() const mdnExample = "fr-CH, de;q=0.7, en;q=0.8, fr;q=0.9, *;q=0.5" expected := []language.Tag{language.MustParse("fr-CH"), language.French, language.English, language.German} parsed, ok := hwgrpc.ParseLocales(mdnExample) @@ -43,6 +45,7 @@ func TestParseLocalesReordered(t *testing.T) { } func TestParseLocalesSimple(t *testing.T) { + t.Parallel() const mdnExample = "de" expected := []language.Tag{language.German} parsed, ok := hwgrpc.ParseLocales(mdnExample) diff --git a/libs/common/hwgrpc/locale_interceptor_test.go b/libs/common/hwgrpc/locale_interceptor_test.go index ef4995156..3c111db0c 100644 --- a/libs/common/hwgrpc/locale_interceptor_test.go +++ b/libs/common/hwgrpc/locale_interceptor_test.go @@ -12,6 +12,8 @@ import ( ) func TestLocaleInterceptor(t *testing.T) { + t.Parallel() + testCases := map[string][]string{ "de": {"de"}, "en": {"en"}, @@ -22,8 +24,11 @@ func TestLocaleInterceptor(t *testing.T) { } for acceptLanguageHeader, expectedLocalesStrings := range testCases { + t.Parallel() t.Run(fmt.Sprintf("Test localeInterceptor with accept-language header of '%s'", acceptLanguageHeader), func(t *testing.T) { + t.Parallel() + ctx := context.Background() md := metadata.New(map[string]string{ diff --git a/libs/common/hwgrpc/panic_interceptor_test.go b/libs/common/hwgrpc/panic_interceptor_test.go index bcfab10e9..ea0561ec3 100644 --- a/libs/common/hwgrpc/panic_interceptor_test.go +++ b/libs/common/hwgrpc/panic_interceptor_test.go @@ -37,6 +37,7 @@ type RecoverySuite struct { } func TestPanicRecoverInterceptor(t *testing.T) { + t.Parallel() telemetry.SetupMetrics(context.Background(), nil) s := &RecoverySuite{ InterceptorTestSuite: &testpb.InterceptorTestSuite{ diff --git a/libs/common/test/grpc_test.go b/libs/common/test/grpc_test.go index 8ad783022..3ca3396dd 100644 --- a/libs/common/test/grpc_test.go +++ b/libs/common/test/grpc_test.go @@ -12,5 +12,6 @@ import ( // - AuthenticatedUserMetadata accesses the AuthenticatedUserClaim map incorrectly // - AuthenticatedUserClaim map is not JSON-able func TestAuthenticatedUserMetadataDoesNotCrash(t *testing.T) { + t.Parallel() _ = AuthenticatedUserMetadata(uuid.NewString()) } diff --git a/libs/hwauthz/spicedb/spicedb_test.go b/libs/hwauthz/spicedb/spicedb_test.go index 1715fd6a9..984bb43a3 100644 --- a/libs/hwauthz/spicedb/spicedb_test.go +++ b/libs/hwauthz/spicedb/spicedb_test.go @@ -52,6 +52,7 @@ func TestMain(m *testing.M) { } func TestBulkCheck(t *testing.T) { + t.Parallel() ctx := context.Background() client := NewSpiceDBAuthZ() @@ -102,6 +103,8 @@ func TestBulkCheck(t *testing.T) { } func TestLookupResources(t *testing.T) { + t.Parallel() + ctx := context.Background() client := NewSpiceDBAuthZ() @@ -134,6 +137,8 @@ func TestLookupResources(t *testing.T) { } func TestDeleteObject(t *testing.T) { + t.Parallel() + // client ctx := context.Background() client := NewSpiceDBAuthZ() diff --git a/libs/hwdb/helper_test.go b/libs/hwdb/helper_test.go index 75d37597d..4135b25cf 100644 --- a/libs/hwdb/helper_test.go +++ b/libs/hwdb/helper_test.go @@ -8,13 +8,19 @@ import ( ) func TestPbToTimestamp(t *testing.T) { + t.Parallel() + t.Run("src = nil", func(t *testing.T) { + t.Parallel() + if hwdb.PbToTimestamp(nil).Valid { t.Error() } }) t.Run("src not nil", func(t *testing.T) { + t.Parallel() + src := timestamppb.Timestamp{ Seconds: 0, Nanos: 0, diff --git a/libs/hwes/aggregate_test.go b/libs/hwes/aggregate_test.go index b1408fd12..bf5c7036c 100644 --- a/libs/hwes/aggregate_test.go +++ b/libs/hwes/aggregate_test.go @@ -8,6 +8,8 @@ import ( ) func TestResolveAggregateIDAndTypeFromStreamID(t *testing.T) { + t.Parallel() + testCases := []struct { streamID string expectedError bool diff --git a/libs/hwes/event_test.go b/libs/hwes/event_test.go index 335847777..05e00ab07 100644 --- a/libs/hwes/event_test.go +++ b/libs/hwes/event_test.go @@ -11,6 +11,8 @@ import ( ) func TestEventWithUserID(t *testing.T) { + t.Parallel() + ctx := context.Background() u := uuid.New() e := hwes.Event{} @@ -25,6 +27,8 @@ func TestEventWithUserID(t *testing.T) { } func TestEventWithOrganizationID(t *testing.T) { + t.Parallel() + ctx := context.Background() u := uuid.New() e := hwes.Event{} diff --git a/libs/hwes/integration_test.go b/libs/hwes/integration_test.go index f246e41ab..4948c7ded 100644 --- a/libs/hwes/integration_test.go +++ b/libs/hwes/integration_test.go @@ -103,6 +103,8 @@ func NewUsernameUpdatedEvent(a hwes.Aggregate, previousUsername, username string } func TestIntegration(t *testing.T) { + t.Parallel() + ctx := context.Background() aggregateStore := test.NewAggregateStore() @@ -154,6 +156,8 @@ func TestIntegration(t *testing.T) { var ErrTest = errors.New("test error") func TestAggregateBase_RegisterEventListener_HandleEvent(t *testing.T) { + t.Parallel() + aggregate := NewUserAggregate(uuid.New()) userInvalidEvent, err := NewUserInvalidEvent(aggregate) diff --git a/libs/hwutil/contains_test.go b/libs/hwutil/contains_test.go index 90d79d81a..c1a68867a 100644 --- a/libs/hwutil/contains_test.go +++ b/libs/hwutil/contains_test.go @@ -16,6 +16,8 @@ type testCase[T comparable] struct { func runTestContains[T comparable](t *testing.T, testCase testCase[T]) { t.Helper() t.Run(fmt.Sprintf("contains %v the value %v", testCase.haystack, testCase.needle), func(t *testing.T) { + t.Parallel() + got := hwutil.Contains(testCase.haystack, testCase.needle) if testCase.expected != got { t.Errorf("expected %t, got %t", testCase.expected, got) @@ -24,6 +26,8 @@ func runTestContains[T comparable](t *testing.T, testCase testCase[T]) { } func TestContains(t *testing.T) { + t.Parallel() + runTestContains(t, testCase[string]{ haystack: []string{"ABC", "DEF", "GHI"}, needle: "DEF", diff --git a/libs/hwutil/parse_test.go b/libs/hwutil/parse_test.go index 4d60be741..98046d565 100644 --- a/libs/hwutil/parse_test.go +++ b/libs/hwutil/parse_test.go @@ -13,6 +13,8 @@ import ( func runPtrToTest[T comparable](t *testing.T, v T) { t.Helper() t.Run(fmt.Sprintf("test value %v as %T", v, v), func(t *testing.T) { + t.Parallel() + vPtr := hwutil.PtrTo(v) if v != *vPtr { t.Errorf("expected %v, got %v", v, *vPtr) @@ -21,6 +23,8 @@ func runPtrToTest[T comparable](t *testing.T, v T) { } func TestPtrTo(t *testing.T) { + t.Parallel() + runPtrToTest(t, true) runPtrToTest(t, "Hello world") runPtrToTest(t, 123) @@ -34,7 +38,11 @@ func TestPtrTo(t *testing.T) { } func TestStringsToUUIDs(t *testing.T) { + t.Parallel() + t.Run("valid uuids", func(t *testing.T) { + t.Parallel() + uuidStrings := []string{ "48441b57-a92a-4022-bfd9-9ded5acdb693", "370472cf-0e4f-449f-a6a4-817d7e025552", @@ -62,6 +70,8 @@ func TestStringsToUUIDs(t *testing.T) { }) t.Run("invalid uuids", func(t *testing.T) { + t.Parallel() + uuidStrings := []string{ "48441b57-a92a-4022-bfd9-9ded5acdb693", "asdasdasdsadsadadadsa", @@ -75,6 +85,8 @@ func TestStringsToUUIDs(t *testing.T) { }) t.Run("empty", func(t *testing.T) { + t.Parallel() + uuidStrings := []string{} actual, err := hwutil.StringsToUUIDs(uuidStrings) if err != nil { @@ -87,7 +99,11 @@ func TestStringsToUUIDs(t *testing.T) { } func TestInterfacesToStrings(t *testing.T) { + t.Parallel() + t.Run("ok path", func(t *testing.T) { + t.Parallel() + expected := []string{ "48441b57-a92a-4022-bfd9-9ded5acdb693", "Unit Test", @@ -104,6 +120,8 @@ func TestInterfacesToStrings(t *testing.T) { }) t.Run("not ok path", func(t *testing.T) { + t.Parallel() + interfaces := []interface{}{ "48441b57-a92a-4022-bfd9-9ded5acdb693", 123, diff --git a/services/property-svc/internal/property-view/api/grpc_test.go b/services/property-svc/internal/property-view/api/grpc_test.go index e8d3a602d..cab555bb5 100644 --- a/services/property-svc/internal/property-view/api/grpc_test.go +++ b/services/property-svc/internal/property-view/api/grpc_test.go @@ -72,6 +72,8 @@ func setup() ( } func TestPropertyViewGrpcService_UpdatePropertyViewRule_Validation(t *testing.T) { + t.Parallel() + ctx, client, _, dbMock, teardown := setup() defer teardown() @@ -217,6 +219,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_Validation(t *testing.T) } func TestPropertyViewGrpcService_UpdatePropertyViewRule_AllEmptyNoEffect(t *testing.T) { + t.Parallel() + ctx, client, as, _, teardown := setup() defer teardown() @@ -240,6 +244,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_AllEmptyNoEffect(t *test } func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_GreenPath_Created(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -308,6 +314,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_Gree } func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_GreenPath_Created(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -376,6 +384,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_G } func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_GreenPath_Updated(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -473,6 +483,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_Gree } func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_GreenPath_Updated(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go index 74ffde3ea..3418a73ea 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go @@ -53,6 +53,8 @@ func setup() (ctx context.Context, projection *Projection, dbMock pgxmock.PgxPoo } func TestPropertyViewPropertyRulesProjection_Create_TaskPropertyMatcher_GreenPath(t *testing.T) { + t.Parallel() + ctx, projection, dbMock, teardown := setup() defer teardown() @@ -105,6 +107,8 @@ func TestPropertyViewPropertyRulesProjection_Create_TaskPropertyMatcher_GreenPat } func TestPropertyViewPropertyRulesProjection_Update_GreenPath(t *testing.T) { + t.Parallel() + ctx, projection, dbMock, teardown := setup() defer teardown() @@ -171,6 +175,8 @@ func TestPropertyViewPropertyRulesProjection_Update_GreenPath(t *testing.T) { } func TestPropertyViewPropertyRulesProjection_Create_PatientPropertyMatcher_GreenPath(t *testing.T) { + t.Parallel() + ctx, projection, dbMock, teardown := setup() defer teardown() @@ -223,6 +229,8 @@ func TestPropertyViewPropertyRulesProjection_Create_PatientPropertyMatcher_Green } func TestPropertyViewPropertyRulesProjection_Create_InvalidPropertyMatcher(t *testing.T) { + t.Parallel() + ctx, projection, _, teardown := setup() defer teardown() diff --git a/services/property-svc/stories/GetPropertieBySubjectType_test.go b/services/property-svc/stories/GetPropertieBySubjectType_test.go index f6e0d4123..111a1b9d0 100644 --- a/services/property-svc/stories/GetPropertieBySubjectType_test.go +++ b/services/property-svc/stories/GetPropertieBySubjectType_test.go @@ -18,6 +18,8 @@ import ( // - Create Properties // - Check GetPropertiesBySubjectType func TestGetProperties(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() diff --git a/services/property-svc/stories/GetProperty_test.go b/services/property-svc/stories/GetProperty_test.go index b2531d65f..bbb90485c 100644 --- a/services/property-svc/stories/GetProperty_test.go +++ b/services/property-svc/stories/GetProperty_test.go @@ -24,6 +24,8 @@ import ( // - Add to always include list for ward and subjectid (matcher too precise) // After each step: GetProperty and check AlwaysIncludedForViewSource for wardid func TestTaskGetPropertyAlwaysIncluded(t *testing.T) { + t.Parallel() + ctx := context.Background() wardID := uuid.New() patientID := uuid.New() @@ -189,6 +191,8 @@ func TestTaskGetPropertyAlwaysIncluded(t *testing.T) { // - Update name // - TODO: conflict detection func TestTaskGetPropertyConsistency(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() diff --git a/services/property-svc/stories/PropertyValueCRUD_test.go b/services/property-svc/stories/PropertyValueCRUD_test.go index 405d3e465..7da9b8dc3 100644 --- a/services/property-svc/stories/PropertyValueCRUD_test.go +++ b/services/property-svc/stories/PropertyValueCRUD_test.go @@ -17,6 +17,8 @@ import ( // - Attach a Value // - Update said value func TestCreateAttachUpdateTextProperty(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() @@ -165,6 +167,8 @@ func TestCreateAttachUpdateTextProperty(t *testing.T) { // - Attach a Value // - Update said value func TestCreateAttachUpdateSelectProperty(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() @@ -333,6 +337,8 @@ func TestCreateAttachUpdateSelectProperty(t *testing.T) { // - Attach a Value // - Update said value func TestCreateAttachUpdateMultiSelectProperty(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() @@ -521,6 +527,8 @@ func TestCreateAttachUpdateMultiSelectProperty(t *testing.T) { // - Upsert an Option // - Attach another Value func TestCreateAttachAddOptionAttachSelectProperty(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() @@ -679,6 +687,8 @@ func TestCreateAttachAddOptionAttachSelectProperty(t *testing.T) { // - Upsert an Option // - Attach another Value func TestCreateAttachAddOptionAttachMultiSelectProperty(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() diff --git a/services/tasks-svc/internal/patient/aggregate/aggregate_test.go b/services/tasks-svc/internal/patient/aggregate/aggregate_test.go index 728eabe3e..dfde3e4b3 100644 --- a/services/tasks-svc/internal/patient/aggregate/aggregate_test.go +++ b/services/tasks-svc/internal/patient/aggregate/aggregate_test.go @@ -26,6 +26,8 @@ func MustApplyEvent(t *testing.T, aggregate hwes.Aggregate, newEvent func() (hwe } func TestPatientAggregate_CreatePatient(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -58,6 +60,8 @@ func TestPatientAggregate_CreatePatient(t *testing.T) { } func TestPatientAggregate_UpdateNotes(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -94,6 +98,8 @@ func TestPatientAggregate_UpdateNotes(t *testing.T) { } func TestPatientAggregate_UpdateHumanReadableIdentifier(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -135,6 +141,8 @@ func TestPatientAggregate_UpdateHumanReadableIdentifier(t *testing.T) { } func TestPatientAggregate_DischargeReadmitPatient(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -176,6 +184,8 @@ func TestPatientAggregate_DischargeReadmitPatient(t *testing.T) { } func TestPatientAggregate_AssignUnassignBed(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -221,6 +231,8 @@ func TestPatientAggregate_AssignUnassignBed(t *testing.T) { } func TestPatientAggregate_DeletePatient(t *testing.T) { + t.Parallel() + ctx := auth.ContextWithUserID(context.Background(), uuid.New()) patientID := uuid.New() diff --git a/services/tasks-svc/internal/patient/api/grpc_test.go b/services/tasks-svc/internal/patient/api/grpc_test.go index 435a37ad4..0d52b0d9c 100644 --- a/services/tasks-svc/internal/patient/api/grpc_test.go +++ b/services/tasks-svc/internal/patient/api/grpc_test.go @@ -69,6 +69,8 @@ func setup(t *testing.T) ( } func TestPatientGrpcService_GetPatientValidation(t *testing.T) { + t.Parallel() + ctx, client, _, teardown := setup(t) defer teardown() @@ -86,6 +88,8 @@ func TestPatientGrpcService_GetPatientValidation(t *testing.T) { } func TestPatientGrpcService_CreatePatient(t *testing.T) { + t.Parallel() + // Setup ctx, client, _, teardown := setup(t) defer teardown() @@ -112,6 +116,8 @@ func TestPatientGrpcService_CreatePatient(t *testing.T) { } func TestPatientGrpcService_UpdatePatient(t *testing.T) { + t.Parallel() + ctx, client, _, teardown := setup(t) defer teardown() @@ -145,6 +151,8 @@ func TestPatientGrpcService_UpdatePatient(t *testing.T) { } func TestPatientGrpcService_AssignBed_Validation(t *testing.T) { + t.Parallel() + ctx, client, _, teardown := setup(t) defer teardown() @@ -162,6 +170,8 @@ func TestPatientGrpcService_AssignBed_Validation(t *testing.T) { } func TestPatientGrpcService_UnassignBed_Validation(t *testing.T) { + t.Parallel() + ctx, client, _, teardown := setup(t) defer teardown() @@ -179,6 +189,8 @@ func TestPatientGrpcService_UnassignBed_Validation(t *testing.T) { } func TestPatientGrpcService_DischargePatient_Validation(t *testing.T) { + t.Parallel() + ctx, client, _, teardown := setup(t) defer teardown() @@ -196,6 +208,8 @@ func TestPatientGrpcService_DischargePatient_Validation(t *testing.T) { } func TestPatientGrpcService_ReadmitPatient_Validation(t *testing.T) { + t.Parallel() + ctx, client, _, teardown := setup(t) defer teardown() @@ -213,6 +227,8 @@ func TestPatientGrpcService_ReadmitPatient_Validation(t *testing.T) { } func TestPatientGrpcService_DeletePatient(t *testing.T) { + t.Parallel() + ctx, client, _, teardown := setup(t) defer teardown() diff --git a/services/tasks-svc/internal/task/aggregate/aggregate_test.go b/services/tasks-svc/internal/task/aggregate/aggregate_test.go index f270e1fcd..a6fa0b2f6 100644 --- a/services/tasks-svc/internal/task/aggregate/aggregate_test.go +++ b/services/tasks-svc/internal/task/aggregate/aggregate_test.go @@ -27,6 +27,8 @@ func MustApplyEvent(t *testing.T, aggregate hwes.Aggregate, newEvent func() (hwe } func TestTaskAggregate_UpdateName(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -64,6 +66,8 @@ func TestTaskAggregate_UpdateName(t *testing.T) { } func TestTaskAggregate_UpdateDescription(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -103,6 +107,8 @@ func TestTaskAggregate_UpdateDescription(t *testing.T) { } func TestTaskAggregate_UpdateSubtaskName(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -147,6 +153,8 @@ func TestTaskAggregate_UpdateSubtaskName(t *testing.T) { } func TestTaskAggregate_CompleteSubtask(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -199,6 +207,8 @@ func TestTaskAggregate_CompleteSubtask(t *testing.T) { } func TestTaskAggregate_AssignTask(t *testing.T) { + t.Parallel() + ctx := context.Background() ctx = auth.ContextWithUserID(ctx, uuid.New()) ctx = auth.ContextWithOrganizationID(ctx, uuid.New()) @@ -234,6 +244,8 @@ func TestTaskAggregate_AssignTask(t *testing.T) { } func TestTaskAggregate_DeleteTask(t *testing.T) { + t.Parallel() + ctx := auth.ContextWithUserID(context.Background(), uuid.New()) taskID := uuid.New() diff --git a/services/tasks-svc/internal/task/api/grpc_test.go b/services/tasks-svc/internal/task/api/grpc_test.go index b078f8e22..8aceaf844 100644 --- a/services/tasks-svc/internal/task/api/grpc_test.go +++ b/services/tasks-svc/internal/task/api/grpc_test.go @@ -43,6 +43,8 @@ func setup() (ctx context.Context, client pb.TaskServiceClient, teardown func()) } func TestTaskGrpcService_CreateTask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -120,6 +122,8 @@ func TestTaskGrpcService_CreateTask_Validation(t *testing.T) { } func TestTaskGrpcService_UpdateTask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -143,6 +147,8 @@ func TestTaskGrpcService_UpdateTask_Validation(t *testing.T) { } func TestTaskGrpcService_AssignTask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -169,6 +175,8 @@ func TestTaskGrpcService_AssignTask_Validation(t *testing.T) { } func TestTaskGrpcService_UnassignTask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -195,6 +203,8 @@ func TestTaskGrpcService_UnassignTask_Validation(t *testing.T) { } func TestTaskGrpcService_CreateSubtask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -243,6 +253,8 @@ func TestTaskGrpcService_CreateSubtask_Validation(t *testing.T) { } func TestTaskGrpcService_UpdateSubtask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -275,6 +287,8 @@ func TestTaskGrpcService_UpdateSubtask_Validation(t *testing.T) { } func TestTaskGrpcService_DeleteSubtask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -301,6 +315,8 @@ func TestTaskGrpcService_DeleteSubtask_Validation(t *testing.T) { } func TestTaskGrpcService_RemoveTaskDueDate_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() @@ -324,6 +340,8 @@ func TestTaskGrpcService_RemoveTaskDueDate_Validation(t *testing.T) { } func TestTaskGrpcService_DeleteTask_Validation(t *testing.T) { + t.Parallel() + ctx, client, teardown := setup() defer teardown() diff --git a/services/tasks-svc/stories/BedCRUD_test.go b/services/tasks-svc/stories/BedCRUD_test.go index dbd39237b..adee05dca 100644 --- a/services/tasks-svc/stories/BedCRUD_test.go +++ b/services/tasks-svc/stories/BedCRUD_test.go @@ -16,6 +16,8 @@ import ( // - Create a new bed // - Update it func TestCreateUpdateGetBed(t *testing.T) { + t.Parallel() + ctx := context.Background() bedClient := bedServiceClient() @@ -78,6 +80,8 @@ func TestCreateUpdateGetBed(t *testing.T) { } func TestGetBedByPatient(t *testing.T) { + t.Parallel() + ctx := context.Background() // first, prepare room @@ -118,6 +122,8 @@ func TestGetBedByPatient(t *testing.T) { } func TestGetBeds(t *testing.T) { + t.Parallel() + bedClient := bedServiceClient() ctx := context.Background() diff --git a/services/tasks-svc/stories/PatientCRUD_test.go b/services/tasks-svc/stories/PatientCRUD_test.go index 9bc3bff04..69a6b8d88 100644 --- a/services/tasks-svc/stories/PatientCRUD_test.go +++ b/services/tasks-svc/stories/PatientCRUD_test.go @@ -19,6 +19,8 @@ import ( ) func TestCreateUpdateGetPatient(t *testing.T) { + t.Parallel() + ctx := context.Background() patientClient := patientServiceClient() @@ -172,6 +174,8 @@ func TestCreateUpdateGetPatient(t *testing.T) { } func TestGetPatientByBed(t *testing.T) { + t.Parallel() + ctx := context.Background() patientClient := patientServiceClient() @@ -217,6 +221,8 @@ func TestGetPatientByBed(t *testing.T) { } func TestGetPatientsByWard(t *testing.T) { + t.Parallel() + ctx := context.Background() patientClient := patientServiceClient() @@ -299,6 +305,8 @@ func TestGetPatientsByWard(t *testing.T) { } func TestGetPatientAssignmentByWard(t *testing.T) { + t.Parallel() + ctx := context.Background() patientClient := patientServiceClient() @@ -367,6 +375,8 @@ func TestGetPatientAssignmentByWard(t *testing.T) { } func TestGetPatientList(t *testing.T) { + t.Parallel() + ctx := context.Background() patientClient := patientServiceClient() taskClient := taskServiceClient() @@ -535,6 +545,8 @@ func TestGetPatientList(t *testing.T) { } func TestGetPatientDetails(t *testing.T) { + t.Parallel() + ctx := context.Background() patientClient := patientServiceClient() @@ -641,6 +653,8 @@ func TestGetPatientDetails(t *testing.T) { } func TestGetRecentPatients(t *testing.T) { + t.Parallel() + ctx := context.Background() userID := uuid.New() // new user for this test, to prevent interference with other tests diff --git a/services/tasks-svc/stories/RoomCRUD_test.go b/services/tasks-svc/stories/RoomCRUD_test.go index cd9721cdd..425c1f5c2 100644 --- a/services/tasks-svc/stories/RoomCRUD_test.go +++ b/services/tasks-svc/stories/RoomCRUD_test.go @@ -17,6 +17,8 @@ import ( // - Create a new room // - Update it func TestCreateUpdateGetRoom(t *testing.T) { + t.Parallel() + ctx := context.Background() roomClient := roomServiceClient() @@ -75,6 +77,8 @@ func TestCreateUpdateGetRoom(t *testing.T) { } func TestGetRooms(t *testing.T) { + t.Parallel() + roomClient := roomServiceClient() ctx := context.Background() @@ -134,6 +138,8 @@ func TestGetRooms(t *testing.T) { } func TestGetRoomOverviewsByWard(t *testing.T) { + t.Parallel() + patientClient := patientServiceClient() taskClient := taskServiceClient() ctx := context.Background() diff --git a/services/tasks-svc/stories/TaskCRUD_test.go b/services/tasks-svc/stories/TaskCRUD_test.go index 26698b2c2..9ef73e12c 100644 --- a/services/tasks-svc/stories/TaskCRUD_test.go +++ b/services/tasks-svc/stories/TaskCRUD_test.go @@ -19,6 +19,8 @@ import ( ) func TestCreateUpdateGetTask(t *testing.T) { + t.Parallel() + ctx := context.Background() taskClient := taskServiceClient() @@ -249,6 +251,8 @@ func TestCreateUpdateGetTask(t *testing.T) { } func TestGetTasksByPatient(t *testing.T) { + t.Parallel() + taskClient := taskServiceClient() ctx := context.Background() @@ -334,6 +338,8 @@ func TestGetTasksByPatient(t *testing.T) { } func TestGetAssignedTasks(t *testing.T) { + t.Parallel() + taskClient := taskServiceClient() ctx := context.Background() diff --git a/services/tasks-svc/stories/TaskTemplateCRUD_test.go b/services/tasks-svc/stories/TaskTemplateCRUD_test.go index 083e27138..823b384be 100644 --- a/services/tasks-svc/stories/TaskTemplateCRUD_test.go +++ b/services/tasks-svc/stories/TaskTemplateCRUD_test.go @@ -23,6 +23,8 @@ func getTaskTemplate(t *testing.T, ctx context.Context, id string) *pb.GetTaskTe } func TestCreateUpdateGetTaskTemplate(t *testing.T) { + t.Parallel() + ctx := context.Background() taskTemplateClient := taskTemplateServiceClient() wardServiceClient := wardServiceClient() diff --git a/services/tasks-svc/stories/WardCRUD_test.go b/services/tasks-svc/stories/WardCRUD_test.go index abf387dd4..c7c02b168 100644 --- a/services/tasks-svc/stories/WardCRUD_test.go +++ b/services/tasks-svc/stories/WardCRUD_test.go @@ -21,6 +21,8 @@ import ( // - Create a new ward // - Update it func TestCreateUpdateGetWard(t *testing.T) { + t.Parallel() + ctx := context.Background() wardClient := wardServiceClient() @@ -91,6 +93,8 @@ func prepareWards(t *testing.T, ctx context.Context, client pb.WardServiceClient } func TestGetRecentWards(t *testing.T) { + t.Parallel() + ctx := context.Background() userID := uuid.New() // new user for this test, to prevent interference with other tests @@ -175,6 +179,8 @@ func TestGetRecentWards(t *testing.T) { } func TestGetWards(t *testing.T) { + t.Parallel() + wardClient := wardServiceClient() ctx := context.Background() @@ -214,6 +220,8 @@ func TestGetWards(t *testing.T) { } func TestGetWardOverviews(t *testing.T) { + t.Parallel() + wardClient := wardServiceClient() patientClient := patientServiceClient() taskClient := taskServiceClient() @@ -285,6 +293,8 @@ func TestGetWardOverviews(t *testing.T) { } func TestGetWardDetails(t *testing.T) { + t.Parallel() + wardClient := wardServiceClient() taskTemplateClient := taskTemplateServiceClient() ctx := context.Background() diff --git a/services/updates-svc/stories/updates_test.go b/services/updates-svc/stories/updates_test.go index 1ef7202fe..0d9a85d7c 100644 --- a/services/updates-svc/stories/updates_test.go +++ b/services/updates-svc/stories/updates_test.go @@ -30,6 +30,8 @@ func requireTrue(t *testing.T, b bool) { } func TestOpenAndClosingReceiveUpdatesStream(t *testing.T) { + t.Parallel() + ctx := context.Background() updatesClient := updatesServiceClient() @@ -40,6 +42,8 @@ func TestOpenAndClosingReceiveUpdatesStream(t *testing.T) { } func TestReceivingEvents(t *testing.T) { + t.Parallel() + ctx := context.Background() es := eventstoredb.SetupEventStoreByEnv() @@ -101,6 +105,8 @@ func TestReceivingEvents(t *testing.T) { } func TestAutoClosingWhenTokenExpiresReceiveUpdateStream(t *testing.T) { + t.Parallel() + ctx := context.Background() updatesClient := updatesServiceClient() diff --git a/services/user-svc/stories/OrganizationCRUD_test.go b/services/user-svc/stories/OrganizationCRUD_test.go index 1181bb0ca..70fa010e0 100644 --- a/services/user-svc/stories/OrganizationCRUD_test.go +++ b/services/user-svc/stories/OrganizationCRUD_test.go @@ -14,6 +14,8 @@ import ( ) func TestCreateUpdateGetOrganization(t *testing.T) { + t.Parallel() + ctx := context.Background() client := pb.NewOrganizationServiceClient(hwtesting.GetGrpcConn("")) From 8c24464e98c6e95d56f992a13e863db0847f9a51 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 16:37:37 +0100 Subject: [PATCH 08/22] let's ignore some --- libs/common/grpc.go | 5 ++++- libs/common/hwgrpc/locale_interceptor_test.go | 1 - libs/hwutil/env.go | 5 +++++ .../internal/property-view/api/grpc_test.go | 15 +++++---------- .../property_rules_postgres_test.go | 3 +-- .../stories/GetPropertieBySubjectType_test.go | 4 ++-- services/tasks-svc/internal/task/api/grpc_test.go | 3 +-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libs/common/grpc.go b/libs/common/grpc.go index 6ae93d02d..c76b38cf0 100644 --- a/libs/common/grpc.go +++ b/libs/common/grpc.go @@ -121,7 +121,10 @@ func DefaultStreamInterceptors(metrics *prometheusGrpcProvider.ServerMetrics) [] func DefaultServerOptions() []grpc.ServerOption { // register new metrics collector with prometheus metrics := prometheusGrpcProvider.NewServerMetrics() - telemetry.PrometheusRegistry().MustRegister(metrics) + + if !hwutil.IsRunningInGoTests() { + telemetry.PrometheusRegistry().MustRegister(metrics) + } unaryInterceptorChain := grpc.ChainUnaryInterceptor(DefaultUnaryInterceptors(metrics)...) streamInterceptorChain := grpc.ChainStreamInterceptor(DefaultStreamInterceptors(metrics)...) diff --git a/libs/common/hwgrpc/locale_interceptor_test.go b/libs/common/hwgrpc/locale_interceptor_test.go index 3c111db0c..4d3b21b18 100644 --- a/libs/common/hwgrpc/locale_interceptor_test.go +++ b/libs/common/hwgrpc/locale_interceptor_test.go @@ -24,7 +24,6 @@ func TestLocaleInterceptor(t *testing.T) { } for acceptLanguageHeader, expectedLocalesStrings := range testCases { - t.Parallel() t.Run(fmt.Sprintf("Test localeInterceptor with accept-language header of '%s'", acceptLanguageHeader), func(t *testing.T) { t.Parallel() diff --git a/libs/hwutil/env.go b/libs/hwutil/env.go index 0225c567c..6b5fb94c3 100644 --- a/libs/hwutil/env.go +++ b/libs/hwutil/env.go @@ -1,6 +1,7 @@ package hwutil import ( + "flag" "os" "github.com/rs/zerolog/log" @@ -29,3 +30,7 @@ func HasEnv(key string) bool { _, found := os.LookupEnv(key) return found } + +func IsRunningInGoTests() bool { + return flag.Lookup("test.v") != nil +} diff --git a/services/property-svc/internal/property-view/api/grpc_test.go b/services/property-svc/internal/property-view/api/grpc_test.go index cab555bb5..8c67c25b0 100644 --- a/services/property-svc/internal/property-view/api/grpc_test.go +++ b/services/property-svc/internal/property-view/api/grpc_test.go @@ -71,9 +71,8 @@ func setup() ( return ctx, client, as, dbMock, teardown } +//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_Validation(t *testing.T) { - t.Parallel() - ctx, client, _, dbMock, teardown := setup() defer teardown() @@ -243,9 +242,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_AllEmptyNoEffect(t *test as.ExpectToBeEmpty(t) } +//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_GreenPath_Created(t *testing.T) { - t.Parallel() - ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -313,9 +311,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_Gree }) } +//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_GreenPath_Created(t *testing.T) { - t.Parallel() - ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -383,9 +380,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_G }) } +//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_GreenPath_Updated(t *testing.T) { - t.Parallel() - ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -482,9 +478,8 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_Gree }) } +//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_GreenPath_Updated(t *testing.T) { - t.Parallel() - ctx, client, as, dbMock, teardown := setup() defer teardown() diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go index 3418a73ea..73df69df0 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go @@ -52,9 +52,8 @@ func setup() (ctx context.Context, projection *Projection, dbMock pgxmock.PgxPoo return ctx, projection, dbMock, teardown } +//nolint:paralleltest func TestPropertyViewPropertyRulesProjection_Create_TaskPropertyMatcher_GreenPath(t *testing.T) { - t.Parallel() - ctx, projection, dbMock, teardown := setup() defer teardown() diff --git a/services/property-svc/stories/GetPropertieBySubjectType_test.go b/services/property-svc/stories/GetPropertieBySubjectType_test.go index 111a1b9d0..fd2e4d74c 100644 --- a/services/property-svc/stories/GetPropertieBySubjectType_test.go +++ b/services/property-svc/stories/GetPropertieBySubjectType_test.go @@ -17,9 +17,9 @@ import ( // TestGetPropertiesBySubjectType: // - Create Properties // - Check GetPropertiesBySubjectType +// +//nolint:paralleltest func TestGetProperties(t *testing.T) { - t.Parallel() - propertyClient := propertyServiceClient() ctx := context.Background() diff --git a/services/tasks-svc/internal/task/api/grpc_test.go b/services/tasks-svc/internal/task/api/grpc_test.go index 8aceaf844..e31a056fe 100644 --- a/services/tasks-svc/internal/task/api/grpc_test.go +++ b/services/tasks-svc/internal/task/api/grpc_test.go @@ -252,9 +252,8 @@ func TestTaskGrpcService_CreateSubtask_Validation(t *testing.T) { require.NoError(t, err, codes.InvalidArgument, "rejects fully valid request") } +//nolint:paralleltest func TestTaskGrpcService_UpdateSubtask_Validation(t *testing.T) { - t.Parallel() - ctx, client, teardown := setup() defer teardown() From 238bf9b3ceb09e3c9f631e0b1267142fdeb59c9d Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 17:02:35 +0100 Subject: [PATCH 09/22] no global prometheus metrics --- libs/common/grpc.go | 26 +++++++------ libs/common/hwgrpc/panic_interceptor.go | 10 ++--- libs/common/hwgrpc/panic_interceptor_test.go | 6 +-- libs/common/setup.go | 2 +- libs/hwutil/env.go | 5 --- libs/telemetry/setup.go | 39 ++++++++++++------- .../internal/property-view/api/grpc_test.go | 2 +- .../internal/patient/api/grpc_test.go | 2 +- .../tasks-svc/internal/task/api/grpc_test.go | 2 +- 9 files changed, 51 insertions(+), 43 deletions(-) diff --git a/libs/common/grpc.go b/libs/common/grpc.go index c76b38cf0..a21ef6d70 100644 --- a/libs/common/grpc.go +++ b/libs/common/grpc.go @@ -41,7 +41,7 @@ func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook fun } // dapr/grpc service - service, ok := daprd.NewServiceWithListener(listener, DefaultServerOptions()...).(*daprd.Server) + service, ok := daprd.NewServiceWithListener(listener, DefaultServerOptions(ctx)...).(*daprd.Server) if !ok { log.Fatal().Msg("dapr service listener is not a *daprd.Server") } @@ -87,10 +87,13 @@ func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook fun // DefaultUnaryInterceptors returns the slice of default interceptors for unary gRPC calls // // chain := grpc.ChainUnaryInterceptor(common.DefaultUnaryInterceptors()...) -func DefaultUnaryInterceptors(metrics *prometheusGrpcProvider.ServerMetrics) []grpc.UnaryServerInterceptor { +func DefaultUnaryInterceptors( + ctx context.Context, + metrics *prometheusGrpcProvider.ServerMetrics, +) []grpc.UnaryServerInterceptor { return []grpc.UnaryServerInterceptor{ metrics.UnaryServerInterceptor(), - hwgrpc.UnaryPanicRecoverInterceptor(), + hwgrpc.UnaryPanicRecoverInterceptor(ctx), hwgrpc.UnaryLoggingInterceptor, hwgrpc.UnaryErrorQualityControlInterceptor, hwgrpc.UnaryLocaleInterceptor, @@ -104,10 +107,13 @@ func DefaultUnaryInterceptors(metrics *prometheusGrpcProvider.ServerMetrics) []g // DefaultStreamInterceptors returns the slice of default interceptors for stream gRPC calls // // chain := grpc.ChainStreamInterceptor(common.DefaultStreamInterceptors()...) -func DefaultStreamInterceptors(metrics *prometheusGrpcProvider.ServerMetrics) []grpc.StreamServerInterceptor { +func DefaultStreamInterceptors( + ctx context.Context, + metrics *prometheusGrpcProvider.ServerMetrics, +) []grpc.StreamServerInterceptor { return []grpc.StreamServerInterceptor{ metrics.StreamServerInterceptor(), - hwgrpc.StreamPanicRecoverInterceptor(), + hwgrpc.StreamPanicRecoverInterceptor(ctx), hwgrpc.StreamLoggingInterceptor, hwgrpc.StreamErrorQualityControlInterceptor, hwgrpc.StreamLocaleInterceptor, @@ -118,16 +124,14 @@ func DefaultStreamInterceptors(metrics *prometheusGrpcProvider.ServerMetrics) [] } } -func DefaultServerOptions() []grpc.ServerOption { +func DefaultServerOptions(ctx context.Context) []grpc.ServerOption { // register new metrics collector with prometheus metrics := prometheusGrpcProvider.NewServerMetrics() - if !hwutil.IsRunningInGoTests() { - telemetry.PrometheusRegistry().MustRegister(metrics) - } + telemetry.PrometheusRegistry(ctx).MustRegister(metrics) - unaryInterceptorChain := grpc.ChainUnaryInterceptor(DefaultUnaryInterceptors(metrics)...) - streamInterceptorChain := grpc.ChainStreamInterceptor(DefaultStreamInterceptors(metrics)...) + unaryInterceptorChain := grpc.ChainUnaryInterceptor(DefaultUnaryInterceptors(ctx, metrics)...) + streamInterceptorChain := grpc.ChainStreamInterceptor(DefaultStreamInterceptors(ctx, metrics)...) statsHandler := grpc.StatsHandler(otelgrpc.NewServerHandler()) return []grpc.ServerOption{unaryInterceptorChain, streamInterceptorChain, statsHandler} diff --git a/libs/common/hwgrpc/panic_interceptor.go b/libs/common/hwgrpc/panic_interceptor.go index 172efd7ac..17316f549 100644 --- a/libs/common/hwgrpc/panic_interceptor.go +++ b/libs/common/hwgrpc/panic_interceptor.go @@ -32,22 +32,22 @@ func recoveryHandlerFn() recovery.RecoveryHandlerFuncContext { _, _ = fmt.Fprintln(os.Stderr, string(debug.Stack())) - panicsRecovered.Counter().Inc() + panicsRecovered.Counter(ctx).Inc() return hwerr.NewStatusError(ctx, codes.Internal, "panic recovered", locale.GenericError(ctx)) } } -func UnaryPanicRecoverInterceptor() grpc.UnaryServerInterceptor { - panicsRecovered.Ensure() +func UnaryPanicRecoverInterceptor(ctx context.Context) grpc.UnaryServerInterceptor { + panicsRecovered.Ensure(ctx) return recovery.UnaryServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), ) } -func StreamPanicRecoverInterceptor() grpc.StreamServerInterceptor { - panicsRecovered.Ensure() +func StreamPanicRecoverInterceptor(ctx context.Context) grpc.StreamServerInterceptor { + panicsRecovered.Ensure(ctx) return recovery.StreamServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), diff --git a/libs/common/hwgrpc/panic_interceptor_test.go b/libs/common/hwgrpc/panic_interceptor_test.go index ea0561ec3..cc6618eb6 100644 --- a/libs/common/hwgrpc/panic_interceptor_test.go +++ b/libs/common/hwgrpc/panic_interceptor_test.go @@ -38,13 +38,13 @@ type RecoverySuite struct { func TestPanicRecoverInterceptor(t *testing.T) { t.Parallel() - telemetry.SetupMetrics(context.Background(), nil) + ctx := telemetry.SetupMetrics(context.Background(), nil) s := &RecoverySuite{ InterceptorTestSuite: &testpb.InterceptorTestSuite{ TestService: &recoveryAssertService{TestServiceServer: &testpb.TestPingService{}}, ServerOpts: []grpc.ServerOption{ - grpc.StreamInterceptor(StreamPanicRecoverInterceptor()), - grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor()), + grpc.StreamInterceptor(StreamPanicRecoverInterceptor(ctx)), + grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor(ctx)), }, }, } diff --git a/libs/common/setup.go b/libs/common/setup.go index 8ac5b28b1..84714a6d1 100644 --- a/libs/common/setup.go +++ b/libs/common/setup.go @@ -123,7 +123,7 @@ func Setup(serviceName, version string, opts ...SetupOption) context.Context { } } - telemetry.SetupMetrics(ctx, Shutdown) + ctx = telemetry.SetupMetrics(ctx, Shutdown) if len(version) == 0 && Mode == ProductionMode { log.Warn().Msg("Version is empty in production build! Recompile using ldflag '-X main.Version='") diff --git a/libs/hwutil/env.go b/libs/hwutil/env.go index 6b5fb94c3..0225c567c 100644 --- a/libs/hwutil/env.go +++ b/libs/hwutil/env.go @@ -1,7 +1,6 @@ package hwutil import ( - "flag" "os" "github.com/rs/zerolog/log" @@ -30,7 +29,3 @@ func HasEnv(key string) bool { _, found := os.LookupEnv(key) return found } - -func IsRunningInGoTests() bool { - return flag.Lookup("test.v") != nil -} diff --git a/libs/telemetry/setup.go b/libs/telemetry/setup.go index 8ab791b46..aeece465f 100644 --- a/libs/telemetry/setup.go +++ b/libs/telemetry/setup.go @@ -4,6 +4,7 @@ import ( "context" "errors" "hwutil" + "hwutil/errs" "net/http" "os" "time" @@ -16,8 +17,6 @@ import ( "github.com/rs/zerolog/log" ) -var prometheusRegistry *prometheus.Registry - func SetupLogging(mode, rawLevel, service, version string) { zerolog.TimeFieldFormat = zerolog.TimeFormatUnix @@ -50,11 +49,12 @@ func SetupLogging(mode, rawLevel, service, version string) { } func startMetricsServer(ctx context.Context, addr string, shutdown func(error)) { + reg := PrometheusRegistry(ctx) server := &http.Server{ Addr: addr, Handler: promhttp.InstrumentMetricHandler( - PrometheusRegistry(), - promhttp.HandlerFor(PrometheusRegistry(), promhttp.HandlerOpts{}), + reg, + promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), ), ReadHeaderTimeout: time.Second * 30, // prevent potential slowloris attack } @@ -85,11 +85,23 @@ func startMetricsServer(ctx context.Context, addr string, shutdown func(error)) cancel() // prevent mem leak } +type promRegKey struct{} + +func PrometheusRegistry(ctx context.Context) *prometheus.Registry { + value := ctx.Value(promRegKey{}) + reg, ok := value.(*prometheus.Registry) + if !ok { + panic(errs.NewCastError("*prometheus.Registry", value)) + } + return reg +} + // SetupMetrics will start a new http server for prometheus to scrape from -func SetupMetrics(ctx context.Context, shutdown func(error)) { +func SetupMetrics(ctx context.Context, shutdown func(error)) context.Context { // create new prometheus registry, we do not use the global default one, // as it causes problems with tests - prometheusRegistry = prometheus.NewRegistry() + prometheusRegistry := prometheus.NewRegistry() + ctx = context.WithValue(ctx, promRegKey{}, prometheusRegistry) l := log.Ctx(ctx) @@ -97,16 +109,13 @@ func SetupMetrics(ctx context.Context, shutdown func(error)) { if addr == "" { l.Warn().Msg("METRICS_ADDR not set, will not export metrics") - return + return ctx } l.Info().Str("addr", addr).Msg("starting metrics server") go startMetricsServer(ctx, addr, shutdown) -} - -func PrometheusRegistry() *prometheus.Registry { - return prometheusRegistry + return ctx } // LazyCounter prevents access to PrometheusRegistry, before it is initialized @@ -123,14 +132,14 @@ func NewLazyCounter(opts prometheus.CounterOpts) LazyCounter { } } -func (lc *LazyCounter) Counter() prometheus.Counter { +func (lc *LazyCounter) Counter(ctx context.Context) prometheus.Counter { if lc.counter != nil { return *lc.counter } - lc.counter = hwutil.PtrTo(promauto.With(prometheusRegistry).NewCounter(lc.opts)) + lc.counter = hwutil.PtrTo(promauto.With(PrometheusRegistry(ctx)).NewCounter(lc.opts)) return *lc.counter } -func (lc *LazyCounter) Ensure() { - lc.Counter() +func (lc *LazyCounter) Ensure(ctx context.Context) { + lc.Counter(ctx) } diff --git a/services/property-svc/internal/property-view/api/grpc_test.go b/services/property-svc/internal/property-view/api/grpc_test.go index 8c67c25b0..6e69aec9b 100644 --- a/services/property-svc/internal/property-view/api/grpc_test.go +++ b/services/property-svc/internal/property-view/api/grpc_test.go @@ -38,7 +38,7 @@ func server() (context.Context, pb.PropertyViewsServiceClient, *hwes_test.Aggreg ctx := common.Setup("property-svc", "test", common.WithFakeAuthOnly()) // Start Server - grpcServer := grpc.NewServer(common.DefaultServerOptions()...) + grpcServer := grpc.NewServer(common.DefaultServerOptions(ctx)...) pb.RegisterPropertyViewsServiceServer(grpcServer, grpcService) conn, closer := common_test.StartGRPCServer(ctx, grpcServer) diff --git a/services/tasks-svc/internal/patient/api/grpc_test.go b/services/tasks-svc/internal/patient/api/grpc_test.go index 0d52b0d9c..5adc8924e 100644 --- a/services/tasks-svc/internal/patient/api/grpc_test.go +++ b/services/tasks-svc/internal/patient/api/grpc_test.go @@ -34,7 +34,7 @@ func server() (context.Context, pb.PatientServiceClient, func()) { ctx := common.Setup("tasks-svc", "test", common.WithFakeAuthOnly()) // Start Server - grpcServer := grpc.NewServer(common.DefaultServerOptions()...) + grpcServer := grpc.NewServer(common.DefaultServerOptions(ctx)...) pb.RegisterPatientServiceServer(grpcServer, patientGrpcService) conn, closer := common_test.StartGRPCServer(ctx, grpcServer) diff --git a/services/tasks-svc/internal/task/api/grpc_test.go b/services/tasks-svc/internal/task/api/grpc_test.go index e31a056fe..f59108a48 100644 --- a/services/tasks-svc/internal/task/api/grpc_test.go +++ b/services/tasks-svc/internal/task/api/grpc_test.go @@ -27,7 +27,7 @@ func server() (context.Context, pb.TaskServiceClient, func()) { ctx := common.Setup("tasks-svc", "test", common.WithFakeAuthOnly()) // Start Server - grpcServer := grpc.NewServer(common.DefaultServerOptions()...) + grpcServer := grpc.NewServer(common.DefaultServerOptions(ctx)...) pb.RegisterTaskServiceServer(grpcServer, taskGrpcService) conn, closer := common_test.StartGRPCServer(ctx, grpcServer) From 93372b8d56211420707c9d7503ca1fbacb528abd Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 17:10:45 +0100 Subject: [PATCH 10/22] add some back --- .../property_rules_postgres/property_rules_postgres_test.go | 3 ++- .../property-svc/stories/GetPropertieBySubjectType_test.go | 4 ++-- services/tasks-svc/internal/task/api/grpc_test.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go index 73df69df0..3418a73ea 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go @@ -52,8 +52,9 @@ func setup() (ctx context.Context, projection *Projection, dbMock pgxmock.PgxPoo return ctx, projection, dbMock, teardown } -//nolint:paralleltest func TestPropertyViewPropertyRulesProjection_Create_TaskPropertyMatcher_GreenPath(t *testing.T) { + t.Parallel() + ctx, projection, dbMock, teardown := setup() defer teardown() diff --git a/services/property-svc/stories/GetPropertieBySubjectType_test.go b/services/property-svc/stories/GetPropertieBySubjectType_test.go index fd2e4d74c..111a1b9d0 100644 --- a/services/property-svc/stories/GetPropertieBySubjectType_test.go +++ b/services/property-svc/stories/GetPropertieBySubjectType_test.go @@ -17,9 +17,9 @@ import ( // TestGetPropertiesBySubjectType: // - Create Properties // - Check GetPropertiesBySubjectType -// -//nolint:paralleltest func TestGetProperties(t *testing.T) { + t.Parallel() + propertyClient := propertyServiceClient() ctx := context.Background() diff --git a/services/tasks-svc/internal/task/api/grpc_test.go b/services/tasks-svc/internal/task/api/grpc_test.go index f59108a48..ac16b377d 100644 --- a/services/tasks-svc/internal/task/api/grpc_test.go +++ b/services/tasks-svc/internal/task/api/grpc_test.go @@ -252,8 +252,8 @@ func TestTaskGrpcService_CreateSubtask_Validation(t *testing.T) { require.NoError(t, err, codes.InvalidArgument, "rejects fully valid request") } -//nolint:paralleltest func TestTaskGrpcService_UpdateSubtask_Validation(t *testing.T) { + t.Parallel() ctx, client, teardown := setup() defer teardown() From 127fa37e14fcdc1337f8912f2f81fb6823494cf8 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 17:48:25 +0100 Subject: [PATCH 11/22] allow org override --- libs/hwauthz/commonPerm/userOrg.go | 6 +++++ libs/hwauthz/spicedb/userOrg.go | 25 +++++++++++++++++++ libs/hwtesting/grpc.go | 24 +++++++++++------- .../stories/GetPropertieBySubjectType_test.go | 13 ++++++++-- .../property-svc/stories/GetProperty_test.go | 6 ++--- .../stories/PropertyValueCRUD_test.go | 10 ++++---- services/property-svc/stories/setup_test.go | 8 +++--- .../tasks-svc/stories/PatientCRUD_test.go | 8 ++---- services/tasks-svc/stories/TaskCRUD_test.go | 8 ++---- services/tasks-svc/stories/WardCRUD_test.go | 16 +++--------- services/tasks-svc/stories/setup_test.go | 12 ++++----- services/updates-svc/stories/setup_test.go | 2 +- .../internal/organization/organization.go | 20 +++++++-------- .../internal/organization/perm/perm.go | 5 ---- services/user-svc/internal/user/perm/perm.go | 4 --- .../user-svc/stories/OrganizationCRUD_test.go | 2 +- 16 files changed, 94 insertions(+), 75 deletions(-) create mode 100644 libs/hwauthz/spicedb/userOrg.go diff --git a/libs/hwauthz/commonPerm/userOrg.go b/libs/hwauthz/commonPerm/userOrg.go index 195d4ad86..212d1ebbd 100644 --- a/libs/hwauthz/commonPerm/userOrg.go +++ b/libs/hwauthz/commonPerm/userOrg.go @@ -28,3 +28,9 @@ func OrganizationFromCtx(ctx context.Context) Organization { organizationID := auth.MustGetOrganizationID(ctx) return Organization(organizationID) } + +const ( + OrganizationMember = "member" + OrganizationLeader = "leader" + UserOrganization = "organization" +) diff --git a/libs/hwauthz/spicedb/userOrg.go b/libs/hwauthz/spicedb/userOrg.go new file mode 100644 index 000000000..25556c783 --- /dev/null +++ b/libs/hwauthz/spicedb/userOrg.go @@ -0,0 +1,25 @@ +package spicedb + +import ( + "context" + "github.com/google/uuid" + "hwauthz" + "hwauthz/commonPerm" +) + +func AddUserToOrganization(ctx context.Context, authz hwauthz.AuthZ, userID, organizationID uuid.UUID, leader bool) error { + permUser := commonPerm.User(userID) + permOrg := commonPerm.Organization(organizationID) + + var role hwauthz.Relation = commonPerm.OrganizationMember + if leader { + role = commonPerm.OrganizationLeader + } + + rel := hwauthz.NewRelationship(permUser, role, permOrg) + backRel := hwauthz.NewRelationship(permOrg, commonPerm.UserOrganization, permUser) + if _, err := authz.Create(rel).Create(backRel).Commit(ctx); err != nil { + return err + } + return nil +} diff --git a/libs/hwtesting/grpc.go b/libs/hwtesting/grpc.go index f4cd7a669..7b1ac1d64 100644 --- a/libs/hwtesting/grpc.go +++ b/libs/hwtesting/grpc.go @@ -39,23 +39,29 @@ const ( FakeTokenOrganization = "3b25c6f5-4705-4074-9fc6-a50c28eba406" //nolint:gosec ) -func GetFakeTokenCredentials(subOverride string) InsecureBearerToken { +func GetFakeTokenCredentials(subOverride, orgOverride string) InsecureBearerToken { + sub := FakeTokenUser + if subOverride != "" { + sub = subOverride + } + + org := FakeTokenOrganization + if orgOverride != "" { + org = orgOverride + } + // README's fake token m := map[string]interface{}{ - "sub": FakeTokenUser, + "sub": sub, "email": "testine.test@helpwave.de", "name": "Testine Test", "preferred_username": "testine.test", "organization": map[string]interface{}{ - "id": FakeTokenOrganization, + "id": org, "name": "helpwave test", }, } - if subOverride != "" { - m["sub"] = subOverride - } - bytes, err := json.Marshal(m) if err != nil { panic(fmt.Errorf("GetFakeTokenCredentials failed: %w", err)) @@ -65,10 +71,10 @@ func GetFakeTokenCredentials(subOverride string) InsecureBearerToken { return InsecureBearerToken(dist) } -func GetGrpcConn(subOverride string) *grpc.ClientConn { +func GetGrpcConn(subOverride, orgOverride string) *grpc.ClientConn { conn, err := grpc.NewClient( common.ResolveAddrFromEnv(), - grpc.WithPerRPCCredentials(GetFakeTokenCredentials(subOverride)), + grpc.WithPerRPCCredentials(GetFakeTokenCredentials(subOverride, orgOverride)), grpc.WithTransportCredentials(insecure.NewCredentials()), ) if err != nil { diff --git a/services/property-svc/stories/GetPropertieBySubjectType_test.go b/services/property-svc/stories/GetPropertieBySubjectType_test.go index 111a1b9d0..acd7e606a 100644 --- a/services/property-svc/stories/GetPropertieBySubjectType_test.go +++ b/services/property-svc/stories/GetPropertieBySubjectType_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" pb "gen/services/property_svc/v1" + "hwauthz/spicedb" "hwtesting" "hwutil" "regexp" @@ -19,10 +20,18 @@ import ( // - Check GetPropertiesBySubjectType func TestGetProperties(t *testing.T) { t.Parallel() + ctx := context.Background() - propertyClient := propertyServiceClient() + // new user and org for this test, to prevent interference with other tests + userID := uuid.New() + orgID := uuid.New() - ctx := context.Background() + // give user appropriate permissions + authz := spicedb.NewSpiceDBAuthZ() + err := spicedb.AddUserToOrganization(ctx, authz, userID, orgID, false) + require.NoError(t, err) + + propertyClient := propertyServiceClient(userID.String(), orgID.String()) // // Create new Properties diff --git a/services/property-svc/stories/GetProperty_test.go b/services/property-svc/stories/GetProperty_test.go index bbb90485c..36b873d03 100644 --- a/services/property-svc/stories/GetProperty_test.go +++ b/services/property-svc/stories/GetProperty_test.go @@ -31,7 +31,7 @@ func TestTaskGetPropertyAlwaysIncluded(t *testing.T) { patientID := uuid.New() taskID := uuid.New() - // give new user appropriate permissions + // give appropriate permissions authz := spicedb.NewSpiceDBAuthZ() patient := commonPerm.GenericObject{Id: patientID.String(), Typ: "patient"} task := commonPerm.GenericObject{Id: taskID.String(), Typ: "task"} @@ -44,7 +44,7 @@ func TestTaskGetPropertyAlwaysIncluded(t *testing.T) { Commit(ctx) require.NoError(t, err) - propertyClient := propertyServiceClient() + propertyClient := propertyServiceClient("", "") propertyViewClient := propertyViewServiceClient() // @@ -193,7 +193,7 @@ func TestTaskGetPropertyAlwaysIncluded(t *testing.T) { func TestTaskGetPropertyConsistency(t *testing.T) { t.Parallel() - propertyClient := propertyServiceClient() + propertyClient := propertyServiceClient("", "") ctx := context.Background() diff --git a/services/property-svc/stories/PropertyValueCRUD_test.go b/services/property-svc/stories/PropertyValueCRUD_test.go index 7da9b8dc3..3e6aa59a3 100644 --- a/services/property-svc/stories/PropertyValueCRUD_test.go +++ b/services/property-svc/stories/PropertyValueCRUD_test.go @@ -19,7 +19,7 @@ import ( func TestCreateAttachUpdateTextProperty(t *testing.T) { t.Parallel() - propertyClient := propertyServiceClient() + propertyClient := propertyServiceClient("", "") ctx := context.Background() // @@ -169,7 +169,7 @@ func TestCreateAttachUpdateTextProperty(t *testing.T) { func TestCreateAttachUpdateSelectProperty(t *testing.T) { t.Parallel() - propertyClient := propertyServiceClient() + propertyClient := propertyServiceClient("", "") ctx := context.Background() // @@ -339,7 +339,7 @@ func TestCreateAttachUpdateSelectProperty(t *testing.T) { func TestCreateAttachUpdateMultiSelectProperty(t *testing.T) { t.Parallel() - propertyClient := propertyServiceClient() + propertyClient := propertyServiceClient("", "") ctx := context.Background() // @@ -529,7 +529,7 @@ func TestCreateAttachUpdateMultiSelectProperty(t *testing.T) { func TestCreateAttachAddOptionAttachSelectProperty(t *testing.T) { t.Parallel() - propertyClient := propertyServiceClient() + propertyClient := propertyServiceClient("", "") ctx := context.Background() // @@ -689,7 +689,7 @@ func TestCreateAttachAddOptionAttachSelectProperty(t *testing.T) { func TestCreateAttachAddOptionAttachMultiSelectProperty(t *testing.T) { t.Parallel() - propertyClient := propertyServiceClient() + propertyClient := propertyServiceClient("", "") ctx := context.Background() // diff --git a/services/property-svc/stories/setup_test.go b/services/property-svc/stories/setup_test.go index 44da2efee..d1a703918 100644 --- a/services/property-svc/stories/setup_test.go +++ b/services/property-svc/stories/setup_test.go @@ -65,16 +65,16 @@ func TestMain(m *testing.M) { os.Exit(exitCode) } -func propertyServiceClient() pb.PropertyServiceClient { - return pb.NewPropertyServiceClient(hwtesting.GetGrpcConn("")) +func propertyServiceClient(subOverride, orgOverride string) pb.PropertyServiceClient { + return pb.NewPropertyServiceClient(hwtesting.GetGrpcConn(subOverride, orgOverride)) } func propertyViewServiceClient() pb.PropertyViewsServiceClient { - return pb.NewPropertyViewsServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewPropertyViewsServiceClient(hwtesting.GetGrpcConn("", "")) } func propertyValueServiceClient() pb.PropertyValueServiceClient { - return pb.NewPropertyValueServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewPropertyValueServiceClient(hwtesting.GetGrpcConn("", "")) } func NamesOf(arr []*pb.GetAttachedPropertyValuesResponse_Value_SelectValueOption) []string { diff --git a/services/tasks-svc/stories/PatientCRUD_test.go b/services/tasks-svc/stories/PatientCRUD_test.go index 69a6b8d88..fa4fbec00 100644 --- a/services/tasks-svc/stories/PatientCRUD_test.go +++ b/services/tasks-svc/stories/PatientCRUD_test.go @@ -3,8 +3,6 @@ package stories import ( "context" pb "gen/services/tasks_svc/v1" - "hwauthz" - "hwauthz/commonPerm" "hwauthz/spicedb" "hwtesting" "hwutil" @@ -661,12 +659,10 @@ func TestGetRecentPatients(t *testing.T) { // give new user appropriate permissions authz := spicedb.NewSpiceDBAuthZ() - user := commonPerm.User(userID) - org := commonPerm.Organization(uuid.MustParse(hwtesting.FakeTokenOrganization)) - _, err := authz.Create(hwauthz.NewRelationship(user, "member", org)).Commit(ctx) + err := spicedb.AddUserToOrganization(ctx, authz, userID, uuid.MustParse(hwtesting.FakeTokenOrganization), false) require.NoError(t, err) - patientClient := pb.NewPatientServiceClient(hwtesting.GetGrpcConn(userID.String())) + patientClient := pb.NewPatientServiceClient(hwtesting.GetGrpcConn(userID.String(), "")) wardID, _ := prepareWard(t, ctx, "") roomId, roomConsistency := prepareRoom(t, ctx, wardID, "") diff --git a/services/tasks-svc/stories/TaskCRUD_test.go b/services/tasks-svc/stories/TaskCRUD_test.go index 9ef73e12c..f976c208b 100644 --- a/services/tasks-svc/stories/TaskCRUD_test.go +++ b/services/tasks-svc/stories/TaskCRUD_test.go @@ -3,8 +3,6 @@ package stories import ( "context" pb "gen/services/tasks_svc/v1" - "hwauthz" - "hwauthz/commonPerm" "hwauthz/spicedb" "hwtesting" "hwutil" @@ -355,9 +353,7 @@ func TestGetAssignedTasks(t *testing.T) { // give new user appropriate permissions authz := spicedb.NewSpiceDBAuthZ() - user := commonPerm.User(userID) - org := commonPerm.Organization(uuid.MustParse(hwtesting.FakeTokenOrganization)) - _, err := authz.Create(hwauthz.NewRelationship(user, "member", org)).Commit(ctx) + err := spicedb.AddUserToOrganization(ctx, authz, userID, uuid.MustParse(hwtesting.FakeTokenOrganization), false) require.NoError(t, err) taskIds := make([]string, 0, len(suffixMap)) @@ -393,7 +389,7 @@ func TestGetAssignedTasks(t *testing.T) { hwtesting.WaitForProjectionsToSettle() // client for userid - customTaskClient := pb.NewTaskServiceClient(hwtesting.GetGrpcConn(userID.String())) + customTaskClient := pb.NewTaskServiceClient(hwtesting.GetGrpcConn(userID.String(), "")) res, err := customTaskClient.GetAssignedTasks(ctx, &pb.GetAssignedTasksRequest{}) require.NoError(t, err) diff --git a/services/tasks-svc/stories/WardCRUD_test.go b/services/tasks-svc/stories/WardCRUD_test.go index c7c02b168..7ea1be7a4 100644 --- a/services/tasks-svc/stories/WardCRUD_test.go +++ b/services/tasks-svc/stories/WardCRUD_test.go @@ -3,8 +3,6 @@ package stories import ( "context" pb "gen/services/tasks_svc/v1" - "hwauthz" - "hwauthz/commonPerm" "hwauthz/spicedb" "hwtesting" "hwutil" @@ -100,18 +98,12 @@ func TestGetRecentWards(t *testing.T) { // give user appropriate permissions authz := spicedb.NewSpiceDBAuthZ() - _, err := authz.Create( - hwauthz.NewRelationship( - commonPerm.User(userID), - "member", - commonPerm.Organization(uuid.MustParse(hwtesting.FakeTokenOrganization)), - ), - ).Commit(ctx) + err := spicedb.AddUserToOrganization(ctx, authz, userID, uuid.MustParse(hwtesting.FakeTokenOrganization), false) require.NoError(t, err) - wardClient := pb.NewWardServiceClient(hwtesting.GetGrpcConn(userID.String())) - taskClient := pb.NewTaskServiceClient(hwtesting.GetGrpcConn(userID.String())) - patientClient := pb.NewPatientServiceClient(hwtesting.GetGrpcConn(userID.String())) + wardClient := pb.NewWardServiceClient(hwtesting.GetGrpcConn(userID.String(), "")) + taskClient := pb.NewTaskServiceClient(hwtesting.GetGrpcConn(userID.String(), "")) + patientClient := pb.NewPatientServiceClient(hwtesting.GetGrpcConn(userID.String(), "")) wardIds := prepareWards(t, ctx, wardClient, 11) consistencies := make(map[string]string) diff --git a/services/tasks-svc/stories/setup_test.go b/services/tasks-svc/stories/setup_test.go index b9c2a570e..86a9159da 100644 --- a/services/tasks-svc/stories/setup_test.go +++ b/services/tasks-svc/stories/setup_test.go @@ -71,27 +71,27 @@ func TestMain(m *testing.M) { } func bedServiceClient() pb.BedServiceClient { - return pb.NewBedServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewBedServiceClient(hwtesting.GetGrpcConn("", "")) } func roomServiceClient() pb.RoomServiceClient { - return pb.NewRoomServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewRoomServiceClient(hwtesting.GetGrpcConn("", "")) } func patientServiceClient() pb.PatientServiceClient { - return pb.NewPatientServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewPatientServiceClient(hwtesting.GetGrpcConn("", "")) } func taskServiceClient() pb.TaskServiceClient { - return pb.NewTaskServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewTaskServiceClient(hwtesting.GetGrpcConn("", "")) } func taskTemplateServiceClient() pb.TaskTemplateServiceClient { - return pb.NewTaskTemplateServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewTaskTemplateServiceClient(hwtesting.GetGrpcConn("", "")) } func wardServiceClient() pb.WardServiceClient { - return pb.NewWardServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewWardServiceClient(hwtesting.GetGrpcConn("", "")) } func prepareWard(t *testing.T, ctx context.Context, suffix string) (wardID, wardConsistency string) { diff --git a/services/updates-svc/stories/setup_test.go b/services/updates-svc/stories/setup_test.go index 66c14499e..5bfad4c9a 100644 --- a/services/updates-svc/stories/setup_test.go +++ b/services/updates-svc/stories/setup_test.go @@ -54,5 +54,5 @@ func TestMain(m *testing.M) { } func updatesServiceClient() pb.UpdatesServiceClient { - return pb.NewUpdatesServiceClient(hwtesting.GetGrpcConn("")) + return pb.NewUpdatesServiceClient(hwtesting.GetGrpcConn("", "")) } diff --git a/services/user-svc/internal/organization/organization.go b/services/user-svc/internal/organization/organization.go index 1e1e9cb71..d17938d2b 100644 --- a/services/user-svc/internal/organization/organization.go +++ b/services/user-svc/internal/organization/organization.go @@ -9,14 +9,13 @@ import ( pb "gen/services/user_svc/v1" "hwauthz" "hwauthz/commonPerm" + "hwauthz/spicedb" "hwdb" "hwlocale" "hwutil" - "user-svc/internal/organization/perm" - userPerm "user-svc/internal/user/perm" - "user-svc/internal/hwkc" + "user-svc/internal/organization/perm" "user-svc/locale" "user-svc/repos/organization_repo" "user-svc/repos/user_repo" @@ -380,9 +379,9 @@ func (s ServiceServer) RemoveMember( deletedUser := commonPerm.User(userID) if _, err := s.authz. - Delete(hwauthz.NewRelationship(deletedUser, perm.OrganizationMember, permOrg)). - Delete(hwauthz.NewRelationship(deletedUser, perm.OrganizationLeader, permOrg)). - Delete(hwauthz.NewRelationship(permOrg, userPerm.UserOrganization, deletedUser)). + Delete(hwauthz.NewRelationship(deletedUser, commonPerm.OrganizationMember, permOrg)). + Delete(hwauthz.NewRelationship(deletedUser, commonPerm.OrganizationLeader, permOrg)). + Delete(hwauthz.NewRelationship(permOrg, commonPerm.UserOrganization, deletedUser)). Commit(ctx); err != nil { return nil, err } @@ -721,6 +720,7 @@ func (s ServiceServer) AcceptInvitation( s.kc, userID, currentInvitation.OrganizationID, + false, ); err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -901,6 +901,7 @@ func CreateOrganizationAndAddUser( kc, userID, organizationID, + true, ); err != nil { return nil, err } @@ -920,6 +921,7 @@ func AddUserToOrganization( kc hwkc.IClient, userID uuid.UUID, organizationID uuid.UUID, + leader bool, ) error { log := zlog.Ctx(ctx) organizationRepo := organization_repo.New(tx) @@ -939,11 +941,7 @@ func AddUserToOrganization( } // add user to org in spice - permUser := commonPerm.User(userID) - permOrg := commonPerm.Organization(organizationID) - rel := hwauthz.NewRelationship(permUser, perm.OrganizationLeader, permOrg) - backRel := hwauthz.NewRelationship(permOrg, userPerm.UserOrganization, permUser) - if _, err := authz.Create(rel).Create(backRel).Commit(ctx); err != nil { + if err := spicedb.AddUserToOrganization(ctx, authz, userID, organizationID, leader); err != nil { return err } diff --git a/services/user-svc/internal/organization/perm/perm.go b/services/user-svc/internal/organization/perm/perm.go index 1e0f11402..f19989b22 100644 --- a/services/user-svc/internal/organization/perm/perm.go +++ b/services/user-svc/internal/organization/perm/perm.go @@ -30,11 +30,6 @@ const ( InviteOrganization = "organization" ) -const ( - OrganizationMember = "member" - OrganizationLeader = "leader" -) - // Permissions const ( diff --git a/services/user-svc/internal/user/perm/perm.go b/services/user-svc/internal/user/perm/perm.go index 85efb4f9e..d27c867bc 100644 --- a/services/user-svc/internal/user/perm/perm.go +++ b/services/user-svc/internal/user/perm/perm.go @@ -1,9 +1,5 @@ package perm -// Direct Relations - -const UserOrganization = "organization" - // Permissions const ( diff --git a/services/user-svc/stories/OrganizationCRUD_test.go b/services/user-svc/stories/OrganizationCRUD_test.go index 70fa010e0..c5cad6fb6 100644 --- a/services/user-svc/stories/OrganizationCRUD_test.go +++ b/services/user-svc/stories/OrganizationCRUD_test.go @@ -18,7 +18,7 @@ func TestCreateUpdateGetOrganization(t *testing.T) { ctx := context.Background() - client := pb.NewOrganizationServiceClient(hwtesting.GetGrpcConn("")) + client := pb.NewOrganizationServiceClient(hwtesting.GetGrpcConn("", "")) // // create new org From 1882b51cc0657757a5ecb38815a534e1477bf3df Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 17:50:59 +0100 Subject: [PATCH 12/22] fix lint issue --- libs/hwauthz/spicedb/userOrg.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/hwauthz/spicedb/userOrg.go b/libs/hwauthz/spicedb/userOrg.go index 25556c783..56af4d3f9 100644 --- a/libs/hwauthz/spicedb/userOrg.go +++ b/libs/hwauthz/spicedb/userOrg.go @@ -2,12 +2,18 @@ package spicedb import ( "context" + "github.com/google/uuid" "hwauthz" "hwauthz/commonPerm" ) -func AddUserToOrganization(ctx context.Context, authz hwauthz.AuthZ, userID, organizationID uuid.UUID, leader bool) error { +func AddUserToOrganization( + ctx context.Context, + authz hwauthz.AuthZ, + userID, organizationID uuid.UUID, + leader bool, +) error { permUser := commonPerm.User(userID) permOrg := commonPerm.Organization(organizationID) From 1e5a759bd9a629bf2ca8cf0a11d08aecc75df934 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 19 Dec 2024 18:08:42 +0100 Subject: [PATCH 13/22] end global db gore --- libs/hwdb/setup.go | 33 +++++++++---------- services/property-svc/cmd/service/main.go | 8 ++--- services/property-svc/cmd/service/replay.go | 2 +- .../commands/v1/attach_property_value.go | 2 +- .../v1/get_property_values_by_subject_id.go | 2 +- .../internal/property-view/api/grpc_test.go | 2 +- .../models/patient_property_matcher.go | 6 ++-- .../models/task_property_matchers.go | 6 ++-- .../property_rules_postgres.go | 8 ++--- .../property_rules_postgres_test.go | 4 +-- .../v1/get_properties_by_subject_type.go | 2 +- .../property/queries/v1/get_property_by_id.go | 2 +- services/tasks-svc/cmd/service/main.go | 7 ++-- services/tasks-svc/internal/bed/bed.go | 14 ++++---- .../tasks-svc/internal/patient/api/grpc.go | 4 +-- .../patient_postgres_projection.go | 4 +-- .../v1/get_all_patients_with_details.go | 2 +- .../v1/get_patient_assignment_by_ward.go | 2 +- .../patient/queries/v1/get_patient_by_bed.go | 2 +- .../v1/get_patient_with_details_by_id.go | 2 +- .../queries/v1/get_patients_by_ward.go | 2 +- services/tasks-svc/internal/room/room.go | 12 +++---- .../internal/task-template/task_template.go | 16 ++++----- .../task_postgres_projection.go | 4 +-- .../queries/v1/get_task_with_patient_by_id.go | 2 +- .../task/queries/v1/get_tasks_by_patient.go | 2 +- .../v1/get_tasks_with_patients_by_asignee.go | 2 +- services/tasks-svc/internal/ward/ward.go | 16 ++++----- services/user-svc/cmd/service/main.go | 2 +- .../internal/organization/organization.go | 30 ++++++++--------- services/user-svc/internal/user/user.go | 4 +-- 31 files changed, 102 insertions(+), 104 deletions(-) diff --git a/libs/hwdb/setup.go b/libs/hwdb/setup.go index 5090fcee2..4322d77c1 100644 --- a/libs/hwdb/setup.go +++ b/libs/hwdb/setup.go @@ -24,9 +24,6 @@ type DBTX interface { Begin(ctx context.Context) (pgx.Tx, error) } -// connectionPool is set in OpenDatabase() and allows for concurrent access to the database -var connectionPool DBTX - // SetupDatabaseFromEnv prefers the env POSTGRES_DSN and will be configured the database connection accordingly. // When this env does not exist, a fallback to the following envs with proper default values will take place. // [NAME_OF_THE_ENV] (DEFAULT) @@ -37,7 +34,7 @@ var connectionPool DBTX // POSTGRES_PORT (5432) // // SetupDatabaseFromEnv returns a close function, which has to be called in order to shut down the database cleanly -func SetupDatabaseFromEnv(context context.Context) func() { +func SetupDatabaseFromEnv(ctx context.Context) (context.Context, func()) { log.Info().Msg("connecting to postgres ...") dsn := hwutil.GetEnvOr("POSTGRES_DSN", "") @@ -46,17 +43,17 @@ func SetupDatabaseFromEnv(context context.Context) func() { log.Debug().Msg("POSTGRES_DSN env not found, built dsn from POSTGRES_HOST, ... envs") } - dbpool, err := openDatabasePool(context, dsn) + dbpool, err := openDatabasePool(ctx, dsn) if err != nil { log.Fatal().Err(err).Msg("could not connect to database") } - // set connectionPool - connectionPool = dbpool + // make db available via GetDB + ctx = WithDB(ctx, dbpool) log.Info().Msg("connected to postgres") - return func() { + return ctx, func() { log.Info().Msg("closing db pool") dbpool.Close() } @@ -80,7 +77,6 @@ func buildDsnFromEnvs() string { } // openDatabasePool simply opens a new database pool to the dsn provided -// it does not set up connectionPool! func openDatabasePool(ctx context.Context, dsn string) (*pgxpool.Pool, error) { pgxConfig, err := pgxpool.ParseConfig(dsn) if err != nil { @@ -106,16 +102,19 @@ func openDatabasePool(ctx context.Context, dsn string) (*pgxpool.Pool, error) { return dbpool, nil } -func GetDB() DBTX { - if connectionPool == nil { +type dbKey struct{} + +func WithDB(ctx context.Context, pool DBTX) context.Context { + return context.WithValue(ctx, dbKey{}, pool) +} + +func GetDB(ctx context.Context) DBTX { + value := ctx.Value(dbKey{}) + db, ok := value.(DBTX) + if db == nil || !ok { log.Error(). Msg("GetDB called without set-up database, you will run into nil-pointers. " + "Make sure to call SetupDatabaseFromEnv()!") } - return connectionPool -} - -// TestingSetDB should only be called by testing code -func TestingSetDB(pool DBTX) { - connectionPool = pool + return db } diff --git a/services/property-svc/cmd/service/main.go b/services/property-svc/cmd/service/main.go index 62451d966..fa74ba2f9 100644 --- a/services/property-svc/cmd/service/main.go +++ b/services/property-svc/cmd/service/main.go @@ -35,7 +35,7 @@ func Main(version string, ready func()) { flag.Parse() log.Debug().Bool("replayMode", *replayMode).Msg("flags") - closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) + ctx, closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) defer closeDBPool() authz := hwspicedb.NewSpiceDBAuthZ() @@ -56,9 +56,9 @@ func Main(version string, ready func()) { common.Shutdown, propertySpiceDBProjection.NewProjection(eventStore, ServiceName, authz), propertySetSpiceDBProjection.NewProjection(eventStore, ServiceName, authz), - propertyPostgresProjection.NewProjection(eventStore, ServiceName, hwdb.GetDB()), - property_value_postgres_projection.NewProjection(eventStore, ServiceName, hwdb.GetDB()), - property_rules_postgres.NewProjection(eventStore, ServiceName), + propertyPostgresProjection.NewProjection(eventStore, ServiceName, hwdb.GetDB(ctx)), + property_value_postgres_projection.NewProjection(eventStore, ServiceName, hwdb.GetDB(ctx)), + property_rules_postgres.NewProjection(ctx, eventStore, ServiceName), ) propertyHandlers := ph.NewPropertyHandlers(aggregateStore, authz) diff --git a/services/property-svc/cmd/service/replay.go b/services/property-svc/cmd/service/replay.go index e89838cfe..daf86a94f 100644 --- a/services/property-svc/cmd/service/replay.go +++ b/services/property-svc/cmd/service/replay.go @@ -24,7 +24,7 @@ func replay(ctx context.Context, eventStore *esdb.Client) error { log.Info().Msg("starting in replay mode") - db := hwdb.GetDB() + db := hwdb.GetDB(ctx) tx, rollback, err := hwdb.BeginTx(db, ctx) if err != nil { return fmt.Errorf("cannot begin transaction: %w", err) diff --git a/services/property-svc/internal/property-value/commands/v1/attach_property_value.go b/services/property-svc/internal/property-value/commands/v1/attach_property_value.go index 56ecb0ac0..f8803b87d 100644 --- a/services/property-svc/internal/property-value/commands/v1/attach_property_value.go +++ b/services/property-svc/internal/property-value/commands/v1/attach_property_value.go @@ -40,7 +40,7 @@ func NewAttachPropertyValueCommandHandler( return 0, err } - propertyValueRepo := property_value_repo.New(hwdb.GetDB()) + propertyValueRepo := property_value_repo.New(hwdb.GetDB(ctx)) var a *aggregate.PropertyValueAggregate query := hwdb.Optional(propertyValueRepo.GetPropertyValueBySubjectIDAndPropertyID) diff --git a/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go b/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go index 5ba702ee6..7b23e71f9 100644 --- a/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go +++ b/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go @@ -33,7 +33,7 @@ func NewGetRelevantPropertyValuesQueryHandler( ) GetRelevantPropertyValuesQueryHandler { return func(ctx context.Context, matcher viewModels.PropertyMatchers) ([]models.PropertyAndValue, error) { viewHandlers := vh.NewPropertyViewHandlers(as, authz) - propertyValueRepo := property_value_repo.New(hwdb.GetDB()) + propertyValueRepo := property_value_repo.New(hwdb.GetDB(ctx)) subjectID, err := matcher.GetSubjectID() if err != nil { diff --git a/services/property-svc/internal/property-view/api/grpc_test.go b/services/property-svc/internal/property-view/api/grpc_test.go index 6e69aec9b..d631e4a17 100644 --- a/services/property-svc/internal/property-view/api/grpc_test.go +++ b/services/property-svc/internal/property-view/api/grpc_test.go @@ -61,7 +61,7 @@ func setup() ( if err != nil { panic(err) } - hwdb.TestingSetDB(dbMock) + ctx = hwdb.WithDB(ctx, dbMock) teardown = func() { closer() diff --git a/services/property-svc/internal/property-view/models/patient_property_matcher.go b/services/property-svc/internal/property-view/models/patient_property_matcher.go index cca2acf13..18bd9fd45 100644 --- a/services/property-svc/internal/property-view/models/patient_property_matcher.go +++ b/services/property-svc/internal/property-view/models/patient_property_matcher.go @@ -23,7 +23,7 @@ type PatientPropertyMatchers struct { } func (m PatientPropertyMatchers) FindExactRuleID(ctx context.Context) (*uuid.UUID, error) { - patientViews := patient_views_repo.New(hwdb.GetDB()) + patientViews := patient_views_repo.New(hwdb.GetDB(ctx)) return hwdb.Optional(patientViews.GetPatientRuleIdUsingExactMatchers)(ctx, patient_views_repo.GetPatientRuleIdUsingExactMatchersParams{ WardID: m.WardID, @@ -52,7 +52,7 @@ func (m PatientPropertyMatchers) GetType() string { } func (m PatientPropertyMatchers) QueryProperties(ctx context.Context) ([]PropertiesQueryRow, error) { - patientViews := patient_views_repo.New(hwdb.GetDB()) + patientViews := patient_views_repo.New(hwdb.GetDB(ctx)) rows, err := patientViews.GetPatientPropertiesUsingMatchers( ctx, @@ -96,7 +96,7 @@ func (m PatientPropertyMatchers) ToMap() map[string]interface{} { } func (m PatientPropertyMatchers) IsPropertyAlwaysIncluded(ctx context.Context, propertyID uuid.UUID) (bool, error) { - repo := patient_views_repo.New(hwdb.GetDB()) + repo := patient_views_repo.New(hwdb.GetDB(ctx)) query := hwdb.Optional(repo.IsPatientPropertyAlwaysIncluded) alwaysInclude, err := query(ctx, patient_views_repo.IsPatientPropertyAlwaysIncludedParams{ PropertyID: propertyID, diff --git a/services/property-svc/internal/property-view/models/task_property_matchers.go b/services/property-svc/internal/property-view/models/task_property_matchers.go index a034dc28c..5926e0de4 100644 --- a/services/property-svc/internal/property-view/models/task_property_matchers.go +++ b/services/property-svc/internal/property-view/models/task_property_matchers.go @@ -24,7 +24,7 @@ type TaskPropertyMatchers struct { } func (m TaskPropertyMatchers) FindExactRuleID(ctx context.Context) (*uuid.UUID, error) { - taskViews := task_views_repo.New(hwdb.GetDB()) + taskViews := task_views_repo.New(hwdb.GetDB(ctx)) return hwdb.Optional(taskViews.GetTaskRuleIdUsingExactMatchers)(ctx, task_views_repo.GetTaskRuleIdUsingExactMatchersParams{ WardID: m.WardID, @@ -53,7 +53,7 @@ func (m TaskPropertyMatchers) GetType() string { } func (m TaskPropertyMatchers) QueryProperties(ctx context.Context) ([]PropertiesQueryRow, error) { - taskViews := task_views_repo.New(hwdb.GetDB()) + taskViews := task_views_repo.New(hwdb.GetDB(ctx)) rows, err := taskViews.GetTaskPropertiesUsingMatchers(ctx, task_views_repo.GetTaskPropertiesUsingMatchersParams{ WardID: m.WardID, @@ -95,7 +95,7 @@ func (m TaskPropertyMatchers) ToMap() map[string]interface{} { } func (m TaskPropertyMatchers) IsPropertyAlwaysIncluded(ctx context.Context, propertyID uuid.UUID) (bool, error) { - repo := task_views_repo.New(hwdb.GetDB()) + repo := task_views_repo.New(hwdb.GetDB(ctx)) query := hwdb.Optional(repo.IsTaskPropertyAlwaysIncluded) alwaysInclude, err := query(ctx, task_views_repo.IsTaskPropertyAlwaysIncludedParams{ PropertyID: propertyID, diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go index 6d1b799d2..331ef7929 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go @@ -31,7 +31,7 @@ type Projection struct { viewsRepo *views_repo.Queries } -func NewProjection(es custom.EventStoreClient, serviceName string) *Projection { +func NewProjection(ctx context.Context, es custom.EventStoreClient, serviceName string) *Projection { subscriptionGroupName := serviceName + "-property-rules-postgres-projection" p := &Projection{ CustomProjection: custom.NewCustomProjection( @@ -39,9 +39,9 @@ func NewProjection(es custom.EventStoreClient, serviceName string) *Projection { subscriptionGroupName, &[]string{aggregate.PropertyViewRuleAggregateType + "-"}, ), - db: hwdb.GetDB(), - taskViewsRepo: task_views_repo.New(hwdb.GetDB()), - viewsRepo: views_repo.New(hwdb.GetDB()), + db: hwdb.GetDB(ctx), + taskViewsRepo: task_views_repo.New(hwdb.GetDB(ctx)), + viewsRepo: views_repo.New(hwdb.GetDB(ctx)), } p.initEventListeners() return p diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go index 3418a73ea..f12545a85 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go @@ -42,10 +42,10 @@ func setup() (ctx context.Context, projection *Projection, dbMock pgxmock.PgxPoo if err != nil { panic(err) } - hwdb.TestingSetDB(dbMock) + ctx = hwdb.WithDB(ctx, dbMock) teardown = dbMock.Close - projection = NewProjection(esClientStub{}, "testing") + projection = NewProjection(ctx, esClientStub{}, "testing") ctx = context.Background() diff --git a/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go b/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go index 8c6228a06..c9fd47cee 100644 --- a/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go +++ b/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go @@ -25,7 +25,7 @@ func NewGetPropertiesQueryHandler(authz hwauthz.AuthZ) GetPropertiesQueryHandler return func(ctx context.Context, subjectType *pb.SubjectType) ([]*models.PropertyWithConsistency, error) { user := commonPerm.UserFromCtx(ctx) - propertyRepo := property_repo.New(hwdb.GetDB()) + propertyRepo := property_repo.New(hwdb.GetDB(ctx)) var subjectTypeID *int32 if subjectType != nil { diff --git a/services/property-svc/internal/property/queries/v1/get_property_by_id.go b/services/property-svc/internal/property/queries/v1/get_property_by_id.go index ef11ba254..93effbe10 100644 --- a/services/property-svc/internal/property/queries/v1/get_property_by_id.go +++ b/services/property-svc/internal/property/queries/v1/get_property_by_id.go @@ -31,7 +31,7 @@ func NewGetPropertyByIDQueryHandler(authz hwauthz.AuthZ) GetPropertyByIDQueryHan return nil, 0, err } - propertyRepo := property_repo.New(hwdb.GetDB()) + propertyRepo := property_repo.New(hwdb.GetDB(ctx)) rows, err := propertyRepo.GetPropertiesWithSelectDataAndOptionsBySubjectTypeOrID( ctx, diff --git a/services/tasks-svc/cmd/service/main.go b/services/tasks-svc/cmd/service/main.go index 8fd6f145b..244f66928 100644 --- a/services/tasks-svc/cmd/service/main.go +++ b/services/tasks-svc/cmd/service/main.go @@ -2,7 +2,6 @@ package service import ( "common" - "context" pb "gen/services/tasks_svc/v1" hwspicedb "hwauthz/spicedb" "hwdb" @@ -34,7 +33,7 @@ const ServiceName = "tasks-svc" func Main(version string, ready func()) { ctx := common.Setup(ServiceName, version, common.WithAuth()) - closeDBPool := hwdb.SetupDatabaseFromEnv(context.Background()) + ctx, closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) defer closeDBPool() tracking.SetupTracking(ctx, ServiceName, 10, 24*time.Hour, 20) @@ -50,8 +49,8 @@ func Main(version string, ready func()) { ctx, common.Shutdown, task_spicedb.NewSpiceDBProjection(eventStore, authz, ServiceName), - task_postgres_projection.NewProjection(eventStore, ServiceName), - patientPostgresProjection.NewProjection(eventStore, ServiceName), + task_postgres_projection.NewProjection(ctx, eventStore, ServiceName), + patientPostgresProjection.NewProjection(ctx, eventStore, ServiceName), patientSpiceDBProjection.NewProjection(eventStore, authz, ServiceName), ) diff --git a/services/tasks-svc/internal/bed/bed.go b/services/tasks-svc/internal/bed/bed.go index 9151329e7..bbc51b7cd 100644 --- a/services/tasks-svc/internal/bed/bed.go +++ b/services/tasks-svc/internal/bed/bed.go @@ -62,7 +62,7 @@ func NewServiceServer(authz hwauthz.AuthZ, es *esdb.Client) *ServiceServer { func (s ServiceServer) CreateBed(ctx context.Context, req *pb.CreateBedRequest) (*pb.CreateBedResponse, error) { log := zlog.Ctx(ctx) - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) // parse inputs roomId, err := uuid.Parse(req.GetRoomId()) @@ -137,7 +137,7 @@ func (s ServiceServer) CreateBed(ctx context.Context, req *pb.CreateBedRequest) } func (s ServiceServer) GetBed(ctx context.Context, req *pb.GetBedRequest) (*pb.GetBedResponse, error) { - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) // parse inputs id, err := uuid.Parse(req.GetId()) @@ -175,7 +175,7 @@ func (s ServiceServer) GetBedByPatient( ctx context.Context, req *pb.GetBedByPatientRequest, ) (*pb.GetBedByPatientResponse, error) { - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) patientId, err := uuid.Parse(req.GetPatientId()) if err != nil { @@ -229,7 +229,7 @@ func (s ServiceServer) GetBeds(ctx context.Context, req *pb.GetBedsRequest) (*pb return nil, status.Error(codes.InvalidArgument, err.Error()) } - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) beds, err := bedRepo.GetBeds(ctx, roomID) if err != nil { @@ -270,7 +270,7 @@ func (s ServiceServer) GetBedsByRoom( return nil, status.Error(codes.InvalidArgument, err.Error()) } - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) beds, err := bedRepo.GetBeds(ctx, uuid.NullUUID{ @@ -312,7 +312,7 @@ func (s ServiceServer) GetBedsByRoom( } func (s ServiceServer) UpdateBed(ctx context.Context, req *pb.UpdateBedRequest) (*pb.UpdateBedResponse, error) { - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) // parse inputs bedID, err := uuid.Parse(req.GetId()) @@ -363,7 +363,7 @@ func (s ServiceServer) UpdateBed(ctx context.Context, req *pb.UpdateBedRequest) func (s ServiceServer) DeleteBed(ctx context.Context, req *pb.DeleteBedRequest) (*pb.DeleteBedResponse, error) { log := zlog.Ctx(ctx) - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) // parse inputs bedID, err := uuid.Parse(req.GetId()) diff --git a/services/tasks-svc/internal/patient/api/grpc.go b/services/tasks-svc/internal/patient/api/grpc.go index 37519cf7a..48754feb8 100644 --- a/services/tasks-svc/internal/patient/api/grpc.go +++ b/services/tasks-svc/internal/patient/api/grpc.go @@ -79,7 +79,7 @@ func (s *PatientGrpcService) GetPatient( return nil, err } - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) // check permissions user := commonPerm.UserFromCtx(ctx) @@ -360,7 +360,7 @@ func (s *PatientGrpcService) GetRecentPatients( _ *pb.GetRecentPatientsRequest, ) (*pb.GetRecentPatientsResponse, error) { log := zlog.Ctx(ctx) - bedRepo := bed_repo.New(hwdb.GetDB()) + bedRepo := bed_repo.New(hwdb.GetDB(ctx)) var recentPatientIdsStrs []string recentPatientIdsStrs, err := tracking.GetRecentPatientsForUser(ctx) diff --git a/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go b/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go index ed1e1a89d..ccb0e4ad3 100644 --- a/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go +++ b/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go @@ -22,7 +22,7 @@ type Projection struct { patientRepo *patient_repo.Queries } -func NewProjection(es *esdb.Client, serviceName string) *Projection { +func NewProjection(ctx context.Context, es *esdb.Client, serviceName string) *Projection { subscriptionGroupName := serviceName + "-patient-postgres-projection" p := &Projection{ CustomProjection: custom.NewCustomProjection( @@ -30,7 +30,7 @@ func NewProjection(es *esdb.Client, serviceName string) *Projection { subscriptionGroupName, &[]string{aggregate.PatientAggregateType + "-"}, ), - patientRepo: patient_repo.New(hwdb.GetDB()), + patientRepo: patient_repo.New(hwdb.GetDB(ctx)), } p.initEventListeners() return p diff --git a/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go b/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go index ca66a2f14..431790ccf 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go @@ -23,7 +23,7 @@ type GetAllPatientsWithDetailsQueryHandler func(ctx context.Context) ([]*models. func NewGetAllPatientsWithDetailsQueryHandler(authz hwauthz.AuthZ) GetAllPatientsWithDetailsQueryHandler { return func(ctx context.Context) ([]*models.PatientDetails, error) { - patientRepo := patient_repo.New(hwdb.GetDB()) + patientRepo := patient_repo.New(hwdb.GetDB(ctx)) // gather inputs organizationID := auth.MustGetOrganizationID(ctx) diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go b/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go index bbdc53a1c..3d9cb72c8 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go @@ -23,7 +23,7 @@ type GetPatientAssignmentByWardQueryHandler func( func NewGetPatientAssignmentByWardQueryHandler(authz hwauthz.AuthZ) GetPatientAssignmentByWardQueryHandler { return func(ctx context.Context, wardID uuid.UUID) ([]*models.RoomWithBedsWithPatient, error) { - roomRepo := room_repo.New(hwdb.GetDB()) + roomRepo := room_repo.New(hwdb.GetDB(ctx)) // check permissions // diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go b/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go index d0b2599ee..1efc26bcb 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go @@ -20,7 +20,7 @@ type GetPatientByBedQueryHandler func(ctx context.Context, bedID uuid.UUID) (*mo func NewGetPatientByBedQueryHandler(authz hwauthz.AuthZ) GetPatientByBedQueryHandler { return func(ctx context.Context, bedID uuid.UUID) (*models.PatientWithConsistency, error) { - patientRepo := patient_repo.New(hwdb.GetDB()) + patientRepo := patient_repo.New(hwdb.GetDB(ctx)) // check bed permissions user := commonPerm.UserFromCtx(ctx) diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go b/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go index 63919654f..7200778ac 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go @@ -23,7 +23,7 @@ func NewGetPatientWithDetailsByIDQueryHandler( as hwes.AggregateStore, authz hwauthz.AuthZ, ) GetPatientDetailsByIDQueryHandler { return func(ctx context.Context, patientID uuid.UUID) (*models.PatientDetails, error) { - patientRepo := patient_repo.New(hwdb.GetDB()) + patientRepo := patient_repo.New(hwdb.GetDB(ctx)) taskHandlers := th.NewTaskHandlers(as, authz) // check permissions diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go b/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go index 969b05180..68e57e739 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go @@ -21,7 +21,7 @@ type GetPatientsByWardQueryHandler func(ctx context.Context, wardID uuid.UUID) ( func NewGetPatientsByWardQueryHandler(authz hwauthz.AuthZ) GetPatientsByWardQueryHandler { return func(ctx context.Context, wardID uuid.UUID) ([]*models.PatientWithConsistency, error) { - patientRepo := patient_repo.New(hwdb.GetDB()) + patientRepo := patient_repo.New(hwdb.GetDB(ctx)) // ensure get-access to ward user := commonPerm.UserFromCtx(ctx) diff --git a/services/tasks-svc/internal/room/room.go b/services/tasks-svc/internal/room/room.go index 1bee3cd98..15bd4651e 100644 --- a/services/tasks-svc/internal/room/room.go +++ b/services/tasks-svc/internal/room/room.go @@ -56,7 +56,7 @@ func NewServiceServer(authz hwauthz.AuthZ, es *esdb.Client) *ServiceServer { func (s ServiceServer) CreateRoom(ctx context.Context, req *pb.CreateRoomRequest) (*pb.CreateRoomResponse, error) { log := zlog.Ctx(ctx) - roomRepo := room_repo.New(hwdb.GetDB()) + roomRepo := room_repo.New(hwdb.GetDB(ctx)) // parse input wardID, err := uuid.Parse(req.GetWardId()) @@ -118,7 +118,7 @@ func (s ServiceServer) CreateRoom(ctx context.Context, req *pb.CreateRoomRequest } func (s ServiceServer) GetRoom(ctx context.Context, req *pb.GetRoomRequest) (*pb.GetRoomResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB()) + roomRepo := room_repo.New(hwdb.GetDB(ctx)) // parse inputs id, err := uuid.Parse(req.GetId()) @@ -169,7 +169,7 @@ func (s ServiceServer) GetRoom(ctx context.Context, req *pb.GetRoomRequest) (*pb } func (s ServiceServer) UpdateRoom(ctx context.Context, req *pb.UpdateRoomRequest) (*pb.UpdateRoomResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB()) + roomRepo := room_repo.New(hwdb.GetDB(ctx)) // parse inputs roomID, err := uuid.Parse(req.GetId()) @@ -212,7 +212,7 @@ func (s ServiceServer) UpdateRoom(ctx context.Context, req *pb.UpdateRoomRequest } func (s ServiceServer) GetRooms(ctx context.Context, req *pb.GetRoomsRequest) (*pb.GetRoomsResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB()) + roomRepo := room_repo.New(hwdb.GetDB(ctx)) // parse inputs wardID, err := hwutil.ParseNullUUID(req.WardId) @@ -277,7 +277,7 @@ func (s ServiceServer) GetRooms(ctx context.Context, req *pb.GetRoomsRequest) (* } func (s ServiceServer) DeleteRoom(ctx context.Context, req *pb.DeleteRoomRequest) (*pb.DeleteRoomResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB()) + roomRepo := room_repo.New(hwdb.GetDB(ctx)) // parse inputs roomID, err := uuid.Parse(req.GetId()) @@ -321,7 +321,7 @@ func (s ServiceServer) GetRoomOverviewsByWard( ctx context.Context, req *pb.GetRoomOverviewsByWardRequest, ) (*pb.GetRoomOverviewsByWardResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB()) + roomRepo := room_repo.New(hwdb.GetDB(ctx)) wardID, err := uuid.Parse(req.GetId()) if err != nil { diff --git a/services/tasks-svc/internal/task-template/task_template.go b/services/tasks-svc/internal/task-template/task_template.go index d84473612..b18d14129 100644 --- a/services/tasks-svc/internal/task-template/task_template.go +++ b/services/tasks-svc/internal/task-template/task_template.go @@ -59,7 +59,7 @@ func (s ServiceServer) CreateTaskTemplate( req *pb.CreateTaskTemplateRequest, ) (*pb.CreateTaskTemplateResponse, error) { log := zlog.Ctx(ctx) - db := hwdb.GetDB() + db := hwdb.GetDB(ctx) user := commonPerm.UserFromCtx(ctx) @@ -163,7 +163,7 @@ func (s ServiceServer) DeleteTaskTemplate( req *pb.DeleteTaskTemplateRequest, ) (*pb.DeleteTaskTemplateResponse, error) { log := zlog.Ctx(ctx) - templateRepo := task_template_repo.New(hwdb.GetDB()) + templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) id, err := uuid.Parse(req.GetId()) if err != nil { @@ -210,7 +210,7 @@ func (s ServiceServer) DeleteTaskTemplateSubTask( ) (*pb.DeleteTaskTemplateSubTaskResponse, error) { log := zlog.Ctx(ctx) - tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(), ctx) + tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(ctx), ctx) if err != nil { return nil, err } @@ -273,7 +273,7 @@ func (s ServiceServer) UpdateTaskTemplate( ctx context.Context, req *pb.UpdateTaskTemplateRequest, ) (*pb.UpdateTaskTemplateResponse, error) { - templateRepo := task_template_repo.New(hwdb.GetDB()) + templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) id, err := uuid.Parse(req.GetId()) if err != nil { @@ -319,7 +319,7 @@ func (s ServiceServer) UpdateTaskTemplateSubTask( req *pb.UpdateTaskTemplateSubTaskRequest, ) (*pb.UpdateTaskTemplateSubTaskResponse, error) { // TX - tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(), ctx) + tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(ctx), ctx) if err != nil { return nil, err } @@ -383,7 +383,7 @@ func (s ServiceServer) CreateTaskTemplateSubTask( req *pb.CreateTaskTemplateSubTaskRequest, ) (*pb.CreateTaskTemplateSubTaskResponse, error) { log := zlog.Ctx(ctx) - templateRepo := task_template_repo.New(hwdb.GetDB()) + templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) taskTemplateID, err := uuid.Parse(req.GetTaskTemplateId()) if err != nil { @@ -436,7 +436,7 @@ func (s ServiceServer) GetAllTaskTemplates( ctx context.Context, req *pb.GetAllTaskTemplatesRequest, ) (*pb.GetAllTaskTemplatesResponse, error) { - templateRepo := task_template_repo.New(hwdb.GetDB()) + templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) user := commonPerm.UserFromCtx(ctx) @@ -512,7 +512,7 @@ func (s ServiceServer) GetTaskTemplate( ctx context.Context, req *pb.GetTaskTemplateRequest, ) (*pb.GetTaskTemplateResponse, error) { - templateRepo := task_template_repo.New(hwdb.GetDB()) + templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) taskTemplateID, err := uuid.Parse(req.Id) if err != nil { diff --git a/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go b/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go index 116676f92..9ad9eb0ec 100644 --- a/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go +++ b/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go @@ -24,7 +24,7 @@ type Projection struct { taskRepo *task_repo.Queries } -func NewProjection(es *esdb.Client, serviceName string) *Projection { +func NewProjection(ctx context.Context, es *esdb.Client, serviceName string) *Projection { subscriptionGroupName := serviceName + "-task-postgres-projection" p := &Projection{ CustomProjection: custom.NewCustomProjection( @@ -32,7 +32,7 @@ func NewProjection(es *esdb.Client, serviceName string) *Projection { subscriptionGroupName, &[]string{aggregate.TaskAggregateType + "-"}, ), - taskRepo: task_repo.New(hwdb.GetDB()), + taskRepo: task_repo.New(hwdb.GetDB(ctx)), } p.initEventListeners() return p diff --git a/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go b/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go index 12d475cdc..c955bd161 100644 --- a/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go +++ b/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go @@ -28,7 +28,7 @@ func NewGetTaskWithPatientByIDQueryHandler(authz hwauthz.AuthZ) GetTaskWithPatie return nil, err } - taskRepo := task_repo.New(hwdb.GetDB()) + taskRepo := task_repo.New(hwdb.GetDB(ctx)) rows, err := taskRepo.GetTaskWithPatientById(ctx, taskID) if err := hwdb.Error(ctx, err); err != nil { diff --git a/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go b/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go index f9132989b..71bc5c9ef 100644 --- a/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go +++ b/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go @@ -32,7 +32,7 @@ func NewGetTasksByPatientIDQueryHandler(authz hwauthz.AuthZ) GetTasksByPatientID return nil, err } - taskRepo := task_repo.New(hwdb.GetDB()) + taskRepo := task_repo.New(hwdb.GetDB(ctx)) tasksWithSubtasks, err := taskRepo.GetTasksWithSubtasksByPatient(ctx, patientID) if err := hwdb.Error(ctx, err); err != nil { diff --git a/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go b/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go index f307a948a..e73c79c4c 100644 --- a/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go +++ b/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go @@ -25,7 +25,7 @@ type GetTasksWithPatientsByAssigneeQueryHandler func( func NewGetTasksWithPatientsByAssigneeQueryHandler(authz hwauthz.AuthZ) GetTasksWithPatientsByAssigneeQueryHandler { return func(ctx context.Context, assigneeID uuid.UUID) ([]*models.TaskWithPatient, error) { - taskRepo := task_repo.New(hwdb.GetDB()) + taskRepo := task_repo.New(hwdb.GetDB(ctx)) user := commonPerm.UserFromCtx(ctx) diff --git a/services/tasks-svc/internal/ward/ward.go b/services/tasks-svc/internal/ward/ward.go index f766cb85b..dcce2d682 100644 --- a/services/tasks-svc/internal/ward/ward.go +++ b/services/tasks-svc/internal/ward/ward.go @@ -57,7 +57,7 @@ func NewServiceServer(authz hwauthz.AuthZ, es *esdb.Client) *ServiceServer { func (s *ServiceServer) CreateWard(ctx context.Context, req *pb.CreateWardRequest) (*pb.CreateWardResponse, error) { log := zlog.Ctx(ctx) - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) // check permissions user := commonPerm.UserFromCtx(ctx) @@ -116,7 +116,7 @@ func (s *ServiceServer) CreateWard(ctx context.Context, req *pb.CreateWardReques } func (s *ServiceServer) GetWard(ctx context.Context, req *pb.GetWardRequest) (*pb.GetWardResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) // parse input id, err := uuid.Parse(req.GetId()) @@ -150,7 +150,7 @@ func (s *ServiceServer) GetWard(ctx context.Context, req *pb.GetWardRequest) (*p } func (s *ServiceServer) GetWards(ctx context.Context, req *pb.GetWardsRequest) (*pb.GetWardsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) wards, err := wardRepo.GetWards(ctx) err = hwdb.Error(ctx, err) @@ -186,7 +186,7 @@ func (s *ServiceServer) GetRecentWards( ctx context.Context, _ *pb.GetRecentWardsRequest, ) (*pb.GetRecentWardsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) log := zlog.Ctx(ctx) recentWardIDsStr, err := tracking.GetRecentWardsForUser(ctx) @@ -247,7 +247,7 @@ func (s *ServiceServer) GetRecentWards( } func (s *ServiceServer) UpdateWard(ctx context.Context, req *pb.UpdateWardRequest) (*pb.UpdateWardResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) // parse input id, err := uuid.Parse(req.GetId()) @@ -293,7 +293,7 @@ func (s *ServiceServer) UpdateWard(ctx context.Context, req *pb.UpdateWardReques } func (s *ServiceServer) DeleteWard(ctx context.Context, req *pb.DeleteWardRequest) (*pb.DeleteWardResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) // parse input wardID, err := uuid.Parse(req.GetId()) @@ -350,7 +350,7 @@ func (s *ServiceServer) GetWardOverviews( ctx context.Context, _ *pb.GetWardOverviewsRequest, ) (*pb.GetWardOverviewsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) rows, err := wardRepo.GetWardsWithCounts(ctx, ward_repo.GetWardsWithCountsParams{ StatusTodo: int32(pb.TaskStatus_TASK_STATUS_TODO), @@ -395,7 +395,7 @@ func (s *ServiceServer) GetWardDetails( ctx context.Context, req *pb.GetWardDetailsRequest, ) (*pb.GetWardDetailsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB()) + wardRepo := ward_repo.New(hwdb.GetDB(ctx)) wardID, err := uuid.Parse(req.GetId()) if err != nil { diff --git a/services/user-svc/cmd/service/main.go b/services/user-svc/cmd/service/main.go index 2bf8cdd88..fd85d5425 100644 --- a/services/user-svc/cmd/service/main.go +++ b/services/user-svc/cmd/service/main.go @@ -21,7 +21,7 @@ func Main(version string, ready func()) { common.WithNonOrganizationMethod(pb.OrganizationService_CreatePersonalOrganization_FullMethodName), ) - closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) + ctx, closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) defer closeDBPool() kc, err := hwkc.BuildClient(ctx) diff --git a/services/user-svc/internal/organization/organization.go b/services/user-svc/internal/organization/organization.go index d17938d2b..88cae36ff 100644 --- a/services/user-svc/internal/organization/organization.go +++ b/services/user-svc/internal/organization/organization.go @@ -78,7 +78,7 @@ func (s ServiceServer) GetOrganization( ctx context.Context, req *pb.GetOrganizationRequest, ) (*pb.GetOrganizationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) id, err := uuid.Parse(req.GetId()) if err != nil { @@ -170,7 +170,7 @@ type OrganizationWithMembers struct { func GetOrganizationsByUserId( ctx context.Context, userId uuid.UUID, authz hwauthz.AuthZ, ) ([]OrganizationWithMembers, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) rows, err := organizationRepo.GetOrganizationsWithMembersByUser(ctx, userId) err = hwdb.Error(ctx, err) @@ -279,7 +279,7 @@ func (s ServiceServer) UpdateOrganization( return nil, err } - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) organizationID, err := uuid.Parse(req.GetId()) if err != nil { @@ -313,7 +313,7 @@ func (s ServiceServer) DeleteOrganization( return nil, err } - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) organizationID, err := uuid.Parse(req.GetId()) if err != nil { @@ -352,7 +352,7 @@ func (s ServiceServer) RemoveMember( } log := zlog.Ctx(ctx) - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) userID, err := uuid.Parse(req.UserId) if err != nil { @@ -399,7 +399,7 @@ func (s ServiceServer) InviteMember( req *pb.InviteMemberRequest, ) (*pb.InviteMemberResponse, error) { log := zlog.Ctx(ctx) - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) // check permissions permUser := commonPerm.UserFromCtx(ctx) @@ -479,7 +479,7 @@ func (s ServiceServer) GetInvitationsByOrganization( ctx context.Context, req *pb.GetInvitationsByOrganizationRequest, ) (*pb.GetInvitationsByOrganizationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) organizationID, err := uuid.Parse(req.OrganizationId) if err != nil { @@ -548,7 +548,7 @@ func (s ServiceServer) GetInvitationsByUser( ctx context.Context, req *pb.GetInvitationsByUserRequest, ) (*pb.GetInvitationsByUserResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) claims, err := auth.GetAuthClaims(ctx) if err != nil { @@ -612,7 +612,7 @@ func (s ServiceServer) GetMembersByOrganization( ctx context.Context, req *pb.GetMembersByOrganizationRequest, ) (*pb.GetMembersByOrganizationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) organizationID, err := uuid.Parse(req.GetId()) if err != nil { @@ -652,7 +652,7 @@ func (s ServiceServer) AcceptInvitation( ctx context.Context, req *pb.AcceptInvitationRequest, ) (*pb.AcceptInvitationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) invitationId, err := uuid.Parse(req.InvitationId) if err != nil { @@ -715,7 +715,7 @@ func (s ServiceServer) AcceptInvitation( // Add user to organization if err := AddUserToOrganization( ctx, - hwdb.GetDB(), + hwdb.GetDB(ctx), s.authz, s.kc, userID, @@ -732,7 +732,7 @@ func (s ServiceServer) DeclineInvitation( ctx context.Context, req *pb.DeclineInvitationRequest, ) (*pb.DeclineInvitationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) invitationId, err := uuid.Parse(req.InvitationId) if err != nil { @@ -797,7 +797,7 @@ func (s ServiceServer) RevokeInvitation( ctx context.Context, req *pb.RevokeInvitationRequest, ) (*pb.RevokeInvitationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB()) + organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) log := zlog.Ctx(ctx) @@ -860,7 +860,7 @@ func CreateOrganizationAndAddUser( authz hwauthz.AuthZ, ) (*organization_repo.Organization, error) { // open tx - tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(), ctx) + tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(ctx), ctx) if err != nil { return nil, err } @@ -996,7 +996,7 @@ func (s ServiceServer) CreatePersonalOrganization( personalOrganizationLocale := hwlocale.Localize(ctx, locale.PersonalOrganizationName(ctx)) organizationName := fmt.Sprintf("%s %s", personalOrganizationLocale, userClaims.Name) - userRepo := user_repo.New(hwdb.GetDB()) + userRepo := user_repo.New(hwdb.GetDB(ctx)) // create user, if it does not exist yet userResult, err := hwdb.Optional(userRepo.GetUserById)(ctx, userID) diff --git a/services/user-svc/internal/user/user.go b/services/user-svc/internal/user/user.go index dddae2d57..14f36ddd7 100644 --- a/services/user-svc/internal/user/user.go +++ b/services/user-svc/internal/user/user.go @@ -41,7 +41,7 @@ func (s ServiceServer) ReadPublicProfile( ctx context.Context, req *pb.ReadPublicProfileRequest, ) (*pb.ReadPublicProfileResponse, error) { - userRepo := user_repo.New(hwdb.GetDB()) + userRepo := user_repo.New(hwdb.GetDB(ctx)) userID, err := uuid.Parse(req.GetId()) if err != nil { @@ -74,7 +74,7 @@ func (s ServiceServer) ReadPublicProfile( func HandleUserUpdatedEvent(ctx context.Context, evt *daprcmn.TopicEvent) (retry bool, err error) { log := zlog.Ctx(ctx) - userRepo := user_repo.New(hwdb.GetDB()) + userRepo := user_repo.New(hwdb.GetDB(ctx)) var payload events.UserUpdatedEvent if err := proto.Unmarshal(evt.RawData, &payload); err != nil { From fad318ed94a3fec704ff03c26ace726c0bf558f9 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Sun, 22 Dec 2024 21:38:52 +0100 Subject: [PATCH 14/22] parallel --- libs/common/go.mod | 10 ++ libs/common/go.sum | 18 +++ libs/common/grpc.go | 78 +++++++++---- libs/common/hwgrpc/db_interceptor.go | 31 +++++ libs/common/hwgrpc/db_interceptor_test.go | 110 ++++++++++++++++++ libs/common/hwgrpc/panic_interceptor.go | 32 ++--- libs/common/hwgrpc/panic_interceptor_test.go | 6 +- libs/hwauthz/go.mod | 9 ++ libs/hwauthz/go.sum | 18 ++- libs/hwdb/go.mod | 7 +- libs/hwdb/go.sum | 10 ++ libs/hwdb/setup.go | 9 +- libs/hwdb/setup_test.go | 17 +++ libs/hwes/go.mod | 9 ++ libs/hwes/go.sum | 16 +++ libs/hwtesting/go.mod | 9 ++ libs/hwtesting/go.sum | 18 ++- libs/telemetry/setup.go | 52 +-------- services/property-svc/cmd/service/main.go | 4 +- .../internal/property-view/api/grpc_test.go | 42 +++---- services/tasks-svc/go.sum | 2 + services/updates-svc/go.mod | 8 ++ services/updates-svc/go.sum | 18 ++- services/user-svc/go.sum | 2 + 24 files changed, 402 insertions(+), 133 deletions(-) create mode 100644 libs/common/hwgrpc/db_interceptor.go create mode 100644 libs/common/hwgrpc/db_interceptor_test.go create mode 100644 libs/hwdb/setup_test.go diff --git a/libs/common/go.mod b/libs/common/go.mod index 5cb5f5ba2..7cfd16107 100644 --- a/libs/common/go.mod +++ b/libs/common/go.mod @@ -3,6 +3,7 @@ module common go 1.23 replace ( + hwdb => ../hwdb hwlocale => ../hwlocale hwutil => ../hwutil telemetry => ../telemetry @@ -18,6 +19,7 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 github.com/joho/godotenv v1.5.1 github.com/nicksnyder/go-i18n/v2 v2.4.1 + github.com/pashagolub/pgxmock/v4 v4.3.0 github.com/prometheus/client_golang v1.20.5 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 @@ -33,6 +35,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 google.golang.org/grpc v1.68.1 google.golang.org/protobuf v1.35.2 + hwdb v0.0.0 hwlocale v0.0.0 hwutil v0.0.0 telemetry v0.0.0 @@ -51,6 +54,11 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect + github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -62,11 +70,13 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect go.opentelemetry.io/otel/metric v1.32.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect golang.org/x/crypto v0.30.0 // indirect golang.org/x/net v0.32.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect diff --git a/libs/common/go.sum b/libs/common/go.sum index ecb13c995..5e563c853 100644 --- a/libs/common/go.sum +++ b/libs/common/go.sum @@ -50,6 +50,16 @@ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwn github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= @@ -74,6 +84,8 @@ github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3 github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -94,9 +106,13 @@ github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 h1:EhPtK0mgrgaTMXpegE69hvoSOVC1Ahk8+QJ9B8b+OdU= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0/go.mod h1:5LtFrNEkgzxHvXPO9eOvcXsSn9/KeKYgx9kjeI2oXQI= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 h1:qtFISDHKolvIxzSs0gIaiPUPR0Cucb0F2coHC7ZLdps= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0/go.mod h1:Y+Pop1Q6hCOnETWTW4NROK/q1hv50hM7yDaUTjG8lp8= go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= @@ -127,6 +143,8 @@ golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/libs/common/grpc.go b/libs/common/grpc.go index a21ef6d70..8a2479379 100644 --- a/libs/common/grpc.go +++ b/libs/common/grpc.go @@ -2,11 +2,13 @@ package common import ( "context" + "github.com/prometheus/client_golang/prometheus" + "hwdb" "hwutil" "net" "telemetry" - auth "common/auth" + "common/auth" "common/hwgrpc" "github.com/dapr/dapr/pkg/proto/runtime/v1" @@ -32,7 +34,7 @@ import ( // api.RegisterMyServiceServer(grpcServer, &myServiceServer{}) // }) // // cleanup after yourself here -func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook func(*daprd.Server)) { +func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook func(*daprd.Server), opts ...DefaultServerOptionsOpt) { log := zlog.Ctx(ctx) listener, err := net.Listen("tcp", addr) @@ -41,7 +43,7 @@ func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook fun } // dapr/grpc service - service, ok := daprd.NewServiceWithListener(listener, DefaultServerOptions(ctx)...).(*daprd.Server) + service, ok := daprd.NewServiceWithListener(listener, DefaultServerOptions(opts...)...).(*daprd.Server) if !ok { log.Fatal().Msg("dapr service listener is not a *daprd.Server") } @@ -87,16 +89,13 @@ func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook fun // DefaultUnaryInterceptors returns the slice of default interceptors for unary gRPC calls // // chain := grpc.ChainUnaryInterceptor(common.DefaultUnaryInterceptors()...) -func DefaultUnaryInterceptors( - ctx context.Context, - metrics *prometheusGrpcProvider.ServerMetrics, -) []grpc.UnaryServerInterceptor { +func DefaultUnaryInterceptors(opt DefaultServerOptionsOpt) []grpc.UnaryServerInterceptor { return []grpc.UnaryServerInterceptor{ - metrics.UnaryServerInterceptor(), - hwgrpc.UnaryPanicRecoverInterceptor(ctx), + hwgrpc.UnaryPanicRecoverInterceptor(opt.prometheusRegistry), hwgrpc.UnaryLoggingInterceptor, hwgrpc.UnaryErrorQualityControlInterceptor, hwgrpc.UnaryLocaleInterceptor, + hwgrpc.UnaryDBInterceptor(opt.db), defaultUnaryAuthInterceptor, defaultUnaryOrganizationInterceptor, hwgrpc.UnaryValidateInterceptor, @@ -107,16 +106,13 @@ func DefaultUnaryInterceptors( // DefaultStreamInterceptors returns the slice of default interceptors for stream gRPC calls // // chain := grpc.ChainStreamInterceptor(common.DefaultStreamInterceptors()...) -func DefaultStreamInterceptors( - ctx context.Context, - metrics *prometheusGrpcProvider.ServerMetrics, -) []grpc.StreamServerInterceptor { +func DefaultStreamInterceptors(opt DefaultServerOptionsOpt) []grpc.StreamServerInterceptor { return []grpc.StreamServerInterceptor{ - metrics.StreamServerInterceptor(), - hwgrpc.StreamPanicRecoverInterceptor(ctx), + hwgrpc.StreamPanicRecoverInterceptor(opt.prometheusRegistry), hwgrpc.StreamLoggingInterceptor, hwgrpc.StreamErrorQualityControlInterceptor, hwgrpc.StreamLocaleInterceptor, + hwgrpc.StreamDBInterceptor(opt.db), defaultStreamAuthInterceptor, defaultStreamOrganizationInterceptor, hwgrpc.StreamValidateInterceptor, @@ -124,14 +120,54 @@ func DefaultStreamInterceptors( } } -func DefaultServerOptions(ctx context.Context) []grpc.ServerOption { - // register new metrics collector with prometheus - metrics := prometheusGrpcProvider.NewServerMetrics() +type DefaultServerOptionsOpt struct { + db hwdb.DBTX + prometheusRegistry *prometheus.Registry +} + +func WithDB(db hwdb.DBTX) DefaultServerOptionsOpt { + return DefaultServerOptionsOpt{db: db} +} + +func WithPrometheusRegistry(registry *prometheus.Registry) DefaultServerOptionsOpt { + return DefaultServerOptionsOpt{prometheusRegistry: registry} +} + +func mergeDefaultServerOptionsOpts(opts []DefaultServerOptionsOpt) DefaultServerOptionsOpt { + res := DefaultServerOptionsOpt{} + for _, opt := range opts { + if opt.db != nil { + res.db = opt.db + } + if opt.prometheusRegistry != nil { + res.prometheusRegistry = opt.prometheusRegistry + } + } + return res +} + +func DefaultServerOptions(opts ...DefaultServerOptionsOpt) []grpc.ServerOption { + opt := mergeDefaultServerOptionsOpts(opts) + + // default interceptors + unaryInterceptors := DefaultUnaryInterceptors(opt) + streamInterceptors := DefaultStreamInterceptors(opt) + + // register new metrics collector with prometheus, if registry provided + if promRegistry := opt.prometheusRegistry; promRegistry != nil { + metrics := prometheusGrpcProvider.NewServerMetrics() + promRegistry.MustRegister(metrics) + + // prepend metrics interceptor + unaryInterceptors = hwutil.Prepend(metrics.UnaryServerInterceptor(), unaryInterceptors) + streamInterceptors = hwutil.Prepend(metrics.StreamServerInterceptor(), streamInterceptors) + } - telemetry.PrometheusRegistry(ctx).MustRegister(metrics) + // create chains + unaryInterceptorChain := grpc.ChainUnaryInterceptor(unaryInterceptors...) + streamInterceptorChain := grpc.ChainStreamInterceptor(streamInterceptors...) - unaryInterceptorChain := grpc.ChainUnaryInterceptor(DefaultUnaryInterceptors(ctx, metrics)...) - streamInterceptorChain := grpc.ChainStreamInterceptor(DefaultStreamInterceptors(ctx, metrics)...) + // otel stats handler statsHandler := grpc.StatsHandler(otelgrpc.NewServerHandler()) return []grpc.ServerOption{unaryInterceptorChain, streamInterceptorChain, statsHandler} diff --git a/libs/common/hwgrpc/db_interceptor.go b/libs/common/hwgrpc/db_interceptor.go new file mode 100644 index 000000000..c14936ae5 --- /dev/null +++ b/libs/common/hwgrpc/db_interceptor.go @@ -0,0 +1,31 @@ +package hwgrpc + +import ( + "context" + "google.golang.org/grpc" + "hwdb" +) + +func UnaryDBInterceptor(db hwdb.DBTX) grpc.UnaryServerInterceptor { + return func( + ctx context.Context, + req any, + _ *grpc.UnaryServerInfo, + next grpc.UnaryHandler, + ) (any, error) { + return next(hwdb.WithDB(ctx, db), req) + } +} + +func StreamDBInterceptor(db hwdb.DBTX) grpc.StreamServerInterceptor { + return func( + req any, + stream grpc.ServerStream, + _ *grpc.StreamServerInfo, + next grpc.StreamHandler, + ) error { + ctx := hwdb.WithDB(stream.Context(), db) + stream = WrapServerStream(stream, ctx) + return next(req, stream) + } +} diff --git a/libs/common/hwgrpc/db_interceptor_test.go b/libs/common/hwgrpc/db_interceptor_test.go new file mode 100644 index 000000000..0e6dd9346 --- /dev/null +++ b/libs/common/hwgrpc/db_interceptor_test.go @@ -0,0 +1,110 @@ +package hwgrpc_test + +import ( + "context" + "github.com/google/uuid" + "github.com/pashagolub/pgxmock/v4" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "hwdb" + "testing" + + "common/hwgrpc" +) + +func TestDBInterceptor(t *testing.T) { + t.Parallel() + + type testCase struct { + db hwdb.DBTX + handler func(t *testing.T, ctx context.Context) + } + + existingDB, err := pgxmock.NewPool() + if err != nil { + panic(err) + } + + testMatrix := map[string]testCase{ + "missing db": { + db: nil, + handler: func(t *testing.T, ctx context.Context) { + // GetDB will not work + require.Panics(t, func() { + hwdb.GetDB(ctx) + }) + }, + }, + "existing db": { + db: existingDB, + handler: func(t *testing.T, ctx context.Context) { + require.Equal(t, existingDB, hwdb.GetDB(ctx)) + }, + }, + } + + for name, test := range testMatrix { + t.Run(name, func(t *testing.T) { + t.Parallel() + ctx := context.Background() + + // + // Stream + // + + streamInterceptor := hwgrpc.StreamDBInterceptor(test.db) + streamHandlerWasCalled := false + + streamNext := func(srv any, stream grpc.ServerStream) error { + streamHandlerWasCalled = true + test.handler(t, stream.Context()) + return nil + } + + stream := &fakeServerStream{ctx: ctx} + err = streamInterceptor(ctx, stream, nil, streamNext) + + // next handler is properly called + require.NoError(t, err) + require.True(t, streamHandlerWasCalled) + + // + // Unary + // + unaryInterceptor := hwgrpc.UnaryDBInterceptor(test.db) + + expValue := uuid.New() + unaryHandlerWasCalled := false + + unaryNext := func(ctx context.Context, req any) (any, error) { + unaryHandlerWasCalled = true + test.handler(t, ctx) + return expValue, nil + } + + value, err := unaryInterceptor(ctx, nil, nil, unaryNext) + + // unaryNext handler is properly called + require.NoError(t, err) + require.True(t, unaryHandlerWasCalled) + require.Equal(t, expValue, value) + }) + } +} + +type fakeServerStream struct { + grpc.ServerStream + ctx context.Context +} + +func (f *fakeServerStream) Context() context.Context { + return f.ctx +} + +func (f *fakeServerStream) SendMsg(_ any) error { + return nil +} + +func (f *fakeServerStream) RecvMsg(_ any) error { + return nil +} diff --git a/libs/common/hwgrpc/panic_interceptor.go b/libs/common/hwgrpc/panic_interceptor.go index 17316f549..7094e7ac3 100644 --- a/libs/common/hwgrpc/panic_interceptor.go +++ b/libs/common/hwgrpc/panic_interceptor.go @@ -1,14 +1,13 @@ package hwgrpc import ( + "common/hwerr" + "common/locale" "context" "fmt" + "github.com/prometheus/client_golang/prometheus/promauto" "os" "runtime/debug" - "telemetry" - - "common/hwerr" - "common/locale" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery" "github.com/prometheus/client_golang/prometheus" @@ -17,10 +16,8 @@ import ( "google.golang.org/grpc/codes" ) -var panicsRecovered = telemetry.NewLazyCounter(prometheus.CounterOpts{ - Name: "services_panics_recovered_total", - Help: "Total number of panics recovered by PanicRecoverInterceptor", -}) +// TODO: remove global state +var panicsRecovered prometheus.Counter func recoveryHandlerFn() recovery.RecoveryHandlerFuncContext { return func(ctx context.Context, recovered any) (err error) { @@ -32,22 +29,31 @@ func recoveryHandlerFn() recovery.RecoveryHandlerFuncContext { _, _ = fmt.Fprintln(os.Stderr, string(debug.Stack())) - panicsRecovered.Counter(ctx).Inc() + panicsRecovered.Inc() return hwerr.NewStatusError(ctx, codes.Internal, "panic recovered", locale.GenericError(ctx)) } } -func UnaryPanicRecoverInterceptor(ctx context.Context) grpc.UnaryServerInterceptor { - panicsRecovered.Ensure(ctx) +func ensureCounter(registry *prometheus.Registry) { + if registry != nil { + panicsRecovered = promauto.With(registry).NewCounter(prometheus.CounterOpts{ + Name: "services_panics_recovered_total", + Help: "Total number of panics recovered by PanicRecoverInterceptor", + }) + } +} + +func UnaryPanicRecoverInterceptor(registry *prometheus.Registry) grpc.UnaryServerInterceptor { + ensureCounter(registry) return recovery.UnaryServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), ) } -func StreamPanicRecoverInterceptor(ctx context.Context) grpc.StreamServerInterceptor { - panicsRecovered.Ensure(ctx) +func StreamPanicRecoverInterceptor(registry *prometheus.Registry) grpc.StreamServerInterceptor { + ensureCounter(registry) return recovery.StreamServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), diff --git a/libs/common/hwgrpc/panic_interceptor_test.go b/libs/common/hwgrpc/panic_interceptor_test.go index cc6618eb6..62acc79dc 100644 --- a/libs/common/hwgrpc/panic_interceptor_test.go +++ b/libs/common/hwgrpc/panic_interceptor_test.go @@ -38,13 +38,13 @@ type RecoverySuite struct { func TestPanicRecoverInterceptor(t *testing.T) { t.Parallel() - ctx := telemetry.SetupMetrics(context.Background(), nil) + registry := telemetry.SetupMetrics(context.Background(), nil) s := &RecoverySuite{ InterceptorTestSuite: &testpb.InterceptorTestSuite{ TestService: &recoveryAssertService{TestServiceServer: &testpb.TestPingService{}}, ServerOpts: []grpc.ServerOption{ - grpc.StreamInterceptor(StreamPanicRecoverInterceptor(ctx)), - grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor(ctx)), + grpc.StreamInterceptor(StreamPanicRecoverInterceptor(registry)), + grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor(registry)), }, }, } diff --git a/libs/hwauthz/go.mod b/libs/hwauthz/go.mod index c7adc7b51..8f40f2bf7 100644 --- a/libs/hwauthz/go.mod +++ b/libs/hwauthz/go.mod @@ -4,6 +4,7 @@ go 1.23 replace ( common => ../common + hwdb => ../hwdb hwlocale => ../hwlocale hwtesting => ../hwtesting hwutil => ../hwutil @@ -63,6 +64,11 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/jzelinskie/stringz v0.0.3 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -102,6 +108,7 @@ require ( github.com/testcontainers/testcontainers-go/modules/redis v0.34.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect + github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect @@ -117,6 +124,7 @@ require ( golang.org/x/crypto v0.30.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect @@ -124,5 +132,6 @@ require ( google.golang.org/protobuf v1.35.2 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + hwdb v0.0.0 // indirect hwlocale v0.0.0 // indirect ) diff --git a/libs/hwauthz/go.sum b/libs/hwauthz/go.sum index dbe5f8feb..6aa8055e4 100644 --- a/libs/hwauthz/go.sum +++ b/libs/hwauthz/go.sum @@ -127,14 +127,16 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= -github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jzelinskie/stringz v0.0.3 h1:0GhG3lVMYrYtIvRbxvQI6zqRTT1P1xyQlpa0FhfUXas= @@ -192,6 +194,8 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -255,6 +259,8 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 h1:EhPtK0mgrgaTMXpegE69hvoSOVC1Ahk8+QJ9B8b+OdU= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0/go.mod h1:5LtFrNEkgzxHvXPO9eOvcXsSn9/KeKYgx9kjeI2oXQI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= diff --git a/libs/hwdb/go.mod b/libs/hwdb/go.mod index 6ff95665a..e014fc486 100644 --- a/libs/hwdb/go.mod +++ b/libs/hwdb/go.mod @@ -11,10 +11,13 @@ replace ( require ( common v0.0.0 + github.com/google/uuid v1.6.0 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/jackc/pgx/v5 v5.7.1 github.com/nicksnyder/go-i18n/v2 v2.4.1 + github.com/pashagolub/pgxmock/v4 v4.3.0 github.com/rs/zerolog v1.33.0 + github.com/stretchr/testify v1.10.0 github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 go.opentelemetry.io/otel v1.32.0 go.opentelemetry.io/otel/trace v1.32.0 @@ -29,6 +32,7 @@ require ( github.com/BurntSushi/toml v1.4.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/fatih/structs v1.1.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -36,7 +40,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.23.0 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect @@ -45,6 +48,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect @@ -56,4 +60,5 @@ require ( golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/libs/hwdb/go.sum b/libs/hwdb/go.sum index e2a9fa645..f5becd156 100644 --- a/libs/hwdb/go.sum +++ b/libs/hwdb/go.sum @@ -44,6 +44,10 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -58,6 +62,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nicksnyder/go-i18n/v2 v2.4.1 h1:zwzjtX4uYyiaU02K5Ia3zSkpJZrByARkRB4V3YPrr0g= github.com/nicksnyder/go-i18n/v2 v2.4.1/go.mod h1:++Pl70FR6Cki7hdzZRnEEqdc2dJt+SAGotyFg/SvZMk= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= @@ -70,6 +76,8 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -106,6 +114,8 @@ google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe0 google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/libs/hwdb/setup.go b/libs/hwdb/setup.go index 4322d77c1..a961cec0b 100644 --- a/libs/hwdb/setup.go +++ b/libs/hwdb/setup.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "hwutil" + "hwutil/errs" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" @@ -34,7 +35,7 @@ type DBTX interface { // POSTGRES_PORT (5432) // // SetupDatabaseFromEnv returns a close function, which has to be called in order to shut down the database cleanly -func SetupDatabaseFromEnv(ctx context.Context) (context.Context, func()) { +func SetupDatabaseFromEnv(ctx context.Context) (DBTX, func()) { log.Info().Msg("connecting to postgres ...") dsn := hwutil.GetEnvOr("POSTGRES_DSN", "") @@ -48,12 +49,9 @@ func SetupDatabaseFromEnv(ctx context.Context) (context.Context, func()) { log.Fatal().Err(err).Msg("could not connect to database") } - // make db available via GetDB - ctx = WithDB(ctx, dbpool) - log.Info().Msg("connected to postgres") - return ctx, func() { + return dbpool, func() { log.Info().Msg("closing db pool") dbpool.Close() } @@ -115,6 +113,7 @@ func GetDB(ctx context.Context) DBTX { log.Error(). Msg("GetDB called without set-up database, you will run into nil-pointers. " + "Make sure to call SetupDatabaseFromEnv()!") + panic(errs.NewCastError("DBTX", value)) } return db } diff --git a/libs/hwdb/setup_test.go b/libs/hwdb/setup_test.go new file mode 100644 index 000000000..96d8576a7 --- /dev/null +++ b/libs/hwdb/setup_test.go @@ -0,0 +1,17 @@ +package hwdb + +import ( + "context" + "github.com/pashagolub/pgxmock/v4" + "github.com/stretchr/testify/require" + "testing" +) + +func TestContextFunctions(t *testing.T) { + dbMock, err := pgxmock.NewPool() + if err != nil { + panic(err) + } + ctx := WithDB(context.Background(), dbMock) + require.Equal(t, dbMock, GetDB(ctx)) +} diff --git a/libs/hwes/go.mod b/libs/hwes/go.mod index f694921bb..3cc0305c3 100644 --- a/libs/hwes/go.mod +++ b/libs/hwes/go.mod @@ -5,6 +5,7 @@ go 1.23 replace ( common => ../common gen => ../../gen/go + hwdb => ../hwdb hwlocale => ../hwlocale hwutil => ../hwutil telemetry => ../telemetry @@ -41,6 +42,11 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect + github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -55,6 +61,7 @@ require ( github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 // indirect go.opentelemetry.io/otel v1.32.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect @@ -68,6 +75,7 @@ require ( golang.org/x/crypto v0.30.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect @@ -75,5 +83,6 @@ require ( google.golang.org/grpc v1.68.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + hwdb v0.0.0 // indirect hwlocale v0.0.0 // indirect ) diff --git a/libs/hwes/go.sum b/libs/hwes/go.sum index 49945c71a..aa78359e4 100644 --- a/libs/hwes/go.sum +++ b/libs/hwes/go.sum @@ -82,6 +82,16 @@ github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwn github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= @@ -124,6 +134,8 @@ github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -153,7 +165,9 @@ github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E= @@ -162,6 +176,8 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 h1:EhPtK0mgrgaTMXpegE69hvoSOVC1Ahk8+QJ9B8b+OdU= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0/go.mod h1:5LtFrNEkgzxHvXPO9eOvcXsSn9/KeKYgx9kjeI2oXQI= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 h1:qtFISDHKolvIxzSs0gIaiPUPR0Cucb0F2coHC7ZLdps= diff --git a/libs/hwtesting/go.mod b/libs/hwtesting/go.mod index f4623cce2..8095448e6 100644 --- a/libs/hwtesting/go.mod +++ b/libs/hwtesting/go.mod @@ -5,6 +5,7 @@ go 1.23 replace ( common => ../common hwauthz => ../hwauthz + hwdb => ../hwdb hwlocale => ../hwlocale hwutil => ../hwutil telemetry => ../telemetry @@ -64,6 +65,11 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/jzelinskie/stringz v0.0.3 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -101,6 +107,7 @@ require ( github.com/stretchr/testify v1.10.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect + github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect @@ -117,6 +124,7 @@ require ( golang.org/x/crypto v0.30.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect @@ -124,6 +132,7 @@ require ( google.golang.org/protobuf v1.35.2 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + hwdb v0.0.0 // indirect hwlocale v0.0.0 // indirect telemetry v0.0.0 // indirect ) diff --git a/libs/hwtesting/go.sum b/libs/hwtesting/go.sum index dbe5f8feb..6aa8055e4 100644 --- a/libs/hwtesting/go.sum +++ b/libs/hwtesting/go.sum @@ -127,14 +127,16 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= -github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jzelinskie/stringz v0.0.3 h1:0GhG3lVMYrYtIvRbxvQI6zqRTT1P1xyQlpa0FhfUXas= @@ -192,6 +194,8 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -255,6 +259,8 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 h1:EhPtK0mgrgaTMXpegE69hvoSOVC1Ahk8+QJ9B8b+OdU= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0/go.mod h1:5LtFrNEkgzxHvXPO9eOvcXsSn9/KeKYgx9kjeI2oXQI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= diff --git a/libs/telemetry/setup.go b/libs/telemetry/setup.go index aeece465f..ed65c093e 100644 --- a/libs/telemetry/setup.go +++ b/libs/telemetry/setup.go @@ -4,13 +4,10 @@ import ( "context" "errors" "hwutil" - "hwutil/errs" "net/http" "os" "time" - "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/rs/zerolog" @@ -48,8 +45,7 @@ func SetupLogging(mode, rawLevel, service, version string) { log.Info().Msg("Logging is set up") } -func startMetricsServer(ctx context.Context, addr string, shutdown func(error)) { - reg := PrometheusRegistry(ctx) +func startMetricsServer(ctx context.Context, reg *prometheus.Registry, addr string, shutdown func(error)) { server := &http.Server{ Addr: addr, Handler: promhttp.InstrumentMetricHandler( @@ -85,23 +81,11 @@ func startMetricsServer(ctx context.Context, addr string, shutdown func(error)) cancel() // prevent mem leak } -type promRegKey struct{} - -func PrometheusRegistry(ctx context.Context) *prometheus.Registry { - value := ctx.Value(promRegKey{}) - reg, ok := value.(*prometheus.Registry) - if !ok { - panic(errs.NewCastError("*prometheus.Registry", value)) - } - return reg -} - // SetupMetrics will start a new http server for prometheus to scrape from -func SetupMetrics(ctx context.Context, shutdown func(error)) context.Context { +func SetupMetrics(ctx context.Context, shutdown func(error)) *prometheus.Registry { // create new prometheus registry, we do not use the global default one, // as it causes problems with tests prometheusRegistry := prometheus.NewRegistry() - ctx = context.WithValue(ctx, promRegKey{}, prometheusRegistry) l := log.Ctx(ctx) @@ -109,37 +93,11 @@ func SetupMetrics(ctx context.Context, shutdown func(error)) context.Context { if addr == "" { l.Warn().Msg("METRICS_ADDR not set, will not export metrics") - return ctx + return prometheusRegistry } l.Info().Str("addr", addr).Msg("starting metrics server") - go startMetricsServer(ctx, addr, shutdown) - return ctx -} - -// LazyCounter prevents access to PrometheusRegistry, before it is initialized -// by creating the counter only when it is needed -type LazyCounter struct { - opts prometheus.CounterOpts - counter *prometheus.Counter -} - -func NewLazyCounter(opts prometheus.CounterOpts) LazyCounter { - return LazyCounter{ - opts: opts, - counter: nil, - } -} - -func (lc *LazyCounter) Counter(ctx context.Context) prometheus.Counter { - if lc.counter != nil { - return *lc.counter - } - lc.counter = hwutil.PtrTo(promauto.With(PrometheusRegistry(ctx)).NewCounter(lc.opts)) - return *lc.counter -} - -func (lc *LazyCounter) Ensure(ctx context.Context) { - lc.Counter(ctx) + go startMetricsServer(ctx, prometheusRegistry, addr, shutdown) + return prometheusRegistry } diff --git a/services/property-svc/cmd/service/main.go b/services/property-svc/cmd/service/main.go index fa74ba2f9..2c65f003e 100644 --- a/services/property-svc/cmd/service/main.go +++ b/services/property-svc/cmd/service/main.go @@ -35,7 +35,7 @@ func Main(version string, ready func()) { flag.Parse() log.Debug().Bool("replayMode", *replayMode).Msg("flags") - ctx, closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) + db, closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) defer closeDBPool() authz := hwspicedb.NewSpiceDBAuthZ() @@ -89,7 +89,7 @@ func Main(version string, ready func()) { if ready != nil { ready() } - }) + }, common.WithDB(db)) common.Shutdown(nil) } diff --git a/services/property-svc/internal/property-view/api/grpc_test.go b/services/property-svc/internal/property-view/api/grpc_test.go index d631e4a17..a460540ca 100644 --- a/services/property-svc/internal/property-view/api/grpc_test.go +++ b/services/property-svc/internal/property-view/api/grpc_test.go @@ -29,7 +29,13 @@ import ( "google.golang.org/grpc" ) -func server() (context.Context, pb.PropertyViewsServiceClient, *hwes_test.AggregateStore, func()) { +func setup() ( + context.Context, + pb.PropertyViewsServiceClient, + *hwes_test.AggregateStore, + pgxmock.PgxPoolIface, + func(), +) { // Build gRPC service aggregateStore := hwes_test.NewAggregateStore() propertyViewHandlers := handlers.NewPropertyViewHandlers(aggregateStore, test.NewTrueAuthZ()) @@ -37,38 +43,28 @@ func server() (context.Context, pb.PropertyViewsServiceClient, *hwes_test.Aggreg ctx := common.Setup("property-svc", "test", common.WithFakeAuthOnly()) - // Start Server - grpcServer := grpc.NewServer(common.DefaultServerOptions(ctx)...) - pb.RegisterPropertyViewsServiceServer(grpcServer, grpcService) - conn, closer := common_test.StartGRPCServer(ctx, grpcServer) - - client := pb.NewPropertyViewsServiceClient(conn) - - return ctx, client, aggregateStore, closer -} - -func setup() ( - ctx context.Context, - client pb.PropertyViewsServiceClient, - as *hwes_test.AggregateStore, - dbMock pgxmock.PgxPoolIface, - teardown func(), -) { - ctx, client, as, closer := server() - ctx = common_test.AuthenticatedUserContext(ctx, uuid.NewString()) - + // database mock dbMock, err := pgxmock.NewPool() if err != nil { panic(err) } ctx = hwdb.WithDB(ctx, dbMock) - teardown = func() { + // auth + ctx = common_test.AuthenticatedUserContext(ctx, uuid.NewString()) + + // Start Server + grpcServer := grpc.NewServer(common.DefaultServerOptions(ctx)...) + pb.RegisterPropertyViewsServiceServer(grpcServer, grpcService) + conn, closer := common_test.StartGRPCServer(ctx, grpcServer) + client := pb.NewPropertyViewsServiceClient(conn) + + teardown := func() { closer() dbMock.Close() } - return ctx, client, as, dbMock, teardown + return ctx, client, aggregateStore, dbMock, teardown } //nolint:paralleltest diff --git a/services/tasks-svc/go.sum b/services/tasks-svc/go.sum index 2d2d036bc..690d4ec9a 100644 --- a/services/tasks-svc/go.sum +++ b/services/tasks-svc/go.sum @@ -212,6 +212,8 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/services/updates-svc/go.mod b/services/updates-svc/go.mod index c43136086..14f6383c4 100644 --- a/services/updates-svc/go.mod +++ b/services/updates-svc/go.mod @@ -69,6 +69,11 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/jzelinskie/stringz v0.0.3 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -108,6 +113,7 @@ require ( github.com/testcontainers/testcontainers-go/modules/redis v0.34.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect + github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.57.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect @@ -124,6 +130,7 @@ require ( golang.org/x/crypto v0.30.0 // indirect golang.org/x/net v0.32.0 // indirect golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect @@ -133,5 +140,6 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect hwauthz v0.0.0 // indirect + hwdb v0.0.0 // indirect hwlocale v0.0.0 // indirect ) diff --git a/services/updates-svc/go.sum b/services/updates-svc/go.sum index 386c7b474..c0511d4ba 100644 --- a/services/updates-svc/go.sum +++ b/services/updates-svc/go.sum @@ -131,14 +131,16 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= -github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jzelinskie/stringz v0.0.3 h1:0GhG3lVMYrYtIvRbxvQI6zqRTT1P1xyQlpa0FhfUXas= @@ -196,6 +198,8 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -259,6 +263,8 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0 h1:EhPtK0mgrgaTMXpegE69hvoSOVC1Ahk8+QJ9B8b+OdU= +github.com/vgarvardt/pgx-google-uuid/v5 v5.6.0/go.mod h1:5LtFrNEkgzxHvXPO9eOvcXsSn9/KeKYgx9kjeI2oXQI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= diff --git a/services/user-svc/go.sum b/services/user-svc/go.sum index 0d76625f4..dd8a72895 100644 --- a/services/user-svc/go.sum +++ b/services/user-svc/go.sum @@ -194,6 +194,8 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= +github.com/pashagolub/pgxmock/v4 v4.3.0/go.mod h1:9VoVHXwS3XR/yPtKGzwQvwZX1kzGB9sM8SviDcHDa3A= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= From 751b3e3eb7a7b6e35c3c0c392599308186f2228b Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Mon, 23 Dec 2024 23:00:05 +0100 Subject: [PATCH 15/22] ctx --- libs/common/grpc.go | 68 ++++++------------- libs/common/hwgrpc/db_interceptor_test.go | 6 +- libs/common/hwgrpc/panic_interceptor.go | 26 ++++--- libs/common/hwgrpc/panic_interceptor_test.go | 6 +- libs/hwdb/setup.go | 6 +- libs/hwdb/setup_test.go | 2 + libs/telemetry/go.mod | 5 ++ libs/telemetry/go.sum | 10 +++ libs/telemetry/setup.go | 26 ++++++- libs/telemetry/setup_test.go | 50 ++++++++++++++ services/property-svc/cmd/service/main.go | 4 +- .../property-value/models/propertyValue.go | 1 + 12 files changed, 140 insertions(+), 70 deletions(-) create mode 100644 libs/telemetry/setup_test.go diff --git a/libs/common/grpc.go b/libs/common/grpc.go index ce80881cb..76bf5a0f1 100644 --- a/libs/common/grpc.go +++ b/libs/common/grpc.go @@ -7,8 +7,6 @@ import ( "net" "telemetry" - "github.com/prometheus/client_golang/prometheus" - "common/auth" "common/hwgrpc" @@ -35,7 +33,7 @@ import ( // api.RegisterMyServiceServer(grpcServer, &myServiceServer{}) // }) // // cleanup after yourself here -func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook func(*daprd.Server), opts ...DefaultServerOptionsOpt) { +func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook func(*daprd.Server)) { log := zlog.Ctx(ctx) listener, err := net.Listen("tcp", addr) @@ -44,7 +42,7 @@ func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook fun } // dapr/grpc service - service, ok := daprd.NewServiceWithListener(listener, DefaultServerOptions(opts...)...).(*daprd.Server) + service, ok := daprd.NewServiceWithListener(listener, DefaultServerOptions(ctx)...).(*daprd.Server) if !ok { log.Fatal().Msg("dapr service listener is not a *daprd.Server") } @@ -90,13 +88,13 @@ func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook fun // DefaultUnaryInterceptors returns the slice of default interceptors for unary gRPC calls // // chain := grpc.ChainUnaryInterceptor(common.DefaultUnaryInterceptors()...) -func DefaultUnaryInterceptors(opt DefaultServerOptionsOpt) []grpc.UnaryServerInterceptor { +func DefaultUnaryInterceptors(ctx context.Context) []grpc.UnaryServerInterceptor { return []grpc.UnaryServerInterceptor{ - hwgrpc.UnaryPanicRecoverInterceptor(opt.prometheusRegistry), + hwgrpc.UnaryPanicRecoverInterceptor(ctx), hwgrpc.UnaryLoggingInterceptor, hwgrpc.UnaryErrorQualityControlInterceptor, hwgrpc.UnaryLocaleInterceptor, - hwgrpc.UnaryDBInterceptor(opt.db), + hwgrpc.UnaryDBInterceptor(hwdb.GetDB(ctx)), defaultUnaryAuthInterceptor, defaultUnaryOrganizationInterceptor, hwgrpc.UnaryValidateInterceptor, @@ -107,13 +105,13 @@ func DefaultUnaryInterceptors(opt DefaultServerOptionsOpt) []grpc.UnaryServerInt // DefaultStreamInterceptors returns the slice of default interceptors for stream gRPC calls // // chain := grpc.ChainStreamInterceptor(common.DefaultStreamInterceptors()...) -func DefaultStreamInterceptors(opt DefaultServerOptionsOpt) []grpc.StreamServerInterceptor { +func DefaultStreamInterceptors(ctx context.Context) []grpc.StreamServerInterceptor { return []grpc.StreamServerInterceptor{ - hwgrpc.StreamPanicRecoverInterceptor(opt.prometheusRegistry), + hwgrpc.StreamPanicRecoverInterceptor(ctx), hwgrpc.StreamLoggingInterceptor, hwgrpc.StreamErrorQualityControlInterceptor, hwgrpc.StreamLocaleInterceptor, - hwgrpc.StreamDBInterceptor(opt.db), + hwgrpc.StreamDBInterceptor(hwdb.GetDB(ctx)), defaultStreamAuthInterceptor, defaultStreamOrganizationInterceptor, hwgrpc.StreamValidateInterceptor, @@ -121,48 +119,20 @@ func DefaultStreamInterceptors(opt DefaultServerOptionsOpt) []grpc.StreamServerI } } -type DefaultServerOptionsOpt struct { - db hwdb.DBTX - prometheusRegistry *prometheus.Registry -} - -func WithDB(db hwdb.DBTX) DefaultServerOptionsOpt { - return DefaultServerOptionsOpt{db: db} -} - -func WithPrometheusRegistry(registry *prometheus.Registry) DefaultServerOptionsOpt { - return DefaultServerOptionsOpt{prometheusRegistry: registry} -} - -func mergeDefaultServerOptionsOpts(opts []DefaultServerOptionsOpt) DefaultServerOptionsOpt { - res := DefaultServerOptionsOpt{} - for _, opt := range opts { - if opt.db != nil { - res.db = opt.db - } - if opt.prometheusRegistry != nil { - res.prometheusRegistry = opt.prometheusRegistry - } - } - return res -} - -func DefaultServerOptions(opts ...DefaultServerOptionsOpt) []grpc.ServerOption { - opt := mergeDefaultServerOptionsOpts(opts) - +// TODO: document expected values in context +func DefaultServerOptions(ctx context.Context) []grpc.ServerOption { // default interceptors - unaryInterceptors := DefaultUnaryInterceptors(opt) - streamInterceptors := DefaultStreamInterceptors(opt) + unaryInterceptors := DefaultUnaryInterceptors(ctx) + streamInterceptors := DefaultStreamInterceptors(ctx) - // register new metrics collector with prometheus, if registry provided - if promRegistry := opt.prometheusRegistry; promRegistry != nil { - metrics := prometheusGrpcProvider.NewServerMetrics() - promRegistry.MustRegister(metrics) + // register new metrics collector with prometheus + promRegistry := telemetry.PrometheusRegistry(ctx) + metrics := prometheusGrpcProvider.NewServerMetrics() + promRegistry.MustRegister(metrics) - // prepend metrics interceptor - unaryInterceptors = hwutil.Prepend(metrics.UnaryServerInterceptor(), unaryInterceptors) - streamInterceptors = hwutil.Prepend(metrics.StreamServerInterceptor(), streamInterceptors) - } + // prepend metrics interceptor + unaryInterceptors = hwutil.Prepend(metrics.UnaryServerInterceptor(), unaryInterceptors) + streamInterceptors = hwutil.Prepend(metrics.StreamServerInterceptor(), streamInterceptors) // create chains unaryInterceptorChain := grpc.ChainUnaryInterceptor(unaryInterceptors...) diff --git a/libs/common/hwgrpc/db_interceptor_test.go b/libs/common/hwgrpc/db_interceptor_test.go index 294aa6e66..e3bad11c3 100644 --- a/libs/common/hwgrpc/db_interceptor_test.go +++ b/libs/common/hwgrpc/db_interceptor_test.go @@ -30,6 +30,8 @@ func TestDBInterceptor(t *testing.T) { "missing db": { db: nil, handler: func(t *testing.T, ctx context.Context) { + t.Helper() + // GetDB will not work require.Panics(t, func() { hwdb.GetDB(ctx) @@ -39,6 +41,8 @@ func TestDBInterceptor(t *testing.T) { "existing db": { db: existingDB, handler: func(t *testing.T, ctx context.Context) { + t.Helper() + require.Equal(t, existingDB, hwdb.GetDB(ctx)) }, }, @@ -95,7 +99,7 @@ func TestDBInterceptor(t *testing.T) { type fakeServerStream struct { grpc.ServerStream - ctx context.Context + ctx context.Context //nolint:containedctx } func (f *fakeServerStream) Context() context.Context { diff --git a/libs/common/hwgrpc/panic_interceptor.go b/libs/common/hwgrpc/panic_interceptor.go index 8ab70a534..c8ac09655 100644 --- a/libs/common/hwgrpc/panic_interceptor.go +++ b/libs/common/hwgrpc/panic_interceptor.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "runtime/debug" + "telemetry" "common/hwerr" "common/locale" @@ -37,25 +38,30 @@ func recoveryHandlerFn() recovery.RecoveryHandlerFuncContext { } } -func ensureCounter(registry *prometheus.Registry) { - if registry != nil { - panicsRecovered = promauto.With(registry).NewCounter(prometheus.CounterOpts{ - Name: "services_panics_recovered_total", - Help: "Total number of panics recovered by PanicRecoverInterceptor", - }) +func ensureCounter(ctx context.Context) { + registry := telemetry.PrometheusRegistry(ctx) + if registry == nil { // prometheus not set up + return } + + // TODO: what if the counter already exists, and has values? + // TODO: when this is not called, nil-pointer issues will arise + panicsRecovered = promauto.With(registry).NewCounter(prometheus.CounterOpts{ + Name: "services_panics_recovered_total", + Help: "Total number of panics recovered by PanicRecoverInterceptor", + }) } -func UnaryPanicRecoverInterceptor(registry *prometheus.Registry) grpc.UnaryServerInterceptor { - ensureCounter(registry) +func UnaryPanicRecoverInterceptor(ctx context.Context) grpc.UnaryServerInterceptor { + ensureCounter(ctx) return recovery.UnaryServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), ) } -func StreamPanicRecoverInterceptor(registry *prometheus.Registry) grpc.StreamServerInterceptor { - ensureCounter(registry) +func StreamPanicRecoverInterceptor(ctx context.Context) grpc.StreamServerInterceptor { + ensureCounter(ctx) return recovery.StreamServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), diff --git a/libs/common/hwgrpc/panic_interceptor_test.go b/libs/common/hwgrpc/panic_interceptor_test.go index 62acc79dc..cc6618eb6 100644 --- a/libs/common/hwgrpc/panic_interceptor_test.go +++ b/libs/common/hwgrpc/panic_interceptor_test.go @@ -38,13 +38,13 @@ type RecoverySuite struct { func TestPanicRecoverInterceptor(t *testing.T) { t.Parallel() - registry := telemetry.SetupMetrics(context.Background(), nil) + ctx := telemetry.SetupMetrics(context.Background(), nil) s := &RecoverySuite{ InterceptorTestSuite: &testpb.InterceptorTestSuite{ TestService: &recoveryAssertService{TestServiceServer: &testpb.TestPingService{}}, ServerOpts: []grpc.ServerOption{ - grpc.StreamInterceptor(StreamPanicRecoverInterceptor(registry)), - grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor(registry)), + grpc.StreamInterceptor(StreamPanicRecoverInterceptor(ctx)), + grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor(ctx)), }, }, } diff --git a/libs/hwdb/setup.go b/libs/hwdb/setup.go index a961cec0b..cc79c0670 100644 --- a/libs/hwdb/setup.go +++ b/libs/hwdb/setup.go @@ -35,7 +35,7 @@ type DBTX interface { // POSTGRES_PORT (5432) // // SetupDatabaseFromEnv returns a close function, which has to be called in order to shut down the database cleanly -func SetupDatabaseFromEnv(ctx context.Context) (DBTX, func()) { +func SetupDatabaseFromEnv(ctx context.Context) (context.Context, func()) { log.Info().Msg("connecting to postgres ...") dsn := hwutil.GetEnvOr("POSTGRES_DSN", "") @@ -49,9 +49,11 @@ func SetupDatabaseFromEnv(ctx context.Context) (DBTX, func()) { log.Fatal().Err(err).Msg("could not connect to database") } + ctx = WithDB(ctx, dbpool) + log.Info().Msg("connected to postgres") - return dbpool, func() { + return ctx, func() { log.Info().Msg("closing db pool") dbpool.Close() } diff --git a/libs/hwdb/setup_test.go b/libs/hwdb/setup_test.go index ffb45fa5e..11fa65f7d 100644 --- a/libs/hwdb/setup_test.go +++ b/libs/hwdb/setup_test.go @@ -9,6 +9,8 @@ import ( ) func TestContextFunctions(t *testing.T) { + t.Parallel() + dbMock, err := pgxmock.NewPool() if err != nil { panic(err) diff --git a/libs/telemetry/go.mod b/libs/telemetry/go.mod index 577d61688..267d06fa3 100644 --- a/libs/telemetry/go.mod +++ b/libs/telemetry/go.mod @@ -8,6 +8,7 @@ require ( github.com/fatih/structs v1.1.0 github.com/prometheus/client_golang v1.20.5 github.com/rs/zerolog v1.33.0 + github.com/stretchr/testify v1.10.0 go.opentelemetry.io/otel v1.32.0 go.opentelemetry.io/otel/trace v1.32.0 hwutil v0.0.0 @@ -16,6 +17,7 @@ require ( require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -24,10 +26,12 @@ require ( github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/klauspost/compress v1.17.9 // indirect + github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect @@ -37,4 +41,5 @@ require ( golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/libs/telemetry/go.sum b/libs/telemetry/go.sum index 24afa1614..5754cdd78 100644 --- a/libs/telemetry/go.sum +++ b/libs/telemetry/go.sum @@ -3,6 +3,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= @@ -29,6 +30,10 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -51,6 +56,8 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -75,5 +82,8 @@ golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/libs/telemetry/setup.go b/libs/telemetry/setup.go index ed65c093e..8e1563826 100644 --- a/libs/telemetry/setup.go +++ b/libs/telemetry/setup.go @@ -82,10 +82,11 @@ func startMetricsServer(ctx context.Context, reg *prometheus.Registry, addr stri } // SetupMetrics will start a new http server for prometheus to scrape from -func SetupMetrics(ctx context.Context, shutdown func(error)) *prometheus.Registry { +func SetupMetrics(ctx context.Context, shutdown func(error)) context.Context { // create new prometheus registry, we do not use the global default one, // as it causes problems with tests prometheusRegistry := prometheus.NewRegistry() + ctx = WithPrometheusRegistry(ctx, prometheusRegistry) l := log.Ctx(ctx) @@ -93,11 +94,30 @@ func SetupMetrics(ctx context.Context, shutdown func(error)) *prometheus.Registr if addr == "" { l.Warn().Msg("METRICS_ADDR not set, will not export metrics") - return prometheusRegistry + return ctx } l.Info().Str("addr", addr).Msg("starting metrics server") go startMetricsServer(ctx, prometheusRegistry, addr, shutdown) - return prometheusRegistry + return ctx +} + +type promRegKey struct{} + +func WithPrometheusRegistry(ctx context.Context, registry *prometheus.Registry) context.Context { + return context.WithValue(ctx, promRegKey{}, registry) +} + +var ErrPrometheusRegistryMissing = errors.New("PrometheusRegistry called, but no (valid) registry in context") + +func PrometheusRegistry(ctx context.Context) *prometheus.Registry { + value := ctx.Value(promRegKey{}) + asReg, ok := value.(*prometheus.Registry) + + // we allow nil (which will not be ok), else panic + if value != nil && !ok { + panic(ErrPrometheusRegistryMissing) + } + return asReg } diff --git a/libs/telemetry/setup_test.go b/libs/telemetry/setup_test.go new file mode 100644 index 000000000..c5a96fe84 --- /dev/null +++ b/libs/telemetry/setup_test.go @@ -0,0 +1,50 @@ +package telemetry + +import ( + "context" + "testing" + + "github.com/prometheus/client_golang/prometheus" + "github.com/stretchr/testify/require" +) + +func TestPrometheusRegistry(t *testing.T) { + t.Parallel() + + defaultContext := context.Background() + + testCases := []struct { + name string + useDefault bool + registry *prometheus.Registry + }{ + { + name: "not calling WithPrometheusRegistry", + useDefault: true, + registry: nil, + }, + { + name: "setting nil registry", + useDefault: false, + registry: nil, + }, + { + name: "setting valid registry", + useDefault: false, + registry: prometheus.NewRegistry(), + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + ctx := defaultContext + if !testCase.useDefault { + ctx = WithPrometheusRegistry(ctx, testCase.registry) + } + + require.Equal(t, testCase.registry, PrometheusRegistry(ctx)) + }) + } +} diff --git a/services/property-svc/cmd/service/main.go b/services/property-svc/cmd/service/main.go index 2c65f003e..fa74ba2f9 100644 --- a/services/property-svc/cmd/service/main.go +++ b/services/property-svc/cmd/service/main.go @@ -35,7 +35,7 @@ func Main(version string, ready func()) { flag.Parse() log.Debug().Bool("replayMode", *replayMode).Msg("flags") - db, closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) + ctx, closeDBPool := hwdb.SetupDatabaseFromEnv(ctx) defer closeDBPool() authz := hwspicedb.NewSpiceDBAuthZ() @@ -89,7 +89,7 @@ func Main(version string, ready func()) { if ready != nil { ready() } - }, common.WithDB(db)) + }) common.Shutdown(nil) } diff --git a/services/property-svc/internal/property-value/models/propertyValue.go b/services/property-svc/internal/property-value/models/propertyValue.go index 2c4f77764..b6f08d6d1 100644 --- a/services/property-svc/internal/property-value/models/propertyValue.go +++ b/services/property-svc/internal/property-value/models/propertyValue.go @@ -1,6 +1,7 @@ package models import ( + "errors" "fmt" pb "gen/services/property_svc/v1" "hwdb" From fe5da650698784d5d0df6648c7a5ed27ae60370d Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Thu, 26 Dec 2024 13:08:31 +0100 Subject: [PATCH 16/22] this wont work --- libs/common/hwgrpc/panic_interceptor.go | 41 ++++++++++++------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/libs/common/hwgrpc/panic_interceptor.go b/libs/common/hwgrpc/panic_interceptor.go index c8ac09655..8c30e55bf 100644 --- a/libs/common/hwgrpc/panic_interceptor.go +++ b/libs/common/hwgrpc/panic_interceptor.go @@ -19,10 +19,19 @@ import ( "google.golang.org/grpc/codes" ) -// TODO: remove global state -var panicsRecovered prometheus.Counter +func newPanicsRecoveredCounter(ctx context.Context) prometheus.Counter { + registry := telemetry.PrometheusRegistry(ctx) + if registry == nil { // prometheus not set up + return nil // TODO: replace with a no-op to prevent nil handling + } -func recoveryHandlerFn() recovery.RecoveryHandlerFuncContext { + return promauto.With(registry).NewCounter(prometheus.CounterOpts{ + Name: "services_panics_recovered_total", + Help: "Total number of panics recovered by PanicRecoverInterceptor", + }) +} + +func recoveryHandlerFn(panicsRecovered prometheus.Counter) recovery.RecoveryHandlerFuncContext { return func(ctx context.Context, recovered any) (err error) { zlog.Ctx(ctx). Error(). @@ -32,38 +41,26 @@ func recoveryHandlerFn() recovery.RecoveryHandlerFuncContext { _, _ = fmt.Fprintln(os.Stderr, string(debug.Stack())) - panicsRecovered.Inc() + if panicsRecovered != nil { + panicsRecovered.Inc() + } return hwerr.NewStatusError(ctx, codes.Internal, "panic recovered", locale.GenericError(ctx)) } } -func ensureCounter(ctx context.Context) { - registry := telemetry.PrometheusRegistry(ctx) - if registry == nil { // prometheus not set up - return - } - - // TODO: what if the counter already exists, and has values? - // TODO: when this is not called, nil-pointer issues will arise - panicsRecovered = promauto.With(registry).NewCounter(prometheus.CounterOpts{ - Name: "services_panics_recovered_total", - Help: "Total number of panics recovered by PanicRecoverInterceptor", - }) -} - func UnaryPanicRecoverInterceptor(ctx context.Context) grpc.UnaryServerInterceptor { - ensureCounter(ctx) + panicsRecovered := newPanicsRecoveredCounter(ctx) return recovery.UnaryServerInterceptor( - recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), + recovery.WithRecoveryHandlerContext(recoveryHandlerFn(panicsRecovered)), ) } func StreamPanicRecoverInterceptor(ctx context.Context) grpc.StreamServerInterceptor { - ensureCounter(ctx) + panicsRecovered := newPanicsRecoveredCounter(ctx) return recovery.StreamServerInterceptor( - recovery.WithRecoveryHandlerContext(recoveryHandlerFn()), + recovery.WithRecoveryHandlerContext(recoveryHandlerFn(panicsRecovered)), ) } From 56382a2cb04f388280b06c3712c605ded09d4d55 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 27 Dec 2024 12:42:15 +0100 Subject: [PATCH 17/22] prepare rename --- libs/common/grpc.go | 17 +++++++++++------ libs/common/hwgrpc/panic_interceptor.go | 10 +++------- libs/common/hwgrpc/panic_interceptor_test.go | 5 +++-- libs/hwdb/setup.go | 19 +++++++++++++++---- .../property_rules_postgres_test.go | 2 +- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/libs/common/grpc.go b/libs/common/grpc.go index 76bf5a0f1..ac328471b 100644 --- a/libs/common/grpc.go +++ b/libs/common/grpc.go @@ -7,6 +7,8 @@ import ( "net" "telemetry" + "github.com/prometheus/client_golang/prometheus" + "common/auth" "common/hwgrpc" @@ -88,9 +90,9 @@ func StartNewGRPCServer(ctx context.Context, addr string, registerServerHook fun // DefaultUnaryInterceptors returns the slice of default interceptors for unary gRPC calls // // chain := grpc.ChainUnaryInterceptor(common.DefaultUnaryInterceptors()...) -func DefaultUnaryInterceptors(ctx context.Context) []grpc.UnaryServerInterceptor { +func DefaultUnaryInterceptors(ctx context.Context, panicsRecovered prometheus.Counter) []grpc.UnaryServerInterceptor { return []grpc.UnaryServerInterceptor{ - hwgrpc.UnaryPanicRecoverInterceptor(ctx), + hwgrpc.UnaryPanicRecoverInterceptor(panicsRecovered), hwgrpc.UnaryLoggingInterceptor, hwgrpc.UnaryErrorQualityControlInterceptor, hwgrpc.UnaryLocaleInterceptor, @@ -105,9 +107,9 @@ func DefaultUnaryInterceptors(ctx context.Context) []grpc.UnaryServerInterceptor // DefaultStreamInterceptors returns the slice of default interceptors for stream gRPC calls // // chain := grpc.ChainStreamInterceptor(common.DefaultStreamInterceptors()...) -func DefaultStreamInterceptors(ctx context.Context) []grpc.StreamServerInterceptor { +func DefaultStreamInterceptors(ctx context.Context, panicsRecovered prometheus.Counter) []grpc.StreamServerInterceptor { return []grpc.StreamServerInterceptor{ - hwgrpc.StreamPanicRecoverInterceptor(ctx), + hwgrpc.StreamPanicRecoverInterceptor(panicsRecovered), hwgrpc.StreamLoggingInterceptor, hwgrpc.StreamErrorQualityControlInterceptor, hwgrpc.StreamLocaleInterceptor, @@ -121,9 +123,12 @@ func DefaultStreamInterceptors(ctx context.Context) []grpc.StreamServerIntercept // TODO: document expected values in context func DefaultServerOptions(ctx context.Context) []grpc.ServerOption { + // counters + panicsRecovered := hwgrpc.NewPanicsRecoveredCounter(ctx) + // default interceptors - unaryInterceptors := DefaultUnaryInterceptors(ctx) - streamInterceptors := DefaultStreamInterceptors(ctx) + unaryInterceptors := DefaultUnaryInterceptors(ctx, panicsRecovered) + streamInterceptors := DefaultStreamInterceptors(ctx, panicsRecovered) // register new metrics collector with prometheus promRegistry := telemetry.PrometheusRegistry(ctx) diff --git a/libs/common/hwgrpc/panic_interceptor.go b/libs/common/hwgrpc/panic_interceptor.go index 8c30e55bf..22fdd5a75 100644 --- a/libs/common/hwgrpc/panic_interceptor.go +++ b/libs/common/hwgrpc/panic_interceptor.go @@ -19,7 +19,7 @@ import ( "google.golang.org/grpc/codes" ) -func newPanicsRecoveredCounter(ctx context.Context) prometheus.Counter { +func NewPanicsRecoveredCounter(ctx context.Context) prometheus.Counter { registry := telemetry.PrometheusRegistry(ctx) if registry == nil { // prometheus not set up return nil // TODO: replace with a no-op to prevent nil handling @@ -49,17 +49,13 @@ func recoveryHandlerFn(panicsRecovered prometheus.Counter) recovery.RecoveryHand } } -func UnaryPanicRecoverInterceptor(ctx context.Context) grpc.UnaryServerInterceptor { - panicsRecovered := newPanicsRecoveredCounter(ctx) - +func UnaryPanicRecoverInterceptor(panicsRecovered prometheus.Counter) grpc.UnaryServerInterceptor { return recovery.UnaryServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn(panicsRecovered)), ) } -func StreamPanicRecoverInterceptor(ctx context.Context) grpc.StreamServerInterceptor { - panicsRecovered := newPanicsRecoveredCounter(ctx) - +func StreamPanicRecoverInterceptor(panicsRecovered prometheus.Counter) grpc.StreamServerInterceptor { return recovery.StreamServerInterceptor( recovery.WithRecoveryHandlerContext(recoveryHandlerFn(panicsRecovered)), ) diff --git a/libs/common/hwgrpc/panic_interceptor_test.go b/libs/common/hwgrpc/panic_interceptor_test.go index cc6618eb6..d1d5844b8 100644 --- a/libs/common/hwgrpc/panic_interceptor_test.go +++ b/libs/common/hwgrpc/panic_interceptor_test.go @@ -39,12 +39,13 @@ type RecoverySuite struct { func TestPanicRecoverInterceptor(t *testing.T) { t.Parallel() ctx := telemetry.SetupMetrics(context.Background(), nil) + counter := NewPanicsRecoveredCounter(ctx) s := &RecoverySuite{ InterceptorTestSuite: &testpb.InterceptorTestSuite{ TestService: &recoveryAssertService{TestServiceServer: &testpb.TestPingService{}}, ServerOpts: []grpc.ServerOption{ - grpc.StreamInterceptor(StreamPanicRecoverInterceptor(ctx)), - grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor(ctx)), + grpc.StreamInterceptor(StreamPanicRecoverInterceptor(counter)), + grpc.UnaryInterceptor(UnaryPanicRecoverInterceptor(counter)), }, }, } diff --git a/libs/hwdb/setup.go b/libs/hwdb/setup.go index cc79c0670..dba65162b 100644 --- a/libs/hwdb/setup.go +++ b/libs/hwdb/setup.go @@ -2,6 +2,7 @@ package hwdb import ( "context" + "errors" "fmt" "hwutil" "hwutil/errs" @@ -111,11 +112,21 @@ func WithDB(ctx context.Context, pool DBTX) context.Context { func GetDB(ctx context.Context) DBTX { value := ctx.Value(dbKey{}) db, ok := value.(DBTX) - if db == nil || !ok { - log.Error(). - Msg("GetDB called without set-up database, you will run into nil-pointers. " + - "Make sure to call SetupDatabaseFromEnv()!") + // TODO: explain + if db != nil && !ok { panic(errs.NewCastError("DBTX", value)) } return db } + +var ErrDBMissing = errors.New("MustGetDB() called without set-up database, use hwdb.WithDB()") + +func MustGetDB2(ctx context.Context) DBTX { + if db := GetDB(ctx); db != nil { + return db + } + + log.Error().Err(ErrDBMissing).Send() + panic(ErrDBMissing) + +} diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go index f12545a85..d6116d9f2 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres_test.go @@ -42,7 +42,7 @@ func setup() (ctx context.Context, projection *Projection, dbMock pgxmock.PgxPoo if err != nil { panic(err) } - ctx = hwdb.WithDB(ctx, dbMock) + ctx = hwdb.WithDB(context.Background(), dbMock) teardown = dbMock.Close projection = NewProjection(ctx, esClientStub{}, "testing") From 4bbe104018f1150934dcd86fe032d31a5be4a749 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 27 Dec 2024 12:59:01 +0100 Subject: [PATCH 18/22] MustGetDB --- libs/common/hwgrpc/db_interceptor_test.go | 9 ++- libs/hwdb/setup.go | 3 +- libs/hwdb/setup_test.go | 68 +++++++++++++++++-- services/property-svc/cmd/service/main.go | 4 +- services/property-svc/cmd/service/replay.go | 2 +- .../commands/v1/attach_property_value.go | 2 +- .../v1/get_property_values_by_subject_id.go | 2 +- .../models/patient_property_matcher.go | 6 +- .../models/task_property_matchers.go | 6 +- .../property_rules_postgres.go | 6 +- .../v1/get_properties_by_subject_type.go | 2 +- .../property/queries/v1/get_property_by_id.go | 2 +- services/tasks-svc/internal/bed/bed.go | 14 ++-- .../tasks-svc/internal/patient/api/grpc.go | 4 +- .../patient_postgres_projection.go | 2 +- .../v1/get_all_patients_with_details.go | 2 +- .../v1/get_patient_assignment_by_ward.go | 2 +- .../patient/queries/v1/get_patient_by_bed.go | 2 +- .../v1/get_patient_with_details_by_id.go | 2 +- .../queries/v1/get_patients_by_ward.go | 2 +- services/tasks-svc/internal/room/room.go | 12 ++-- .../internal/task-template/task_template.go | 16 ++--- .../task_postgres_projection.go | 2 +- .../queries/v1/get_task_with_patient_by_id.go | 2 +- .../task/queries/v1/get_tasks_by_patient.go | 2 +- .../v1/get_tasks_with_patients_by_asignee.go | 2 +- services/tasks-svc/internal/ward/ward.go | 16 ++--- .../internal/organization/organization.go | 30 ++++---- services/user-svc/internal/user/user.go | 4 +- 29 files changed, 145 insertions(+), 83 deletions(-) diff --git a/libs/common/hwgrpc/db_interceptor_test.go b/libs/common/hwgrpc/db_interceptor_test.go index e3bad11c3..cea60743b 100644 --- a/libs/common/hwgrpc/db_interceptor_test.go +++ b/libs/common/hwgrpc/db_interceptor_test.go @@ -32,9 +32,12 @@ func TestDBInterceptor(t *testing.T) { handler: func(t *testing.T, ctx context.Context) { t.Helper() - // GetDB will not work + // GetDB will return nil + require.Nil(t, hwdb.GetDB(ctx)) + + // MustGetDB will not work require.Panics(t, func() { - hwdb.GetDB(ctx) + hwdb.MustGetDB(ctx) }) }, }, @@ -43,7 +46,7 @@ func TestDBInterceptor(t *testing.T) { handler: func(t *testing.T, ctx context.Context) { t.Helper() - require.Equal(t, existingDB, hwdb.GetDB(ctx)) + require.Equal(t, existingDB, hwdb.MustGetDB(ctx)) }, }, } diff --git a/libs/hwdb/setup.go b/libs/hwdb/setup.go index dba65162b..eb5a743d8 100644 --- a/libs/hwdb/setup.go +++ b/libs/hwdb/setup.go @@ -121,12 +121,11 @@ func GetDB(ctx context.Context) DBTX { var ErrDBMissing = errors.New("MustGetDB() called without set-up database, use hwdb.WithDB()") -func MustGetDB2(ctx context.Context) DBTX { +func MustGetDB(ctx context.Context) DBTX { if db := GetDB(ctx); db != nil { return db } log.Error().Err(ErrDBMissing).Send() panic(ErrDBMissing) - } diff --git a/libs/hwdb/setup_test.go b/libs/hwdb/setup_test.go index 11fa65f7d..fa987e15a 100644 --- a/libs/hwdb/setup_test.go +++ b/libs/hwdb/setup_test.go @@ -8,13 +8,73 @@ import ( "github.com/stretchr/testify/require" ) -func TestContextFunctions(t *testing.T) { +func TestMustGetDB(t *testing.T) { t.Parallel() - dbMock, err := pgxmock.NewPool() + t.Run("Green", func(t *testing.T) { + t.Parallel() + + dbMock, err := pgxmock.NewPool() + if err != nil { + panic(err) + } + + ctx := WithDB(context.Background(), dbMock) + require.Equal(t, dbMock, MustGetDB(ctx)) + }) + + t.Run("Panic", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + require.Panics(t, func() { + _ = MustGetDB(ctx) + }) + }) +} + +func TestGetDB(t *testing.T) { + t.Parallel() + + defaultContext := context.Background() + + validDB, err := pgxmock.NewPool() if err != nil { panic(err) } - ctx := WithDB(context.Background(), dbMock) - require.Equal(t, dbMock, GetDB(ctx)) + + testCases := []struct { + name string + useDefault bool + db DBTX + }{ + { + name: "not calling WithDB", + useDefault: true, + db: nil, + }, + { + name: "setting nil db", + useDefault: false, + db: nil, + }, + { + name: "setting valid db", + useDefault: false, + db: validDB, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + ctx := defaultContext + if !testCase.useDefault { + ctx = WithDB(ctx, testCase.db) + } + + require.Equal(t, testCase.db, GetDB(ctx)) + }) + } } diff --git a/services/property-svc/cmd/service/main.go b/services/property-svc/cmd/service/main.go index fa74ba2f9..2c9c765a2 100644 --- a/services/property-svc/cmd/service/main.go +++ b/services/property-svc/cmd/service/main.go @@ -56,8 +56,8 @@ func Main(version string, ready func()) { common.Shutdown, propertySpiceDBProjection.NewProjection(eventStore, ServiceName, authz), propertySetSpiceDBProjection.NewProjection(eventStore, ServiceName, authz), - propertyPostgresProjection.NewProjection(eventStore, ServiceName, hwdb.GetDB(ctx)), - property_value_postgres_projection.NewProjection(eventStore, ServiceName, hwdb.GetDB(ctx)), + propertyPostgresProjection.NewProjection(eventStore, ServiceName, hwdb.MustGetDB(ctx)), + property_value_postgres_projection.NewProjection(eventStore, ServiceName, hwdb.MustGetDB(ctx)), property_rules_postgres.NewProjection(ctx, eventStore, ServiceName), ) diff --git a/services/property-svc/cmd/service/replay.go b/services/property-svc/cmd/service/replay.go index daf86a94f..caf49c637 100644 --- a/services/property-svc/cmd/service/replay.go +++ b/services/property-svc/cmd/service/replay.go @@ -24,7 +24,7 @@ func replay(ctx context.Context, eventStore *esdb.Client) error { log.Info().Msg("starting in replay mode") - db := hwdb.GetDB(ctx) + db := hwdb.MustGetDB(ctx) tx, rollback, err := hwdb.BeginTx(db, ctx) if err != nil { return fmt.Errorf("cannot begin transaction: %w", err) diff --git a/services/property-svc/internal/property-value/commands/v1/attach_property_value.go b/services/property-svc/internal/property-value/commands/v1/attach_property_value.go index 1d77bcc2e..d630d62f6 100644 --- a/services/property-svc/internal/property-value/commands/v1/attach_property_value.go +++ b/services/property-svc/internal/property-value/commands/v1/attach_property_value.go @@ -42,7 +42,7 @@ func NewAttachPropertyValueCommandHandler( return 0, err } - propertyValueRepo := property_value_repo.New(hwdb.GetDB(ctx)) + propertyValueRepo := property_value_repo.New(hwdb.MustGetDB(ctx)) var a *aggregate.PropertyValueAggregate query := hwdb.Optional(propertyValueRepo.GetPropertyValueBySubjectIDAndPropertyID) diff --git a/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go b/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go index 7b23e71f9..d8de63e46 100644 --- a/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go +++ b/services/property-svc/internal/property-value/queries/v1/get_property_values_by_subject_id.go @@ -33,7 +33,7 @@ func NewGetRelevantPropertyValuesQueryHandler( ) GetRelevantPropertyValuesQueryHandler { return func(ctx context.Context, matcher viewModels.PropertyMatchers) ([]models.PropertyAndValue, error) { viewHandlers := vh.NewPropertyViewHandlers(as, authz) - propertyValueRepo := property_value_repo.New(hwdb.GetDB(ctx)) + propertyValueRepo := property_value_repo.New(hwdb.MustGetDB(ctx)) subjectID, err := matcher.GetSubjectID() if err != nil { diff --git a/services/property-svc/internal/property-view/models/patient_property_matcher.go b/services/property-svc/internal/property-view/models/patient_property_matcher.go index 18bd9fd45..6b1215a90 100644 --- a/services/property-svc/internal/property-view/models/patient_property_matcher.go +++ b/services/property-svc/internal/property-view/models/patient_property_matcher.go @@ -23,7 +23,7 @@ type PatientPropertyMatchers struct { } func (m PatientPropertyMatchers) FindExactRuleID(ctx context.Context) (*uuid.UUID, error) { - patientViews := patient_views_repo.New(hwdb.GetDB(ctx)) + patientViews := patient_views_repo.New(hwdb.MustGetDB(ctx)) return hwdb.Optional(patientViews.GetPatientRuleIdUsingExactMatchers)(ctx, patient_views_repo.GetPatientRuleIdUsingExactMatchersParams{ WardID: m.WardID, @@ -52,7 +52,7 @@ func (m PatientPropertyMatchers) GetType() string { } func (m PatientPropertyMatchers) QueryProperties(ctx context.Context) ([]PropertiesQueryRow, error) { - patientViews := patient_views_repo.New(hwdb.GetDB(ctx)) + patientViews := patient_views_repo.New(hwdb.MustGetDB(ctx)) rows, err := patientViews.GetPatientPropertiesUsingMatchers( ctx, @@ -96,7 +96,7 @@ func (m PatientPropertyMatchers) ToMap() map[string]interface{} { } func (m PatientPropertyMatchers) IsPropertyAlwaysIncluded(ctx context.Context, propertyID uuid.UUID) (bool, error) { - repo := patient_views_repo.New(hwdb.GetDB(ctx)) + repo := patient_views_repo.New(hwdb.MustGetDB(ctx)) query := hwdb.Optional(repo.IsPatientPropertyAlwaysIncluded) alwaysInclude, err := query(ctx, patient_views_repo.IsPatientPropertyAlwaysIncludedParams{ PropertyID: propertyID, diff --git a/services/property-svc/internal/property-view/models/task_property_matchers.go b/services/property-svc/internal/property-view/models/task_property_matchers.go index 5926e0de4..0445fd44d 100644 --- a/services/property-svc/internal/property-view/models/task_property_matchers.go +++ b/services/property-svc/internal/property-view/models/task_property_matchers.go @@ -24,7 +24,7 @@ type TaskPropertyMatchers struct { } func (m TaskPropertyMatchers) FindExactRuleID(ctx context.Context) (*uuid.UUID, error) { - taskViews := task_views_repo.New(hwdb.GetDB(ctx)) + taskViews := task_views_repo.New(hwdb.MustGetDB(ctx)) return hwdb.Optional(taskViews.GetTaskRuleIdUsingExactMatchers)(ctx, task_views_repo.GetTaskRuleIdUsingExactMatchersParams{ WardID: m.WardID, @@ -53,7 +53,7 @@ func (m TaskPropertyMatchers) GetType() string { } func (m TaskPropertyMatchers) QueryProperties(ctx context.Context) ([]PropertiesQueryRow, error) { - taskViews := task_views_repo.New(hwdb.GetDB(ctx)) + taskViews := task_views_repo.New(hwdb.MustGetDB(ctx)) rows, err := taskViews.GetTaskPropertiesUsingMatchers(ctx, task_views_repo.GetTaskPropertiesUsingMatchersParams{ WardID: m.WardID, @@ -95,7 +95,7 @@ func (m TaskPropertyMatchers) ToMap() map[string]interface{} { } func (m TaskPropertyMatchers) IsPropertyAlwaysIncluded(ctx context.Context, propertyID uuid.UUID) (bool, error) { - repo := task_views_repo.New(hwdb.GetDB(ctx)) + repo := task_views_repo.New(hwdb.MustGetDB(ctx)) query := hwdb.Optional(repo.IsTaskPropertyAlwaysIncluded) alwaysInclude, err := query(ctx, task_views_repo.IsTaskPropertyAlwaysIncludedParams{ PropertyID: propertyID, diff --git a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go index 331ef7929..0598d3bbf 100644 --- a/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go +++ b/services/property-svc/internal/property-view/projections/property_rules_postgres/property_rules_postgres.go @@ -39,9 +39,9 @@ func NewProjection(ctx context.Context, es custom.EventStoreClient, serviceName subscriptionGroupName, &[]string{aggregate.PropertyViewRuleAggregateType + "-"}, ), - db: hwdb.GetDB(ctx), - taskViewsRepo: task_views_repo.New(hwdb.GetDB(ctx)), - viewsRepo: views_repo.New(hwdb.GetDB(ctx)), + db: hwdb.MustGetDB(ctx), + taskViewsRepo: task_views_repo.New(hwdb.MustGetDB(ctx)), + viewsRepo: views_repo.New(hwdb.MustGetDB(ctx)), } p.initEventListeners() return p diff --git a/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go b/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go index c9fd47cee..20c374deb 100644 --- a/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go +++ b/services/property-svc/internal/property/queries/v1/get_properties_by_subject_type.go @@ -25,7 +25,7 @@ func NewGetPropertiesQueryHandler(authz hwauthz.AuthZ) GetPropertiesQueryHandler return func(ctx context.Context, subjectType *pb.SubjectType) ([]*models.PropertyWithConsistency, error) { user := commonPerm.UserFromCtx(ctx) - propertyRepo := property_repo.New(hwdb.GetDB(ctx)) + propertyRepo := property_repo.New(hwdb.MustGetDB(ctx)) var subjectTypeID *int32 if subjectType != nil { diff --git a/services/property-svc/internal/property/queries/v1/get_property_by_id.go b/services/property-svc/internal/property/queries/v1/get_property_by_id.go index 93effbe10..5dfe36d86 100644 --- a/services/property-svc/internal/property/queries/v1/get_property_by_id.go +++ b/services/property-svc/internal/property/queries/v1/get_property_by_id.go @@ -31,7 +31,7 @@ func NewGetPropertyByIDQueryHandler(authz hwauthz.AuthZ) GetPropertyByIDQueryHan return nil, 0, err } - propertyRepo := property_repo.New(hwdb.GetDB(ctx)) + propertyRepo := property_repo.New(hwdb.MustGetDB(ctx)) rows, err := propertyRepo.GetPropertiesWithSelectDataAndOptionsBySubjectTypeOrID( ctx, diff --git a/services/tasks-svc/internal/bed/bed.go b/services/tasks-svc/internal/bed/bed.go index bbc51b7cd..1a3975358 100644 --- a/services/tasks-svc/internal/bed/bed.go +++ b/services/tasks-svc/internal/bed/bed.go @@ -62,7 +62,7 @@ func NewServiceServer(authz hwauthz.AuthZ, es *esdb.Client) *ServiceServer { func (s ServiceServer) CreateBed(ctx context.Context, req *pb.CreateBedRequest) (*pb.CreateBedResponse, error) { log := zlog.Ctx(ctx) - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) // parse inputs roomId, err := uuid.Parse(req.GetRoomId()) @@ -137,7 +137,7 @@ func (s ServiceServer) CreateBed(ctx context.Context, req *pb.CreateBedRequest) } func (s ServiceServer) GetBed(ctx context.Context, req *pb.GetBedRequest) (*pb.GetBedResponse, error) { - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) // parse inputs id, err := uuid.Parse(req.GetId()) @@ -175,7 +175,7 @@ func (s ServiceServer) GetBedByPatient( ctx context.Context, req *pb.GetBedByPatientRequest, ) (*pb.GetBedByPatientResponse, error) { - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) patientId, err := uuid.Parse(req.GetPatientId()) if err != nil { @@ -229,7 +229,7 @@ func (s ServiceServer) GetBeds(ctx context.Context, req *pb.GetBedsRequest) (*pb return nil, status.Error(codes.InvalidArgument, err.Error()) } - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) beds, err := bedRepo.GetBeds(ctx, roomID) if err != nil { @@ -270,7 +270,7 @@ func (s ServiceServer) GetBedsByRoom( return nil, status.Error(codes.InvalidArgument, err.Error()) } - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) beds, err := bedRepo.GetBeds(ctx, uuid.NullUUID{ @@ -312,7 +312,7 @@ func (s ServiceServer) GetBedsByRoom( } func (s ServiceServer) UpdateBed(ctx context.Context, req *pb.UpdateBedRequest) (*pb.UpdateBedResponse, error) { - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) // parse inputs bedID, err := uuid.Parse(req.GetId()) @@ -363,7 +363,7 @@ func (s ServiceServer) UpdateBed(ctx context.Context, req *pb.UpdateBedRequest) func (s ServiceServer) DeleteBed(ctx context.Context, req *pb.DeleteBedRequest) (*pb.DeleteBedResponse, error) { log := zlog.Ctx(ctx) - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) // parse inputs bedID, err := uuid.Parse(req.GetId()) diff --git a/services/tasks-svc/internal/patient/api/grpc.go b/services/tasks-svc/internal/patient/api/grpc.go index 48754feb8..2c8b86f2b 100644 --- a/services/tasks-svc/internal/patient/api/grpc.go +++ b/services/tasks-svc/internal/patient/api/grpc.go @@ -79,7 +79,7 @@ func (s *PatientGrpcService) GetPatient( return nil, err } - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) // check permissions user := commonPerm.UserFromCtx(ctx) @@ -360,7 +360,7 @@ func (s *PatientGrpcService) GetRecentPatients( _ *pb.GetRecentPatientsRequest, ) (*pb.GetRecentPatientsResponse, error) { log := zlog.Ctx(ctx) - bedRepo := bed_repo.New(hwdb.GetDB(ctx)) + bedRepo := bed_repo.New(hwdb.MustGetDB(ctx)) var recentPatientIdsStrs []string recentPatientIdsStrs, err := tracking.GetRecentPatientsForUser(ctx) diff --git a/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go b/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go index ccb0e4ad3..3757e7761 100644 --- a/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go +++ b/services/tasks-svc/internal/patient/projections/patientPostgresProjection/patient_postgres_projection.go @@ -30,7 +30,7 @@ func NewProjection(ctx context.Context, es *esdb.Client, serviceName string) *Pr subscriptionGroupName, &[]string{aggregate.PatientAggregateType + "-"}, ), - patientRepo: patient_repo.New(hwdb.GetDB(ctx)), + patientRepo: patient_repo.New(hwdb.MustGetDB(ctx)), } p.initEventListeners() return p diff --git a/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go b/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go index 431790ccf..f4e53c96e 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_all_patients_with_details.go @@ -23,7 +23,7 @@ type GetAllPatientsWithDetailsQueryHandler func(ctx context.Context) ([]*models. func NewGetAllPatientsWithDetailsQueryHandler(authz hwauthz.AuthZ) GetAllPatientsWithDetailsQueryHandler { return func(ctx context.Context) ([]*models.PatientDetails, error) { - patientRepo := patient_repo.New(hwdb.GetDB(ctx)) + patientRepo := patient_repo.New(hwdb.MustGetDB(ctx)) // gather inputs organizationID := auth.MustGetOrganizationID(ctx) diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go b/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go index 3d9cb72c8..92ef14a5c 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patient_assignment_by_ward.go @@ -23,7 +23,7 @@ type GetPatientAssignmentByWardQueryHandler func( func NewGetPatientAssignmentByWardQueryHandler(authz hwauthz.AuthZ) GetPatientAssignmentByWardQueryHandler { return func(ctx context.Context, wardID uuid.UUID) ([]*models.RoomWithBedsWithPatient, error) { - roomRepo := room_repo.New(hwdb.GetDB(ctx)) + roomRepo := room_repo.New(hwdb.MustGetDB(ctx)) // check permissions // diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go b/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go index 1efc26bcb..a0d16ea5e 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patient_by_bed.go @@ -20,7 +20,7 @@ type GetPatientByBedQueryHandler func(ctx context.Context, bedID uuid.UUID) (*mo func NewGetPatientByBedQueryHandler(authz hwauthz.AuthZ) GetPatientByBedQueryHandler { return func(ctx context.Context, bedID uuid.UUID) (*models.PatientWithConsistency, error) { - patientRepo := patient_repo.New(hwdb.GetDB(ctx)) + patientRepo := patient_repo.New(hwdb.MustGetDB(ctx)) // check bed permissions user := commonPerm.UserFromCtx(ctx) diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go b/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go index 7200778ac..588f73ac8 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patient_with_details_by_id.go @@ -23,7 +23,7 @@ func NewGetPatientWithDetailsByIDQueryHandler( as hwes.AggregateStore, authz hwauthz.AuthZ, ) GetPatientDetailsByIDQueryHandler { return func(ctx context.Context, patientID uuid.UUID) (*models.PatientDetails, error) { - patientRepo := patient_repo.New(hwdb.GetDB(ctx)) + patientRepo := patient_repo.New(hwdb.MustGetDB(ctx)) taskHandlers := th.NewTaskHandlers(as, authz) // check permissions diff --git a/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go b/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go index 68e57e739..7328998ec 100644 --- a/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go +++ b/services/tasks-svc/internal/patient/queries/v1/get_patients_by_ward.go @@ -21,7 +21,7 @@ type GetPatientsByWardQueryHandler func(ctx context.Context, wardID uuid.UUID) ( func NewGetPatientsByWardQueryHandler(authz hwauthz.AuthZ) GetPatientsByWardQueryHandler { return func(ctx context.Context, wardID uuid.UUID) ([]*models.PatientWithConsistency, error) { - patientRepo := patient_repo.New(hwdb.GetDB(ctx)) + patientRepo := patient_repo.New(hwdb.MustGetDB(ctx)) // ensure get-access to ward user := commonPerm.UserFromCtx(ctx) diff --git a/services/tasks-svc/internal/room/room.go b/services/tasks-svc/internal/room/room.go index 15bd4651e..f7085d498 100644 --- a/services/tasks-svc/internal/room/room.go +++ b/services/tasks-svc/internal/room/room.go @@ -56,7 +56,7 @@ func NewServiceServer(authz hwauthz.AuthZ, es *esdb.Client) *ServiceServer { func (s ServiceServer) CreateRoom(ctx context.Context, req *pb.CreateRoomRequest) (*pb.CreateRoomResponse, error) { log := zlog.Ctx(ctx) - roomRepo := room_repo.New(hwdb.GetDB(ctx)) + roomRepo := room_repo.New(hwdb.MustGetDB(ctx)) // parse input wardID, err := uuid.Parse(req.GetWardId()) @@ -118,7 +118,7 @@ func (s ServiceServer) CreateRoom(ctx context.Context, req *pb.CreateRoomRequest } func (s ServiceServer) GetRoom(ctx context.Context, req *pb.GetRoomRequest) (*pb.GetRoomResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB(ctx)) + roomRepo := room_repo.New(hwdb.MustGetDB(ctx)) // parse inputs id, err := uuid.Parse(req.GetId()) @@ -169,7 +169,7 @@ func (s ServiceServer) GetRoom(ctx context.Context, req *pb.GetRoomRequest) (*pb } func (s ServiceServer) UpdateRoom(ctx context.Context, req *pb.UpdateRoomRequest) (*pb.UpdateRoomResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB(ctx)) + roomRepo := room_repo.New(hwdb.MustGetDB(ctx)) // parse inputs roomID, err := uuid.Parse(req.GetId()) @@ -212,7 +212,7 @@ func (s ServiceServer) UpdateRoom(ctx context.Context, req *pb.UpdateRoomRequest } func (s ServiceServer) GetRooms(ctx context.Context, req *pb.GetRoomsRequest) (*pb.GetRoomsResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB(ctx)) + roomRepo := room_repo.New(hwdb.MustGetDB(ctx)) // parse inputs wardID, err := hwutil.ParseNullUUID(req.WardId) @@ -277,7 +277,7 @@ func (s ServiceServer) GetRooms(ctx context.Context, req *pb.GetRoomsRequest) (* } func (s ServiceServer) DeleteRoom(ctx context.Context, req *pb.DeleteRoomRequest) (*pb.DeleteRoomResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB(ctx)) + roomRepo := room_repo.New(hwdb.MustGetDB(ctx)) // parse inputs roomID, err := uuid.Parse(req.GetId()) @@ -321,7 +321,7 @@ func (s ServiceServer) GetRoomOverviewsByWard( ctx context.Context, req *pb.GetRoomOverviewsByWardRequest, ) (*pb.GetRoomOverviewsByWardResponse, error) { - roomRepo := room_repo.New(hwdb.GetDB(ctx)) + roomRepo := room_repo.New(hwdb.MustGetDB(ctx)) wardID, err := uuid.Parse(req.GetId()) if err != nil { diff --git a/services/tasks-svc/internal/task-template/task_template.go b/services/tasks-svc/internal/task-template/task_template.go index b18d14129..4225f852e 100644 --- a/services/tasks-svc/internal/task-template/task_template.go +++ b/services/tasks-svc/internal/task-template/task_template.go @@ -59,7 +59,7 @@ func (s ServiceServer) CreateTaskTemplate( req *pb.CreateTaskTemplateRequest, ) (*pb.CreateTaskTemplateResponse, error) { log := zlog.Ctx(ctx) - db := hwdb.GetDB(ctx) + db := hwdb.MustGetDB(ctx) user := commonPerm.UserFromCtx(ctx) @@ -163,7 +163,7 @@ func (s ServiceServer) DeleteTaskTemplate( req *pb.DeleteTaskTemplateRequest, ) (*pb.DeleteTaskTemplateResponse, error) { log := zlog.Ctx(ctx) - templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) + templateRepo := task_template_repo.New(hwdb.MustGetDB(ctx)) id, err := uuid.Parse(req.GetId()) if err != nil { @@ -210,7 +210,7 @@ func (s ServiceServer) DeleteTaskTemplateSubTask( ) (*pb.DeleteTaskTemplateSubTaskResponse, error) { log := zlog.Ctx(ctx) - tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(ctx), ctx) + tx, rollback, err := hwdb.BeginTx(hwdb.MustGetDB(ctx), ctx) if err != nil { return nil, err } @@ -273,7 +273,7 @@ func (s ServiceServer) UpdateTaskTemplate( ctx context.Context, req *pb.UpdateTaskTemplateRequest, ) (*pb.UpdateTaskTemplateResponse, error) { - templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) + templateRepo := task_template_repo.New(hwdb.MustGetDB(ctx)) id, err := uuid.Parse(req.GetId()) if err != nil { @@ -319,7 +319,7 @@ func (s ServiceServer) UpdateTaskTemplateSubTask( req *pb.UpdateTaskTemplateSubTaskRequest, ) (*pb.UpdateTaskTemplateSubTaskResponse, error) { // TX - tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(ctx), ctx) + tx, rollback, err := hwdb.BeginTx(hwdb.MustGetDB(ctx), ctx) if err != nil { return nil, err } @@ -383,7 +383,7 @@ func (s ServiceServer) CreateTaskTemplateSubTask( req *pb.CreateTaskTemplateSubTaskRequest, ) (*pb.CreateTaskTemplateSubTaskResponse, error) { log := zlog.Ctx(ctx) - templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) + templateRepo := task_template_repo.New(hwdb.MustGetDB(ctx)) taskTemplateID, err := uuid.Parse(req.GetTaskTemplateId()) if err != nil { @@ -436,7 +436,7 @@ func (s ServiceServer) GetAllTaskTemplates( ctx context.Context, req *pb.GetAllTaskTemplatesRequest, ) (*pb.GetAllTaskTemplatesResponse, error) { - templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) + templateRepo := task_template_repo.New(hwdb.MustGetDB(ctx)) user := commonPerm.UserFromCtx(ctx) @@ -512,7 +512,7 @@ func (s ServiceServer) GetTaskTemplate( ctx context.Context, req *pb.GetTaskTemplateRequest, ) (*pb.GetTaskTemplateResponse, error) { - templateRepo := task_template_repo.New(hwdb.GetDB(ctx)) + templateRepo := task_template_repo.New(hwdb.MustGetDB(ctx)) taskTemplateID, err := uuid.Parse(req.Id) if err != nil { diff --git a/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go b/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go index 9ad9eb0ec..ade539bbc 100644 --- a/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go +++ b/services/tasks-svc/internal/task/projections/task_postgres_projection/task_postgres_projection.go @@ -32,7 +32,7 @@ func NewProjection(ctx context.Context, es *esdb.Client, serviceName string) *Pr subscriptionGroupName, &[]string{aggregate.TaskAggregateType + "-"}, ), - taskRepo: task_repo.New(hwdb.GetDB(ctx)), + taskRepo: task_repo.New(hwdb.MustGetDB(ctx)), } p.initEventListeners() return p diff --git a/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go b/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go index c955bd161..f63d1202a 100644 --- a/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go +++ b/services/tasks-svc/internal/task/queries/v1/get_task_with_patient_by_id.go @@ -28,7 +28,7 @@ func NewGetTaskWithPatientByIDQueryHandler(authz hwauthz.AuthZ) GetTaskWithPatie return nil, err } - taskRepo := task_repo.New(hwdb.GetDB(ctx)) + taskRepo := task_repo.New(hwdb.MustGetDB(ctx)) rows, err := taskRepo.GetTaskWithPatientById(ctx, taskID) if err := hwdb.Error(ctx, err); err != nil { diff --git a/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go b/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go index 71bc5c9ef..d4c788b63 100644 --- a/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go +++ b/services/tasks-svc/internal/task/queries/v1/get_tasks_by_patient.go @@ -32,7 +32,7 @@ func NewGetTasksByPatientIDQueryHandler(authz hwauthz.AuthZ) GetTasksByPatientID return nil, err } - taskRepo := task_repo.New(hwdb.GetDB(ctx)) + taskRepo := task_repo.New(hwdb.MustGetDB(ctx)) tasksWithSubtasks, err := taskRepo.GetTasksWithSubtasksByPatient(ctx, patientID) if err := hwdb.Error(ctx, err); err != nil { diff --git a/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go b/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go index e73c79c4c..cac4e5dfa 100644 --- a/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go +++ b/services/tasks-svc/internal/task/queries/v1/get_tasks_with_patients_by_asignee.go @@ -25,7 +25,7 @@ type GetTasksWithPatientsByAssigneeQueryHandler func( func NewGetTasksWithPatientsByAssigneeQueryHandler(authz hwauthz.AuthZ) GetTasksWithPatientsByAssigneeQueryHandler { return func(ctx context.Context, assigneeID uuid.UUID) ([]*models.TaskWithPatient, error) { - taskRepo := task_repo.New(hwdb.GetDB(ctx)) + taskRepo := task_repo.New(hwdb.MustGetDB(ctx)) user := commonPerm.UserFromCtx(ctx) diff --git a/services/tasks-svc/internal/ward/ward.go b/services/tasks-svc/internal/ward/ward.go index dcce2d682..2151b97ea 100644 --- a/services/tasks-svc/internal/ward/ward.go +++ b/services/tasks-svc/internal/ward/ward.go @@ -57,7 +57,7 @@ func NewServiceServer(authz hwauthz.AuthZ, es *esdb.Client) *ServiceServer { func (s *ServiceServer) CreateWard(ctx context.Context, req *pb.CreateWardRequest) (*pb.CreateWardResponse, error) { log := zlog.Ctx(ctx) - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) // check permissions user := commonPerm.UserFromCtx(ctx) @@ -116,7 +116,7 @@ func (s *ServiceServer) CreateWard(ctx context.Context, req *pb.CreateWardReques } func (s *ServiceServer) GetWard(ctx context.Context, req *pb.GetWardRequest) (*pb.GetWardResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) // parse input id, err := uuid.Parse(req.GetId()) @@ -150,7 +150,7 @@ func (s *ServiceServer) GetWard(ctx context.Context, req *pb.GetWardRequest) (*p } func (s *ServiceServer) GetWards(ctx context.Context, req *pb.GetWardsRequest) (*pb.GetWardsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) wards, err := wardRepo.GetWards(ctx) err = hwdb.Error(ctx, err) @@ -186,7 +186,7 @@ func (s *ServiceServer) GetRecentWards( ctx context.Context, _ *pb.GetRecentWardsRequest, ) (*pb.GetRecentWardsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) log := zlog.Ctx(ctx) recentWardIDsStr, err := tracking.GetRecentWardsForUser(ctx) @@ -247,7 +247,7 @@ func (s *ServiceServer) GetRecentWards( } func (s *ServiceServer) UpdateWard(ctx context.Context, req *pb.UpdateWardRequest) (*pb.UpdateWardResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) // parse input id, err := uuid.Parse(req.GetId()) @@ -293,7 +293,7 @@ func (s *ServiceServer) UpdateWard(ctx context.Context, req *pb.UpdateWardReques } func (s *ServiceServer) DeleteWard(ctx context.Context, req *pb.DeleteWardRequest) (*pb.DeleteWardResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) // parse input wardID, err := uuid.Parse(req.GetId()) @@ -350,7 +350,7 @@ func (s *ServiceServer) GetWardOverviews( ctx context.Context, _ *pb.GetWardOverviewsRequest, ) (*pb.GetWardOverviewsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) rows, err := wardRepo.GetWardsWithCounts(ctx, ward_repo.GetWardsWithCountsParams{ StatusTodo: int32(pb.TaskStatus_TASK_STATUS_TODO), @@ -395,7 +395,7 @@ func (s *ServiceServer) GetWardDetails( ctx context.Context, req *pb.GetWardDetailsRequest, ) (*pb.GetWardDetailsResponse, error) { - wardRepo := ward_repo.New(hwdb.GetDB(ctx)) + wardRepo := ward_repo.New(hwdb.MustGetDB(ctx)) wardID, err := uuid.Parse(req.GetId()) if err != nil { diff --git a/services/user-svc/internal/organization/organization.go b/services/user-svc/internal/organization/organization.go index 88cae36ff..fcb9d2a96 100644 --- a/services/user-svc/internal/organization/organization.go +++ b/services/user-svc/internal/organization/organization.go @@ -78,7 +78,7 @@ func (s ServiceServer) GetOrganization( ctx context.Context, req *pb.GetOrganizationRequest, ) (*pb.GetOrganizationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) id, err := uuid.Parse(req.GetId()) if err != nil { @@ -170,7 +170,7 @@ type OrganizationWithMembers struct { func GetOrganizationsByUserId( ctx context.Context, userId uuid.UUID, authz hwauthz.AuthZ, ) ([]OrganizationWithMembers, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) rows, err := organizationRepo.GetOrganizationsWithMembersByUser(ctx, userId) err = hwdb.Error(ctx, err) @@ -279,7 +279,7 @@ func (s ServiceServer) UpdateOrganization( return nil, err } - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) organizationID, err := uuid.Parse(req.GetId()) if err != nil { @@ -313,7 +313,7 @@ func (s ServiceServer) DeleteOrganization( return nil, err } - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) organizationID, err := uuid.Parse(req.GetId()) if err != nil { @@ -352,7 +352,7 @@ func (s ServiceServer) RemoveMember( } log := zlog.Ctx(ctx) - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) userID, err := uuid.Parse(req.UserId) if err != nil { @@ -399,7 +399,7 @@ func (s ServiceServer) InviteMember( req *pb.InviteMemberRequest, ) (*pb.InviteMemberResponse, error) { log := zlog.Ctx(ctx) - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) // check permissions permUser := commonPerm.UserFromCtx(ctx) @@ -479,7 +479,7 @@ func (s ServiceServer) GetInvitationsByOrganization( ctx context.Context, req *pb.GetInvitationsByOrganizationRequest, ) (*pb.GetInvitationsByOrganizationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) organizationID, err := uuid.Parse(req.OrganizationId) if err != nil { @@ -548,7 +548,7 @@ func (s ServiceServer) GetInvitationsByUser( ctx context.Context, req *pb.GetInvitationsByUserRequest, ) (*pb.GetInvitationsByUserResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) claims, err := auth.GetAuthClaims(ctx) if err != nil { @@ -612,7 +612,7 @@ func (s ServiceServer) GetMembersByOrganization( ctx context.Context, req *pb.GetMembersByOrganizationRequest, ) (*pb.GetMembersByOrganizationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) organizationID, err := uuid.Parse(req.GetId()) if err != nil { @@ -652,7 +652,7 @@ func (s ServiceServer) AcceptInvitation( ctx context.Context, req *pb.AcceptInvitationRequest, ) (*pb.AcceptInvitationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) invitationId, err := uuid.Parse(req.InvitationId) if err != nil { @@ -715,7 +715,7 @@ func (s ServiceServer) AcceptInvitation( // Add user to organization if err := AddUserToOrganization( ctx, - hwdb.GetDB(ctx), + hwdb.MustGetDB(ctx), s.authz, s.kc, userID, @@ -732,7 +732,7 @@ func (s ServiceServer) DeclineInvitation( ctx context.Context, req *pb.DeclineInvitationRequest, ) (*pb.DeclineInvitationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) invitationId, err := uuid.Parse(req.InvitationId) if err != nil { @@ -797,7 +797,7 @@ func (s ServiceServer) RevokeInvitation( ctx context.Context, req *pb.RevokeInvitationRequest, ) (*pb.RevokeInvitationResponse, error) { - organizationRepo := organization_repo.New(hwdb.GetDB(ctx)) + organizationRepo := organization_repo.New(hwdb.MustGetDB(ctx)) log := zlog.Ctx(ctx) @@ -860,7 +860,7 @@ func CreateOrganizationAndAddUser( authz hwauthz.AuthZ, ) (*organization_repo.Organization, error) { // open tx - tx, rollback, err := hwdb.BeginTx(hwdb.GetDB(ctx), ctx) + tx, rollback, err := hwdb.BeginTx(hwdb.MustGetDB(ctx), ctx) if err != nil { return nil, err } @@ -996,7 +996,7 @@ func (s ServiceServer) CreatePersonalOrganization( personalOrganizationLocale := hwlocale.Localize(ctx, locale.PersonalOrganizationName(ctx)) organizationName := fmt.Sprintf("%s %s", personalOrganizationLocale, userClaims.Name) - userRepo := user_repo.New(hwdb.GetDB(ctx)) + userRepo := user_repo.New(hwdb.MustGetDB(ctx)) // create user, if it does not exist yet userResult, err := hwdb.Optional(userRepo.GetUserById)(ctx, userID) diff --git a/services/user-svc/internal/user/user.go b/services/user-svc/internal/user/user.go index 14f36ddd7..e95e4ce80 100644 --- a/services/user-svc/internal/user/user.go +++ b/services/user-svc/internal/user/user.go @@ -41,7 +41,7 @@ func (s ServiceServer) ReadPublicProfile( ctx context.Context, req *pb.ReadPublicProfileRequest, ) (*pb.ReadPublicProfileResponse, error) { - userRepo := user_repo.New(hwdb.GetDB(ctx)) + userRepo := user_repo.New(hwdb.MustGetDB(ctx)) userID, err := uuid.Parse(req.GetId()) if err != nil { @@ -74,7 +74,7 @@ func (s ServiceServer) ReadPublicProfile( func HandleUserUpdatedEvent(ctx context.Context, evt *daprcmn.TopicEvent) (retry bool, err error) { log := zlog.Ctx(ctx) - userRepo := user_repo.New(hwdb.GetDB(ctx)) + userRepo := user_repo.New(hwdb.MustGetDB(ctx)) var payload events.UserUpdatedEvent if err := proto.Unmarshal(evt.RawData, &payload); err != nil { From 508602c79575dde916102731e2b8e52d1ebcf10f Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 27 Dec 2024 13:11:43 +0100 Subject: [PATCH 19/22] passing --- libs/common/grpc.go | 12 +++++++----- libs/hwdb/setup.go | 5 ++++- services/tasks-svc/go.mod | 1 + .../tasks-svc/internal/patient/api/grpc_test.go | 15 ++++++++++++++- services/tasks-svc/stories/PatientCRUD_test.go | 1 + 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/libs/common/grpc.go b/libs/common/grpc.go index ac328471b..7d0c75011 100644 --- a/libs/common/grpc.go +++ b/libs/common/grpc.go @@ -132,12 +132,14 @@ func DefaultServerOptions(ctx context.Context) []grpc.ServerOption { // register new metrics collector with prometheus promRegistry := telemetry.PrometheusRegistry(ctx) - metrics := prometheusGrpcProvider.NewServerMetrics() - promRegistry.MustRegister(metrics) + if promRegistry != nil { + metrics := prometheusGrpcProvider.NewServerMetrics() + promRegistry.MustRegister(metrics) - // prepend metrics interceptor - unaryInterceptors = hwutil.Prepend(metrics.UnaryServerInterceptor(), unaryInterceptors) - streamInterceptors = hwutil.Prepend(metrics.StreamServerInterceptor(), streamInterceptors) + // prepend metrics interceptor + unaryInterceptors = hwutil.Prepend(metrics.UnaryServerInterceptor(), unaryInterceptors) + streamInterceptors = hwutil.Prepend(metrics.StreamServerInterceptor(), streamInterceptors) + } // create chains unaryInterceptorChain := grpc.ChainUnaryInterceptor(unaryInterceptors...) diff --git a/libs/hwdb/setup.go b/libs/hwdb/setup.go index eb5a743d8..2914f5baf 100644 --- a/libs/hwdb/setup.go +++ b/libs/hwdb/setup.go @@ -109,10 +109,12 @@ func WithDB(ctx context.Context, pool DBTX) context.Context { return context.WithValue(ctx, dbKey{}, pool) } +// GetDB attempts to retrieve the DBTX stored in the context, and returns nil if its missing. +// Also see MustGetDB. func GetDB(ctx context.Context) DBTX { value := ctx.Value(dbKey{}) db, ok := value.(DBTX) - // TODO: explain + // we allow nil (which will not be ok), else panic if db != nil && !ok { panic(errs.NewCastError("DBTX", value)) } @@ -121,6 +123,7 @@ func GetDB(ctx context.Context) DBTX { var ErrDBMissing = errors.New("MustGetDB() called without set-up database, use hwdb.WithDB()") +// MustGetDB does the same as GetDB, but panics if no DBTX is found in the context. func MustGetDB(ctx context.Context) DBTX { if db := GetDB(ctx); db != nil { return db diff --git a/services/tasks-svc/go.mod b/services/tasks-svc/go.mod index e10b865f5..da7a365a3 100644 --- a/services/tasks-svc/go.mod +++ b/services/tasks-svc/go.mod @@ -26,6 +26,7 @@ require ( github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.7.1 github.com/nicksnyder/go-i18n/v2 v2.4.1 + github.com/pashagolub/pgxmock/v4 v4.3.0 github.com/rs/zerolog v1.33.0 github.com/stretchr/testify v1.10.0 golang.org/x/net v0.32.0 diff --git a/services/tasks-svc/internal/patient/api/grpc_test.go b/services/tasks-svc/internal/patient/api/grpc_test.go index 5adc8924e..bcd73f5eb 100644 --- a/services/tasks-svc/internal/patient/api/grpc_test.go +++ b/services/tasks-svc/internal/patient/api/grpc_test.go @@ -6,7 +6,9 @@ import ( "context" "decaying_lru" pb "gen/services/tasks_svc/v1" + "github.com/pashagolub/pgxmock/v4" "hwauthz/test" + "hwdb" hwes_test "hwes/test" "testing" "time" @@ -33,6 +35,12 @@ func server() (context.Context, pb.PatientServiceClient, func()) { ctx := common.Setup("tasks-svc", "test", common.WithFakeAuthOnly()) + dbMock, err := pgxmock.NewPool() + if err != nil { + panic(err) + } + ctx = hwdb.WithDB(context.Background(), dbMock) + // Start Server grpcServer := grpc.NewServer(common.DefaultServerOptions(ctx)...) pb.RegisterPatientServiceServer(grpcServer, patientGrpcService) @@ -40,7 +48,12 @@ func server() (context.Context, pb.PatientServiceClient, func()) { client := pb.NewPatientServiceClient(conn) - return ctx, client, closer + teardown := func() { + dbMock.Close() + closer() + } + + return ctx, client, teardown } func setup(t *testing.T) ( diff --git a/services/tasks-svc/stories/PatientCRUD_test.go b/services/tasks-svc/stories/PatientCRUD_test.go index fa4fbec00..1e26cce82 100644 --- a/services/tasks-svc/stories/PatientCRUD_test.go +++ b/services/tasks-svc/stories/PatientCRUD_test.go @@ -192,6 +192,7 @@ func TestGetPatientByBed(t *testing.T) { } createRes, err := patientClient.CreatePatient(ctx, createReq) require.NoError(t, err, "could not create patient") + hwtesting.WaitForProjectionsToSettle() patientId := createRes.GetId() From f8716c2524e96712f851c0d4bae388536f31005b Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 27 Dec 2024 13:17:01 +0100 Subject: [PATCH 20/22] remove nolints --- .../internal/property-view/api/grpc_test.go | 15 ++++++++++----- .../tasks-svc/internal/patient/api/grpc_test.go | 5 +++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/services/property-svc/internal/property-view/api/grpc_test.go b/services/property-svc/internal/property-view/api/grpc_test.go index a460540ca..716b7fed8 100644 --- a/services/property-svc/internal/property-view/api/grpc_test.go +++ b/services/property-svc/internal/property-view/api/grpc_test.go @@ -67,8 +67,9 @@ func setup() ( return ctx, client, aggregateStore, dbMock, teardown } -//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_Validation(t *testing.T) { + t.Parallel() + ctx, client, _, dbMock, teardown := setup() defer teardown() @@ -238,8 +239,9 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_AllEmptyNoEffect(t *test as.ExpectToBeEmpty(t) } -//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_GreenPath_Created(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -307,8 +309,9 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_Gree }) } -//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_GreenPath_Created(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -376,8 +379,9 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_G }) } -//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_GreenPath_Updated(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() @@ -474,8 +478,9 @@ func TestPropertyViewGrpcService_UpdatePropertyViewRule_TaskPropertyMatcher_Gree }) } -//nolint:paralleltest func TestPropertyViewGrpcService_UpdatePropertyViewRule_PatientPropertyMatcher_GreenPath_Updated(t *testing.T) { + t.Parallel() + ctx, client, as, dbMock, teardown := setup() defer teardown() diff --git a/services/tasks-svc/internal/patient/api/grpc_test.go b/services/tasks-svc/internal/patient/api/grpc_test.go index bcd73f5eb..7d9ec6b90 100644 --- a/services/tasks-svc/internal/patient/api/grpc_test.go +++ b/services/tasks-svc/internal/patient/api/grpc_test.go @@ -6,13 +6,14 @@ import ( "context" "decaying_lru" pb "gen/services/tasks_svc/v1" - "github.com/pashagolub/pgxmock/v4" "hwauthz/test" "hwdb" hwes_test "hwes/test" "testing" "time" + "github.com/pashagolub/pgxmock/v4" + "github.com/go-redis/redismock/v9" "github.com/google/uuid" "github.com/stretchr/testify/assert" @@ -39,7 +40,7 @@ func server() (context.Context, pb.PatientServiceClient, func()) { if err != nil { panic(err) } - ctx = hwdb.WithDB(context.Background(), dbMock) + ctx = hwdb.WithDB(ctx, dbMock) // Start Server grpcServer := grpc.NewServer(common.DefaultServerOptions(ctx)...) From 338e1c086a94638eb4d86ed2987678e212cc77d0 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Fri, 27 Dec 2024 13:22:52 +0100 Subject: [PATCH 21/22] close TODO --- libs/common/grpc.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/common/grpc.go b/libs/common/grpc.go index 7d0c75011..a3eb31ae6 100644 --- a/libs/common/grpc.go +++ b/libs/common/grpc.go @@ -121,7 +121,8 @@ func DefaultStreamInterceptors(ctx context.Context, panicsRecovered prometheus.C } } -// TODO: document expected values in context +// DefaultServerOptions respects telemetry.WithPrometheusRegistry and hwdb.WithDB context values. +// These will then be propagated into request contexts, if provided. func DefaultServerOptions(ctx context.Context) []grpc.ServerOption { // counters panicsRecovered := hwgrpc.NewPanicsRecoveredCounter(ctx) From fd1e65ccbdd0a3a13abf4ee79eb36b68da032524 Mon Sep 17 00:00:00 2001 From: Max Baumann Date: Mon, 24 Feb 2025 14:59:30 +0100 Subject: [PATCH 22/22] fix merge issue --- libs/hwauthz/spicedb/userOrg.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/hwauthz/spicedb/userOrg.go b/libs/hwauthz/spicedb/userOrg.go index 56af4d3f9..379dd86ee 100644 --- a/libs/hwauthz/spicedb/userOrg.go +++ b/libs/hwauthz/spicedb/userOrg.go @@ -5,7 +5,7 @@ import ( "github.com/google/uuid" "hwauthz" - "hwauthz/commonPerm" + "hwauthz/commonperm" ) func AddUserToOrganization( @@ -14,16 +14,16 @@ func AddUserToOrganization( userID, organizationID uuid.UUID, leader bool, ) error { - permUser := commonPerm.User(userID) - permOrg := commonPerm.Organization(organizationID) + permUser := commonperm.User(userID) + permOrg := commonperm.Organization(organizationID) - var role hwauthz.Relation = commonPerm.OrganizationMember + var role hwauthz.Relation = commonperm.OrganizationMember if leader { - role = commonPerm.OrganizationLeader + role = commonperm.OrganizationLeader } rel := hwauthz.NewRelationship(permUser, role, permOrg) - backRel := hwauthz.NewRelationship(permOrg, commonPerm.UserOrganization, permUser) + backRel := hwauthz.NewRelationship(permOrg, commonperm.UserOrganization, permUser) if _, err := authz.Create(rel).Create(backRel).Commit(ctx); err != nil { return err }