@@ -3,11 +3,14 @@ package com.twitter.zipkin.receiver.kafka
3
3
import java .util .concurrent .LinkedBlockingQueue
4
4
5
5
import com .github .charithe .kafka .KafkaJunitRule
6
+ import com .twitter .io .Buf
6
7
import com .twitter .util .{Await , Future , Promise }
7
8
import com .twitter .zipkin .common ._
8
9
import com .twitter .zipkin .conversions .thrift ._
9
10
import com .twitter .zipkin .thriftscala .{Span => ThriftSpan }
10
11
import kafka .producer ._
12
+ import org .apache .thrift .protocol .{TType , TList , TBinaryProtocol }
13
+ import org .apache .thrift .transport .TMemoryBuffer
11
14
import org .junit .{ClassRule , Test }
12
15
import org .scalatest .junit .JUnitSuite
13
16
@@ -26,7 +29,7 @@ class KafkaProcessorSpec extends JUnitSuite {
26
29
val annotation = Annotation (1 , " value" , Some (Endpoint (1 , 2 , " service" )))
27
30
// Intentionally leaving timestamp and duration unset, as legacy instrumentation don't set this.
28
31
val span = Span (1234 , " methodname" , 4567 , annotations = List (annotation))
29
- val codec = new SpanCodec ()
32
+ val codec = new SpanDecoder ()
30
33
31
34
@ Test def messageWithSingleSpan () {
32
35
val topic = " single_span"
@@ -38,14 +41,33 @@ class KafkaProcessorSpec extends JUnitSuite {
38
41
}, codec, codec)
39
42
40
43
val producer = new Producer [Array [Byte ], Array [Byte ]](kafkaRule.producerConfigWithDefaultEncoder())
41
- producer.send(new KeyedMessage (topic, codec. encode(span)))
44
+ producer.send(new KeyedMessage (topic, encode(span)))
42
45
producer.close()
43
46
44
47
assert(Await .result(recvdSpan) == Seq (span.toThrift))
45
48
46
49
Await .result(service.close())
47
50
}
48
51
52
+ @ Test def messageWithMultipleSpans () {
53
+ val topic = " multiple_spans"
54
+ val recvdSpan = new Promise [Seq [ThriftSpan ]]
55
+
56
+ val service = KafkaProcessor (Map (topic -> 1 ), kafkaRule.consumerConfig(), { s =>
57
+ recvdSpan.setValue(s)
58
+ Future .value(true )
59
+ }, codec, codec)
60
+
61
+ val producer = new Producer [Array [Byte ], Array [Byte ]](kafkaRule.producerConfigWithDefaultEncoder())
62
+ producer.send(new KeyedMessage (topic, encode(Seq (span, span)))) // 2 spans in one message
63
+ producer.close()
64
+
65
+ // make sure we decoded both spans from the same message
66
+ assert(Await .result(recvdSpan) == Seq (span.toThrift, span.toThrift))
67
+
68
+ Await .result(service.close())
69
+ }
70
+
49
71
@ Test def skipsMalformedData () {
50
72
val topic = " malformed"
51
73
val recvdSpans = new LinkedBlockingQueue [Seq [ThriftSpan ]](3 )
@@ -57,14 +79,32 @@ class KafkaProcessorSpec extends JUnitSuite {
57
79
58
80
val producer = new Producer [Array [Byte ], Array [Byte ]](kafkaRule.producerConfigWithDefaultEncoder())
59
81
60
- producer.send(new KeyedMessage (topic, codec. encode(span)))
82
+ producer.send(new KeyedMessage (topic, encode(span)))
61
83
producer.send(new KeyedMessage (topic, " malformed" .getBytes()))
62
- producer.send(new KeyedMessage (topic, codec. encode(span)))
84
+ producer.send(new KeyedMessage (topic, encode(span)))
63
85
producer.close()
64
86
65
87
for (elem <- 1 until 2 )
66
88
assert(recvdSpans.take() == Seq (span.toThrift))
67
89
68
90
Await .result(service.close())
69
91
}
92
+
93
+ def encode (span : Span ) = {
94
+ val transport = new TMemoryBuffer (0 )
95
+ val oproto = new TBinaryProtocol (transport)
96
+ val tspan = spanToThriftSpan(span)
97
+ tspan.toThrift.write(oproto)
98
+ transport.getArray()
99
+ }
100
+
101
+ def encode (spans : Seq [Span ]) = {
102
+ // serialize all spans as a thrift list
103
+ val transport = new TMemoryBuffer (0 )
104
+ val oproto = new TBinaryProtocol (transport)
105
+ oproto.writeListBegin(new TList (TType .STRUCT , spans.size))
106
+ spans.map(spanToThriftSpan).foreach(_.toThrift.write(oproto))
107
+ oproto.writeListEnd()
108
+ transport.getArray()
109
+ }
70
110
}
0 commit comments