opentelemetry-extra-0.4.0: unit-tests/TestEventlogStreaming.hs
{-# LANGUAGE OverloadedStrings #-}
module TestEventlogStreaming where
import Data.Function
import qualified Data.HashMap.Strict as HM
import qualified Data.HashSet as HS
import Data.Hashable
import Data.List (foldl', sort)
import qualified Data.Text as T
import Data.Word
import GHC.RTS.Events
import OpenTelemetry.Common hiding (Event)
import OpenTelemetry.EventlogStreaming_Internal
import OpenTelemetry.SpanContext
import Test.QuickCheck
import Text.Printf
import TextShow
instance Arbitrary SpanId where
arbitrary = SId <$> arbitrary
processEvents :: [Event] -> State -> (State, [Span])
processEvents events st0 = foldl' go (st0, []) events
where
go (st, sps) e =
let (st', sps') = processEvent e st
in (st', sps' <> sps)
prop_number_of_spans_in_eventlog_is_number_of_spans_exported :: [(Word64, Int)] -> Bool
prop_number_of_spans_in_eventlog_is_number_of_spans_exported spans =
let input_events = concatMap convert spans
convert (span_serial_number, thread_id) =
[ Event 0 (UserMessage {msg = T.pack $ printf "ot2 begin span %d %d" span_serial_number thread_id}) (Just 0),
Event 42 (UserMessage {msg = T.pack $ printf "ot2 end span %d" span_serial_number}) (Just 0)
]
(_end_state, emitted_spans) = processEvents input_events (initialState 0 (error "randomGen seed"))
in length emitted_spans == length spans
prop_user_specified_span_ids_are_used :: [(Word64, SpanId, Int)] -> Bool
prop_user_specified_span_ids_are_used spans =
let input_events = concatMap convert spans
convert (span_serial_number, SId sid, thread_id) =
[ Event 0 (UserMessage {msg = T.pack $ printf "ot2 begin span %d %d" span_serial_number thread_id}) (Just 0),
Event 1 (UserMessage {msg = T.pack $ printf "ot2 set spanid %d %016x" span_serial_number sid}) (Just 0),
Event 42 (UserMessage {msg = T.pack $ printf "ot2 end span %d" span_serial_number}) (Just 0)
]
(_end_state, emitted_spans) = processEvents input_events (initialState 0 (error "randomGen seed"))
in sort (map (\(_, x, _) -> x) spans) == sort (map spanId emitted_spans)
prop_user_specified_things_are_used :: [(Word64, SpanId, Int)] -> Property
prop_user_specified_things_are_used spans =
distinct (map (\(serial, _, _) -> serial) spans)
==> distinct (map (\(_, span_id, _) -> span_id) spans)
==> classify (length spans > 1) "multiple spans"
$ let input_events = concatMap convert spans
convert (span_serial_number, SId sid, thread_id) =
[ Event 0 (UserMessage {msg = T.pack $ printf "ot2 begin span %d %d" span_serial_number thread_id}) (Just 0),
Event 1 (UserMessage {msg = T.pack $ printf "ot2 set spanid %d %016x" span_serial_number sid}) (Just 0),
Event 2 (UserMessage {msg = T.pack $ printf "ot2 set tag %d color %d" span_serial_number sid}) (Just 0),
Event 3 (UserMessage {msg = T.pack $ printf "ot2 set traceid %d %016x" span_serial_number sid}) (Just 0),
Event 4 (UserMessage {msg = T.pack $ printf "ot2 add event %d message %d" span_serial_number sid}) (Just 0),
Event 42 (UserMessage {msg = T.pack $ printf "ot2 end span %d" span_serial_number}) (Just 0)
]
(_end_state, emitted_spans) = processEvents input_events (initialState 0 (error "randomGen seed"))
corresponding_span_was_emitted (_serial, SId sid, _thread_id) =
emitted_spans
& filter
( \sp ->
and
[ spanId sp == SId sid,
spanTraceId sp == TId sid,
HM.lookup "color" (spanTags sp) == Just (StringTagValue (showt sid)),
any
(\SpanEvent {..} -> spanEventKey == "message" && spanEventValue == showt sid)
(spanEvents sp)
]
)
& length
& (== (1 :: Int))
in conjoin $ map corresponding_span_was_emitted spans
prop_parenting_works_when_everything_is_on_one_thread_and_nested_properly :: [Word64] -> Property
prop_parenting_works_when_everything_is_on_one_thread_and_nested_properly serials =
distinct serials ==> length serials > 1
==> let input_events = prelude <> map convert_begin serials <> map convert_end (reverse serials)
prelude = [Event 0 (CreateThread 1) (Just 0)]
convert_begin serial =
Event 1 (UserMessage {msg = T.pack $ printf "ot2 begin span %d %d" serial serial}) (Just 0)
convert_end serial =
Event 42 (UserMessage {msg = T.pack $ printf "ot2 end span %d" serial}) (Just 0)
(_end_state, emitted_spans) = processEvents input_events (initialState 0 (error "randomGen seed"))
check_relationship (sp, psp) = spanParentId sp === Just (spanId psp)
in conjoin $ map check_relationship (zip (tail emitted_spans) emitted_spans)
prop_beginning_a_span_on_one_thread_and_ending_on_another_is_fine :: Word64 -> ThreadId -> ThreadId -> Int -> Int -> Property
prop_beginning_a_span_on_one_thread_and_ending_on_another_is_fine serial begin_tid end_tid begin_cap end_cap =
let input_events =
[ Event 0 (CreateThread begin_tid) (Just begin_cap),
Event 1 (RunThread begin_tid) (Just begin_cap),
Event 2 (UserMessage {msg = T.pack $ printf "ot2 begin span %d %d" serial serial}) (Just begin_cap),
Event 3 (CreateThread end_tid) (Just end_cap),
Event 4 (RunThread end_tid) (Just end_cap),
Event 5 (UserMessage {msg = T.pack $ printf "ot2 end span %d" serial}) (Just end_cap)
]
(end_state, emitted_spans) = processEvents input_events (initialState 0 (error "randomGen seed"))
in conjoin
[ length emitted_spans === 1,
spanOperation (head emitted_spans) === showt serial,
spanStartedAt (head emitted_spans) === 2,
spanFinishedAt (head emitted_spans) === 5,
spanThreadId (head emitted_spans) === begin_tid,
True === null (spans end_state),
True === null (serial2sid end_state)
]
distinct :: (Eq a, Hashable a) => [a] -> Bool
distinct things = length things == HS.size (foldMap HS.singleton things)