Skip to content

Commit 83935e3

Browse files
Merge remote-tracking branch 'origin/main' into feat-redis-tls
# Conflicts: # pkg/api/cmd/server.go
2 parents a0b4b5e + faba45f commit 83935e3

112 files changed

Lines changed: 6402 additions & 309 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

go.mod

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ require (
5050
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
5151
golang.org/x/oauth2 v0.36.0
5252
golang.org/x/sync v0.22.0
53-
golang.org/x/text v0.40.0
53+
golang.org/x/text v0.41.0
5454
golang.org/x/time v0.15.0
5555
gonum.org/v1/gonum v0.17.0
5656
google.golang.org/api v0.291.0
@@ -139,12 +139,12 @@ require (
139139
go.opentelemetry.io/otel/trace v1.44.0 // indirect
140140
go.uber.org/atomic v1.11.0 // indirect
141141
go.uber.org/multierr v1.10.0 // indirect
142-
golang.org/x/crypto v0.54.0 // indirect
143-
golang.org/x/mod v0.37.0 // indirect
144-
golang.org/x/net v0.57.0 // indirect
142+
golang.org/x/crypto v0.55.0 // indirect
143+
golang.org/x/mod v0.40.0 // indirect
144+
golang.org/x/net v0.58.0 // indirect
145145
golang.org/x/sys v0.47.0 // indirect
146-
golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57 // indirect
147-
golang.org/x/tools v0.47.0 // indirect
146+
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5 // indirect
147+
golang.org/x/tools v0.49.0 // indirect
148148
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
149149
gopkg.in/yaml.v3 v3.0.1 // indirect
150150
nhooyr.io/websocket v1.8.6 // indirect

go.sum

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,8 +1526,8 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
15261526
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
15271527
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
15281528
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
1529-
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw=
1530-
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk=
1529+
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
1530+
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
15311531
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
15321532
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
15331533
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1581,8 +1581,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
15811581
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
15821582
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
15831583
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
1584-
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
1585-
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
1584+
golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs=
1585+
golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE=
15861586
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
15871587
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
15881588
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1656,8 +1656,8 @@ golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qx
16561656
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
16571657
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
16581658
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
1659-
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE=
1660-
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU=
1659+
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
1660+
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
16611661
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
16621662
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
16631663
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1822,8 +1822,8 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
18221822
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
18231823
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
18241824
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
1825-
golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57 h1:nwGZBCt+FnXUrGsj5vjzAsEmkcaFvd82BbOjECiFYZc=
1826-
golang.org/x/telemetry v0.0.0-20260625142307-59b4966ccb57/go.mod h1:3AWMyWHS+caVoiEXpiq6+tzKA40J4vQT3MYr80ZtQpc=
1825+
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5 h1:ZUSxONxc981v7AW7QUg+I9WwZzSTTJ019ENBYr5pV/Q=
1826+
golang.org/x/telemetry v0.0.0-20260811182544-a038080d80e5/go.mod h1:LVehoXe41cL5SCVQilsV7Gg6BNG+Js6P9PhSbYTIUkQ=
18271827
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
18281828
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
18291829
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -1839,8 +1839,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
18391839
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
18401840
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
18411841
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
1842-
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
1843-
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
1842+
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
1843+
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
18441844
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
18451845
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
18461846
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1932,8 +1932,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
19321932
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
19331933
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
19341934
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
1935-
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
1936-
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
1935+
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
1936+
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
19371937
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
19381938
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
19391939
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

manifests/bucketeer/charts/api/templates/deployment.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ spec:
225225
- name: BUCKETEER_API_SSE_MAX_CONNECTIONS
226226
value: "{{ .Values.env.sseMaxConnections }}"
227227
{{- end }}
228+
{{- if .Values.env.sseReadinessThreshold }}
229+
- name: BUCKETEER_API_SSE_READINESS_THRESHOLD
230+
value: "{{ .Values.env.sseReadinessThreshold }}"
231+
{{- end }}
228232
- name: BUCKETEER_API_SERVICE_TOKEN
229233
value: /usr/local/service-token/token
230234
- name: BUCKETEER_API_CERT

manifests/bucketeer/charts/api/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ env:
7676
cacheInvalidationTopic:
7777
sseHeartbeatInterval: 25s
7878
sseMaxConnections: 10000
79+
sseReadinessThreshold: 0.95
7980
logLevel: info
8081
grpcGatewayPort: 9089
8182
port: 9090
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Modify "audit_log" table: organization-level events are stored here with an
2+
-- empty environment_id, so organization admins can read their own activity.
3+
ALTER TABLE `audit_log` ADD COLUMN `organization_id` varchar(255) NOT NULL DEFAULT '', ALGORITHM=INSTANT;
4+
CREATE INDEX `idx_organization_id_timestamp_desc` ON `audit_log` (`organization_id`, `timestamp` DESC);

migration/mysql/atlas.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
h1:8YDpIU578LqzbUEvkNKDitZCF1LqIotUqMUsDTn5g08=
1+
h1:sS2p63rku0jPZajD6/sreQgblM6HPitbdC5vlWn+gNE=
22
20240626022133_initialization.sql h1:reSmqMhqnsrdIdPU2ezv/PXSL0COlRFX4gQA4U3/wMo=
33
20240708065726_update_audit_log_table.sql h1:fi8Xxw4WfSlHDyvq2Ni/8JUiZW8z/0qWWyWm6jFdUy8=
44
20240815043128_update_auto_ops_rule_table.sql h1:IKSW9W/XO6SWAYl5WPLJSg6KdsfcZ3rfQhIrf7aOnYc=
@@ -43,3 +43,4 @@ h1:8YDpIU578LqzbUEvkNKDitZCF1LqIotUqMUsDTn5g08=
4343
20260514000000_update_feature_variation_value_schema.sql h1:ocGacenoNr4+sVeCeWASFDnUn+Sn2n04XmZpSf+82qM=
4444
20260713000000_create_notification_tables.sql h1:87SKJUcoNMMv48953z5QyaS9c/AxzJamnf+SZ6/SMJU=
4545
20260728000000_add_notification_deleted.sql h1:yky/5yXtjVf4Vl9si/FJ5ODUSPzjC1NfUsyfLCTh97I=
46+
20260826000000_add_audit_log_organization_id.sql h1:rgjKMBWwGhPyBpm7UrSaQMNjW+YuMWpqD3ELK9rZaWo=
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- atlas:txmode none
2+
3+
-- Modify "audit_log" table: organization-level events are stored here with an
4+
-- empty environment_id, so organization admins can read their own activity.
5+
ALTER TABLE audit_log ADD COLUMN organization_id VARCHAR(255) NOT NULL DEFAULT '';
6+
CREATE INDEX CONCURRENTLY idx_audit_log_organization_timestamp ON audit_log (organization_id, timestamp DESC);

migration/postgres/atlas.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
h1:s6kmbtFcVifKk1JOyBlaUyVfQtEFuVNgbbGIlTM7A10=
1+
h1:lS18LuoPXqICDLNHWc+AfUWz0jFwtTggjgnjGw/z9pA=
22
20260226174000_initialization.sql h1:orWPjklxeOP046jFps+1UhJDdaSDPwDjlODiSe/479c=
33
20260514000000_update_feature_variation_value_schema.sql h1:Jp91HETgQvAvqNGTgSBip8ipx3aAI5C4Tsa2z8eplB4=
44
20260713000000_create_notification_tables.sql h1:TqsueyglKP41Towy2FsYTGyxI3+h4bRbpGS4MZLLNhw=
55
20260728000000_add_notification_deleted.sql h1:OqtTB/u1YAJXjuhwfCJjfTfuNuaLtSvbUvbXD/82L6E=
6+
20260826000000_add_audit_log_organization_id.sql h1:/o7AtAf2nIjI3jkKtmXn5BuR+odCMvNkGoIikRGGxZg=

pkg/api/api/grpc_status.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ func convertErrorReason(errorType pkgErr.ErrorType) string {
123123
return "EXCEEDED_MAX"
124124
case pkgErr.ErrorTypeOutOfRange:
125125
return "OUT_OF_RANGE"
126+
case pkgErr.ErrorTypeVariationInUseByOffVariation:
127+
return "VARIATION_IN_USE_BY_OFF_VARIATION"
128+
case pkgErr.ErrorTypeVariationInUseByDefaultStrategy:
129+
return "VARIATION_IN_USE_BY_DEFAULT_STRATEGY"
130+
case pkgErr.ErrorTypeVariationInUseByTargetingRule:
131+
return "VARIATION_IN_USE_BY_TARGETING_RULE"
132+
case pkgErr.ErrorTypeVariationInUseByIndividualTarget:
133+
return "VARIATION_IN_USE_BY_INDIVIDUAL_TARGETING"
134+
case pkgErr.ErrorTypeVariationInUseByPrerequisite:
135+
return "VARIATION_IN_USE_BY_PREREQUISITE"
136+
case pkgErr.ErrorTypeVariationInUseByFeatureFlagRule:
137+
return "VARIATION_IN_USE_BY_FEATURE_FLAG_RULE"
126138
default:
127139
return "UNKNOWN"
128140
}
@@ -150,7 +162,13 @@ func convertStatusCode(errorType pkgErr.ErrorType) codes.Code {
150162
return codes.Internal
151163
case pkgErr.ErrorTypeInternal:
152164
return codes.Internal
153-
case pkgErr.ErrorTypeFailedPrecondition:
165+
case pkgErr.ErrorTypeFailedPrecondition,
166+
pkgErr.ErrorTypeVariationInUseByOffVariation,
167+
pkgErr.ErrorTypeVariationInUseByDefaultStrategy,
168+
pkgErr.ErrorTypeVariationInUseByTargetingRule,
169+
pkgErr.ErrorTypeVariationInUseByIndividualTarget,
170+
pkgErr.ErrorTypeVariationInUseByPrerequisite,
171+
pkgErr.ErrorTypeVariationInUseByFeatureFlagRule:
154172
return codes.FailedPrecondition
155173
case pkgErr.ErrorTypeUnavailable:
156174
return codes.Unavailable

pkg/api/api/grpc_status_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"testing"
2020

2121
"github.com/stretchr/testify/assert"
22+
"github.com/stretchr/testify/require"
2223
"google.golang.org/genproto/googleapis/rpc/errdetails"
2324
"google.golang.org/grpc/codes"
2425

@@ -230,3 +231,74 @@ func TestNewGRPCStatus_EdgeCases(t *testing.T) {
230231
})
231232
}
232233
}
234+
235+
func TestNewGRPCStatus_VariationInUse(t *testing.T) {
236+
t.Parallel()
237+
238+
tests := []struct {
239+
name string
240+
errorType pkgErr.ErrorType
241+
expectedReason string
242+
}{
243+
{
244+
name: "off variation",
245+
errorType: pkgErr.ErrorTypeVariationInUseByOffVariation,
246+
expectedReason: "VARIATION_IN_USE_BY_OFF_VARIATION",
247+
},
248+
{
249+
name: "default strategy",
250+
errorType: pkgErr.ErrorTypeVariationInUseByDefaultStrategy,
251+
expectedReason: "VARIATION_IN_USE_BY_DEFAULT_STRATEGY",
252+
},
253+
{
254+
name: "targeting rule",
255+
errorType: pkgErr.ErrorTypeVariationInUseByTargetingRule,
256+
expectedReason: "VARIATION_IN_USE_BY_TARGETING_RULE",
257+
},
258+
{
259+
name: "individual targeting",
260+
errorType: pkgErr.ErrorTypeVariationInUseByIndividualTarget,
261+
expectedReason: "VARIATION_IN_USE_BY_INDIVIDUAL_TARGETING",
262+
},
263+
{
264+
name: "prerequisite",
265+
errorType: pkgErr.ErrorTypeVariationInUseByPrerequisite,
266+
expectedReason: "VARIATION_IN_USE_BY_PREREQUISITE",
267+
},
268+
{
269+
name: "feature flag rule",
270+
errorType: pkgErr.ErrorTypeVariationInUseByFeatureFlagRule,
271+
expectedReason: "VARIATION_IN_USE_BY_FEATURE_FLAG_RULE",
272+
},
273+
}
274+
275+
for _, tt := range tests {
276+
t.Run(tt.name, func(t *testing.T) {
277+
t.Parallel()
278+
279+
st := NewGRPCStatus(pkgErr.NewErrorVariationInUse(
280+
pkgErr.FeaturePackageName,
281+
tt.errorType,
282+
"variation in use",
283+
map[string]string{"featureId": "feature-2", "featureName": "Flag B"},
284+
))
285+
286+
assert.Equal(t, codes.FailedPrecondition, st.Code())
287+
assert.Equal(t, "feature:variation in use", st.Message())
288+
289+
var errorInfo *errdetails.ErrorInfo
290+
for _, detail := range st.Details() {
291+
if info, ok := detail.(*errdetails.ErrorInfo); ok {
292+
errorInfo = info
293+
break
294+
}
295+
}
296+
require.NotNil(t, errorInfo, "status must carry an ErrorInfo detail")
297+
298+
assert.Equal(t, tt.expectedReason, errorInfo.Reason)
299+
assert.Equal(t, string(tt.errorType), errorInfo.Metadata["messageKey"])
300+
assert.Equal(t, "feature-2", errorInfo.Metadata["featureId"])
301+
assert.Equal(t, "Flag B", errorInfo.Metadata["featureName"])
302+
})
303+
}
304+
}

0 commit comments

Comments
 (0)