github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/remotewrite/client_test.go (about)

     1  package remotewrite_test
     2  
     3  import (
     4  	"context"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"sync"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  	"github.com/prometheus/client_golang/prometheus"
    13  	"github.com/sirupsen/logrus"
    14  
    15  	"github.com/pyroscope-io/pyroscope/pkg/config"
    16  	"github.com/pyroscope-io/pyroscope/pkg/convert/profile"
    17  	"github.com/pyroscope-io/pyroscope/pkg/ingestion"
    18  	"github.com/pyroscope-io/pyroscope/pkg/remotewrite"
    19  	"github.com/pyroscope-io/pyroscope/pkg/storage/metadata"
    20  	"github.com/pyroscope-io/pyroscope/pkg/storage/segment"
    21  	"github.com/pyroscope-io/pyroscope/pkg/util/attime"
    22  )
    23  
    24  // TODO(eh-am): clean up these bunch of putInput
    25  
    26  var _ = Describe("TrafficShadower", func() {
    27  	var logger *logrus.Logger
    28  
    29  	BeforeEach(func() {
    30  		logger = logrus.New()
    31  		logger.SetOutput(ioutil.Discard)
    32  	})
    33  
    34  	Context("happy path", func() {
    35  		var remoteHandler http.HandlerFunc
    36  		var wg sync.WaitGroup
    37  		var cfg config.RemoteWriteTarget
    38  		var in ingestion.IngestInput
    39  
    40  		BeforeEach(func() {
    41  			remoteHandler = func(w http.ResponseWriter, r *http.Request) {}
    42  
    43  			cfg.Address = ""
    44  			cfg.AuthToken = ""
    45  			cfg.Tags = make(map[string]string)
    46  		})
    47  
    48  		run := func() {
    49  			remoteServer := httptest.NewServer(http.HandlerFunc(
    50  				func(w http.ResponseWriter, r *http.Request) {
    51  					remoteHandler(w, r)
    52  					wg.Done()
    53  				}),
    54  			)
    55  
    56  			cfg.Address = remoteServer.URL
    57  			client := remotewrite.NewClient(logger, prometheus.NewRegistry(), "targetName", cfg)
    58  
    59  			wg.Add(1)
    60  			client.Ingest(context.TODO(), &in)
    61  			wg.Wait()
    62  		}
    63  
    64  		It("sends request to remote", func() {
    65  			in = ingestion.IngestInput{
    66  				Metadata: ingestion.Metadata{
    67  					Key: segment.NewKey(map[string]string{
    68  						"__name__": "myapp",
    69  					}),
    70  
    71  					StartTime:       attime.Parse("1654110240"),
    72  					EndTime:         attime.Parse("1654110250"),
    73  					SampleRate:      100,
    74  					SpyName:         "gospy",
    75  					Units:           metadata.SamplesUnits,
    76  					AggregationType: metadata.SumAggregationType,
    77  				},
    78  
    79  				Profile: new(profile.RawProfile),
    80  				Format:  ingestion.FormatGroups,
    81  			}
    82  
    83  			remoteHandler = func(w http.ResponseWriter, r *http.Request) {
    84  				defer GinkgoRecover()
    85  
    86  				Expect(r.URL.Query().Get("name")).To(Equal("myapp{}"))
    87  				Expect(r.URL.Query().Get("from")).To(Equal("1654110240"))
    88  				Expect(r.URL.Query().Get("until")).To(Equal("1654110250"))
    89  				Expect(r.URL.Query().Get("sampleRate")).To(Equal("100"))
    90  				Expect(r.URL.Query().Get("spyName")).To(Equal("gospy"))
    91  				Expect(r.URL.Query().Get("units")).To(Equal("samples"))
    92  				Expect(r.URL.Query().Get("aggregationType")).To(Equal("sum"))
    93  				Expect(r.URL.Query().Get("format")).To(Equal(string(ingestion.FormatGroups)))
    94  			}
    95  
    96  			run()
    97  		})
    98  
    99  		When("auth is configured", func() {
   100  			BeforeEach(func() {
   101  				cfg.AuthToken = "myauthtoken"
   102  			})
   103  
   104  			It("sets the Authorization header", func() {
   105  				in = ingestion.IngestInput{
   106  					Metadata: ingestion.Metadata{
   107  						Key: segment.NewKey(map[string]string{
   108  							"__name__": "myapp",
   109  							"my":       "tag",
   110  						}),
   111  
   112  						StartTime:       attime.Parse("1654110240"),
   113  						EndTime:         attime.Parse("1654110250"),
   114  						SampleRate:      100,
   115  						SpyName:         "gospy",
   116  						Units:           metadata.SamplesUnits,
   117  						AggregationType: metadata.SumAggregationType,
   118  					},
   119  
   120  					Profile: new(profile.RawProfile),
   121  				}
   122  
   123  				remoteHandler = func(w http.ResponseWriter, r *http.Request) {
   124  					defer GinkgoRecover()
   125  
   126  					Expect(r.Header.Get("Authorization")).To(Equal("Bearer myauthtoken"))
   127  				}
   128  
   129  				run()
   130  			})
   131  		})
   132  
   133  		When("tags are configured", func() {
   134  			BeforeEach(func() {
   135  				cfg.Tags = make(map[string]string)
   136  
   137  				cfg.Tags["minha"] = "tag"
   138  				cfg.Tags["nuestra"] = "etiqueta"
   139  			})
   140  
   141  			It("enhances the app name with tags", func() {
   142  				in = ingestion.IngestInput{
   143  					Metadata: ingestion.Metadata{
   144  						Key: segment.NewKey(map[string]string{
   145  							"__name__": "myapp",
   146  							"my":       "tag",
   147  						}),
   148  
   149  						StartTime:       attime.Parse("1654110240"),
   150  						EndTime:         attime.Parse("1654110250"),
   151  						SampleRate:      100,
   152  						SpyName:         "gospy",
   153  						Units:           metadata.SamplesUnits,
   154  						AggregationType: metadata.SumAggregationType,
   155  					},
   156  
   157  					Profile: new(profile.RawProfile),
   158  				}
   159  
   160  				remoteHandler = func(w http.ResponseWriter, r *http.Request) {
   161  					defer GinkgoRecover()
   162  
   163  					key, err := segment.ParseKey(r.URL.Query().Get("name"))
   164  					Expect(err).NotTo(HaveOccurred())
   165  
   166  					Expect(key).To(Equal(
   167  						segment.NewKey(map[string]string{
   168  							"__name__": "myapp",
   169  							"my":       "tag",
   170  							"minha":    "tag",
   171  							"nuestra":  "etiqueta",
   172  						}),
   173  					))
   174  				}
   175  
   176  				run()
   177  			})
   178  		})
   179  	})
   180  
   181  	Context("sad path", func() {
   182  		When("it can't convert PutInput into a http.Request", func() {
   183  			It("fails with ErrConvertPutInputToRequest", func() {
   184  				client := remotewrite.NewClient(logger, prometheus.NewRegistry(), "targetName",
   185  					config.RemoteWriteTarget{
   186  						Address: "%%",
   187  					})
   188  				in := ingestion.IngestInput{
   189  					Metadata: ingestion.Metadata{
   190  						Key: segment.NewKey(map[string]string{
   191  							"__name__": "myapp",
   192  						}),
   193  					},
   194  					Profile: new(profile.RawProfile),
   195  				}
   196  
   197  				err := client.Ingest(context.TODO(), &in)
   198  				Expect(err).To(MatchError(remotewrite.ErrConvertPutInputToRequest))
   199  			})
   200  		})
   201  
   202  		When("it can't send to remote", func() {
   203  			It("fails with ErrMakingRequest", func() {
   204  				client := remotewrite.NewClient(logger, prometheus.NewRegistry(), "targetName",
   205  					config.RemoteWriteTarget{
   206  						Address: "//inexistent-url",
   207  					})
   208  				in := ingestion.IngestInput{
   209  					Metadata: ingestion.Metadata{
   210  						Key: segment.NewKey(map[string]string{
   211  							"__name__": "myapp",
   212  							"my":       "tag",
   213  						}),
   214  
   215  						StartTime:       attime.Parse("1654110240"),
   216  						EndTime:         attime.Parse("1654110250"),
   217  						SampleRate:      100,
   218  						SpyName:         "gospy",
   219  						Units:           metadata.SamplesUnits,
   220  						AggregationType: metadata.SumAggregationType,
   221  					},
   222  
   223  					Profile: new(profile.RawProfile),
   224  				}
   225  
   226  				err := client.Ingest(context.TODO(), &in)
   227  				Expect(err).To(MatchError(remotewrite.ErrMakingRequest))
   228  			})
   229  		})
   230  
   231  		When("response is not within the 2xx range", func() {
   232  			It("fails with ErrNotOkResponse", func() {
   233  				remoteServer := httptest.NewServer(http.HandlerFunc(
   234  					func(w http.ResponseWriter, r *http.Request) {
   235  						w.WriteHeader(500)
   236  					}),
   237  				)
   238  
   239  				client := remotewrite.NewClient(logger, prometheus.NewRegistry(), "targetName",
   240  					config.RemoteWriteTarget{
   241  						Address: remoteServer.URL,
   242  					})
   243  				in := ingestion.IngestInput{
   244  					Metadata: ingestion.Metadata{
   245  						Key: segment.NewKey(map[string]string{
   246  							"__name__": "myapp",
   247  							"my":       "tag",
   248  						}),
   249  
   250  						StartTime:       attime.Parse("1654110240"),
   251  						EndTime:         attime.Parse("1654110250"),
   252  						SampleRate:      100,
   253  						SpyName:         "gospy",
   254  						Units:           metadata.SamplesUnits,
   255  						AggregationType: metadata.SumAggregationType,
   256  					},
   257  
   258  					Profile: new(profile.RawProfile),
   259  				}
   260  
   261  				err := client.Ingest(context.TODO(), &in)
   262  				Expect(err).To(MatchError(remotewrite.ErrNotOkResponse))
   263  			})
   264  		})
   265  	})
   266  })