github.com/kiali/kiali@v1.84.0/graph/telemetry/istio/appender/throughput_test.go (about)

     1  package appender
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/prometheus/common/model"
     8  	"github.com/stretchr/testify/assert"
     9  
    10  	"github.com/kiali/kiali/config"
    11  	"github.com/kiali/kiali/graph"
    12  )
    13  
    14  func TestResponseThroughput(t *testing.T) {
    15  	assert := assert.New(t)
    16  
    17  	q0 := `round(sum(rate(istio_response_bytes_sum{reporter="destination",source_workload_namespace!="bookinfo",destination_service_namespace="bookinfo"}[60s])) by (source_cluster,source_workload_namespace,source_workload,source_canonical_service,source_canonical_revision,destination_cluster,destination_service_namespace,destination_service,destination_service_name,destination_workload_namespace,destination_workload,destination_canonical_service,destination_canonical_revision) > 0,0.001)`
    18  	q0m0 := model.Metric{
    19  		"source_cluster":                 config.DefaultClusterID,
    20  		"source_workload_namespace":      "istio-system",
    21  		"source_workload":                "ingressgateway-unknown",
    22  		"source_canonical_service":       "ingressgateway",
    23  		"source_canonical_revision":      model.LabelValue(graph.Unknown),
    24  		"destination_cluster":            config.DefaultClusterID,
    25  		"destination_service_namespace":  "bookinfo",
    26  		"destination_service":            "productpage.bookinfo.svc.cluster.local",
    27  		"destination_service_name":       "productpage",
    28  		"destination_workload_namespace": "bookinfo",
    29  		"destination_workload":           "productpage-v1",
    30  		"destination_canonical_service":  "productpage",
    31  		"destination_canonical_revision": "v1"}
    32  	v0 := model.Vector{
    33  		&model.Sample{
    34  			Metric: q0m0,
    35  			Value:  1000.0},
    36  	}
    37  
    38  	q1 := `round(sum(rate(istio_response_bytes_sum{reporter="destination",source_workload_namespace="bookinfo"}[60s])) by (source_cluster,source_workload_namespace,source_workload,source_canonical_service,source_canonical_revision,destination_cluster,destination_service_namespace,destination_service,destination_service_name,destination_workload_namespace,destination_workload,destination_canonical_service,destination_canonical_revision) > 0,0.001)`
    39  	q1m0 := model.Metric{
    40  		"source_cluster":                 config.DefaultClusterID,
    41  		"source_workload_namespace":      "bookinfo",
    42  		"source_workload":                "productpage-v1",
    43  		"source_canonical_service":       "productpage",
    44  		"source_canonical_revision":      "v1",
    45  		"destination_cluster":            config.DefaultClusterID,
    46  		"destination_service_namespace":  "bookinfo",
    47  		"destination_service":            "reviews.bookinfo.svc.cluster.local",
    48  		"destination_service_name":       "reviews",
    49  		"destination_workload_namespace": "bookinfo",
    50  		"destination_workload":           "reviews-v1",
    51  		"destination_canonical_service":  "reviews",
    52  		"destination_canonical_revision": "v1"}
    53  	q1m1 := model.Metric{
    54  		"source_cluster":                 config.DefaultClusterID,
    55  		"source_workload_namespace":      "bookinfo",
    56  		"source_workload":                "productpage-v1",
    57  		"source_canonical_service":       "productpage",
    58  		"source_canonical_revision":      "v1",
    59  		"destination_cluster":            config.DefaultClusterID,
    60  		"destination_service_namespace":  "bookinfo",
    61  		"destination_service":            "reviews.bookinfo.svc.cluster.local",
    62  		"destination_service_name":       "reviews",
    63  		"destination_workload_namespace": "bookinfo",
    64  		"destination_workload":           "reviews-v2",
    65  		"destination_canonical_service":  "reviews",
    66  		"destination_canonical_revision": "v2"}
    67  	q1m2 := model.Metric{
    68  		"source_cluster":                 config.DefaultClusterID,
    69  		"source_workload_namespace":      "bookinfo",
    70  		"source_workload":                "reviews-v1",
    71  		"source_canonical_service":       "reviews",
    72  		"source_canonical_revision":      "v1",
    73  		"destination_cluster":            config.DefaultClusterID,
    74  		"destination_service_namespace":  "bookinfo",
    75  		"destination_service":            "ratings.bookinfo.svc.cluster.local",
    76  		"destination_service_name":       "ratings",
    77  		"destination_workload_namespace": "bookinfo",
    78  		"destination_workload":           "ratings-v1",
    79  		"destination_canonical_service":  "ratings",
    80  		"destination_canonical_revision": "v1"}
    81  	q1m3 := model.Metric{
    82  		"source_cluster":                 config.DefaultClusterID,
    83  		"source_workload_namespace":      "bookinfo",
    84  		"source_workload":                "reviews-v2",
    85  		"source_canonical_service":       "reviews",
    86  		"source_canonical_revision":      "v2",
    87  		"destination_cluster":            config.DefaultClusterID,
    88  		"destination_service_namespace":  "bookinfo",
    89  		"destination_service":            "ratings.bookinfo.svc.cluster.local",
    90  		"destination_service_name":       "ratings",
    91  		"destination_workload_namespace": "bookinfo",
    92  		"destination_workload":           "ratings-v1",
    93  		"destination_canonical_service":  "ratings",
    94  		"destination_canonical_revision": "v1"}
    95  	v1 := model.Vector{
    96  		&model.Sample{
    97  			Metric: q1m0,
    98  			Value:  1000.0},
    99  		&model.Sample{
   100  			Metric: q1m1,
   101  			Value:  2000.0},
   102  		&model.Sample{
   103  			Metric: q1m2,
   104  			Value:  1000.0},
   105  		&model.Sample{
   106  			Metric: q1m3,
   107  			Value:  2000.0}}
   108  
   109  	client, api, err := setupMocked()
   110  	if err != nil {
   111  		t.Error(err)
   112  		return
   113  	}
   114  	mockQuery(api, q0, &v0)
   115  	mockQuery(api, q1, &v1)
   116  
   117  	trafficMap := responseThroughputTestTraffic()
   118  	ingressID, _, _ := graph.Id(config.DefaultClusterID, "istio-system", "", "istio-system", "ingressgateway-unknown", "ingressgateway", graph.Unknown, graph.GraphTypeVersionedApp)
   119  	ingress, ok := trafficMap[ingressID]
   120  	assert.Equal(true, ok)
   121  	assert.Equal("ingressgateway", ingress.App)
   122  	assert.Equal(1, len(ingress.Edges))
   123  	assert.Equal(nil, ingress.Edges[0].Metadata[graph.Throughput])
   124  
   125  	duration, _ := time.ParseDuration("60s")
   126  	appender := ThroughputAppender{
   127  		GraphType:          graph.GraphTypeVersionedApp,
   128  		InjectServiceNodes: true,
   129  		Namespaces: map[string]graph.NamespaceInfo{
   130  			"bookinfo": {
   131  				Name:     "bookinfo",
   132  				Duration: duration,
   133  			},
   134  		},
   135  		QueryTime: time.Now().Unix(),
   136  		Rates: graph.RequestedRates{
   137  			Grpc: graph.RateRequests,
   138  			Http: graph.RateRequests,
   139  			Tcp:  graph.RateTotal,
   140  		},
   141  		ThroughputType: "response",
   142  	}
   143  
   144  	appender.appendGraph(trafficMap, "bookinfo", client)
   145  
   146  	ingress, ok = trafficMap[ingressID]
   147  	assert.Equal(true, ok)
   148  	assert.Equal("ingressgateway", ingress.App)
   149  	assert.Equal(1, len(ingress.Edges))
   150  	_, ok = ingress.Edges[0].Metadata[graph.Throughput]
   151  	assert.Equal(false, ok)
   152  
   153  	productpageService := ingress.Edges[0].Dest
   154  	assert.Equal(graph.NodeTypeService, productpageService.NodeType)
   155  	assert.Equal("productpage", productpageService.Service)
   156  	assert.Equal(nil, productpageService.Metadata[graph.Throughput])
   157  	assert.Equal(1, len(productpageService.Edges))
   158  	assert.Equal(1000.0, productpageService.Edges[0].Metadata[graph.Throughput])
   159  
   160  	productpage := productpageService.Edges[0].Dest
   161  	assert.Equal("productpage", productpage.App)
   162  	assert.Equal("v1", productpage.Version)
   163  	assert.Equal(nil, productpage.Metadata[graph.Throughput])
   164  	assert.Equal(1, len(productpage.Edges))
   165  	_, ok = productpage.Edges[0].Metadata[graph.Throughput]
   166  	assert.Equal(false, ok)
   167  
   168  	reviewsService := productpage.Edges[0].Dest
   169  	assert.Equal(graph.NodeTypeService, reviewsService.NodeType)
   170  	assert.Equal("reviews", reviewsService.Service)
   171  	assert.Equal(nil, reviewsService.Metadata[graph.Throughput])
   172  	assert.Equal(2, len(reviewsService.Edges))
   173  	assert.Equal(1000.0, reviewsService.Edges[0].Metadata[graph.Throughput])
   174  	assert.Equal(2000.0, reviewsService.Edges[1].Metadata[graph.Throughput])
   175  
   176  	reviews1 := reviewsService.Edges[0].Dest
   177  	assert.Equal("reviews", reviews1.App)
   178  	assert.Equal("v1", reviews1.Version)
   179  	assert.Equal(nil, reviews1.Metadata[graph.Throughput])
   180  	assert.Equal(1, len(reviews1.Edges))
   181  	_, ok = reviews1.Edges[0].Metadata[graph.Throughput]
   182  	assert.Equal(false, ok)
   183  
   184  	reviews2 := reviewsService.Edges[1].Dest
   185  	assert.Equal("reviews", reviews2.App)
   186  	assert.Equal("v2", reviews2.Version)
   187  	assert.Equal(nil, reviews2.Metadata[graph.Throughput])
   188  	assert.Equal(1, len(reviews2.Edges))
   189  	_, ok = reviews2.Edges[0].Metadata[graph.Throughput]
   190  	assert.False(ok)
   191  
   192  	ratingsService := reviews1.Edges[0].Dest
   193  	assert.Equal(graph.NodeTypeService, ratingsService.NodeType)
   194  	assert.Equal("ratings", ratingsService.Service)
   195  	assert.Equal(nil, ratingsService.Metadata[graph.Throughput])
   196  	assert.Equal(1, len(ratingsService.Edges))
   197  	assert.Equal(3000.0, ratingsService.Edges[0].Metadata[graph.Throughput])
   198  
   199  	assert.Equal(ratingsService, reviews2.Edges[0].Dest)
   200  
   201  	ratings := ratingsService.Edges[0].Dest
   202  	assert.Equal("ratings", ratings.App)
   203  	assert.Equal("v1", ratings.Version)
   204  	assert.Equal(nil, ratings.Metadata[graph.Throughput])
   205  	assert.Equal(0, len(ratings.Edges))
   206  }
   207  
   208  func responseThroughputTestTraffic() graph.TrafficMap {
   209  	ingress, _ := graph.NewNode(config.DefaultClusterID, "istio-system", "", "istio-system", "ingressgateway-unknown", "ingressgateway", graph.Unknown, graph.GraphTypeVersionedApp)
   210  	productpageService, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "productpage", "", "", "", "", graph.GraphTypeVersionedApp)
   211  	productpage, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "productpage", "bookinfo", "productpage-v1", "productpage", "v1", graph.GraphTypeVersionedApp)
   212  	reviewsService, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "reviews", "", "", "", "", graph.GraphTypeVersionedApp)
   213  	reviewsV1, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "reviews", "bookinfo", "reviews-v1", "reviews", "v1", graph.GraphTypeVersionedApp)
   214  	reviewsV2, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "reviews", "bookinfo", "reviews-v2", "reviews", "v2", graph.GraphTypeVersionedApp)
   215  	ratingsService, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "ratings", "", "", "", "", graph.GraphTypeVersionedApp)
   216  	ratings, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "ratings", "bookinfo", "ratings-v1", "ratings", "v1", graph.GraphTypeVersionedApp)
   217  	trafficMap := graph.NewTrafficMap()
   218  
   219  	trafficMap[ingress.ID] = ingress
   220  	trafficMap[productpageService.ID] = productpageService
   221  	trafficMap[productpage.ID] = productpage
   222  	trafficMap[reviewsService.ID] = reviewsService
   223  	trafficMap[reviewsV1.ID] = reviewsV1
   224  	trafficMap[reviewsV2.ID] = reviewsV2
   225  	trafficMap[ratingsService.ID] = ratingsService
   226  	trafficMap[ratings.ID] = ratings
   227  
   228  	ingress.AddEdge(productpageService).Metadata[graph.ProtocolKey] = "http"
   229  	productpageService.AddEdge(productpage).Metadata[graph.ProtocolKey] = "http"
   230  	productpage.AddEdge(reviewsService).Metadata[graph.ProtocolKey] = "http"
   231  	reviewsService.AddEdge(reviewsV1).Metadata[graph.ProtocolKey] = "http"
   232  	reviewsService.AddEdge(reviewsV2).Metadata[graph.ProtocolKey] = "http"
   233  	reviewsV1.AddEdge(ratingsService).Metadata[graph.ProtocolKey] = "http"
   234  	reviewsV2.AddEdge(ratingsService).Metadata[graph.ProtocolKey] = "http"
   235  	ratingsService.AddEdge(ratings).Metadata[graph.ProtocolKey] = "http"
   236  
   237  	return trafficMap
   238  }
   239  
   240  func TestRequestThroughput(t *testing.T) {
   241  	assert := assert.New(t)
   242  
   243  	q0 := `round(sum(rate(istio_request_bytes_sum{reporter="source",source_workload_namespace!="bookinfo",destination_service_namespace="bookinfo"}[60s])) by (source_cluster,source_workload_namespace,source_workload,source_canonical_service,source_canonical_revision,destination_cluster,destination_service_namespace,destination_service,destination_service_name,destination_workload_namespace,destination_workload,destination_canonical_service,destination_canonical_revision) > 0,0.001)`
   244  	q0m0 := model.Metric{
   245  		"source_cluster":                 config.DefaultClusterID,
   246  		"source_workload_namespace":      "istio-system",
   247  		"source_workload":                "ingressgateway-unknown",
   248  		"source_canonical_service":       "ingressgateway",
   249  		"source_canonical_revision":      model.LabelValue(graph.Unknown),
   250  		"destination_cluster":            config.DefaultClusterID,
   251  		"destination_service_namespace":  "bookinfo",
   252  		"destination_service":            "productpage.bookinfo.svc.cluster.local",
   253  		"destination_service_name":       "productpage",
   254  		"destination_workload_namespace": "bookinfo",
   255  		"destination_workload":           "productpage-v1",
   256  		"destination_canonical_service":  "productpage",
   257  		"destination_canonical_revision": "v1"}
   258  	v0 := model.Vector{
   259  		&model.Sample{
   260  			Metric: q0m0,
   261  			Value:  1000.0},
   262  	}
   263  
   264  	q1 := `round(sum(rate(istio_request_bytes_sum{reporter="source",source_workload_namespace="bookinfo"}[60s])) by (source_cluster,source_workload_namespace,source_workload,source_canonical_service,source_canonical_revision,destination_cluster,destination_service_namespace,destination_service,destination_service_name,destination_workload_namespace,destination_workload,destination_canonical_service,destination_canonical_revision) > 0,0.001)`
   265  	q1m0 := model.Metric{
   266  		"source_cluster":                 config.DefaultClusterID,
   267  		"source_workload_namespace":      "bookinfo",
   268  		"source_workload":                "productpage-v1",
   269  		"source_canonical_service":       "productpage",
   270  		"source_canonical_revision":      "v1",
   271  		"destination_cluster":            config.DefaultClusterID,
   272  		"destination_service_namespace":  "bookinfo",
   273  		"destination_service":            "reviews.bookinfo.svc.cluster.local",
   274  		"destination_service_name":       "reviews",
   275  		"destination_workload_namespace": "unknown", // simulate failed requests to reviews service
   276  		"destination_workload":           "unknown",
   277  		"destination_canonical_service":  "unknown",
   278  		"destination_canonical_revision": "unknown"}
   279  	v1 := model.Vector{
   280  		&model.Sample{
   281  			Metric: q1m0,
   282  			Value:  1000.0}}
   283  
   284  	client, api, err := setupMocked()
   285  	if err != nil {
   286  		t.Error(err)
   287  		return
   288  	}
   289  	mockQuery(api, q0, &v0)
   290  	mockQuery(api, q1, &v1)
   291  
   292  	trafficMap := requestThroughputTestTraffic()
   293  	ingressID, _, _ := graph.Id(config.DefaultClusterID, "istio-system", "", "istio-system", "ingressgateway-unknown", "ingressgateway", graph.Unknown, graph.GraphTypeVersionedApp)
   294  	ingress, ok := trafficMap[ingressID]
   295  	assert.Equal(true, ok)
   296  	assert.Equal("ingressgateway", ingress.App)
   297  	assert.Equal(1, len(ingress.Edges))
   298  	assert.Equal(nil, ingress.Edges[0].Metadata[graph.Throughput])
   299  
   300  	duration, _ := time.ParseDuration("60s")
   301  	appender := ThroughputAppender{
   302  		GraphType:          graph.GraphTypeVersionedApp,
   303  		InjectServiceNodes: true,
   304  		Namespaces: map[string]graph.NamespaceInfo{
   305  			"bookinfo": {
   306  				Name:     "bookinfo",
   307  				Duration: duration,
   308  			},
   309  		},
   310  		QueryTime: time.Now().Unix(),
   311  		Rates: graph.RequestedRates{
   312  			Grpc: graph.RateRequests,
   313  			Http: graph.RateRequests,
   314  			Tcp:  graph.RateTotal,
   315  		},
   316  		ThroughputType: "request",
   317  	}
   318  
   319  	appender.appendGraph(trafficMap, "bookinfo", client)
   320  
   321  	ingress, ok = trafficMap[ingressID]
   322  	assert.Equal(true, ok)
   323  	assert.Equal("ingressgateway", ingress.App)
   324  	assert.Equal(1, len(ingress.Edges))
   325  	_, ok = ingress.Edges[0].Metadata[graph.Throughput]
   326  	assert.Equal(false, ok)
   327  
   328  	productpageService := ingress.Edges[0].Dest
   329  	assert.Equal(graph.NodeTypeService, productpageService.NodeType)
   330  	assert.Equal("productpage", productpageService.Service)
   331  	assert.Equal(nil, productpageService.Metadata[graph.Throughput])
   332  	assert.Equal(1, len(productpageService.Edges))
   333  	assert.Equal(1000.0, productpageService.Edges[0].Metadata[graph.Throughput])
   334  
   335  	productpage := productpageService.Edges[0].Dest
   336  	assert.Equal("productpage", productpage.App)
   337  	assert.Equal("v1", productpage.Version)
   338  	assert.Equal(nil, productpage.Metadata[graph.Throughput])
   339  	assert.Equal(1, len(productpage.Edges))
   340  	assert.Equal(1000.0, productpage.Edges[0].Metadata[graph.Throughput])
   341  
   342  	reviewsService := productpage.Edges[0].Dest
   343  	assert.Equal(graph.NodeTypeService, reviewsService.NodeType)
   344  	assert.Equal("reviews", reviewsService.Service)
   345  	assert.Equal(nil, reviewsService.Metadata[graph.Throughput])
   346  	assert.Equal(0, len(reviewsService.Edges))
   347  }
   348  
   349  func TestRequestThroughputSkipRates(t *testing.T) {
   350  	assert := assert.New(t)
   351  
   352  	q0 := `round(sum(rate(istio_request_bytes_sum{reporter="source",source_workload_namespace!="bookinfo",destination_service_namespace="bookinfo"}[60s])) by (source_cluster,source_workload_namespace,source_workload,source_canonical_service,source_canonical_revision,destination_cluster,destination_service_namespace,destination_service,destination_service_name,destination_workload_namespace,destination_workload,destination_canonical_service,destination_canonical_revision) > 0,0.001)`
   353  	q0m0 := model.Metric{
   354  		"source_cluster":                 config.DefaultClusterID,
   355  		"source_workload_namespace":      "istio-system",
   356  		"source_workload":                "ingressgateway-unknown",
   357  		"source_canonical_service":       "ingressgateway",
   358  		"source_canonical_revision":      model.LabelValue(graph.Unknown),
   359  		"destination_cluster":            config.DefaultClusterID,
   360  		"destination_service_namespace":  "bookinfo",
   361  		"destination_service":            "productpage.bookinfo.svc.cluster.local",
   362  		"destination_service_name":       "productpage",
   363  		"destination_workload_namespace": "bookinfo",
   364  		"destination_workload":           "productpage-v1",
   365  		"destination_canonical_service":  "productpage",
   366  		"destination_canonical_revision": "v1"}
   367  	v0 := model.Vector{
   368  		&model.Sample{
   369  			Metric: q0m0,
   370  			Value:  1000.0},
   371  	}
   372  
   373  	q1 := `round(sum(rate(istio_request_bytes_sum{reporter="source",source_workload_namespace="bookinfo"}[60s])) by (source_cluster,source_workload_namespace,source_workload,source_canonical_service,source_canonical_revision,destination_cluster,destination_service_namespace,destination_service,destination_service_name,destination_workload_namespace,destination_workload,destination_canonical_service,destination_canonical_revision) > 0,0.001)`
   374  	q1m0 := model.Metric{
   375  		"source_cluster":                 config.DefaultClusterID,
   376  		"source_workload_namespace":      "bookinfo",
   377  		"source_workload":                "productpage-v1",
   378  		"source_canonical_service":       "productpage",
   379  		"source_canonical_revision":      "v1",
   380  		"destination_cluster":            config.DefaultClusterID,
   381  		"destination_service_namespace":  "bookinfo",
   382  		"destination_service":            "reviews.bookinfo.svc.cluster.local",
   383  		"destination_service_name":       "reviews",
   384  		"destination_workload_namespace": "unknown", // simulate failed requests to reviews service
   385  		"destination_workload":           "unknown",
   386  		"destination_canonical_service":  "unknown",
   387  		"destination_canonical_revision": "unknown"}
   388  	v1 := model.Vector{
   389  		&model.Sample{
   390  			Metric: q1m0,
   391  			Value:  1000.0}}
   392  
   393  	_, api, err := setupMocked()
   394  	if err != nil {
   395  		t.Error(err)
   396  		return
   397  	}
   398  	mockQuery(api, q0, &v0)
   399  	mockQuery(api, q1, &v1)
   400  
   401  	trafficMap := requestThroughputTestTraffic()
   402  	ingressID, _, _ := graph.Id(config.DefaultClusterID, "istio-system", "", "istio-system", "ingressgateway-unknown", "ingressgateway", graph.Unknown, graph.GraphTypeVersionedApp)
   403  	ingress, ok := trafficMap[ingressID]
   404  	assert.Equal(true, ok)
   405  	assert.Equal("ingressgateway", ingress.App)
   406  	assert.Equal(1, len(ingress.Edges))
   407  	assert.Equal(nil, ingress.Edges[0].Metadata[graph.Throughput])
   408  
   409  	duration, _ := time.ParseDuration("60s")
   410  	appender := ThroughputAppender{
   411  		GraphType:          graph.GraphTypeVersionedApp,
   412  		InjectServiceNodes: true,
   413  		Namespaces: map[string]graph.NamespaceInfo{
   414  			"bookinfo": {
   415  				Name:     "bookinfo",
   416  				Duration: duration,
   417  			},
   418  		},
   419  		QueryTime: time.Now().Unix(),
   420  		Rates: graph.RequestedRates{
   421  			Grpc: graph.RateRequests,
   422  			Http: graph.RateNone,
   423  			Tcp:  graph.RateTotal,
   424  		},
   425  		ThroughputType: "request",
   426  	}
   427  
   428  	appender.AppendGraph(trafficMap, nil, nil)
   429  
   430  	ingress, ok = trafficMap[ingressID]
   431  	assert.Equal(true, ok)
   432  	assert.Equal("ingressgateway", ingress.App)
   433  	assert.Equal(1, len(ingress.Edges))
   434  	_, ok = ingress.Edges[0].Metadata[graph.Throughput]
   435  	assert.Equal(false, ok)
   436  
   437  	productpageService := ingress.Edges[0].Dest
   438  	assert.Equal(graph.NodeTypeService, productpageService.NodeType)
   439  	assert.Equal("productpage", productpageService.Service)
   440  	assert.Equal(nil, productpageService.Metadata[graph.Throughput])
   441  	assert.Equal(1, len(productpageService.Edges))
   442  	assert.Equal(nil, productpageService.Edges[0].Metadata[graph.Throughput])
   443  
   444  	productpage := productpageService.Edges[0].Dest
   445  	assert.Equal("productpage", productpage.App)
   446  	assert.Equal("v1", productpage.Version)
   447  	assert.Equal(nil, productpage.Metadata[graph.Throughput])
   448  	assert.Equal(1, len(productpage.Edges))
   449  	assert.Equal(nil, productpage.Edges[0].Metadata[graph.Throughput])
   450  
   451  	reviewsService := productpage.Edges[0].Dest
   452  	assert.Equal(graph.NodeTypeService, reviewsService.NodeType)
   453  	assert.Equal("reviews", reviewsService.Service)
   454  	assert.Equal(nil, reviewsService.Metadata[graph.Throughput])
   455  	assert.Equal(0, len(reviewsService.Edges))
   456  }
   457  
   458  func requestThroughputTestTraffic() graph.TrafficMap {
   459  	ingress, _ := graph.NewNode(config.DefaultClusterID, "istio-system", "", "istio-system", "ingressgateway-unknown", "ingressgateway", graph.Unknown, graph.GraphTypeVersionedApp)
   460  	productpageService, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "productpage", "", "", "", "", graph.GraphTypeVersionedApp)
   461  	productpage, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "productpage", "bookinfo", "productpage-v1", "productpage", "v1", graph.GraphTypeVersionedApp)
   462  	reviewsService, _ := graph.NewNode(config.DefaultClusterID, "bookinfo", "reviews", "", "", "", "", graph.GraphTypeVersionedApp)
   463  	trafficMap := graph.NewTrafficMap()
   464  
   465  	trafficMap[ingress.ID] = ingress
   466  	trafficMap[productpageService.ID] = productpageService
   467  	trafficMap[productpage.ID] = productpage
   468  	trafficMap[reviewsService.ID] = reviewsService
   469  
   470  	ingress.AddEdge(productpageService).Metadata[graph.ProtocolKey] = "http"
   471  	productpageService.AddEdge(productpage).Metadata[graph.ProtocolKey] = "http"
   472  	productpage.AddEdge(reviewsService).Metadata[graph.ProtocolKey] = "http"
   473  
   474  	return trafficMap
   475  }