@@ -17,6 +17,7 @@ import (
1717 "github.com/google/go-cmp/cmp"
1818 "github.com/google/go-cmp/cmp/cmpopts"
1919 pkgErrors "github.com/pkg/errors"
20+ "github.com/stretchr/testify/assert"
2021 "github.com/stretchr/testify/require"
2122)
2223
@@ -1054,3 +1055,185 @@ func TestClient_SetupTelemetryBuffer_NoDSN(t *testing.T) {
10541055 t .Fatalf ("expected noopTransport, got %T" , client .Transport )
10551056 }
10561057}
1058+
1059+ type multiClientEnv struct {
1060+ client1 , client2 * Client
1061+ transport1 , transport2 * MockTransport
1062+ hub1 , hub2 * Hub
1063+ ctx1 , ctx2 context.Context
1064+ traceID1 , traceID2 TraceID
1065+ }
1066+
1067+ func setupMultiClientEnv (t * testing.T ) * multiClientEnv {
1068+ t .Helper ()
1069+ mkClient := func (dsn string ) (* Client , * MockTransport ) {
1070+ tr := & MockTransport {}
1071+ c , err := NewClient (ClientOptions {
1072+ Dsn : dsn ,
1073+ Transport : tr ,
1074+ EnableLogs : true ,
1075+ Integrations : func (_ []Integration ) []Integration {
1076+ return []Integration {}
1077+ },
1078+ })
1079+ require .NoError (t , err )
1080+ return c , tr
1081+ }
1082+
1083+ e := & multiClientEnv {}
1084+ e .client1 , e .transport1 = mkClient ("https://public@example.com/sentry/1" )
1085+ e .client2 , e .transport2 = mkClient ("https://public@example.com/sentry/2" )
1086+ e .traceID1 = TraceIDFromHex ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1" )
1087+ e .traceID2 = TraceIDFromHex ("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb2" )
1088+
1089+ scope1 := NewScope ()
1090+ scope1 .SetPropagationContext (PropagationContext {TraceID : e .traceID1 })
1091+ scope2 := NewScope ()
1092+ scope2 .SetPropagationContext (PropagationContext {TraceID : e .traceID2 })
1093+
1094+ e .hub1 = NewHub (e .client1 , scope1 )
1095+ e .hub2 = NewHub (e .client2 , scope2 )
1096+ e .ctx1 = SetHubOnContext (context .Background (), e .hub1 )
1097+ e .ctx2 = SetHubOnContext (context .Background (), e .hub2 )
1098+
1099+ t .Cleanup (func () {
1100+ e .client1 .Close ()
1101+ e .client2 .Close ()
1102+ })
1103+ return e
1104+ }
1105+
1106+ func (e * multiClientEnv ) resetTransports () {
1107+ e .transport1 .mu .Lock ()
1108+ e .transport1 .events = nil
1109+ e .transport1 .mu .Unlock ()
1110+ e .transport2 .mu .Lock ()
1111+ e .transport2 .events = nil
1112+ e .transport2 .mu .Unlock ()
1113+ }
1114+
1115+ func (e * multiClientEnv ) flushAll () {
1116+ e .client1 .Flush (5 * time .Second )
1117+ e .client2 .Flush (5 * time .Second )
1118+ }
1119+
1120+ func eventTraceID (t * testing.T , ev * Event ) TraceID {
1121+ t .Helper ()
1122+ traceCtx , ok := ev .Contexts ["trace" ]
1123+ require .True (t , ok , "event should have a trace context" )
1124+ tid , ok := traceCtx ["trace_id" ].(TraceID )
1125+ require .True (t , ok , "trace context should contain a TraceID" )
1126+ return tid
1127+ }
1128+
1129+ func TestClient_MultiClientSetup (t * testing.T ) {
1130+ t .Run ("signals_route_to_correct_client" , func (t * testing.T ) {
1131+ e := setupMultiClientEnv (t )
1132+
1133+ e .hub1 .CaptureMessage ("msg-from-client1" )
1134+ e .hub2 .CaptureMessage ("msg-from-client2" )
1135+
1136+ require .Len (t , e .transport1 .Events (), 1 )
1137+ require .Len (t , e .transport2 .Events (), 1 )
1138+ assert .Equal (t , "msg-from-client1" , e .transport1 .Events ()[0 ].Message )
1139+ assert .Equal (t , "msg-from-client2" , e .transport2 .Events ()[0 ].Message )
1140+ assert .Equal (t , e .traceID1 , eventTraceID (t , e .transport1 .Events ()[0 ]),
1141+ "event on client1 should carry hub1's trace ID" )
1142+ assert .Equal (t , e .traceID2 , eventTraceID (t , e .transport2 .Events ()[0 ]),
1143+ "event on client2 should carry hub2's trace ID" )
1144+ e .resetTransports ()
1145+
1146+ NewLogger (e .ctx1 ).Info ().WithCtx (e .ctx1 ).Emit ("log-from-client1" )
1147+ NewLogger (e .ctx2 ).Info ().WithCtx (e .ctx2 ).Emit ("log-from-client2" )
1148+ e .flushAll ()
1149+
1150+ require .Len (t , e .transport1 .Events (), 1 , "client1 transport should have 1 log event" )
1151+ require .Len (t , e .transport2 .Events (), 1 , "client2 transport should have 1 log event" )
1152+ require .Len (t , e .transport1 .Events ()[0 ].Logs , 1 )
1153+ require .Len (t , e .transport2 .Events ()[0 ].Logs , 1 )
1154+ assert .Equal (t , "log-from-client1" , e .transport1 .Events ()[0 ].Logs [0 ].Body )
1155+ assert .Equal (t , "log-from-client2" , e .transport2 .Events ()[0 ].Logs [0 ].Body )
1156+ assert .Equal (t , e .traceID1 , e .transport1 .Events ()[0 ].Logs [0 ].TraceID ,
1157+ "log on client1 should carry hub1's trace ID" )
1158+ assert .Equal (t , e .traceID2 , e .transport2 .Events ()[0 ].Logs [0 ].TraceID ,
1159+ "log on client2 should carry hub2's trace ID" )
1160+ e .resetTransports ()
1161+
1162+ NewMeter (e .ctx1 ).Count ("counter-from-client1" , 1 )
1163+ NewMeter (e .ctx2 ).Count ("counter-from-client2" , 2 )
1164+ e .flushAll ()
1165+
1166+ require .Len (t , e .transport1 .Events (), 1 , "client1 transport should have 1 metric event" )
1167+ require .Len (t , e .transport2 .Events (), 1 , "client2 transport should have 1 metric event" )
1168+ require .Len (t , e .transport1 .Events ()[0 ].Metrics , 1 )
1169+ require .Len (t , e .transport2 .Events ()[0 ].Metrics , 1 )
1170+ assert .Equal (t , "counter-from-client1" , e .transport1 .Events ()[0 ].Metrics [0 ].Name )
1171+ assert .Equal (t , "counter-from-client2" , e .transport2 .Events ()[0 ].Metrics [0 ].Name )
1172+ })
1173+
1174+ t .Run ("signals_respect_emit_context_client" , func (t * testing.T ) {
1175+ e := setupMultiClientEnv (t )
1176+ logger := NewLogger (e .ctx1 )
1177+ meter := NewMeter (e .ctx1 )
1178+ logger .Info ().WithCtx (e .ctx2 ).Emit ("cross-context-log" )
1179+ meter .WithCtx (e .ctx2 ).Count ("cross-context-count" , 1 )
1180+ e .flushAll ()
1181+
1182+ assert .Empty (t , e .transport1 .Events (),
1183+ "creation-time client should NOT receive the log when emit context points elsewhere" )
1184+ require .Len (t , e .transport2 .Events (), 2 ,
1185+ "emit-context client should receive the signals" )
1186+ require .Len (t , e .transport2 .Events ()[0 ].Logs , 1 )
1187+ require .Len (t , e .transport2 .Events ()[1 ].Metrics , 1 )
1188+ assert .Equal (t , "cross-context-log" , e .transport2 .Events ()[0 ].Logs [0 ].Body )
1189+ assert .Equal (t , "cross-context-count" , e .transport2 .Events ()[1 ].Metrics [0 ].Name )
1190+ assert .Equal (t , e .traceID2 , e .transport2 .Events ()[0 ].Logs [0 ].TraceID ,
1191+ "trace ID should come from the emit context's hub, not the creation context" )
1192+ })
1193+
1194+ t .Run ("signals_follow_bind_client" , func (t * testing.T ) {
1195+ e := setupMultiClientEnv (t )
1196+
1197+ traceID := TraceIDFromHex ("cccccccccccccccccccccccccccccccc" )
1198+ scope := NewScope ()
1199+ scope .SetPropagationContext (PropagationContext {TraceID : traceID })
1200+ hub := NewHub (e .client1 , scope )
1201+ ctx := SetHubOnContext (context .Background (), hub )
1202+ logger := NewLogger (ctx )
1203+ meter := NewMeter (ctx )
1204+
1205+ hub .BindClient (e .client2 )
1206+
1207+ hub .CaptureMessage ("event-after-rebind" )
1208+ logger .Info ().WithCtx (ctx ).Emit ("log-after-rebind" )
1209+ meter .WithCtx (ctx ).Count ("count-after-rebind" , 1 )
1210+ e .flushAll ()
1211+
1212+ assert .Empty (t , e .transport1 .Events (),
1213+ "old client should not receive any signals after BindClient" )
1214+ require .Len (t , e .transport2 .Events (), 3 ,
1215+ "new client should receive all signals" )
1216+
1217+ var gotEvent , gotLog , gotMetric bool
1218+ for _ , ev := range e .transport2 .Events () {
1219+ if ev .Message == "event-after-rebind" {
1220+ gotEvent = true
1221+ assert .Equal (t , traceID , eventTraceID (t , ev ),
1222+ "event should carry the hub's trace ID" )
1223+ }
1224+ if len (ev .Logs ) == 1 && ev .Logs [0 ].Body == "log-after-rebind" {
1225+ gotLog = true
1226+ assert .Equal (t , traceID , ev .Logs [0 ].TraceID ,
1227+ "log should carry the hub's trace ID" )
1228+ }
1229+ if len (ev .Metrics ) == 1 && ev .Metrics [0 ].Name == "count-after-rebind" {
1230+ gotMetric = true
1231+ assert .Equal (t , traceID , ev .Metrics [0 ].TraceID ,
1232+ "count should carry the hub's trace ID" )
1233+ }
1234+ }
1235+ assert .True (t , gotEvent , "event should arrive at new client" )
1236+ assert .True (t , gotLog , "log should arrive at new client" )
1237+ assert .True (t , gotMetric , "count should arrive at new client" )
1238+ })
1239+ }
0 commit comments