Common updates to better support Oura and work system#916
Common updates to better support Oura and work system#916darinkrauss wants to merge 1 commit intoBACK-4028-oura-webhook-subscriptions-basefrom
Conversation
darinkrauss
commented
Mar 11, 2026
- Update request parsing code to allow parsing of decoded maps with options
- Add expanded pagination functionality
- Add direct metadata encoding and decoding
- Add generic functions to pointer package
- Add times.TimeRange common structure
- Add OAuthToken.IsExpired
- Remove .vscode directory
- Add various mocks
- Fix various typos
- Add and update tests
| return &value | ||
| } | ||
|
|
||
| func FromAny[T any](value T) *T { |
There was a problem hiding this comment.
I suggest renaming this instead of introducing a new function
| func From[T any](value T) *T { |
There was a problem hiding this comment.
Going to leave as-is for now. As I mentioned in Slack, I have an in-progress branch to cleanup the pointer package to consistently use generics. There will be a mass rename.
|
|
||
| func DecodeRequestBody(req *http.Request, object interface{}) error { | ||
| type DecodeOption struct { | ||
| ignoreNotParsed *bool |
There was a problem hiding this comment.
Considering removing the pointer here. I don't thing there is a practical need to distinguish between not set and set to false.
There was a problem hiding this comment.
It is only an issue if we have multiple DecodeOptions and we list them at the end of a function. For example, Decode(<whatever>, request.IgnoreNotParsed(), request.SomeOtherOption(). When those are merged using request.DecodeOptions the pointer allows the second option to not step on the value of the first option.
times/times.go
Outdated
|
|
||
| import "time" | ||
|
|
||
| func Pin(value time.Time, minimum time.Time, maximum time.Time) time.Time { |
There was a problem hiding this comment.
I believe the standard naming for this functionality is Clamp
b711d7d to
c7466f5
Compare
- Update request parsing code to allow parsing of decoded maps with options - Add expanded pagination functionality - Add direct metadata encoding and decoding - Add generic functions to pointer package - Add times.TimeRange common structure - Add OAuthToken.IsExpired - Remove .vscode directory - Add various mocks - Fix various typos - Fix intermittent consent test failure - Add and update tests
c7466f5 to
86d60fc
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces shared utilities and developer tooling to better support integrations (e.g., Oura) and “work” system behavior, including improved request decoding, richer pagination helpers, and new common time-range structures. It also adds mocks/tests and cleans up repo-local editor artifacts.
Changes:
- Expanded request decoding to support decoding from streams and already-decoded objects/arrays, with an option to ignore “not parsed” fields.
- Added common utilities:
times.Clamp,times.TimeRange(+metadata), and generic pointer helpers (From,To,Clone,Equal,DefaultPointer). - Added/updated pagination helpers (
Collect,First,Processvariants), mocks (mockgen), tests, and Ginkgo Makefile/template tooling.
Reviewed changes
Copilot reviewed 52 out of 53 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| work/test/processor.go | Adds test Provider and mock metadata helpers for work processors. |
| work/service/coordinator.go | Fixes typo in RegisterProcessorFactories parameter naming. |
| work/base/processor_factory_test.go | Improves test descriptions (“returns an error …”). |
| work/base/process_result_test.go | Refactors gomock controller setup for ProcessResult tests. |
| times/times.go | Adds times.Clamp utility. |
| times/times_test.go | Adds unit tests for times.Clamp. |
| times/times_suite_test.go | Adds Ginkgo suite bootstrap for times package tests. |
| times/time_range.go | Introduces TimeRange + TimeRangeMetadata parsing/validation/helpers. |
| times/time_range_test.go | Adds comprehensive tests for TimeRange and metadata parsing/validation/helpers. |
| times/test/time_range.go | Adds test factories/clone/object builders for time range types. |
| test/optional.go | Adds generic optional/random optional helpers used across tests. |
| test/int64.go | Adjusts random int64 bounds helpers. |
| test/closer.go | Adds ErrorCloser wrapper and supporting ReadCloser types. |
| summary/summary.go | Adds Client interface + go:generate for gomock. |
| summary/test/summary_mocks.go | Adds generated gomock mocks for summary.Client and Summarizer. |
| store/structured/mongo/test/test.go | Improves uniqueness of generated Mongo collection name prefixes. |
| request/parser.go | Adds decode options + stream/object/array decoding and parsing helpers; renames/reshapes decode functions. |
| request/parser_test.go | Adds tests for new decode options; refactors header parsing tests; tweaks loop generation. |
| request/values_parser.go | Simplifies map access for parsed indices. |
| private/plugin/abbott | Updates submodule pointer. |
| pointer/from.go | Adds generic pointer.From. |
| pointer/from_test.go | Adds tests for generic From, FromInt64, FromAny. |
| pointer/to.go | Adds generic pointer.To. |
| pointer/to_test.go | Adds tests for generic To. |
| pointer/clone.go | Adds generic pointer.Clone. |
| pointer/clone_test.go | Adds tests for generic Clone. |
| pointer/equal.go | Adds generic pointer.Equal. |
| pointer/equal_test.go | Adds tests for generic Equal; fixes mislabeled table name. |
| pointer/default.go | Adds DefaultPointer. |
| pointer/default_test.go | Adds tests for generic Default + DefaultPointer; clarifies expectations in existing tests. |
| page/pagination.go | Adds Pager, expands collection helpers (Collect/First/Process) with size variants. |
| page/pagination_test.go | Adds extensive tests for new pagination collection helpers and edge cases. |
| metadata/metadata.go | Updates parsing calls; removes some helpers; adds generic Encode/Decode against map metadata. |
| metadata/metadata_test.go | Adds coverage for MetadataFromMap, plus encode/decode behaviors with decode options. |
| metadata/test/metadata.go | Refactors metadata test factories/cloners/builders using maps.Clone and pointer helpers. |
| log/test/serializer.go | Improves assertion failure output with JSON dumps; adjusts field-join behavior. |
| devicetokens/devicetokens_test.go | Migrates decoding usage to request.DecodeStream. |
| data/source/service/client/client.go | Adds go:generate mockgen directive for Provider. |
| data/source/service/client/test/client_mocks.go | Adds generated gomock for data source client Provider. |
| data/deduplicator/deduplicator.go | Adds go:generate mockgen directives for Factory and Deduplicator. |
| data/deduplicator/test/deduplicator_mocks.go | Adds generated gomock mocks for deduplicator Factory and Deduplicator. |
| consent/store/mongo/consent_record_repository.go | Adjusts aggregation group key and adds explicit sort for deterministic output. |
| consent/consent_record_test.go | Migrates decoding usage to request.DecodeStream. |
| client/client.go | Migrates decoding usage to request.DecodeStream. |
| auth/token.go | Adds OAuthToken.IsExpired. |
| auth/token_test.go | Adds test coverage for IsExpired. |
| auth/auth_test.go | Fixes a typo in test description. |
| alerts/config_test.go | Migrates decoding usage to request.DecodeStream. |
| Makefile | Adds ginkgo repeat/until-fail targets and bootstrapping/generate helpers with templates. |
| .ginkgo/templates/bootstrap | Adds custom Ginkgo bootstrap template. |
| .ginkgo/templates/generate | Adds custom Ginkgo generate template including common imports. |
| .vscode/launch.json | Removes repository-stored VS Code launch configuration. |
| .gitignore | Ignores .vscode directory. |
Comments suppressed due to low confidence (5)
work/base/process_result_test.go:1
- The
gomock.Controllercreated inBeforeEachis not finished/cleaned up anywhere in this test file. This can leak expectations across tests and cause flaky failures. AddDeferCleanup(mockController.Finish)after controller creation (orAfterEach(mockController.Finish)) so mocks are always finalized.
request/parser_test.go:1 - This uses Go’s
for range <int>form (introduced in Go 1.22). If the repository’sgo.mod/CI Go version is < 1.22, this will not compile. Either ensure the project toolchain is pinned to Go 1.22+ or rewrite this loop to a traditionalfor loops := 0; loops < maxLoops; loops++ { ... }to preserve compatibility.
request/parser.go:1 - These error paths drop the underlying
err, which makes diagnosing decode failures much harder (especially since callers wrap these messages). Prefer wrapping/attaching the original error so the failure reason (e.g., unsupported type, invalid JSON shape) is preserved.
test/int64.go:1 RandomInt64Maximum()/RandomInt64Minimum()no longer return the true int64 extrema, which makes the names misleading and can break callers that expect full-range bounds. Either restore the original semantics or rename/document these as safe/random-generation bounds (e.g., to avoid overflow during downstream operations).
test/int64.go:1RandomInt64Maximum()/RandomInt64Minimum()no longer return the true int64 extrema, which makes the names misleading and can break callers that expect full-range bounds. Either restore the original semantics or rename/document these as safe/random-generation bounds (e.g., to avoid overflow during downstream operations).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func RandomMetadataMap() map[string]any { | ||
| return RandomMetadata().AsMap() | ||
| datum := map[string]any{} | ||
| for range test.RandomIntFromRange(1, 3) { | ||
| datum[RandomMetadataKey()] = RandomMetadataValue() | ||
| } | ||
| return datum | ||
| } |
| func Decode[T any](ctx context.Context, metadata map[string]any, decodeOptions ...request.DecodeOption) (*T, error) { | ||
| if metadata == nil { | ||
| return nil, nil | ||
| } | ||
|
|
||
| object := new(T) | ||
| if err := request.DecodeObject(ctx, structure.NewPointerSource(), metadata, object, decodeOptions...); err != nil { | ||
| return nil, errors.Wrap(err, "unable to decode metadata") | ||
| } | ||
|
|
||
| return object, nil | ||
| } |
| actual, _ := json.MarshalIndent(s.SerializedFields, "", " ") | ||
| expected, _ := json.MarshalIndent(joinedContainsFields, "", " ") | ||
| panic(fmt.Sprintf("logger does not contain specified message and fields, expected:\n%s\nto contain:\n%s\n", string(actual), string(expected))) | ||
| } | ||
|
|
| } | ||
|
|
||
| func (o *OAuthToken) IsExpired() bool { | ||
| return o.ExpirationTime.Before(time.Now()) |
| ginkgo-bootstrap: ginkgo | ||
| @echo "ginkgo bootstrap $(TEST_PACKAGE)" | ||
| @cd "$(TEST_DIRECTORY)" && \ | ||
| [ -f "$(TEST_PACKAGE_NAME)_suite_test.go" ] || \ | ||
| ginkgo bootstrap --template "$(ROOT_DIRECTORY)/.ginkgo/templates/bootstrap" | ||
|
|
||
| ginkgo-generate: ginkgo-bootstrap |