Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 4de36c5

Browse files
author
Patrick Thomson
committed
Rewrite the Stat tests so they're not racy.
1 parent 0a3c11d commit 4de36c5

File tree

3 files changed

+86
-68
lines changed

3 files changed

+86
-68
lines changed

semantic.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ test-suite test
393393
, tasty-golden ^>= 2.3.2
394394
, tasty-hedgehog ^>= 1.0.0.1
395395
, tasty-hspec ^>= 1.1.5.1
396+
, tasty-hunit ^>= 0.10.0.2
396397
, HUnit ^>= 1.6.0.0
397398
, leancheck >= 0.8 && <1
398399
, temporary ^>= 1.3

test/Semantic/Stat/Spec.hs

Lines changed: 83 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
module Semantic.Stat.Spec (spec) where
1+
{-# LANGUAGE TemplateHaskell #-}
2+
3+
module Semantic.Stat.Spec (testTree) where
24

35
import Control.Exception
46
import Network.Socket hiding (recv)
@@ -7,80 +9,95 @@ import Semantic.Telemetry.Stat
79
import Semantic.Config
810
import System.Environment
911

10-
import SpecHelpers
12+
import Test.Tasty
13+
import Test.Tasty.HUnit
14+
import Test.Tasty.Runners
1115

1216
withSocketPair :: ((Socket, Socket) -> IO c) -> IO c
1317
withSocketPair = bracket create release
1418
where create = socketPair AF_UNIX Datagram defaultProtocol
1519
release (client, server) = close client >> close server
1620

17-
withEnvironment :: String -> String -> (() -> IO ()) -> IO ()
18-
withEnvironment key value = bracket (setEnv key value) (const (unsetEnv key))
21+
withEnvironment :: String -> String -> IO () -> IO ()
22+
withEnvironment key value = bracket (setEnv key value) (const (unsetEnv key)) . const
1923

2024
-- NOTE: These cannot easily run in parallel because we test things like
2125
-- setting/unsetting the environment.
22-
spec :: Spec
23-
spec = do
24-
describe "defaultStatsClient" $ do
25-
it "sets appropriate defaults" $ do
26-
StatsClient{..} <- defaultStatsClient
27-
statsClientNamespace `shouldBe` "semantic"
28-
statsClientUDPHost `shouldBe` "127.0.0.1"
29-
statsClientUDPPort `shouldBe` "28125"
30-
31-
around (withEnvironment "STATS_ADDR" "localhost:8125") $
32-
it "takes STATS_ADDR from environment" $ do
33-
StatsClient{..} <- defaultStatsClient
34-
statsClientUDPHost `shouldBe` "localhost"
35-
statsClientUDPPort `shouldBe` "8125"
36-
37-
around (withEnvironment "STATS_ADDR" "localhost") $
38-
it "handles STATS_ADDR with just hostname" $ do
39-
StatsClient{..} <- defaultStatsClient
40-
statsClientUDPHost `shouldBe` "localhost"
41-
statsClientUDPPort `shouldBe` "28125"
42-
43-
around (withEnvironment "DOGSTATSD_HOST" "0.0.0.0") $
44-
it "takes DOGSTATSD_HOST from environment" $ do
45-
StatsClient{..} <- defaultStatsClient
46-
statsClientUDPHost `shouldBe` "0.0.0.0"
47-
statsClientUDPPort `shouldBe` "28125"
48-
49-
describe "renderDatagram" $ do
50-
let key = "app.metric"
51-
52-
describe "counters" $ do
53-
it "renders increment" $
54-
renderDatagram "" (increment key []) `shouldBe` "app.metric:1|c"
55-
it "renders decrement" $
56-
renderDatagram "" (decrement key []) `shouldBe` "app.metric:-1|c"
57-
it "renders count" $
58-
renderDatagram "" (count key 8 []) `shouldBe` "app.metric:8|c"
59-
60-
it "renders statsClientNamespace" $
61-
renderDatagram "pre" (increment key []) `shouldBe` "pre.app.metric:1|c"
62-
63-
describe "tags" $ do
64-
it "renders a tag" $ do
65-
let inc = increment key [("key", "value")]
66-
renderDatagram "" inc `shouldBe` "app.metric:1|c|#key:value"
67-
it "renders a tag without value" $ do
68-
let inc = increment key [("a", "")]
69-
renderDatagram "" inc `shouldBe` "app.metric:1|c|#a"
70-
it "renders tags" $ do
71-
let inc = increment key [("key", "value"), ("a", "true")]
72-
renderDatagram "" inc `shouldBe` "app.metric:1|c|#key:value,a:true"
73-
it "renders tags without value" $ do
74-
let inc = increment key [("key", "value"), ("a", "")]
75-
renderDatagram "" inc `shouldBe` "app.metric:1|c|#key:value,a"
76-
77-
describe "sendStat" $
78-
it "delivers datagram" $ do
79-
client@StatsClient{..} <- defaultStatsClient
80-
withSocketPair $ \(clientSoc, serverSoc) -> do
81-
sendStat client { statsClientUDPSocket = clientSoc } (increment "app.metric" [])
82-
info <- recv serverSoc 1024
83-
info `shouldBe` "semantic.app.metric:1|c"
26+
testTree :: TestTree
27+
testTree = testCaseSteps "Semantic.Stat.Spec" $ \step -> do
28+
step "Sets appropriate defaults"
29+
case_sets_appropriate_defaults
30+
step "Takes stats addr from environment"
31+
case_takes_stats_addr_from_environment
32+
step "Handles stats addr with just hostname"
33+
case_handles_stats_addr_with_just_hostname
34+
step "takes dogstats host from environment"
35+
case_takes_stats_addr_from_environment
36+
step "rendering"
37+
case_render_counters *> case_render_tags
38+
step "stats deliver datagram"
39+
case_sendstat_delivers_datagram
40+
41+
42+
case_sets_appropriate_defaults :: Assertion
43+
case_sets_appropriate_defaults = do
44+
StatsClient{..} <- defaultStatsClient
45+
statsClientNamespace @?= "semantic"
46+
statsClientUDPHost @?= "127.0.0.1"
47+
statsClientUDPPort @?= "28125"
48+
49+
case_takes_stats_addr_from_environment :: Assertion
50+
case_takes_stats_addr_from_environment =
51+
withEnvironment "STATS_ADDR" "localhost:8125" $ do
52+
StatsClient{..} <- defaultStatsClient
53+
statsClientUDPHost @?= "localhost"
54+
statsClientUDPPort @?= "8125"
55+
56+
case_handles_stats_addr_with_just_hostname :: Assertion
57+
case_handles_stats_addr_with_just_hostname =
58+
withEnvironment "STATS_ADDR" "localhost" $ do
59+
StatsClient{..} <- defaultStatsClient
60+
statsClientUDPHost @?= "localhost"
61+
statsClientUDPPort @?= "28125"
62+
63+
case_takes_dogstats_host_from_environment :: Assertion
64+
case_takes_dogstats_host_from_environment =
65+
withEnvironment "DOGSTATSD_HOST" "0.0.0.0" $ do
66+
StatsClient{..} <- defaultStatsClient
67+
statsClientUDPHost @?= "0.0.0.0"
68+
statsClientUDPPort @?= "28125"
69+
70+
key :: String
71+
key = "app.metric"
72+
73+
case_render_counters :: Assertion
74+
case_render_counters = do
75+
renderDatagram "" (increment key []) @?= "app.metric:1|c"
76+
renderDatagram "" (decrement key []) @?= "app.metric:-1|c"
77+
renderDatagram "" (count key 8 []) @?= "app.metric:8|c"
78+
renderDatagram "pre" (increment key []) @?= "pre.app.metric:1|c"
79+
80+
case_render_tags :: Assertion
81+
case_render_tags = do
82+
let incTag = increment key [("key", "value")]
83+
renderDatagram "" incTag @?= "app.metric:1|c|#key:value"
84+
85+
let tagWithoutValue = increment key [("a", "")]
86+
renderDatagram "" tagWithoutValue @?= "app.metric:1|c|#a"
87+
88+
let tags = increment key [("key", "value"), ("a", "true")]
89+
renderDatagram "" tags @?= "app.metric:1|c|#key:value,a:true"
90+
91+
let tagsWithoutValue = increment key [("key", "value"), ("a", "")]
92+
renderDatagram "" tagsWithoutValue @?= "app.metric:1|c|#key:value,a"
93+
94+
case_sendstat_delivers_datagram :: Assertion
95+
case_sendstat_delivers_datagram = do
96+
client@StatsClient{..} <- defaultStatsClient
97+
withSocketPair $ \(clientSoc, serverSoc) -> do
98+
sendStat client { statsClientUDPSocket = clientSoc } (increment "app.metric" [])
99+
info <- recv serverSoc 1024
100+
info @?= "semantic.app.metric:1|c"
84101

85102
-- Defaults are all driven by defaultConfig.
86103
defaultStatsClient :: IO StatsClient

test/Spec.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ tests =
4747
[ Integration.Spec.spec
4848
, Semantic.CLI.Spec.spec
4949
, Data.Source.Spec.testTree
50+
, Semantic.Stat.Spec.testTree
5051
]
5152

5253
-- We can't bring this out of the IO monad until we divest
@@ -64,8 +65,7 @@ allTests = do
6465
-- using one or the other.") Instead, create a new TestTree value
6566
-- in your spec module and add it to the above 'tests' list.
6667
legacySpecs :: (?session :: TaskSession) => Spec
67-
legacySpecs = do
68-
describe "Semantic.Stat" Semantic.Stat.Spec.spec
68+
legacySpecs = parallel $ do
6969
describe "Analysis.Go" Analysis.Go.Spec.spec
7070
describe "Analysis.PHP" Analysis.PHP.Spec.spec
7171
describe "Analysis.Python" Analysis.Python.Spec.spec

0 commit comments

Comments
 (0)