@@ -18,6 +18,7 @@ import (
1818
1919 "github.com/stretchr/testify/assert"
2020 "github.com/stretchr/testify/require"
21+ "go.opentelemetry.io/otel/trace"
2122
2223 "go.opentelemetry.io/collector/component"
2324 "go.opentelemetry.io/collector/component/componenttest"
@@ -1205,3 +1206,181 @@ func requireCurrentlyDispatchedItemsEqual(t *testing.T, pq *persistentQueue[uint
12051206 defer pq .mu .Unlock ()
12061207 assert .ElementsMatch (t , compare , pq .currentlyDispatchedItems )
12071208}
1209+
1210+ func TestSpanContextFromWrapper (t * testing.T ) {
1211+ testCases := []struct {
1212+ name string
1213+ wrapper spanContextConfigWrapper
1214+ expectErr bool
1215+ errContains string
1216+ expectNil bool
1217+ expectValid bool
1218+ expectTraceID string
1219+ expectSpanID string
1220+ expectFlags string
1221+ expectState string
1222+ expectRemote bool
1223+ }{
1224+ {
1225+ name : "invalid trace id" ,
1226+ wrapper : spanContextConfigWrapper {
1227+ TraceID : "invalidtraceid" ,
1228+ SpanID : "0102030405060708" ,
1229+ TraceFlags : "01" ,
1230+ TraceState : "" ,
1231+ Remote : false ,
1232+ },
1233+ expectErr : true ,
1234+ expectNil : true ,
1235+ },
1236+ {
1237+ name : "invalid span id" ,
1238+ wrapper : spanContextConfigWrapper {
1239+ TraceID : "0102030405060708090a0b0c0d0e0f10" ,
1240+ SpanID : "invalidspanid" ,
1241+ TraceFlags : "01" ,
1242+ TraceState : "" ,
1243+ Remote : false ,
1244+ },
1245+ expectErr : true ,
1246+ expectNil : true ,
1247+ },
1248+ {
1249+ name : "invalid trace flags hex" ,
1250+ wrapper : spanContextConfigWrapper {
1251+ TraceID : "0102030405060708090a0b0c0d0e0f10" ,
1252+ SpanID : "0102030405060708" ,
1253+ TraceFlags : "zz" ,
1254+ TraceState : "" ,
1255+ Remote : false ,
1256+ },
1257+ expectErr : true ,
1258+ expectNil : true ,
1259+ },
1260+ {
1261+ name : "invalid trace flags length" ,
1262+ wrapper : spanContextConfigWrapper {
1263+ TraceID : "0102030405060708090a0b0c0d0e0f10" ,
1264+ SpanID : "0102030405060708" ,
1265+ TraceFlags : "0102" ,
1266+ TraceState : "" ,
1267+ Remote : false ,
1268+ },
1269+ expectErr : true ,
1270+ expectNil : true ,
1271+ errContains : errInvalidTraceFlagsLength ,
1272+ },
1273+ {
1274+ name : "invalid trace state" ,
1275+ wrapper : spanContextConfigWrapper {
1276+ TraceID : "0102030405060708090a0b0c0d0e0f10" ,
1277+ SpanID : "0102030405060708" ,
1278+ TraceFlags : "01" ,
1279+ TraceState : "invalid=tracestate,=bad" ,
1280+ Remote : false ,
1281+ },
1282+ expectErr : true ,
1283+ expectNil : true ,
1284+ },
1285+ {
1286+ name : "valid span context" ,
1287+ wrapper : spanContextConfigWrapper {
1288+ TraceID : "0102030405060708090a0b0c0d0e0f10" ,
1289+ SpanID : "0102030405060708" ,
1290+ TraceFlags : "01" ,
1291+ TraceState : "vendor=value" ,
1292+ Remote : true ,
1293+ },
1294+ expectErr : false ,
1295+ expectNil : false ,
1296+ expectValid : true ,
1297+ expectTraceID : "0102030405060708090a0b0c0d0e0f10" ,
1298+ expectSpanID : "0102030405060708" ,
1299+ expectFlags : "01" ,
1300+ expectState : "vendor=value" ,
1301+ expectRemote : true ,
1302+ },
1303+ }
1304+
1305+ for _ , tc := range testCases {
1306+ t .Run (tc .name , func (t * testing.T ) {
1307+ scc , err := SpanContextFromWrapper (tc .wrapper )
1308+ if tc .expectErr {
1309+ require .Error (t , err )
1310+ if tc .errContains != "" {
1311+ assert .Contains (t , err .Error (), tc .errContains )
1312+ }
1313+ } else {
1314+ require .NoError (t , err )
1315+ }
1316+ if tc .expectNil {
1317+ assert .Nil (t , scc )
1318+ } else {
1319+ assert .NotNil (t , scc )
1320+ if tc .expectValid {
1321+ assert .True (t , scc .IsValid ())
1322+ assert .Equal (t , tc .expectTraceID , scc .TraceID ().String ())
1323+ assert .Equal (t , tc .expectSpanID , scc .SpanID ().String ())
1324+ assert .Equal (t , tc .expectFlags , scc .TraceFlags ().String ())
1325+ assert .Equal (t , tc .expectState , scc .TraceState ().String ())
1326+ assert .Equal (t , tc .expectRemote , scc .IsRemote ())
1327+ }
1328+ }
1329+ })
1330+ }
1331+ }
1332+
1333+ func TestPersistentQueue_SpanContextRoundTrip (t * testing.T ) {
1334+ // Setup a minimal persistent queue using uint64Encoding and uint64
1335+ pq := newPersistentQueue [uint64 ](persistentQueueSettings [uint64 ]{
1336+ sizer : request.RequestsSizer [uint64 ]{},
1337+ capacity : 10 ,
1338+ signal : pipeline .SignalTraces ,
1339+ storageID : component.ID {},
1340+ encoding : uint64Encoding {},
1341+ id : component .NewID (exportertest .NopType ),
1342+ telemetry : componenttest .NewNopTelemetrySettings (),
1343+ }).(* persistentQueue [uint64 ])
1344+
1345+ ext := storagetest .NewMockStorageExtension (nil )
1346+ client , err := ext .GetClient (context .Background (), component .KindExporter , pq .set .id , pq .set .signal .String ())
1347+ require .NoError (t , err )
1348+ pq .initClient (context .Background (), client )
1349+
1350+ // Create a valid SpanContext
1351+ traceID , _ := trace .TraceIDFromHex ("0102030405060708090a0b0c0d0e0f10" )
1352+ spanID , _ := trace .SpanIDFromHex ("0102030405060708" )
1353+ sc := trace .NewSpanContext (trace.SpanContextConfig {
1354+ TraceID : traceID ,
1355+ SpanID : spanID ,
1356+ TraceFlags : 0x01 ,
1357+ TraceState : trace.TraceState {},
1358+ Remote : true ,
1359+ })
1360+ ctxWithSC := trace .ContextWithSpanContext (context .Background (), sc )
1361+
1362+ // Offer a request with this context
1363+ req := uint64 (42 )
1364+ require .NoError (t , pq .Offer (ctxWithSC , req ))
1365+
1366+ // Read the request and restored context
1367+ restoredCtx , gotReq , _ , ok := pq .Read (context .Background ())
1368+ require .True (t , ok )
1369+ assert .Equal (t , req , gotReq )
1370+ restoredSC := trace .SpanContextFromContext (restoredCtx )
1371+ assert .True (t , restoredSC .IsValid ())
1372+ assert .Equal (t , sc .TraceID (), restoredSC .TraceID ())
1373+ assert .Equal (t , sc .SpanID (), restoredSC .SpanID ())
1374+ assert .Equal (t , sc .TraceFlags (), restoredSC .TraceFlags ())
1375+ assert .Equal (t , sc .TraceState ().String (), restoredSC .TraceState ().String ())
1376+ assert .Equal (t , sc .IsRemote (), restoredSC .IsRemote ())
1377+
1378+ // Also test with a context with no SpanContext
1379+ req2 := uint64 (99 )
1380+ require .NoError (t , pq .Offer (context .Background (), req2 ))
1381+ restoredCtx2 , gotReq2 , _ , ok2 := pq .Read (context .Background ())
1382+ require .True (t , ok2 )
1383+ assert .Equal (t , req2 , gotReq2 )
1384+ restoredSC2 := trace .SpanContextFromContext (restoredCtx2 )
1385+ assert .False (t , restoredSC2 .IsValid ())
1386+ }
0 commit comments