instana-haskell-trace-sdk-0.3.0.0: test/unit/Instana/SDK/Internal/SpanStackTest.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Instana.SDK.Internal.SpanStackTest (allTests) where
import Data.Aeson (Value)
import qualified Data.Aeson as Aeson
import Test.HUnit
import qualified Instana.SDK.Internal.Id as Id
import Instana.SDK.Internal.SpanStack (SpanStack)
import qualified Instana.SDK.Internal.SpanStack as SpanStack
import Instana.SDK.Span.EntrySpan (EntrySpan (RootEntrySpan))
import Instana.SDK.Span.ExitSpan (ExitSpan (ExitSpan))
import qualified Instana.SDK.Span.ExitSpan as ExitSpan
import Instana.SDK.Span.RootEntry (RootEntry (RootEntry))
import qualified Instana.SDK.Span.RootEntry as RootEntry
import Instana.SDK.Span.Span (Span (..), SpanKind (..))
allTests :: Test
allTests =
TestList
[ TestLabel "shouldCreateEmpty" shouldCreateEmpty
, TestLabel "popShouldReturnNothingOnEmpty" popShouldReturnNothingOnEmpty
, TestLabel "popWhenMatchesShouldReturnNothingOnEmpty"
popWhenMatchesShouldReturnNothingOnEmpty
, TestLabel "peekShouldReturnNothingOnEmpty" peekShouldReturnNothingOnEmpty
, TestLabel "popEmptyShouldLeaveEmpty" popEmptyShouldLeaveEmpty
, TestLabel "popWhenMatchesEmptyShouldLeaveEmpty"
popWhenMatchesEmptyShouldLeaveEmpty
, TestLabel "shouldPushEntry" shouldPushEntry
, TestLabel "shouldNotPushExitOnEmpty" shouldNotPushExitOnEmpty
, TestLabel "popShouldReturnEntry" popShouldReturnEntry
, TestLabel "popWhenMatchesShouldReturnEntry"
popWhenMatchesShouldReturnEntry
, TestLabel "popWhenNotMatchesEntryShouldReturnNothing"
popWhenNotMatchesEntryShouldReturnNothing
, TestLabel "peekShouldReturnEntry" peekShouldReturnEntry
, TestLabel "popEntryShouldLeaveEmpty" popEntryShouldLeaveEmpty
, TestLabel "popEntryWhenMatchesShouldLeaveEmpty"
popEntryWhenMatchesShouldLeaveEmpty
, TestLabel "popEntryWhenNotMatchesEntryShouldLeaveStackUnchanged"
popEntryWhenNotMatchesEntryShouldLeaveStackUnchanged
, TestLabel "shouldPushExit" shouldPushExit
, TestLabel "shouldNotPushEntryOnEntry" shouldNotPushEntryOnEntry
, TestLabel "popShouldReturnExit" popShouldReturnExit
, TestLabel "popWhenMatchesShouldReturnExit" popWhenMatchesShouldReturnExit
, TestLabel "popWhenNotMatchesExitShouldReturnNothing"
popWhenNotMatchesExitShouldReturnNothing
, TestLabel "peekShouldReturnExit" peekShouldReturnExit
, TestLabel "popExitShouldLeaveNotEmpty" popExitShouldLeaveNotEmpty
, TestLabel "popExitWhenMatcheShouldLeaveNotEmpty"
popExitWhenMatcheShouldLeaveNotEmpty
, TestLabel "popExitWhenNotMatcheExitShouldLeaveNotEmpty"
popExitWhenNotMatcheExitShouldLeaveNotEmpty
, TestLabel "popPopShouldReturnEntry" popPopShouldReturnEntry
, TestLabel "popPeekShouldReturnEntry" popPeekShouldReturnEntry
, TestLabel "popPopShouldLeaveEmpty" popPopShouldLeaveEmpty
]
shouldCreateEmpty :: Test
shouldCreateEmpty =
TestCase $
assertBool "empty" $ SpanStack.isEmpty empty
popShouldReturnNothingOnEmpty :: Test
popShouldReturnNothingOnEmpty =
TestCase $
assertEqual "empty#pop" Nothing (snd $ SpanStack.pop empty)
popWhenMatchesShouldReturnNothingOnEmpty :: Test
popWhenMatchesShouldReturnNothingOnEmpty =
TestCase $
assertEqual "empty#popWhenMatches" Nothing (snd3 $ SpanStack.popWhenMatches EntryKind empty)
peekShouldReturnNothingOnEmpty :: Test
peekShouldReturnNothingOnEmpty =
TestCase $
assertEqual "empty#peek" Nothing (SpanStack.peek empty)
popEmptyShouldLeaveEmpty :: Test
popEmptyShouldLeaveEmpty =
TestCase $
assertBool "empty#pop leaves empty" $
SpanStack.isEmpty $ (fst $ SpanStack.pop empty)
popWhenMatchesEmptyShouldLeaveEmpty :: Test
popWhenMatchesEmptyShouldLeaveEmpty =
TestCase $
assertBool "empty#popWhenMatches leaves empty" $
SpanStack.isEmpty $ (fst3 $ SpanStack.popWhenMatches EntryKind empty)
shouldPushEntry :: Test
shouldPushEntry =
TestCase $
assertBool "push entry" $ not $ SpanStack.isEmpty entryOnly
shouldNotPushExitOnEmpty :: Test
shouldNotPushExitOnEmpty =
let
stack = SpanStack.push (Exit exitSpan) $ SpanStack.empty
in
TestCase $
assertBool "push exit on emtpy" $ SpanStack.isEmpty stack
popShouldReturnEntry :: Test
popShouldReturnEntry =
TestCase $
assertEqual "push/pop"
(Just $ Entry entrySpan)
(snd $ SpanStack.pop entryOnly)
popWhenMatchesShouldReturnEntry :: Test
popWhenMatchesShouldReturnEntry =
TestCase $
assertEqual "push/popWhenMatches"
(Just $ Entry entrySpan)
(snd3 $ SpanStack.popWhenMatches EntryKind entryOnly)
popWhenNotMatchesEntryShouldReturnNothing :: Test
popWhenNotMatchesEntryShouldReturnNothing =
TestCase $
assertEqual "push/popWhenNotMatches"
(Nothing)
(snd3 $ SpanStack.popWhenMatches ExitKind entryOnly)
peekShouldReturnEntry :: Test
peekShouldReturnEntry =
TestCase $
assertEqual "push/peek"
(Just $ Entry entrySpan)
(SpanStack.peek entryOnly)
popEntryShouldLeaveEmpty :: Test
popEntryShouldLeaveEmpty =
TestCase $
assertBool "push/pop leaves empty" $
SpanStack.isEmpty $ (fst $ SpanStack.pop entryOnly)
popEntryWhenMatchesShouldLeaveEmpty :: Test
popEntryWhenMatchesShouldLeaveEmpty =
TestCase $
assertBool "push/popWhenMatches leaves empty" $
SpanStack.isEmpty $ (fst3 $ SpanStack.popWhenMatches EntryKind entryOnly)
popEntryWhenNotMatchesEntryShouldLeaveStackUnchanged :: Test
popEntryWhenNotMatchesEntryShouldLeaveStackUnchanged =
let
newStack = fst3 $ SpanStack.popWhenMatches ExitKind entryOnly
top = SpanStack.peek newStack
in
TestCase $
assertEqual "push/popWhenNotMatches leaves stack unchanged"
(Just $ Entry entrySpan)
top
shouldPushExit :: Test
shouldPushExit =
TestCase $
assertBool "push exit" $ not $ SpanStack.isEmpty entryAndExit
shouldNotPushEntryOnEntry :: Test
shouldNotPushEntryOnEntry =
let
stack = SpanStack.push (Entry entrySpan) $ entryOnly
top = SpanStack.peek stack
in
TestCase $
assertEqual "push entry on entry"
(Just $ Entry entrySpan)
top
popShouldReturnExit :: Test
popShouldReturnExit =
TestCase $
assertEqual "push/push/pop"
(Just $ Exit exitSpan)
(snd $ SpanStack.pop entryAndExit)
popWhenMatchesShouldReturnExit :: Test
popWhenMatchesShouldReturnExit =
TestCase $
assertEqual "push/push/popWhenMatches"
(Just $ Exit exitSpan)
(snd3 $ SpanStack.popWhenMatches ExitKind entryAndExit)
popWhenNotMatchesExitShouldReturnNothing :: Test
popWhenNotMatchesExitShouldReturnNothing =
let
in
TestCase $
assertEqual "push/push/popWhenNotMatches"
Nothing
(snd3 $ SpanStack.popWhenMatches EntryKind entryAndExit)
peekShouldReturnExit :: Test
peekShouldReturnExit =
TestCase $
assertEqual "push/push/peek"
(Just $ Exit exitSpan)
(SpanStack.peek entryAndExit)
popExitShouldLeaveNotEmpty :: Test
popExitShouldLeaveNotEmpty =
TestCase $
assertBool "push/push/pop leaves not empty" $
not $ SpanStack.isEmpty $ (fst $ SpanStack.pop entryAndExit)
popExitWhenMatcheShouldLeaveNotEmpty :: Test
popExitWhenMatcheShouldLeaveNotEmpty =
TestCase $
assertBool "push/push/popWhenMatches leaves not empty" $
not $ SpanStack.isEmpty $
(fst3 $ SpanStack.popWhenMatches ExitKind entryAndExit)
popExitWhenNotMatcheExitShouldLeaveNotEmpty :: Test
popExitWhenNotMatcheExitShouldLeaveNotEmpty =
let
newStack = fst3 $ SpanStack.popWhenMatches EntryKind entryAndExit
top = SpanStack.peek newStack
in
TestCase $
assertEqual "push/push/popWhenNotMatches leaves stack unchanged"
(Just $ Exit exitSpan)
top
popPopShouldReturnEntry :: Test
popPopShouldReturnEntry =
TestCase $
assertEqual "push/push/pop/pop"
(Just $ Entry entrySpan)
(snd $ SpanStack.pop $ fst $ SpanStack.pop entryAndExit)
popPeekShouldReturnEntry :: Test
popPeekShouldReturnEntry =
TestCase $
assertEqual "push/push/pop/peek"
(Just $ Entry entrySpan)
(SpanStack.peek $ fst $ SpanStack.pop entryAndExit)
popPopShouldLeaveEmpty :: Test
popPopShouldLeaveEmpty =
TestCase $
assertBool "push/push/pop/pop leaves empty" $
SpanStack.isEmpty $
fst $ SpanStack.pop $
fst $ SpanStack.pop entryAndExit
empty :: SpanStack
empty =
SpanStack.empty
entryOnly :: SpanStack
entryOnly =
SpanStack.push (Entry entrySpan) $ empty
entryAndExit :: SpanStack
entryAndExit =
SpanStack.push (Exit exitSpan) $ entryOnly
entrySpan :: EntrySpan
entrySpan =
RootEntrySpan $
RootEntry
{ RootEntry.spanAndTraceId = Id.fromString "traceId"
, RootEntry.spanName = "test.entry"
, RootEntry.timestamp = 1514761200000
, RootEntry.errorCount = 0
, RootEntry.serviceName = Nothing
, RootEntry.spanData = emptyValue
}
exitSpan :: ExitSpan
exitSpan =
ExitSpan
{ ExitSpan.parentSpan = entrySpan
, ExitSpan.spanId = Id.fromString "spanId"
, ExitSpan.spanName = "test.exit"
, ExitSpan.timestamp = 1514761201000
, ExitSpan.errorCount = 0
, ExitSpan.serviceName = Nothing
, ExitSpan.spanData = emptyValue
}
emptyValue :: Value
emptyValue = Aeson.object []
fst3 :: (a, b, c) -> a
fst3 (a, _, _) = a
snd3 :: (a, b, c) -> b
snd3 (_, b, _) = b