@@ -21,9 +21,12 @@ package prometheus_test
21
21
22
22
import (
23
23
"bytes"
24
+ "math/rand"
24
25
"net/http"
25
26
"net/http/httptest"
27
+ "sync"
26
28
"testing"
29
+ "time"
27
30
28
31
dto "github.com/prometheus/client_model/go"
29
32
@@ -772,3 +775,99 @@ func TestAlreadyRegistered(t *testing.T) {
772
775
t .Error ("unexpected error:" , err )
773
776
}
774
777
}
778
+
779
+ // TestHistogramVecRegisterGatherConcurrency is an end-to-end test that
780
+ // concurrently calls Observe on random elements of a HistogramVec while the
781
+ // same HistogramVec is registered concurrently and the Gather method of the
782
+ // registry is called concurrently.
783
+ func TestHistogramVecRegisterGatherConcurrency (t * testing.T ) {
784
+ var (
785
+ reg = prometheus .NewPedanticRegistry ()
786
+ hv = prometheus .NewHistogramVec (
787
+ prometheus.HistogramOpts {
788
+ Name : "test_histogram" ,
789
+ Help : "This helps testing." ,
790
+ ConstLabels : prometheus.Labels {"foo" : "bar" },
791
+ },
792
+ []string {"one" , "two" , "three" },
793
+ )
794
+ labelValues = []string {"a" , "b" , "c" , "alpha" , "beta" , "gamma" , "aleph" , "beth" , "gimel" }
795
+ quit = make (chan struct {})
796
+ wg sync.WaitGroup
797
+ )
798
+
799
+ observe := func () {
800
+ defer wg .Done ()
801
+ for {
802
+ select {
803
+ case <- quit :
804
+ return
805
+ default :
806
+ obs := rand .NormFloat64 ()* .1 + .2
807
+ hv .WithLabelValues (
808
+ labelValues [rand .Intn (len (labelValues ))],
809
+ labelValues [rand .Intn (len (labelValues ))],
810
+ labelValues [rand .Intn (len (labelValues ))],
811
+ ).Observe (obs )
812
+ }
813
+ }
814
+ }
815
+
816
+ register := func () {
817
+ defer wg .Done ()
818
+ for {
819
+ select {
820
+ case <- quit :
821
+ return
822
+ default :
823
+ if err := reg .Register (hv ); err != nil {
824
+ if _ , ok := err .(prometheus.AlreadyRegisteredError ); ! ok {
825
+ t .Error ("Registering failed:" , err )
826
+ }
827
+ }
828
+ time .Sleep (7 * time .Millisecond )
829
+ }
830
+ }
831
+ }
832
+
833
+ gather := func () {
834
+ defer wg .Done ()
835
+ for {
836
+ select {
837
+ case <- quit :
838
+ return
839
+ default :
840
+ if g , err := reg .Gather (); err != nil {
841
+ t .Error ("Gathering failed:" , err )
842
+ } else {
843
+ if len (g ) == 0 {
844
+ continue
845
+ }
846
+ if len (g ) != 1 {
847
+ t .Error ("Gathered unexpected number of metric families:" , len (g ))
848
+ }
849
+ if len (g [0 ].Metric [0 ].Label ) != 4 {
850
+ t .Error ("Gathered unexpected number of label pairs:" , len (g [0 ].Metric [0 ].Label ))
851
+ }
852
+ }
853
+ time .Sleep (4 * time .Millisecond )
854
+ }
855
+ }
856
+ }
857
+
858
+ wg .Add (10 )
859
+ go observe ()
860
+ go observe ()
861
+ go register ()
862
+ go observe ()
863
+ go gather ()
864
+ go observe ()
865
+ go register ()
866
+ go observe ()
867
+ go gather ()
868
+ go observe ()
869
+
870
+ time .Sleep (time .Second )
871
+ close (quit )
872
+ wg .Wait ()
873
+ }
0 commit comments