How to use main method of main Package

Best Gauge code snippet using main.main

compile_test.go

Source:compile_test.go Github

copy

Full Screen

...87				require.NoError(t, entry.Normalize())88				require.NoError(t, entry.Validate())89			}90			req := CompileRequest{91				ServiceName:           "main",92				EvaluateInNamespace:   "default",93				EvaluateInDatacenter:  "dc1",94				EvaluateInTrustDomain: "trustdomain.consul",95				UseInDatacenter:       "dc1",96				Entries:               tc.entries,97			}98			if tc.setup != nil {99				tc.setup(&req)100			}101			res, err := Compile(req)102			if tc.expectErr != "" {103				require.Error(t, err)104				require.Contains(t, err.Error(), tc.expectErr)105				_, ok := err.(*structs.ConfigEntryGraphError)106				if tc.expectGraphErr {107					require.True(t, ok, "%T is not a *ConfigEntryGraphError", err)108				} else {109					require.False(t, ok, "did not expect a *ConfigEntryGraphError here: %v", err)110				}111			} else {112				require.NoError(t, err)113				// Avoid requiring unnecessary test boilerplate and inject these114				// ourselves.115				tc.expect.ServiceName = "main"116				tc.expect.Namespace = "default"117				tc.expect.Datacenter = "dc1"118				if tc.expectCustom {119					require.NotEmpty(t, res.CustomizationHash)120					res.CustomizationHash = ""121				} else {122					require.Empty(t, res.CustomizationHash)123				}124				require.Equal(t, tc.expect, res)125				require.Equal(t, tc.expectIsDefault, res.IsDefault())126			}127		})128	}129}130func testcase_JustRouterWithDefaults() compileTestCase {131	entries := newEntries()132	setServiceProtocol(entries, "main", "http")133	entries.AddRouters(134		&structs.ServiceRouterConfigEntry{135			Kind: "service-router",136			Name: "main",137		},138	)139	expect := &structs.CompiledDiscoveryChain{140		Protocol:  "http",141		StartNode: "router:main.default",142		Nodes: map[string]*structs.DiscoveryGraphNode{143			"router:main.default": {144				Type: structs.DiscoveryGraphNodeTypeRouter,145				Name: "main.default",146				Routes: []*structs.DiscoveryRoute{147					{148						Definition: newDefaultServiceRoute("main", "default"),149						NextNode:   "resolver:main.default.dc1",150					},151				},152			},153			"resolver:main.default.dc1": {154				Type: structs.DiscoveryGraphNodeTypeResolver,155				Name: "main.default.dc1",156				Resolver: &structs.DiscoveryResolver{157					Default:        true,158					ConnectTimeout: 5 * time.Second,159					Target:         "main.default.dc1",160				},161			},162		},163		Targets: map[string]*structs.DiscoveryTarget{164			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),165		},166	}167	return compileTestCase{entries: entries, expect: expect}168}169func testcase_JustRouterWithNoDestination() compileTestCase {170	entries := newEntries()171	setServiceProtocol(entries, "main", "http")172	entries.AddRouters(173		&structs.ServiceRouterConfigEntry{174			Kind: "service-router",175			Name: "main",176			Routes: []structs.ServiceRoute{177				{178					Match: &structs.ServiceRouteMatch{179						HTTP: &structs.ServiceRouteHTTPMatch{180							PathPrefix: "/",181						},182					},183				},184			},185		},186	)187	expect := &structs.CompiledDiscoveryChain{188		Protocol:  "http",189		StartNode: "router:main.default",190		Nodes: map[string]*structs.DiscoveryGraphNode{191			"router:main.default": {192				Type: structs.DiscoveryGraphNodeTypeRouter,193				Name: "main.default",194				Routes: []*structs.DiscoveryRoute{195					{196						Definition: &structs.ServiceRoute{197							Match: &structs.ServiceRouteMatch{198								HTTP: &structs.ServiceRouteHTTPMatch{199									PathPrefix: "/",200								},201							},202						},203						NextNode: "resolver:main.default.dc1",204					},205					{206						Definition: newDefaultServiceRoute("main", "default"),207						NextNode:   "resolver:main.default.dc1",208					},209				},210			},211			"resolver:main.default.dc1": {212				Type: structs.DiscoveryGraphNodeTypeResolver,213				Name: "main.default.dc1",214				Resolver: &structs.DiscoveryResolver{215					Default:        true,216					ConnectTimeout: 5 * time.Second,217					Target:         "main.default.dc1",218				},219			},220		},221		Targets: map[string]*structs.DiscoveryTarget{222			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),223		},224	}225	return compileTestCase{entries: entries, expect: expect}226}227func testcase_RouterWithDefaults_NoSplit_WithResolver() compileTestCase {228	entries := newEntries()229	setServiceProtocol(entries, "main", "http")230	entries.AddRouters(231		&structs.ServiceRouterConfigEntry{232			Kind: "service-router",233			Name: "main",234		},235	)236	entries.AddResolvers(237		&structs.ServiceResolverConfigEntry{238			Kind:           "service-resolver",239			Name:           "main",240			ConnectTimeout: 33 * time.Second,241		},242	)243	expect := &structs.CompiledDiscoveryChain{244		Protocol:  "http",245		StartNode: "router:main.default",246		Nodes: map[string]*structs.DiscoveryGraphNode{247			"router:main.default": {248				Type: structs.DiscoveryGraphNodeTypeRouter,249				Name: "main.default",250				Routes: []*structs.DiscoveryRoute{251					{252						Definition: newDefaultServiceRoute("main", "default"),253						NextNode:   "resolver:main.default.dc1",254					},255				},256			},257			"resolver:main.default.dc1": {258				Type: structs.DiscoveryGraphNodeTypeResolver,259				Name: "main.default.dc1",260				Resolver: &structs.DiscoveryResolver{261					ConnectTimeout: 33 * time.Second,262					Target:         "main.default.dc1",263				},264			},265		},266		Targets: map[string]*structs.DiscoveryTarget{267			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),268		},269	}270	return compileTestCase{entries: entries, expect: expect}271}272func testcase_RouterWithDefaults_WithNoopSplit_DefaultResolver() compileTestCase {273	entries := newEntries()274	setServiceProtocol(entries, "main", "http")275	entries.AddRouters(276		&structs.ServiceRouterConfigEntry{277			Kind: "service-router",278			Name: "main",279		},280	)281	entries.AddSplitters(282		&structs.ServiceSplitterConfigEntry{283			Kind: "service-splitter",284			Name: "main",285			Splits: []structs.ServiceSplit{286				{Weight: 100},287			},288		},289	)290	expect := &structs.CompiledDiscoveryChain{291		Protocol:  "http",292		StartNode: "router:main.default",293		Nodes: map[string]*structs.DiscoveryGraphNode{294			"router:main.default": {295				Type: structs.DiscoveryGraphNodeTypeRouter,296				Name: "main.default",297				Routes: []*structs.DiscoveryRoute{298					{299						Definition: newDefaultServiceRoute("main", "default"),300						NextNode:   "splitter:main.default",301					},302				},303			},304			"splitter:main.default": {305				Type: structs.DiscoveryGraphNodeTypeSplitter,306				Name: "main.default",307				Splits: []*structs.DiscoverySplit{308					{309						Weight:   100,310						NextNode: "resolver:main.default.dc1",311					},312				},313			},314			"resolver:main.default.dc1": {315				Type: structs.DiscoveryGraphNodeTypeResolver,316				Name: "main.default.dc1",317				Resolver: &structs.DiscoveryResolver{318					Default:        true,319					ConnectTimeout: 5 * time.Second,320					Target:         "main.default.dc1",321				},322			},323		},324		Targets: map[string]*structs.DiscoveryTarget{325			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),326		},327	}328	return compileTestCase{entries: entries, expect: expect}329}330func testcase_NoopSplit_DefaultResolver_ProtocolFromProxyDefaults() compileTestCase {331	entries := newEntries()332	setGlobalProxyProtocol(entries, "http")333	entries.AddRouters(334		&structs.ServiceRouterConfigEntry{335			Kind: "service-router",336			Name: "main",337		},338	)339	entries.AddSplitters(340		&structs.ServiceSplitterConfigEntry{341			Kind: "service-splitter",342			Name: "main",343			Splits: []structs.ServiceSplit{344				{Weight: 100},345			},346		},347	)348	expect := &structs.CompiledDiscoveryChain{349		Protocol:  "http",350		StartNode: "router:main.default",351		Nodes: map[string]*structs.DiscoveryGraphNode{352			"router:main.default": {353				Type: structs.DiscoveryGraphNodeTypeRouter,354				Name: "main.default",355				Routes: []*structs.DiscoveryRoute{356					{357						Definition: newDefaultServiceRoute("main", "default"),358						NextNode:   "splitter:main.default",359					},360				},361			},362			"splitter:main.default": {363				Type: structs.DiscoveryGraphNodeTypeSplitter,364				Name: "main.default",365				Splits: []*structs.DiscoverySplit{366					{367						Weight:   100,368						NextNode: "resolver:main.default.dc1",369					},370				},371			},372			"resolver:main.default.dc1": {373				Type: structs.DiscoveryGraphNodeTypeResolver,374				Name: "main.default.dc1",375				Resolver: &structs.DiscoveryResolver{376					Default:        true,377					ConnectTimeout: 5 * time.Second,378					Target:         "main.default.dc1",379				},380			},381		},382		Targets: map[string]*structs.DiscoveryTarget{383			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),384		},385	}386	return compileTestCase{entries: entries, expect: expect}387}388func testcase_RouterWithDefaults_WithNoopSplit_WithResolver() compileTestCase {389	entries := newEntries()390	setServiceProtocol(entries, "main", "http")391	entries.AddRouters(392		&structs.ServiceRouterConfigEntry{393			Kind: "service-router",394			Name: "main",395		},396	)397	entries.AddSplitters(398		&structs.ServiceSplitterConfigEntry{399			Kind: "service-splitter",400			Name: "main",401			Splits: []structs.ServiceSplit{402				{Weight: 100},403			},404		},405	)406	entries.AddResolvers(407		&structs.ServiceResolverConfigEntry{408			Kind:           "service-resolver",409			Name:           "main",410			ConnectTimeout: 33 * time.Second,411		},412	)413	expect := &structs.CompiledDiscoveryChain{414		Protocol:  "http",415		StartNode: "router:main.default",416		Nodes: map[string]*structs.DiscoveryGraphNode{417			"router:main.default": {418				Type: structs.DiscoveryGraphNodeTypeRouter,419				Name: "main.default",420				Routes: []*structs.DiscoveryRoute{421					{422						Definition: newDefaultServiceRoute("main", "default"),423						NextNode:   "splitter:main.default",424					},425				},426			},427			"splitter:main.default": {428				Type: structs.DiscoveryGraphNodeTypeSplitter,429				Name: "main.default",430				Splits: []*structs.DiscoverySplit{431					{432						Weight:   100,433						NextNode: "resolver:main.default.dc1",434					},435				},436			},437			"resolver:main.default.dc1": {438				Type: structs.DiscoveryGraphNodeTypeResolver,439				Name: "main.default.dc1",440				Resolver: &structs.DiscoveryResolver{441					ConnectTimeout: 33 * time.Second,442					Target:         "main.default.dc1",443				},444			},445		},446		Targets: map[string]*structs.DiscoveryTarget{447			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),448		},449	}450	return compileTestCase{entries: entries, expect: expect}451}452func testcase_RouteBypassesSplit() compileTestCase {453	entries := newEntries()454	setServiceProtocol(entries, "main", "http")455	setServiceProtocol(entries, "other", "http")456	entries.AddRouters(457		&structs.ServiceRouterConfigEntry{458			Kind: "service-router",459			Name: "main",460			Routes: []structs.ServiceRoute{461				// route direct subset reference (bypass split)462				newSimpleRoute("other", func(r *structs.ServiceRoute) {463					r.Destination.ServiceSubset = "bypass"464				}),465			},466		},467	)468	entries.AddSplitters(469		&structs.ServiceSplitterConfigEntry{470			Kind: "service-splitter",471			Name: "other",472			Splits: []structs.ServiceSplit{473				{Weight: 100, Service: "ignored"},474			},475		},476	)477	entries.AddResolvers(478		&structs.ServiceResolverConfigEntry{479			Kind: "service-resolver",480			Name: "other",481			Subsets: map[string]structs.ServiceResolverSubset{482				"bypass": {483					Filter: "Service.Meta.version == bypass",484				},485			},486		},487	)488	router := entries.GetRouter(structs.NewServiceID("main", nil))489	expect := &structs.CompiledDiscoveryChain{490		Protocol:  "http",491		StartNode: "router:main.default",492		Nodes: map[string]*structs.DiscoveryGraphNode{493			"router:main.default": {494				Type: structs.DiscoveryGraphNodeTypeRouter,495				Name: "main.default",496				Routes: []*structs.DiscoveryRoute{497					{498						Definition: &router.Routes[0],499						NextNode:   "resolver:bypass.other.default.dc1",500					},501					{502						Definition: newDefaultServiceRoute("main", "default"),503						NextNode:   "resolver:main.default.dc1",504					},505				},506			},507			"resolver:main.default.dc1": {508				Type: structs.DiscoveryGraphNodeTypeResolver,509				Name: "main.default.dc1",510				Resolver: &structs.DiscoveryResolver{511					Default:        true,512					ConnectTimeout: 5 * time.Second,513					Target:         "main.default.dc1",514				},515			},516			"resolver:bypass.other.default.dc1": {517				Type: structs.DiscoveryGraphNodeTypeResolver,518				Name: "bypass.other.default.dc1",519				Resolver: &structs.DiscoveryResolver{520					ConnectTimeout: 5 * time.Second,521					Target:         "bypass.other.default.dc1",522				},523			},524		},525		Targets: map[string]*structs.DiscoveryTarget{526			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),527			"bypass.other.default.dc1": newTarget("other", "bypass", "default", "dc1", func(t *structs.DiscoveryTarget) {528				t.Subset = structs.ServiceResolverSubset{529					Filter: "Service.Meta.version == bypass",530				}531			}),532		},533	}534	return compileTestCase{entries: entries, expect: expect}535}536func testcase_NoopSplit_DefaultResolver() compileTestCase {537	entries := newEntries()538	setServiceProtocol(entries, "main", "http")539	entries.AddSplitters(540		&structs.ServiceSplitterConfigEntry{541			Kind: "service-splitter",542			Name: "main",543			Splits: []structs.ServiceSplit{544				{Weight: 100},545			},546		},547	)548	expect := &structs.CompiledDiscoveryChain{549		Protocol:  "http",550		StartNode: "splitter:main.default",551		Nodes: map[string]*structs.DiscoveryGraphNode{552			"splitter:main.default": {553				Type: structs.DiscoveryGraphNodeTypeSplitter,554				Name: "main.default",555				Splits: []*structs.DiscoverySplit{556					{557						Weight:   100,558						NextNode: "resolver:main.default.dc1",559					},560				},561			},562			"resolver:main.default.dc1": {563				Type: structs.DiscoveryGraphNodeTypeResolver,564				Name: "main.default.dc1",565				Resolver: &structs.DiscoveryResolver{566					Default:        true,567					ConnectTimeout: 5 * time.Second,568					Target:         "main.default.dc1",569				},570			},571		},572		Targets: map[string]*structs.DiscoveryTarget{573			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),574		},575	}576	return compileTestCase{entries: entries, expect: expect}577}578func testcase_NoopSplit_WithResolver() compileTestCase {579	entries := newEntries()580	setServiceProtocol(entries, "main", "http")581	entries.AddSplitters(582		&structs.ServiceSplitterConfigEntry{583			Kind: "service-splitter",584			Name: "main",585			Splits: []structs.ServiceSplit{586				{Weight: 100},587			},588		},589	)590	entries.AddResolvers(591		&structs.ServiceResolverConfigEntry{592			Kind:           "service-resolver",593			Name:           "main",594			ConnectTimeout: 33 * time.Second,595		},596	)597	expect := &structs.CompiledDiscoveryChain{598		Protocol:  "http",599		StartNode: "splitter:main.default",600		Nodes: map[string]*structs.DiscoveryGraphNode{601			"splitter:main.default": {602				Type: structs.DiscoveryGraphNodeTypeSplitter,603				Name: "main.default",604				Splits: []*structs.DiscoverySplit{605					{606						Weight:   100,607						NextNode: "resolver:main.default.dc1",608					},609				},610			},611			"resolver:main.default.dc1": {612				Type: structs.DiscoveryGraphNodeTypeResolver,613				Name: "main.default.dc1",614				Resolver: &structs.DiscoveryResolver{615					ConnectTimeout: 33 * time.Second,616					Target:         "main.default.dc1",617				},618			},619		},620		Targets: map[string]*structs.DiscoveryTarget{621			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),622		},623	}624	return compileTestCase{entries: entries, expect: expect}625}626func testcase_SubsetSplit() compileTestCase {627	entries := newEntries()628	setServiceProtocol(entries, "main", "http")629	entries.AddSplitters(630		&structs.ServiceSplitterConfigEntry{631			Kind: "service-splitter",632			Name: "main",633			Splits: []structs.ServiceSplit{634				{Weight: 60, ServiceSubset: "v2"},635				{Weight: 40, ServiceSubset: "v1"},636			},637		},638	)639	entries.AddResolvers(640		&structs.ServiceResolverConfigEntry{641			Kind: "service-resolver",642			Name: "main",643			Subsets: map[string]structs.ServiceResolverSubset{644				"v1": {645					Filter: "Service.Meta.version == 1",646				},647				"v2": {648					Filter: "Service.Meta.version == 2",649				},650			},651		},652	)653	expect := &structs.CompiledDiscoveryChain{654		Protocol:  "http",655		StartNode: "splitter:main.default",656		Nodes: map[string]*structs.DiscoveryGraphNode{657			"splitter:main.default": {658				Type: structs.DiscoveryGraphNodeTypeSplitter,659				Name: "main.default",660				Splits: []*structs.DiscoverySplit{661					{662						Weight:   60,663						NextNode: "resolver:v2.main.default.dc1",664					},665					{666						Weight:   40,667						NextNode: "resolver:v1.main.default.dc1",668					},669				},670			},671			"resolver:v2.main.default.dc1": {672				Type: structs.DiscoveryGraphNodeTypeResolver,673				Name: "v2.main.default.dc1",674				Resolver: &structs.DiscoveryResolver{675					ConnectTimeout: 5 * time.Second,676					Target:         "v2.main.default.dc1",677				},678			},679			"resolver:v1.main.default.dc1": {680				Type: structs.DiscoveryGraphNodeTypeResolver,681				Name: "v1.main.default.dc1",682				Resolver: &structs.DiscoveryResolver{683					ConnectTimeout: 5 * time.Second,684					Target:         "v1.main.default.dc1",685				},686			},687		},688		Targets: map[string]*structs.DiscoveryTarget{689			"v2.main.default.dc1": newTarget("main", "v2", "default", "dc1", func(t *structs.DiscoveryTarget) {690				t.Subset = structs.ServiceResolverSubset{691					Filter: "Service.Meta.version == 2",692				}693			}),694			"v1.main.default.dc1": newTarget("main", "v1", "default", "dc1", func(t *structs.DiscoveryTarget) {695				t.Subset = structs.ServiceResolverSubset{696					Filter: "Service.Meta.version == 1",697				}698			}),699		},700	}701	return compileTestCase{entries: entries, expect: expect}702}703func testcase_ServiceSplit() compileTestCase {704	entries := newEntries()705	setServiceProtocol(entries, "main", "http")706	setServiceProtocol(entries, "foo", "http")707	setServiceProtocol(entries, "bar", "http")708	entries.AddSplitters(709		&structs.ServiceSplitterConfigEntry{710			Kind: "service-splitter",711			Name: "main",712			Splits: []structs.ServiceSplit{713				{Weight: 60, Service: "foo"},714				{Weight: 40, Service: "bar"},715			},716		},717	)718	expect := &structs.CompiledDiscoveryChain{719		Protocol:  "http",720		StartNode: "splitter:main.default",721		Nodes: map[string]*structs.DiscoveryGraphNode{722			"splitter:main.default": {723				Type: structs.DiscoveryGraphNodeTypeSplitter,724				Name: "main.default",725				Splits: []*structs.DiscoverySplit{726					{727						Weight:   60,728						NextNode: "resolver:foo.default.dc1",729					},730					{731						Weight:   40,732						NextNode: "resolver:bar.default.dc1",733					},734				},735			},736			"resolver:foo.default.dc1": {737				Type: structs.DiscoveryGraphNodeTypeResolver,738				Name: "foo.default.dc1",739				Resolver: &structs.DiscoveryResolver{740					Default:        true,741					ConnectTimeout: 5 * time.Second,742					Target:         "foo.default.dc1",743				},744			},745			"resolver:bar.default.dc1": {746				Type: structs.DiscoveryGraphNodeTypeResolver,747				Name: "bar.default.dc1",748				Resolver: &structs.DiscoveryResolver{749					Default:        true,750					ConnectTimeout: 5 * time.Second,751					Target:         "bar.default.dc1",752				},753			},754		},755		Targets: map[string]*structs.DiscoveryTarget{756			"foo.default.dc1": newTarget("foo", "", "default", "dc1", nil),757			"bar.default.dc1": newTarget("bar", "", "default", "dc1", nil),758		},759	}760	return compileTestCase{entries: entries, expect: expect}761}762func testcase_SplitBypassesSplit() compileTestCase {763	entries := newEntries()764	setServiceProtocol(entries, "main", "http")765	setServiceProtocol(entries, "next", "http")766	entries.AddSplitters(767		&structs.ServiceSplitterConfigEntry{768			Kind: "service-splitter",769			Name: "main",770			Splits: []structs.ServiceSplit{771				{772					Weight:        100,773					Service:       "next",774					ServiceSubset: "bypassed",775				},776			},777		},778		&structs.ServiceSplitterConfigEntry{779			Kind: "service-splitter",780			Name: "next",781			Splits: []structs.ServiceSplit{782				{783					Weight:        100,784					ServiceSubset: "not-bypassed",785				},786			},787		},788	)789	entries.AddResolvers(790		&structs.ServiceResolverConfigEntry{791			Kind: "service-resolver",792			Name: "next",793			Subsets: map[string]structs.ServiceResolverSubset{794				"bypassed": {795					Filter: "Service.Meta.version == bypass",796				},797				"not-bypassed": {798					Filter: "Service.Meta.version != bypass",799				},800			},801		},802	)803	expect := &structs.CompiledDiscoveryChain{804		Protocol:  "http",805		StartNode: "splitter:main.default",806		Nodes: map[string]*structs.DiscoveryGraphNode{807			"splitter:main.default": {808				Type: structs.DiscoveryGraphNodeTypeSplitter,809				Name: "main.default",810				Splits: []*structs.DiscoverySplit{811					{812						Weight:   100,813						NextNode: "resolver:bypassed.next.default.dc1",814					},815				},816			},817			"resolver:bypassed.next.default.dc1": {818				Type: structs.DiscoveryGraphNodeTypeResolver,819				Name: "bypassed.next.default.dc1",820				Resolver: &structs.DiscoveryResolver{821					ConnectTimeout: 5 * time.Second,822					Target:         "bypassed.next.default.dc1",823				},824			},825		},826		Targets: map[string]*structs.DiscoveryTarget{827			"bypassed.next.default.dc1": newTarget("next", "bypassed", "default", "dc1", func(t *structs.DiscoveryTarget) {828				t.Subset = structs.ServiceResolverSubset{829					Filter: "Service.Meta.version == bypass",830				}831			}),832		},833	}834	return compileTestCase{entries: entries, expect: expect}835}836func testcase_ServiceRedirect() compileTestCase {837	entries := newEntries()838	entries.AddResolvers(839		&structs.ServiceResolverConfigEntry{840			Kind: "service-resolver",841			Name: "main",842			Redirect: &structs.ServiceResolverRedirect{843				Service: "other",844			},845		},846	)847	expect := &structs.CompiledDiscoveryChain{848		Protocol:  "tcp",849		StartNode: "resolver:other.default.dc1",850		Nodes: map[string]*structs.DiscoveryGraphNode{851			"resolver:other.default.dc1": {852				Type: structs.DiscoveryGraphNodeTypeResolver,853				Name: "other.default.dc1",854				Resolver: &structs.DiscoveryResolver{855					Default:        true,856					ConnectTimeout: 5 * time.Second,857					Target:         "other.default.dc1",858				},859			},860		},861		Targets: map[string]*structs.DiscoveryTarget{862			"other.default.dc1": newTarget("other", "", "default", "dc1", nil),863		},864	}865	return compileTestCase{entries: entries, expect: expect}866}867func testcase_ServiceAndSubsetRedirect() compileTestCase {868	entries := newEntries()869	entries.AddResolvers(870		&structs.ServiceResolverConfigEntry{871			Kind: "service-resolver",872			Name: "main",873			Redirect: &structs.ServiceResolverRedirect{874				Service:       "other",875				ServiceSubset: "v2",876			},877		},878		&structs.ServiceResolverConfigEntry{879			Kind: "service-resolver",880			Name: "other",881			Subsets: map[string]structs.ServiceResolverSubset{882				"v1": {883					Filter: "Service.Meta.version == 1",884				},885				"v2": {886					Filter: "Service.Meta.version == 2",887				},888			},889		},890	)891	expect := &structs.CompiledDiscoveryChain{892		Protocol:  "tcp",893		StartNode: "resolver:v2.other.default.dc1",894		Nodes: map[string]*structs.DiscoveryGraphNode{895			"resolver:v2.other.default.dc1": {896				Type: structs.DiscoveryGraphNodeTypeResolver,897				Name: "v2.other.default.dc1",898				Resolver: &structs.DiscoveryResolver{899					ConnectTimeout: 5 * time.Second,900					Target:         "v2.other.default.dc1",901				},902			},903		},904		Targets: map[string]*structs.DiscoveryTarget{905			"v2.other.default.dc1": newTarget("other", "v2", "default", "dc1", func(t *structs.DiscoveryTarget) {906				t.Subset = structs.ServiceResolverSubset{907					Filter: "Service.Meta.version == 2",908				}909			}),910		},911	}912	return compileTestCase{entries: entries, expect: expect}913}914func testcase_DatacenterRedirect() compileTestCase {915	entries := newEntries()916	entries.AddResolvers(917		&structs.ServiceResolverConfigEntry{918			Kind: "service-resolver",919			Name: "main",920			Redirect: &structs.ServiceResolverRedirect{921				Datacenter: "dc9",922			},923		},924	)925	expect := &structs.CompiledDiscoveryChain{926		Protocol:  "tcp",927		StartNode: "resolver:main.default.dc9",928		Nodes: map[string]*structs.DiscoveryGraphNode{929			"resolver:main.default.dc9": {930				Type: structs.DiscoveryGraphNodeTypeResolver,931				Name: "main.default.dc9",932				Resolver: &structs.DiscoveryResolver{933					ConnectTimeout: 5 * time.Second,934					Target:         "main.default.dc9",935				},936			},937		},938		Targets: map[string]*structs.DiscoveryTarget{939			"main.default.dc9": newTarget("main", "", "default", "dc9", nil),940		},941	}942	return compileTestCase{entries: entries, expect: expect}943}944func testcase_DatacenterRedirect_WithMeshGateways() compileTestCase {945	entries := newEntries()946	entries.GlobalProxy = &structs.ProxyConfigEntry{947		Kind: structs.ProxyDefaults,948		Name: structs.ProxyConfigGlobal,949		MeshGateway: structs.MeshGatewayConfig{950			Mode: structs.MeshGatewayModeRemote,951		},952	}953	entries.AddResolvers(954		&structs.ServiceResolverConfigEntry{955			Kind: "service-resolver",956			Name: "main",957			Redirect: &structs.ServiceResolverRedirect{958				Datacenter: "dc9",959			},960		},961	)962	expect := &structs.CompiledDiscoveryChain{963		Protocol:  "tcp",964		StartNode: "resolver:main.default.dc9",965		Nodes: map[string]*structs.DiscoveryGraphNode{966			"resolver:main.default.dc9": {967				Type: structs.DiscoveryGraphNodeTypeResolver,968				Name: "main.default.dc9",969				Resolver: &structs.DiscoveryResolver{970					ConnectTimeout: 5 * time.Second,971					Target:         "main.default.dc9",972				},973			},974		},975		Targets: map[string]*structs.DiscoveryTarget{976			"main.default.dc9": newTarget("main", "", "default", "dc9", func(t *structs.DiscoveryTarget) {977				t.MeshGateway = structs.MeshGatewayConfig{978					Mode: structs.MeshGatewayModeRemote,979				}980			}),981		},982	}983	return compileTestCase{entries: entries, expect: expect}984}985func testcase_ServiceFailover() compileTestCase {986	entries := newEntries()987	entries.AddResolvers(988		&structs.ServiceResolverConfigEntry{989			Kind: "service-resolver",990			Name: "main",991			Failover: map[string]structs.ServiceResolverFailover{992				"*": {Service: "backup"},993			},994		},995	)996	expect := &structs.CompiledDiscoveryChain{997		Protocol:  "tcp",998		StartNode: "resolver:main.default.dc1",999		Nodes: map[string]*structs.DiscoveryGraphNode{1000			"resolver:main.default.dc1": {1001				Type: structs.DiscoveryGraphNodeTypeResolver,1002				Name: "main.default.dc1",1003				Resolver: &structs.DiscoveryResolver{1004					ConnectTimeout: 5 * time.Second,1005					Target:         "main.default.dc1",1006					Failover: &structs.DiscoveryFailover{1007						Targets: []string{"backup.default.dc1"},1008					},1009				},1010			},1011		},1012		Targets: map[string]*structs.DiscoveryTarget{1013			"main.default.dc1":   newTarget("main", "", "default", "dc1", nil),1014			"backup.default.dc1": newTarget("backup", "", "default", "dc1", nil),1015		},1016	}1017	return compileTestCase{entries: entries, expect: expect}1018}1019func testcase_ServiceFailoverThroughRedirect() compileTestCase {1020	entries := newEntries()1021	entries.AddResolvers(1022		&structs.ServiceResolverConfigEntry{1023			Kind: "service-resolver",1024			Name: "backup",1025			Redirect: &structs.ServiceResolverRedirect{1026				Service: "actual",1027			},1028		},1029		&structs.ServiceResolverConfigEntry{1030			Kind: "service-resolver",1031			Name: "main",1032			Failover: map[string]structs.ServiceResolverFailover{1033				"*": {Service: "backup"},1034			},1035		},1036	)1037	expect := &structs.CompiledDiscoveryChain{1038		Protocol:  "tcp",1039		StartNode: "resolver:main.default.dc1",1040		Nodes: map[string]*structs.DiscoveryGraphNode{1041			"resolver:main.default.dc1": {1042				Type: structs.DiscoveryGraphNodeTypeResolver,1043				Name: "main.default.dc1",1044				Resolver: &structs.DiscoveryResolver{1045					ConnectTimeout: 5 * time.Second,1046					Target:         "main.default.dc1",1047					Failover: &structs.DiscoveryFailover{1048						Targets: []string{"actual.default.dc1"},1049					},1050				},1051			},1052		},1053		Targets: map[string]*structs.DiscoveryTarget{1054			"main.default.dc1":   newTarget("main", "", "default", "dc1", nil),1055			"actual.default.dc1": newTarget("actual", "", "default", "dc1", nil),1056		},1057	}1058	return compileTestCase{entries: entries, expect: expect}1059}1060func testcase_Resolver_CircularFailover() compileTestCase {1061	entries := newEntries()1062	entries.AddResolvers(1063		&structs.ServiceResolverConfigEntry{1064			Kind: "service-resolver",1065			Name: "backup",1066			Failover: map[string]structs.ServiceResolverFailover{1067				"*": {Service: "main"},1068			},1069		},1070		&structs.ServiceResolverConfigEntry{1071			Kind: "service-resolver",1072			Name: "main",1073			Failover: map[string]structs.ServiceResolverFailover{1074				"*": {Service: "backup"},1075			},1076		},1077	)1078	expect := &structs.CompiledDiscoveryChain{1079		Protocol:  "tcp",1080		StartNode: "resolver:main.default.dc1",1081		Nodes: map[string]*structs.DiscoveryGraphNode{1082			"resolver:main.default.dc1": {1083				Type: structs.DiscoveryGraphNodeTypeResolver,1084				Name: "main.default.dc1",1085				Resolver: &structs.DiscoveryResolver{1086					ConnectTimeout: 5 * time.Second,1087					Target:         "main.default.dc1",1088					Failover: &structs.DiscoveryFailover{1089						Targets: []string{"backup.default.dc1"},1090					},1091				},1092			},1093		},1094		Targets: map[string]*structs.DiscoveryTarget{1095			"main.default.dc1":   newTarget("main", "", "default", "dc1", nil),1096			"backup.default.dc1": newTarget("backup", "", "default", "dc1", nil),1097		},1098	}1099	return compileTestCase{entries: entries, expect: expect}1100}1101func testcase_ServiceAndSubsetFailover() compileTestCase {1102	entries := newEntries()1103	entries.AddResolvers(1104		&structs.ServiceResolverConfigEntry{1105			Kind: "service-resolver",1106			Name: "main",1107			Subsets: map[string]structs.ServiceResolverSubset{1108				"backup": {1109					Filter: "Service.Meta.version == backup",1110				},1111			},1112			Failover: map[string]structs.ServiceResolverFailover{1113				"*": {ServiceSubset: "backup"},1114			},1115		},1116	)1117	expect := &structs.CompiledDiscoveryChain{1118		Protocol:  "tcp",1119		StartNode: "resolver:main.default.dc1",1120		Nodes: map[string]*structs.DiscoveryGraphNode{1121			"resolver:main.default.dc1": {1122				Type: structs.DiscoveryGraphNodeTypeResolver,1123				Name: "main.default.dc1",1124				Resolver: &structs.DiscoveryResolver{1125					ConnectTimeout: 5 * time.Second,1126					Target:         "main.default.dc1",1127					Failover: &structs.DiscoveryFailover{1128						Targets: []string{"backup.main.default.dc1"},1129					},1130				},1131			},1132		},1133		Targets: map[string]*structs.DiscoveryTarget{1134			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),1135			"backup.main.default.dc1": newTarget("main", "backup", "default", "dc1", func(t *structs.DiscoveryTarget) {1136				t.Subset = structs.ServiceResolverSubset{1137					Filter: "Service.Meta.version == backup",1138				}1139			}),1140		},1141	}1142	return compileTestCase{entries: entries, expect: expect}1143}1144func testcase_DatacenterFailover() compileTestCase {1145	entries := newEntries()1146	entries.AddResolvers(1147		&structs.ServiceResolverConfigEntry{1148			Kind: "service-resolver",1149			Name: "main",1150			Failover: map[string]structs.ServiceResolverFailover{1151				"*": {Datacenters: []string{"dc2", "dc4"}},1152			},1153		},1154	)1155	expect := &structs.CompiledDiscoveryChain{1156		Protocol:  "tcp",1157		StartNode: "resolver:main.default.dc1",1158		Nodes: map[string]*structs.DiscoveryGraphNode{1159			"resolver:main.default.dc1": {1160				Type: structs.DiscoveryGraphNodeTypeResolver,1161				Name: "main.default.dc1",1162				Resolver: &structs.DiscoveryResolver{1163					ConnectTimeout: 5 * time.Second,1164					Target:         "main.default.dc1",1165					Failover: &structs.DiscoveryFailover{1166						Targets: []string{"main.default.dc2", "main.default.dc4"},1167					},1168				},1169			},1170		},1171		Targets: map[string]*structs.DiscoveryTarget{1172			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),1173			"main.default.dc2": newTarget("main", "", "default", "dc2", nil),1174			"main.default.dc4": newTarget("main", "", "default", "dc4", nil),1175		},1176	}1177	return compileTestCase{entries: entries, expect: expect}1178}1179func testcase_DatacenterFailover_WithMeshGateways() compileTestCase {1180	entries := newEntries()1181	entries.GlobalProxy = &structs.ProxyConfigEntry{1182		Kind: structs.ProxyDefaults,1183		Name: structs.ProxyConfigGlobal,1184		MeshGateway: structs.MeshGatewayConfig{1185			Mode: structs.MeshGatewayModeRemote,1186		},1187	}1188	entries.AddResolvers(1189		&structs.ServiceResolverConfigEntry{1190			Kind: "service-resolver",1191			Name: "main",1192			Failover: map[string]structs.ServiceResolverFailover{1193				"*": {Datacenters: []string{"dc2", "dc4"}},1194			},1195		},1196	)1197	expect := &structs.CompiledDiscoveryChain{1198		Protocol:  "tcp",1199		StartNode: "resolver:main.default.dc1",1200		Nodes: map[string]*structs.DiscoveryGraphNode{1201			"resolver:main.default.dc1": {1202				Type: structs.DiscoveryGraphNodeTypeResolver,1203				Name: "main.default.dc1",1204				Resolver: &structs.DiscoveryResolver{1205					ConnectTimeout: 5 * time.Second,1206					Target:         "main.default.dc1",1207					Failover: &structs.DiscoveryFailover{1208						Targets: []string{1209							"main.default.dc2",1210							"main.default.dc4",1211						},1212					},1213				},1214			},1215		},1216		Targets: map[string]*structs.DiscoveryTarget{1217			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),1218			"main.default.dc2": newTarget("main", "", "default", "dc2", func(t *structs.DiscoveryTarget) {1219				t.MeshGateway = structs.MeshGatewayConfig{1220					Mode: structs.MeshGatewayModeRemote,1221				}1222			}),1223			"main.default.dc4": newTarget("main", "", "default", "dc4", func(t *structs.DiscoveryTarget) {1224				t.MeshGateway = structs.MeshGatewayConfig{1225					Mode: structs.MeshGatewayModeRemote,1226				}1227			}),1228		},1229	}1230	return compileTestCase{entries: entries, expect: expect}1231}1232func testcase_NoopSplit_WithDefaultSubset() compileTestCase {1233	entries := newEntries()1234	setServiceProtocol(entries, "main", "http")1235	entries.AddSplitters(1236		&structs.ServiceSplitterConfigEntry{1237			Kind: "service-splitter",1238			Name: "main",1239			Splits: []structs.ServiceSplit{1240				{Weight: 100},1241			},1242		},1243	)1244	entries.AddResolvers(1245		&structs.ServiceResolverConfigEntry{1246			Kind:          "service-resolver",1247			Name:          "main",1248			DefaultSubset: "v2",1249			Subsets: map[string]structs.ServiceResolverSubset{1250				"v1": {Filter: "Service.Meta.version == 1"},1251				"v2": {Filter: "Service.Meta.version == 2"},1252			},1253		},1254	)1255	expect := &structs.CompiledDiscoveryChain{1256		Protocol:  "http",1257		StartNode: "splitter:main.default",1258		Nodes: map[string]*structs.DiscoveryGraphNode{1259			"splitter:main.default": {1260				Type: structs.DiscoveryGraphNodeTypeSplitter,1261				Name: "main.default",1262				Splits: []*structs.DiscoverySplit{1263					{1264						Weight:   100,1265						NextNode: "resolver:v2.main.default.dc1",1266					},1267				},1268			},1269			"resolver:v2.main.default.dc1": {1270				Type: structs.DiscoveryGraphNodeTypeResolver,1271				Name: "v2.main.default.dc1",1272				Resolver: &structs.DiscoveryResolver{1273					ConnectTimeout: 5 * time.Second,1274					Target:         "v2.main.default.dc1",1275				},1276			},1277		},1278		Targets: map[string]*structs.DiscoveryTarget{1279			"v2.main.default.dc1": newTarget("main", "v2", "default", "dc1", func(t *structs.DiscoveryTarget) {1280				t.Subset = structs.ServiceResolverSubset{1281					Filter: "Service.Meta.version == 2",1282				}1283			}),1284		},1285	}1286	return compileTestCase{entries: entries, expect: expect}1287}1288func testcase_DefaultResolver() compileTestCase {1289	entries := newEntries()1290	expect := &structs.CompiledDiscoveryChain{1291		Protocol:  "tcp",1292		StartNode: "resolver:main.default.dc1",1293		Nodes: map[string]*structs.DiscoveryGraphNode{1294			"resolver:main.default.dc1": {1295				Type: structs.DiscoveryGraphNodeTypeResolver,1296				Name: "main.default.dc1",1297				Resolver: &structs.DiscoveryResolver{1298					Default:        true,1299					ConnectTimeout: 5 * time.Second,1300					Target:         "main.default.dc1",1301				},1302			},1303		},1304		Targets: map[string]*structs.DiscoveryTarget{1305			// TODO-TARGET1306			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),1307		},1308	}1309	return compileTestCase{entries: entries, expect: expect, expectIsDefault: true}1310}1311func testcase_DefaultResolver_WithProxyDefaults() compileTestCase {1312	entries := newEntries()1313	entries.GlobalProxy = &structs.ProxyConfigEntry{1314		Kind: structs.ProxyDefaults,1315		Name: structs.ProxyConfigGlobal,1316		Config: map[string]interface{}{1317			"protocol": "grpc",1318		},1319		MeshGateway: structs.MeshGatewayConfig{1320			Mode: structs.MeshGatewayModeRemote,1321		},1322	}1323	expect := &structs.CompiledDiscoveryChain{1324		Protocol:  "grpc",1325		StartNode: "resolver:main.default.dc1",1326		Nodes: map[string]*structs.DiscoveryGraphNode{1327			"resolver:main.default.dc1": {1328				Type: structs.DiscoveryGraphNodeTypeResolver,1329				Name: "main.default.dc1",1330				Resolver: &structs.DiscoveryResolver{1331					Default:        true,1332					ConnectTimeout: 5 * time.Second,1333					Target:         "main.default.dc1",1334				},1335			},1336		},1337		Targets: map[string]*structs.DiscoveryTarget{1338			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),1339		},1340	}1341	return compileTestCase{entries: entries, expect: expect, expectIsDefault: true}1342}1343func testcase_RedirectToDefaultResolverIsNotDefaultChain() compileTestCase {1344	entries := newEntries()1345	entries.AddResolvers(1346		&structs.ServiceResolverConfigEntry{1347			Kind: structs.ServiceResolver,1348			Name: "main",1349			Redirect: &structs.ServiceResolverRedirect{1350				Service: "other",1351			},1352		},1353	)1354	expect := &structs.CompiledDiscoveryChain{1355		Protocol:  "tcp",1356		StartNode: "resolver:other.default.dc1",1357		Nodes: map[string]*structs.DiscoveryGraphNode{1358			"resolver:other.default.dc1": {1359				Type: structs.DiscoveryGraphNodeTypeResolver,1360				Name: "other.default.dc1",1361				Resolver: &structs.DiscoveryResolver{1362					Default:        true,1363					ConnectTimeout: 5 * time.Second,1364					Target:         "other.default.dc1",1365				},1366			},1367		},1368		Targets: map[string]*structs.DiscoveryTarget{1369			"other.default.dc1": newTarget("other", "", "default", "dc1", nil),1370		},1371	}1372	return compileTestCase{entries: entries, expect: expect, expectIsDefault: false /*being explicit here because this is the whole point of this test*/}1373}1374func testcase_Resolve_WithDefaultSubset() compileTestCase {1375	entries := newEntries()1376	entries.AddResolvers(1377		&structs.ServiceResolverConfigEntry{1378			Kind:          "service-resolver",1379			Name:          "main",1380			DefaultSubset: "v2",1381			Subsets: map[string]structs.ServiceResolverSubset{1382				"v1": {Filter: "Service.Meta.version == 1"},1383				"v2": {Filter: "Service.Meta.version == 2"},1384			},1385		},1386	)1387	expect := &structs.CompiledDiscoveryChain{1388		Protocol:  "tcp",1389		StartNode: "resolver:v2.main.default.dc1",1390		Nodes: map[string]*structs.DiscoveryGraphNode{1391			"resolver:v2.main.default.dc1": {1392				Type: structs.DiscoveryGraphNodeTypeResolver,1393				Name: "v2.main.default.dc1",1394				Resolver: &structs.DiscoveryResolver{1395					ConnectTimeout: 5 * time.Second,1396					Target:         "v2.main.default.dc1",1397				},1398			},1399		},1400		Targets: map[string]*structs.DiscoveryTarget{1401			"v2.main.default.dc1": newTarget("main", "v2", "default", "dc1", func(t *structs.DiscoveryTarget) {1402				t.Subset = structs.ServiceResolverSubset{1403					Filter: "Service.Meta.version == 2",1404				}1405			}),1406		},1407	}1408	return compileTestCase{entries: entries, expect: expect}1409}1410func testcase_DefaultResolver_ExternalSNI() compileTestCase {1411	entries := newEntries()1412	entries.AddServices(&structs.ServiceConfigEntry{1413		Kind:        structs.ServiceDefaults,1414		Name:        "main",1415		ExternalSNI: "main.some.other.service.mesh",1416	})1417	expect := &structs.CompiledDiscoveryChain{1418		Protocol:  "tcp",1419		StartNode: "resolver:main.default.dc1",1420		Nodes: map[string]*structs.DiscoveryGraphNode{1421			"resolver:main.default.dc1": {1422				Type: structs.DiscoveryGraphNodeTypeResolver,1423				Name: "main.default.dc1",1424				Resolver: &structs.DiscoveryResolver{1425					Default:        true,1426					ConnectTimeout: 5 * time.Second,1427					Target:         "main.default.dc1",1428				},1429			},1430		},1431		Targets: map[string]*structs.DiscoveryTarget{1432			"main.default.dc1": newTarget("main", "", "default", "dc1", func(t *structs.DiscoveryTarget) {1433				t.SNI = "main.some.other.service.mesh"1434				t.External = true1435			}),1436		},1437	}1438	return compileTestCase{entries: entries, expect: expect, expectIsDefault: true}1439}1440func testcase_Resolver_ExternalSNI_FailoverNotAllowed() compileTestCase {1441	entries := newEntries()1442	entries.AddServices(&structs.ServiceConfigEntry{1443		Kind:        structs.ServiceDefaults,1444		Name:        "main",1445		ExternalSNI: "main.some.other.service.mesh",1446	})1447	entries.AddResolvers(&structs.ServiceResolverConfigEntry{1448		Kind:           "service-resolver",1449		Name:           "main",1450		ConnectTimeout: 33 * time.Second,1451		Failover: map[string]structs.ServiceResolverFailover{1452			"*": {Service: "backup"},1453		},1454	})1455	return compileTestCase{1456		entries:        entries,1457		expectErr:      `service "main" has an external SNI set; cannot define failover for external services`,1458		expectGraphErr: true,1459	}1460}1461func testcase_Resolver_ExternalSNI_SubsetsNotAllowed() compileTestCase {1462	entries := newEntries()1463	entries.AddServices(&structs.ServiceConfigEntry{1464		Kind:        structs.ServiceDefaults,1465		Name:        "main",1466		ExternalSNI: "main.some.other.service.mesh",1467	})1468	entries.AddResolvers(&structs.ServiceResolverConfigEntry{1469		Kind:           "service-resolver",1470		Name:           "main",1471		ConnectTimeout: 33 * time.Second,1472		Subsets: map[string]structs.ServiceResolverSubset{1473			"canary": {1474				Filter: "Service.Meta.version == canary",1475			},1476		},1477	})1478	return compileTestCase{1479		entries:        entries,1480		expectErr:      `service "main" has an external SNI set; cannot define subsets for external services`,1481		expectGraphErr: true,1482	}1483}1484func testcase_Resolver_ExternalSNI_RedirectNotAllowed() compileTestCase {1485	entries := newEntries()1486	entries.AddServices(&structs.ServiceConfigEntry{1487		Kind:        structs.ServiceDefaults,1488		Name:        "main",1489		ExternalSNI: "main.some.other.service.mesh",1490	})1491	entries.AddResolvers(&structs.ServiceResolverConfigEntry{1492		Kind:           "service-resolver",1493		Name:           "main",1494		ConnectTimeout: 33 * time.Second,1495		Redirect: &structs.ServiceResolverRedirect{1496			Datacenter: "dc2",1497		},1498	})1499	return compileTestCase{1500		entries:        entries,1501		expectErr:      `service "main" has an external SNI set; cannot define redirects for external services`,1502		expectGraphErr: true,1503	}1504}1505func testcase_MultiDatacenterCanary() compileTestCase {1506	entries := newEntries()1507	setServiceProtocol(entries, "main", "http")1508	setServiceProtocol(entries, "main-dc2", "http")1509	setServiceProtocol(entries, "main-dc3", "http")1510	entries.AddSplitters(1511		&structs.ServiceSplitterConfigEntry{1512			Kind: "service-splitter",1513			Name: "main",1514			Splits: []structs.ServiceSplit{1515				{Weight: 60, Service: "main-dc2"},1516				{Weight: 40, Service: "main-dc3"},1517			},1518		},1519	)1520	entries.AddResolvers(1521		&structs.ServiceResolverConfigEntry{1522			Kind: "service-resolver",1523			Name: "main-dc2",1524			Redirect: &structs.ServiceResolverRedirect{1525				Service:    "main",1526				Datacenter: "dc2",1527			},1528		},1529		&structs.ServiceResolverConfigEntry{1530			Kind: "service-resolver",1531			Name: "main-dc3",1532			Redirect: &structs.ServiceResolverRedirect{1533				Service:    "main",1534				Datacenter: "dc3",1535			},1536		},1537		&structs.ServiceResolverConfigEntry{1538			Kind:           "service-resolver",1539			Name:           "main",1540			ConnectTimeout: 33 * time.Second,1541		},1542	)1543	expect := &structs.CompiledDiscoveryChain{1544		Protocol:  "http",1545		StartNode: "splitter:main.default",1546		Nodes: map[string]*structs.DiscoveryGraphNode{1547			"splitter:main.default": {1548				Type: structs.DiscoveryGraphNodeTypeSplitter,1549				Name: "main.default",1550				Splits: []*structs.DiscoverySplit{1551					{1552						Weight:   60,1553						NextNode: "resolver:main.default.dc2",1554					},1555					{1556						Weight:   40,1557						NextNode: "resolver:main.default.dc3",1558					},1559				},1560			},1561			"resolver:main.default.dc2": {1562				Type: structs.DiscoveryGraphNodeTypeResolver,1563				Name: "main.default.dc2",1564				Resolver: &structs.DiscoveryResolver{1565					ConnectTimeout: 33 * time.Second,1566					Target:         "main.default.dc2",1567				},1568			},1569			"resolver:main.default.dc3": {1570				Type: structs.DiscoveryGraphNodeTypeResolver,1571				Name: "main.default.dc3",1572				Resolver: &structs.DiscoveryResolver{1573					ConnectTimeout: 33 * time.Second,1574					Target:         "main.default.dc3",1575				},1576			},1577		},1578		Targets: map[string]*structs.DiscoveryTarget{1579			"main.default.dc2": newTarget("main", "", "default", "dc2", nil),1580			"main.default.dc3": newTarget("main", "", "default", "dc3", nil),1581		},1582	}1583	return compileTestCase{entries: entries, expect: expect}1584}1585func testcase_AllBellsAndWhistles() compileTestCase {1586	entries := newEntries()1587	setServiceProtocol(entries, "main", "http")1588	setServiceProtocol(entries, "svc-redirect", "http")1589	setServiceProtocol(entries, "svc-redirect-again", "http")1590	setServiceProtocol(entries, "svc-split", "http")1591	setServiceProtocol(entries, "svc-split-again", "http")1592	setServiceProtocol(entries, "svc-split-one-more-time", "http")1593	setServiceProtocol(entries, "redirected", "http")1594	entries.AddRouters(1595		&structs.ServiceRouterConfigEntry{1596			Kind: "service-router",1597			Name: "main",1598			Routes: []structs.ServiceRoute{1599				newSimpleRoute("svc-redirect"), // double redirected to a default subset1600				newSimpleRoute("svc-split"),    // one split is split further1601			},1602		},1603	)1604	entries.AddSplitters(1605		&structs.ServiceSplitterConfigEntry{1606			Kind: "service-splitter",1607			Name: "svc-split",1608			Splits: []structs.ServiceSplit{1609				{Weight: 60, Service: "svc-redirect"},    // double redirected to a default subset1610				{Weight: 40, Service: "svc-split-again"}, // split again1611			},1612		},1613		&structs.ServiceSplitterConfigEntry{1614			Kind: "service-splitter",1615			Name: "svc-split-again",1616			Splits: []structs.ServiceSplit{1617				{Weight: 75, Service: "main", ServiceSubset: "v1"},1618				{Weight: 25, Service: "svc-split-one-more-time"},1619			},1620		},1621		&structs.ServiceSplitterConfigEntry{1622			Kind: "service-splitter",1623			Name: "svc-split-one-more-time",1624			Splits: []structs.ServiceSplit{1625				{Weight: 80, Service: "main", ServiceSubset: "v2"},1626				{Weight: 20, Service: "main", ServiceSubset: "v3"},1627			},1628		},1629	)1630	entries.AddResolvers(1631		&structs.ServiceResolverConfigEntry{1632			Kind: "service-resolver",1633			Name: "svc-redirect",1634			Redirect: &structs.ServiceResolverRedirect{1635				Service: "svc-redirect-again",1636			},1637		},1638		&structs.ServiceResolverConfigEntry{1639			Kind: "service-resolver",1640			Name: "svc-redirect-again",1641			Redirect: &structs.ServiceResolverRedirect{1642				Service: "redirected",1643			},1644		},1645		&structs.ServiceResolverConfigEntry{1646			Kind:          "service-resolver",1647			Name:          "redirected",1648			DefaultSubset: "prod",1649			Subsets: map[string]structs.ServiceResolverSubset{1650				"prod": {Filter: "ServiceMeta.env == prod"},1651				"qa":   {Filter: "ServiceMeta.env == qa"},1652			},1653			LoadBalancer: &structs.LoadBalancer{1654				Policy: "ring_hash",1655				RingHashConfig: &structs.RingHashConfig{1656					MaximumRingSize: 100,1657				},1658				HashPolicies: []structs.HashPolicy{1659					{1660						SourceIP: true,1661					},1662				},1663			},1664		},1665		&structs.ServiceResolverConfigEntry{1666			Kind:          "service-resolver",1667			Name:          "main",1668			DefaultSubset: "default-subset",1669			Subsets: map[string]structs.ServiceResolverSubset{1670				"v1":             {Filter: "Service.Meta.version == 1"},1671				"v2":             {Filter: "Service.Meta.version == 2"},1672				"v3":             {Filter: "Service.Meta.version == 3"},1673				"default-subset": {OnlyPassing: true},1674			},1675		},1676	)1677	var (1678		router = entries.GetRouter(structs.NewServiceID("main", nil))1679	)1680	expect := &structs.CompiledDiscoveryChain{1681		Protocol:  "http",1682		StartNode: "router:main.default",1683		Nodes: map[string]*structs.DiscoveryGraphNode{1684			"router:main.default": {1685				Type: structs.DiscoveryGraphNodeTypeRouter,1686				Name: "main.default",1687				Routes: []*structs.DiscoveryRoute{1688					{1689						Definition: &router.Routes[0],1690						NextNode:   "resolver:prod.redirected.default.dc1",1691					},1692					{1693						Definition: &router.Routes[1],1694						NextNode:   "splitter:svc-split.default",1695					},1696					{1697						Definition: newDefaultServiceRoute("main", "default"),1698						NextNode:   "resolver:default-subset.main.default.dc1",1699					},1700				},1701			},1702			"splitter:svc-split.default": {1703				Type: structs.DiscoveryGraphNodeTypeSplitter,1704				Name: "svc-split.default",1705				Splits: []*structs.DiscoverySplit{1706					{1707						Weight:   60,1708						NextNode: "resolver:prod.redirected.default.dc1",1709					},1710					{1711						Weight:   30,1712						NextNode: "resolver:v1.main.default.dc1",1713					},1714					{1715						Weight:   8,1716						NextNode: "resolver:v2.main.default.dc1",1717					},1718					{1719						Weight:   2,1720						NextNode: "resolver:v3.main.default.dc1",1721					},1722				},1723				LoadBalancer: &structs.LoadBalancer{1724					Policy: "ring_hash",1725					RingHashConfig: &structs.RingHashConfig{1726						MaximumRingSize: 100,1727					},1728					HashPolicies: []structs.HashPolicy{1729						{1730							SourceIP: true,1731						},1732					},1733				},1734			},1735			"resolver:prod.redirected.default.dc1": {1736				Type: structs.DiscoveryGraphNodeTypeResolver,1737				Name: "prod.redirected.default.dc1",1738				Resolver: &structs.DiscoveryResolver{1739					ConnectTimeout: 5 * time.Second,1740					Target:         "prod.redirected.default.dc1",1741				},1742				LoadBalancer: &structs.LoadBalancer{1743					Policy: "ring_hash",1744					RingHashConfig: &structs.RingHashConfig{1745						MaximumRingSize: 100,1746					},1747					HashPolicies: []structs.HashPolicy{1748						{1749							SourceIP: true,1750						},1751					},1752				},1753			},1754			"resolver:v1.main.default.dc1": {1755				Type: structs.DiscoveryGraphNodeTypeResolver,1756				Name: "v1.main.default.dc1",1757				Resolver: &structs.DiscoveryResolver{1758					ConnectTimeout: 5 * time.Second,1759					Target:         "v1.main.default.dc1",1760				},1761			},1762			"resolver:v2.main.default.dc1": {1763				Type: structs.DiscoveryGraphNodeTypeResolver,1764				Name: "v2.main.default.dc1",1765				Resolver: &structs.DiscoveryResolver{1766					ConnectTimeout: 5 * time.Second,1767					Target:         "v2.main.default.dc1",1768				},1769			},1770			"resolver:v3.main.default.dc1": {1771				Type: structs.DiscoveryGraphNodeTypeResolver,1772				Name: "v3.main.default.dc1",1773				Resolver: &structs.DiscoveryResolver{1774					ConnectTimeout: 5 * time.Second,1775					Target:         "v3.main.default.dc1",1776				},1777			},1778			"resolver:default-subset.main.default.dc1": {1779				Type: structs.DiscoveryGraphNodeTypeResolver,1780				Name: "default-subset.main.default.dc1",1781				Resolver: &structs.DiscoveryResolver{1782					ConnectTimeout: 5 * time.Second,1783					Target:         "default-subset.main.default.dc1",1784				},1785			},1786		},1787		Targets: map[string]*structs.DiscoveryTarget{1788			"prod.redirected.default.dc1": newTarget("redirected", "prod", "default", "dc1", func(t *structs.DiscoveryTarget) {1789				t.Subset = structs.ServiceResolverSubset{1790					Filter: "ServiceMeta.env == prod",1791				}1792			}),1793			"v1.main.default.dc1": newTarget("main", "v1", "default", "dc1", func(t *structs.DiscoveryTarget) {1794				t.Subset = structs.ServiceResolverSubset{1795					Filter: "Service.Meta.version == 1",1796				}1797			}),1798			"v2.main.default.dc1": newTarget("main", "v2", "default", "dc1", func(t *structs.DiscoveryTarget) {1799				t.Subset = structs.ServiceResolverSubset{1800					Filter: "Service.Meta.version == 2",1801				}1802			}),1803			"v3.main.default.dc1": newTarget("main", "v3", "default", "dc1", func(t *structs.DiscoveryTarget) {1804				t.Subset = structs.ServiceResolverSubset{1805					Filter: "Service.Meta.version == 3",1806				}1807			}),1808			"default-subset.main.default.dc1": newTarget("main", "default-subset", "default", "dc1", func(t *structs.DiscoveryTarget) {1809				t.Subset = structs.ServiceResolverSubset{OnlyPassing: true}1810			}),1811		},1812	}1813	return compileTestCase{entries: entries, expect: expect}1814}1815func testcase_SplitterRequiresValidProtocol() compileTestCase {1816	entries := newEntries()1817	setServiceProtocol(entries, "main", "tcp")1818	entries.AddSplitters(1819		&structs.ServiceSplitterConfigEntry{1820			Kind: structs.ServiceSplitter,1821			Name: "main",1822			Splits: []structs.ServiceSplit{1823				{Weight: 90, Namespace: "v1"},1824				{Weight: 10, Namespace: "v2"},1825			},1826		},1827	)1828	return compileTestCase{1829		entries:        entries,1830		expectErr:      "does not permit advanced routing or splitting behavior",1831		expectGraphErr: true,1832	}1833}1834func testcase_RouterRequiresValidProtocol() compileTestCase {1835	entries := newEntries()1836	setServiceProtocol(entries, "main", "tcp")1837	entries.AddRouters(1838		&structs.ServiceRouterConfigEntry{1839			Kind: structs.ServiceRouter,1840			Name: "main",1841			Routes: []structs.ServiceRoute{1842				{1843					Match: &structs.ServiceRouteMatch{1844						HTTP: &structs.ServiceRouteHTTPMatch{1845							PathExact: "/other",1846						},1847					},1848					Destination: &structs.ServiceRouteDestination{1849						Namespace: "other",1850					},1851				},1852			},1853		},1854	)1855	return compileTestCase{1856		entries:        entries,1857		expectErr:      "does not permit advanced routing or splitting behavior",1858		expectGraphErr: true,1859	}1860}1861func testcase_SplitToUnsplittableProtocol() compileTestCase {1862	entries := newEntries()1863	setServiceProtocol(entries, "main", "tcp")1864	setServiceProtocol(entries, "other", "tcp")1865	entries.AddSplitters(1866		&structs.ServiceSplitterConfigEntry{1867			Kind: structs.ServiceSplitter,1868			Name: "main",1869			Splits: []structs.ServiceSplit{1870				{Weight: 90},1871				{Weight: 10, Service: "other"},1872			},1873		},1874	)1875	return compileTestCase{1876		entries:        entries,1877		expectErr:      "does not permit advanced routing or splitting behavior",1878		expectGraphErr: true,1879	}1880}1881func testcase_RouteToUnroutableProtocol() compileTestCase {1882	entries := newEntries()1883	setServiceProtocol(entries, "main", "tcp")1884	setServiceProtocol(entries, "other", "tcp")1885	entries.AddRouters(1886		&structs.ServiceRouterConfigEntry{1887			Kind: structs.ServiceRouter,1888			Name: "main",1889			Routes: []structs.ServiceRoute{1890				{1891					Match: &structs.ServiceRouteMatch{1892						HTTP: &structs.ServiceRouteHTTPMatch{1893							PathExact: "/other",1894						},1895					},1896					Destination: &structs.ServiceRouteDestination{1897						Service: "other",1898					},1899				},1900			},1901		},1902	)1903	return compileTestCase{1904		entries:        entries,1905		expectErr:      "does not permit advanced routing or splitting behavior",1906		expectGraphErr: true,1907	}1908}1909func testcase_FailoverCrossesProtocols() compileTestCase {1910	entries := newEntries()1911	setServiceProtocol(entries, "main", "grpc")1912	setServiceProtocol(entries, "other", "tcp")1913	entries.AddResolvers(1914		&structs.ServiceResolverConfigEntry{1915			Kind: structs.ServiceResolver,1916			Name: "main",1917			Failover: map[string]structs.ServiceResolverFailover{1918				"*": {1919					Service: "other",1920				},1921			},1922		},1923	)1924	return compileTestCase{1925		entries:        entries,1926		expectErr:      "uses inconsistent protocols",1927		expectGraphErr: true,1928	}1929}1930func testcase_RedirectCrossesProtocols() compileTestCase {1931	entries := newEntries()1932	setServiceProtocol(entries, "main", "grpc")1933	setServiceProtocol(entries, "other", "tcp")1934	entries.AddResolvers(1935		&structs.ServiceResolverConfigEntry{1936			Kind: structs.ServiceResolver,1937			Name: "main",1938			Redirect: &structs.ServiceResolverRedirect{1939				Service: "other",1940			},1941		},1942	)1943	return compileTestCase{1944		entries:        entries,1945		expectErr:      "uses inconsistent protocols",1946		expectGraphErr: true,1947	}1948}1949func testcase_RedirectToMissingSubset() compileTestCase {1950	entries := newEntries()1951	entries.AddResolvers(1952		&structs.ServiceResolverConfigEntry{1953			Kind:           structs.ServiceResolver,1954			Name:           "other",1955			ConnectTimeout: 33 * time.Second,1956		},1957		&structs.ServiceResolverConfigEntry{1958			Kind: structs.ServiceResolver,1959			Name: "main",1960			Redirect: &structs.ServiceResolverRedirect{1961				Service:       "other",1962				ServiceSubset: "v1",1963			},1964		},1965	)1966	return compileTestCase{1967		entries:        entries,1968		expectErr:      `does not have a subset named "v1"`,1969		expectGraphErr: true,1970	}1971}1972func testcase_ResolverProtocolOverride() compileTestCase {1973	entries := newEntries()1974	setServiceProtocol(entries, "main", "grpc")1975	expect := &structs.CompiledDiscoveryChain{1976		Protocol:  "http2",1977		StartNode: "resolver:main.default.dc1",1978		Nodes: map[string]*structs.DiscoveryGraphNode{1979			"resolver:main.default.dc1": {1980				Type: structs.DiscoveryGraphNodeTypeResolver,1981				Name: "main.default.dc1",1982				Resolver: &structs.DiscoveryResolver{1983					Default:        true,1984					ConnectTimeout: 5 * time.Second,1985					Target:         "main.default.dc1",1986				},1987			},1988		},1989		Targets: map[string]*structs.DiscoveryTarget{1990			// TODO-TARGET1991			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),1992		},1993	}1994	return compileTestCase{entries: entries, expect: expect, expectIsDefault: true,1995		expectCustom: true,1996		setup: func(req *CompileRequest) {1997			req.OverrideProtocol = "http2"1998		},1999	}2000}2001func testcase_ResolverProtocolOverrideIgnored() compileTestCase {2002	// This shows that if you try to override the protocol to its current value2003	// the override is completely ignored.2004	entries := newEntries()2005	setServiceProtocol(entries, "main", "http2")2006	expect := &structs.CompiledDiscoveryChain{2007		Protocol:  "http2",2008		StartNode: "resolver:main.default.dc1",2009		Nodes: map[string]*structs.DiscoveryGraphNode{2010			"resolver:main.default.dc1": {2011				Type: structs.DiscoveryGraphNodeTypeResolver,2012				Name: "main.default.dc1",2013				Resolver: &structs.DiscoveryResolver{2014					Default:        true,2015					ConnectTimeout: 5 * time.Second,2016					Target:         "main.default.dc1",2017				},2018			},2019		},2020		Targets: map[string]*structs.DiscoveryTarget{2021			// TODO-TARGET2022			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),2023		},2024	}2025	return compileTestCase{entries: entries, expect: expect, expectIsDefault: true,2026		setup: func(req *CompileRequest) {2027			req.OverrideProtocol = "http2"2028		},2029	}2030}2031func testcase_RouterIgnored_ResolverProtocolOverride() compileTestCase {2032	entries := newEntries()2033	setServiceProtocol(entries, "main", "grpc")2034	entries.AddRouters(2035		&structs.ServiceRouterConfigEntry{2036			Kind: "service-router",2037			Name: "main",2038		},2039	)2040	expect := &structs.CompiledDiscoveryChain{2041		Protocol:  "tcp",2042		StartNode: "resolver:main.default.dc1",2043		Nodes: map[string]*structs.DiscoveryGraphNode{2044			"resolver:main.default.dc1": {2045				Type: structs.DiscoveryGraphNodeTypeResolver,2046				Name: "main.default.dc1",2047				Resolver: &structs.DiscoveryResolver{2048					Default:        true,2049					ConnectTimeout: 5 * time.Second,2050					Target:         "main.default.dc1",2051				},2052			},2053		},2054		Targets: map[string]*structs.DiscoveryTarget{2055			// TODO-TARGET2056			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),2057		},2058	}2059	return compileTestCase{entries: entries, expect: expect, expectIsDefault: true,2060		expectCustom: true,2061		setup: func(req *CompileRequest) {2062			req.OverrideProtocol = "tcp"2063		},2064	}2065}2066func testcase_Resolver_CircularRedirect() compileTestCase {2067	entries := newEntries()2068	entries.AddResolvers(2069		&structs.ServiceResolverConfigEntry{2070			Kind: "service-resolver",2071			Name: "main",2072			Redirect: &structs.ServiceResolverRedirect{2073				Service: "other",2074			},2075		},2076		&structs.ServiceResolverConfigEntry{2077			Kind: "service-resolver",2078			Name: "other",2079			Redirect: &structs.ServiceResolverRedirect{2080				Service: "main",2081			},2082		},2083	)2084	return compileTestCase{entries: entries,2085		expectErr:      "detected circular resolver redirect",2086		expectGraphErr: true,2087	}2088}2089func testcase_CircularSplit() compileTestCase {2090	entries := newEntries()2091	setGlobalProxyProtocol(entries, "http")2092	entries.AddSplitters(2093		&structs.ServiceSplitterConfigEntry{2094			Kind: "service-splitter",2095			Name: "main",2096			Splits: []structs.ServiceSplit{2097				{Weight: 100, Service: "other"},2098			},2099		},2100		&structs.ServiceSplitterConfigEntry{2101			Kind: "service-splitter",2102			Name: "other",2103			Splits: []structs.ServiceSplit{2104				{Weight: 100, Service: "main"},2105			},2106		},2107	)2108	return compileTestCase{entries: entries,2109		expectErr:      "detected circular reference",2110		expectGraphErr: true,2111	}2112}2113func testcase_LBSplitterAndResolver() compileTestCase {2114	entries := newEntries()2115	setServiceProtocol(entries, "foo", "http")2116	setServiceProtocol(entries, "bar", "http")2117	setServiceProtocol(entries, "baz", "http")2118	entries.AddSplitters(2119		&structs.ServiceSplitterConfigEntry{2120			Kind: "service-splitter",2121			Name: "main",2122			Splits: []structs.ServiceSplit{2123				{Weight: 60, Service: "foo"},2124				{Weight: 20, Service: "bar"},2125				{Weight: 20, Service: "baz"},2126			},2127		},2128	)2129	entries.AddResolvers(2130		&structs.ServiceResolverConfigEntry{2131			Kind: "service-resolver",2132			Name: "foo",2133			LoadBalancer: &structs.LoadBalancer{2134				Policy: "least_request",2135				LeastRequestConfig: &structs.LeastRequestConfig{2136					ChoiceCount: 3,2137				},2138			},2139		},2140		&structs.ServiceResolverConfigEntry{2141			Kind: "service-resolver",2142			Name: "bar",2143			LoadBalancer: &structs.LoadBalancer{2144				Policy: "ring_hash",2145				RingHashConfig: &structs.RingHashConfig{2146					MaximumRingSize: 101,2147				},2148				HashPolicies: []structs.HashPolicy{2149					{2150						SourceIP: true,2151					},2152				},2153			},2154		},2155		&structs.ServiceResolverConfigEntry{2156			Kind: "service-resolver",2157			Name: "baz",2158			LoadBalancer: &structs.LoadBalancer{2159				Policy: "maglev",2160				HashPolicies: []structs.HashPolicy{2161					{2162						Field:      "cookie",2163						FieldValue: "chocolate-chip",2164						CookieConfig: &structs.CookieConfig{2165							TTL:  2 * time.Minute,2166							Path: "/bowl",2167						},2168						Terminal: true,2169					},2170				},2171			},2172		},2173	)2174	expect := &structs.CompiledDiscoveryChain{2175		Protocol:  "http",2176		StartNode: "splitter:main.default",2177		Nodes: map[string]*structs.DiscoveryGraphNode{2178			"splitter:main.default": {2179				Type: structs.DiscoveryGraphNodeTypeSplitter,2180				Name: "main.default",2181				Splits: []*structs.DiscoverySplit{2182					{2183						Weight:   60,2184						NextNode: "resolver:foo.default.dc1",2185					},2186					{2187						Weight:   20,2188						NextNode: "resolver:bar.default.dc1",2189					},2190					{2191						Weight:   20,2192						NextNode: "resolver:baz.default.dc1",2193					},2194				},2195				// The LB config from bar is attached because splitters only care about hash-based policies,2196				// and it's the config from bar not baz because we pick the first one we encounter in the Splits.2197				LoadBalancer: &structs.LoadBalancer{2198					Policy: "ring_hash",2199					RingHashConfig: &structs.RingHashConfig{2200						MaximumRingSize: 101,2201					},2202					HashPolicies: []structs.HashPolicy{2203						{2204							SourceIP: true,2205						},2206					},2207				},2208			},2209			// Each service's LB config is passed down from the service-resolver to the resolver node2210			"resolver:foo.default.dc1": {2211				Type: structs.DiscoveryGraphNodeTypeResolver,2212				Name: "foo.default.dc1",2213				Resolver: &structs.DiscoveryResolver{2214					Default:        false,2215					ConnectTimeout: 5 * time.Second,2216					Target:         "foo.default.dc1",2217				},2218				LoadBalancer: &structs.LoadBalancer{2219					Policy: "least_request",2220					LeastRequestConfig: &structs.LeastRequestConfig{2221						ChoiceCount: 3,2222					},2223				},2224			},2225			"resolver:bar.default.dc1": {2226				Type: structs.DiscoveryGraphNodeTypeResolver,2227				Name: "bar.default.dc1",2228				Resolver: &structs.DiscoveryResolver{2229					Default:        false,2230					ConnectTimeout: 5 * time.Second,2231					Target:         "bar.default.dc1",2232				},2233				LoadBalancer: &structs.LoadBalancer{2234					Policy: "ring_hash",2235					RingHashConfig: &structs.RingHashConfig{2236						MaximumRingSize: 101,2237					},2238					HashPolicies: []structs.HashPolicy{2239						{2240							SourceIP: true,2241						},2242					},2243				},2244			},2245			"resolver:baz.default.dc1": {2246				Type: structs.DiscoveryGraphNodeTypeResolver,2247				Name: "baz.default.dc1",2248				Resolver: &structs.DiscoveryResolver{2249					Default:        false,2250					ConnectTimeout: 5 * time.Second,2251					Target:         "baz.default.dc1",2252				},2253				LoadBalancer: &structs.LoadBalancer{2254					Policy: "maglev",2255					HashPolicies: []structs.HashPolicy{2256						{2257							Field:      "cookie",2258							FieldValue: "chocolate-chip",2259							CookieConfig: &structs.CookieConfig{2260								TTL:  2 * time.Minute,2261								Path: "/bowl",2262							},2263							Terminal: true,2264						},2265					},2266				},2267			},2268		},2269		Targets: map[string]*structs.DiscoveryTarget{2270			"foo.default.dc1": newTarget("foo", "", "default", "dc1", nil),2271			"bar.default.dc1": newTarget("bar", "", "default", "dc1", nil),2272			"baz.default.dc1": newTarget("baz", "", "default", "dc1", nil),2273		},2274	}2275	return compileTestCase{entries: entries, expect: expect}2276}2277// ensure chain with LB cfg in resolver isn't a default chain (!IsDefault)2278func testcase_LBResolver() compileTestCase {2279	entries := newEntries()2280	setServiceProtocol(entries, "main", "http")2281	entries.AddResolvers(2282		&structs.ServiceResolverConfigEntry{2283			Kind: "service-resolver",2284			Name: "main",2285			LoadBalancer: &structs.LoadBalancer{2286				Policy: "ring_hash",2287				RingHashConfig: &structs.RingHashConfig{2288					MaximumRingSize: 101,2289				},2290				HashPolicies: []structs.HashPolicy{2291					{2292						SourceIP: true,2293					},2294				},2295			},2296		},2297	)2298	expect := &structs.CompiledDiscoveryChain{2299		Protocol:  "http",2300		StartNode: "resolver:main.default.dc1",2301		Nodes: map[string]*structs.DiscoveryGraphNode{2302			"resolver:main.default.dc1": {2303				Type: structs.DiscoveryGraphNodeTypeResolver,2304				Name: "main.default.dc1",2305				Resolver: &structs.DiscoveryResolver{2306					Default:        false,2307					ConnectTimeout: 5 * time.Second,2308					Target:         "main.default.dc1",2309				},2310				LoadBalancer: &structs.LoadBalancer{2311					Policy: "ring_hash",2312					RingHashConfig: &structs.RingHashConfig{2313						MaximumRingSize: 101,2314					},2315					HashPolicies: []structs.HashPolicy{2316						{2317							SourceIP: true,2318						},2319					},2320				},2321			},2322		},2323		Targets: map[string]*structs.DiscoveryTarget{2324			"main.default.dc1": newTarget("main", "", "default", "dc1", nil),2325		},2326	}2327	return compileTestCase{entries: entries, expect: expect}2328}2329func newSimpleRoute(name string, muts ...func(*structs.ServiceRoute)) structs.ServiceRoute {2330	r := structs.ServiceRoute{2331		Match: &structs.ServiceRouteMatch{2332			HTTP: &structs.ServiceRouteHTTPMatch{PathPrefix: "/" + name},2333		},2334		Destination: &structs.ServiceRouteDestination{Service: name},2335	}2336	for _, mut := range muts {2337		mut(&r)2338	}2339	return r2340}2341func setGlobalProxyProtocol(entries *structs.DiscoveryChainConfigEntries, protocol string) {2342	entries.GlobalProxy = &structs.ProxyConfigEntry{2343		Kind: structs.ProxyDefaults,2344		Name: structs.ProxyConfigGlobal,2345		Config: map[string]interface{}{2346			"protocol": protocol,2347		},2348	}2349}2350func setServiceProtocol(entries *structs.DiscoveryChainConfigEntries, name, protocol string) {2351	entries.AddServices(&structs.ServiceConfigEntry{2352		Kind:     structs.ServiceDefaults,2353		Name:     name,2354		Protocol: protocol,2355	})2356}2357func newEntries() *structs.DiscoveryChainConfigEntries {2358	return &structs.DiscoveryChainConfigEntries{2359		Routers:   make(map[structs.ServiceID]*structs.ServiceRouterConfigEntry),2360		Splitters: make(map[structs.ServiceID]*structs.ServiceSplitterConfigEntry),2361		Resolvers: make(map[structs.ServiceID]*structs.ServiceResolverConfigEntry),2362	}2363}2364func newTarget(service, serviceSubset, namespace, datacenter string, modFn func(t *structs.DiscoveryTarget)) *structs.DiscoveryTarget {2365	t := structs.NewDiscoveryTarget(service, serviceSubset, namespace, datacenter)2366	t.SNI = connect.TargetSNI(t, "trustdomain.consul")2367	t.Name = t.SNI2368	if modFn != nil {2369		modFn(t)2370	}2371	return t2372}...

Full Screen

Full Screen

imports_test.go

Source:imports_test.go Github

copy

Full Screen

...38var addTests = []test{39	{40		name: "leave os alone",41		pkg:  "os",42		in: `package main43import (44	"os"45)46`,47		out: `package main48import (49	"os"50)51`,52	},53	{54		name: "import.1",55		pkg:  "os",56		in: `package main57`,58		out: `package main59import "os"60`,61	},62	{63		name: "import.2",64		pkg:  "os",65		in: `package main66// Comment67import "C"68`,69		out: `package main70// Comment71import "C"72import "os"73`,74	},75	{76		name: "import.3",77		pkg:  "os",78		in: `package main79// Comment80import "C"81import (82	"io"83	"utf8"84)85`,86		out: `package main87// Comment88import "C"89import (90	"io"91	"os"92	"utf8"93)94`,95	},96	{97		name: "import.17",98		pkg:  "x/y/z",99		in: `package main100// Comment101import "C"102import (103	"a"104	"b"105	"x/w"106	"d/f"107)108`,109		out: `package main110// Comment111import "C"112import (113	"a"114	"b"115	"x/w"116	"x/y/z"117	"d/f"118)119`,120	},121	{122		name: "import into singular group",123		pkg:  "bytes",124		in: `package main125import "os"126`,127		out: `package main128import (129	"bytes"130	"os"131)132`,133	},134	{135		name: "import into singular group with comment",136		pkg:  "bytes",137		in: `package main138import /* why */ /* comment here? */ "os"139`,140		out: `package main141import /* why */ /* comment here? */ (142	"bytes"143	"os"144)145`,146	},147	{148		name: "import into group with leading comment",149		pkg:  "strings",150		in: `package main151import (152	// comment before bytes153	"bytes"154	"os"155)156`,157		out: `package main158import (159	// comment before bytes160	"bytes"161	"os"162	"strings"163)164`,165	},166	{167		name:       "",168		renamedPkg: "fmtpkg",169		pkg:        "fmt",170		in: `package main171import "os"172`,173		out: `package main174import (175	fmtpkg "fmt"176	"os"177)178`,179	},180	{181		name: "struct comment",182		pkg:  "time",183		in: `package main184// This is a comment before a struct.185type T struct {186	t  time.Time187}188`,189		out: `package main190import "time"191// This is a comment before a struct.192type T struct {193	t time.Time194}195`,196	},197	{198		name: "issue 8729 import C",199		pkg:  "time",200		in: `package main201import "C"202// comment203type T time.Time204`,205		out: `package main206import "C"207import "time"208// comment209type T time.Time210`,211	},212	{213		name: "issue 8729 empty import",214		pkg:  "time",215		in: `package main216import ()217// comment218type T time.Time219`,220		out: `package main221import "time"222// comment223type T time.Time224`,225	},226	{227		name: "issue 8729 comment on package line",228		pkg:  "time",229		in: `package main // comment230type T time.Time231`,232		out: `package main // comment233import "time"234type T time.Time235`,236	},237	{238		name: "issue 8729 comment after package",239		pkg:  "time",240		in: `package main241// comment242type T time.Time243`,244		out: `package main245import "time"246// comment247type T time.Time248`,249	},250	{251		name: "issue 8729 comment before and on package line",252		pkg:  "time",253		in: `// comment before254package main // comment on255type T time.Time256`,257		out: `// comment before258package main // comment on259import "time"260type T time.Time261`,262	},263	// Issue 9961: Match prefixes using path segments rather than bytes264	{265		name: "issue 9961",266		pkg:  "regexp",267		in: `package main268import (269	"flag"270	"testing"271	"rsc.io/p"272)273`,274		out: `package main275import (276	"flag"277	"regexp"278	"testing"279	"rsc.io/p"280)281`,282	},283}284func TestAddImport(t *testing.T) {285	for _, test := range addTests {286		file := parse(t, test.name, test.in)287		var before bytes.Buffer288		ast.Fprint(&before, fset, file, nil)289		AddNamedImport(fset, file, test.renamedPkg, test.pkg)290		if got := print(t, test.name, file); got != test.out {291			if test.broken {292				t.Logf("%s is known broken:\ngot: %s\nwant: %s", test.name, got, test.out)293			} else {294				t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out)295			}296			var after bytes.Buffer297			ast.Fprint(&after, fset, file, nil)298			t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String())299		}300	}301}302func TestDoubleAddImport(t *testing.T) {303	file := parse(t, "doubleimport", "package main\n")304	AddImport(fset, file, "os")305	AddImport(fset, file, "bytes")306	want := `package main307import (308	"bytes"309	"os"310)311`312	if got := print(t, "doubleimport", file); got != want {313		t.Errorf("got: %s\nwant: %s", got, want)314	}315}316// Part of issue 8729.317func TestDoubleAddImportWithDeclComment(t *testing.T) {318	file := parse(t, "doubleimport", `package main319import (320)321// comment322type I int323`)324	// The AddImport order here matters.325	AddImport(fset, file, "llvm.org/llgo/third_party/gotools/go/ast/astutil")326	AddImport(fset, file, "os")327	want := `package main328import (329	"llvm.org/llgo/third_party/gotools/go/ast/astutil"330	"os"331)332// comment333type I int334`335	if got := print(t, "doubleimport_with_decl_comment", file); got != want {336		t.Errorf("got: %s\nwant: %s", got, want)337	}338}339var deleteTests = []test{340	{341		name: "import.4",342		pkg:  "os",343		in: `package main344import (345	"os"346)347`,348		out: `package main349`,350	},351	{352		name: "import.5",353		pkg:  "os",354		in: `package main355// Comment356import "C"357import "os"358`,359		out: `package main360// Comment361import "C"362`,363	},364	{365		name: "import.6",366		pkg:  "os",367		in: `package main368// Comment369import "C"370import (371	"io"372	"os"373	"utf8"374)375`,376		out: `package main377// Comment378import "C"379import (380	"io"381	"utf8"382)383`,384	},385	{386		name: "import.7",387		pkg:  "io",388		in: `package main389import (390	"io"   // a391	"os"   // b392	"utf8" // c393)394`,395		out: `package main396import (397	// a398	"os"   // b399	"utf8" // c400)401`,402	},403	{404		name: "import.8",405		pkg:  "os",406		in: `package main407import (408	"io"   // a409	"os"   // b410	"utf8" // c411)412`,413		out: `package main414import (415	"io" // a416	// b417	"utf8" // c418)419`,420	},421	{422		name: "import.9",423		pkg:  "utf8",424		in: `package main425import (426	"io"   // a427	"os"   // b428	"utf8" // c429)430`,431		out: `package main432import (433	"io" // a434	"os" // b435	// c436)437`,438	},439	{440		name: "import.10",441		pkg:  "io",442		in: `package main443import (444	"io"445	"os"446	"utf8"447)448`,449		out: `package main450import (451	"os"452	"utf8"453)454`,455	},456	{457		name: "import.11",458		pkg:  "os",459		in: `package main460import (461	"io"462	"os"463	"utf8"464)465`,466		out: `package main467import (468	"io"469	"utf8"470)471`,472	},473	{474		name: "import.12",475		pkg:  "utf8",476		in: `package main477import (478	"io"479	"os"480	"utf8"481)482`,483		out: `package main484import (485	"io"486	"os"487)488`,489	},490	{491		name: "handle.raw.quote.imports",492		pkg:  "os",493		in:   "package main\n\nimport `os`",494		out: `package main495`,496	},497	{498		name: "import.13",499		pkg:  "io",500		in: `package main501import (502	"fmt"503	"io"504	"os"505	"utf8"506	"go/format"507)508`,509		out: `package main510import (511	"fmt"512	"os"513	"utf8"514	"go/format"515)516`,517	},518	{519		name: "import.14",520		pkg:  "io",521		in: `package main522import (523	"fmt" // a524	"io"   // b525	"os"   // c526	"utf8" // d527	"go/format" // e528)529`,530		out: `package main531import (532	"fmt" // a533	// b534	"os"   // c535	"utf8" // d536	"go/format" // e537)538`,539	},540	{541		name: "import.15",542		pkg:  "double",543		in: `package main544import (545	"double"546	"double"547)548`,549		out: `package main550`,551	},552	{553		name: "import.16",554		pkg:  "bubble",555		in: `package main556import (557	"toil"558	"bubble"559	"bubble"560	"trouble"561)562`,563		out: `package main564import (565	"toil"566	"trouble"567)568`,569	},570	{571		name: "import.17",572		pkg:  "quad",573		in: `package main574import (575	"quad"576	"quad"577)578import (579	"quad"580	"quad"581)582`,583		out: `package main584`,585	},586}587func TestDeleteImport(t *testing.T) {588	for _, test := range deleteTests {589		file := parse(t, test.name, test.in)590		DeleteImport(fset, file, test.pkg)591		if got := print(t, test.name, file); got != test.out {592			t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out)593		}594	}595}596type rewriteTest struct {597	name   string598	srcPkg string599	dstPkg string600	in     string601	out    string602}603var rewriteTests = []rewriteTest{604	{605		name:   "import.13",606		srcPkg: "utf8",607		dstPkg: "encoding/utf8",608		in: `package main609import (610	"io"611	"os"612	"utf8" // thanks ken613)614`,615		out: `package main616import (617	"encoding/utf8" // thanks ken618	"io"619	"os"620)621`,622	},623	{624		name:   "import.14",625		srcPkg: "asn1",626		dstPkg: "encoding/asn1",627		in: `package main628import (629	"asn1"630	"crypto"631	"crypto/rsa"632	_ "crypto/sha1"633	"crypto/x509"634	"crypto/x509/pkix"635	"time"636)637var x = 1638`,639		out: `package main640import (641	"crypto"642	"crypto/rsa"643	_ "crypto/sha1"644	"crypto/x509"645	"crypto/x509/pkix"646	"encoding/asn1"647	"time"648)649var x = 1650`,651	},652	{653		name:   "import.15",654		srcPkg: "url",655		dstPkg: "net/url",656		in: `package main657import (658	"bufio"659	"net"660	"path"661	"url"662)663var x = 1 // comment on x, not on url664`,665		out: `package main666import (667	"bufio"668	"net"669	"net/url"670	"path"671)672var x = 1 // comment on x, not on url673`,674	},675	{676		name:   "import.16",677		srcPkg: "http",678		dstPkg: "net/http",679		in: `package main680import (681	"flag"682	"http"683	"log"684	"text/template"685)686var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18687`,688		out: `package main689import (690	"flag"691	"log"692	"net/http"693	"text/template"694)695var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18696`,697	},698}699func TestRewriteImport(t *testing.T) {700	for _, test := range rewriteTests {701		file := parse(t, test.name, test.in)702		RewriteImport(fset, file, test.srcPkg, test.dstPkg)...

Full Screen

Full Screen

output_test.go

Source:output_test.go Github

copy

Full Screen

...26			t.Logf("test %v runs only on %v, skipping: ", test.name, test.goos)27			continue28		}29		dir := t.TempDir()30		source := "main.go"31		if test.run == "test" {32			source = "main_test.go"33		}34		src := filepath.Join(dir, source)35		f, err := os.Create(src)36		if err != nil {37			t.Fatalf("failed to create file: %v", err)38		}39		_, err = f.WriteString(test.source)40		if err != nil {41			f.Close()42			t.Fatalf("failed to write: %v", err)43		}44		if err := f.Close(); err != nil {45			t.Fatalf("failed to close file: %v", err)46		}47		cmd := exec.Command(testenv.GoToolPath(t), test.run, "-race", "-pkgdir="+pkgdir, src)48		// GODEBUG spoils program output, GOMAXPROCS makes it flaky.49		for _, env := range os.Environ() {50			if strings.HasPrefix(env, "GODEBUG=") ||51				strings.HasPrefix(env, "GOMAXPROCS=") ||52				strings.HasPrefix(env, "GORACE=") {53				continue54			}55			cmd.Env = append(cmd.Env, env)56		}57		cmd.Env = append(cmd.Env,58			"GOMAXPROCS=1", // see comment in race_test.go59			"GORACE="+test.gorace,60		)61		got, _ := cmd.CombinedOutput()62		matched := false63		for _, re := range test.re {64			if regexp.MustCompile(re).MatchString(string(got)) {65				matched = true66				break67			}68		}69		if !matched {70			exp := fmt.Sprintf("expect:\n%v\n", test.re[0])71			if len(test.re) > 1 {72				exp = fmt.Sprintf("expected one of %d patterns:\n",73					len(test.re))74				for k, re := range test.re {75					exp += fmt.Sprintf("pattern %d:\n%v\n", k, re)76				}77			}78			t.Fatalf("failed test case %v, %sgot:\n%s",79				test.name, exp, got)80		}81	}82}83var tests = []struct {84	name   string85	run    string86	goos   string87	gorace string88	source string89	re     []string90}{91	{"simple", "run", "", "atexit_sleep_ms=0", `92package main93import "time"94var xptr *int95var donechan chan bool96func main() {97	done := make(chan bool)98	x := 099	startRacer(&x, done)100	store(&x, 43)101	<-done102}103func store(x *int, v int) {104	*x = v105}106func startRacer(x *int, done chan bool) {107	xptr = x108	donechan = done109	go racer()110}111func racer() {112	time.Sleep(10*time.Millisecond)113	store(xptr, 42)114	donechan <- true115}116`, []string{`==================117WARNING: DATA RACE118Write at 0x[0-9,a-f]+ by goroutine [0-9]:119  main\.store\(\)120      .+/main\.go:14 \+0x[0-9,a-f]+121  main\.racer\(\)122      .+/main\.go:23 \+0x[0-9,a-f]+123Previous write at 0x[0-9,a-f]+ by main goroutine:124  main\.store\(\)125      .+/main\.go:14 \+0x[0-9,a-f]+126  main\.main\(\)127      .+/main\.go:10 \+0x[0-9,a-f]+128Goroutine [0-9] \(running\) created at:129  main\.startRacer\(\)130      .+/main\.go:19 \+0x[0-9,a-f]+131  main\.main\(\)132      .+/main\.go:9 \+0x[0-9,a-f]+133==================134Found 1 data race\(s\)135exit status 66136`}},137	{"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `138package main139func main() {140	done := make(chan bool)141	x := 0142	go func() {143		x = 42144		done <- true145	}()146	x = 43147	<-done148}149`, []string{`exit status 13`}},150	{"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `151package main152func main() {153	done := make(chan bool)154	x := 0155	go func() {156		x = 42157		done <- true158	}()159	x = 43160	<-done161}162`, []string{`163      go:7 \+0x[0-9,a-f]+164`}},165	{"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `166package main167func main() {168	done := make(chan bool)169	x := 0170	go func() {171		x = 42172		done <- true173	}()174	x = 43175	<-done176}177`, []string{`178==================179exit status 66180`}},181	{"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `182package main_test183import "testing"184func TestFail(t *testing.T) {185	done := make(chan bool)186	x := 0187	_ = x188	go func() {189		x = 42190		done <- true191	}()192	x = 43193	<-done194	t.Log(t.Failed())195}196`, []string{`197==================198--- FAIL: TestFail \(0...s\)199.*main_test.go:14: true200.*testing.go:.*: race detected during execution of test201FAIL`}},202	{"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `203package main204func main() {205	done := make(chan string)206	data := make([]byte, 10)207	go func() {208		done <- string(data)209	}()210	data[0] = 1211	<-done212}213`, []string{`214  runtime\.slicebytetostring\(\)215      .*/runtime/string\.go:.*216  main\.main\.func1\(\)217      .*/main.go:7`}},218	// Test for https://golang.org/issue/33309219	{"midstack_inlining_traceback", "run", "linux", "atexit_sleep_ms=0", `220package main221var x int222var c chan int223func main() {224	c = make(chan int)225	go f()226	x = 1227	<-c228}229func f() {230	g(c)231}232func g(c chan int) {233	h(c)234}235func h(c chan int) {236	c <- x237}238`, []string{`==================239WARNING: DATA RACE240Read at 0x[0-9,a-f]+ by goroutine [0-9]:241  main\.h\(\)242      .+/main\.go:22 \+0x[0-9,a-f]+243  main\.g\(\)244      .+/main\.go:18 \+0x[0-9,a-f]+245  main\.f\(\)246      .+/main\.go:14 \+0x[0-9,a-f]+247Previous write at 0x[0-9,a-f]+ by main goroutine:248  main\.main\(\)249      .+/main\.go:9 \+0x[0-9,a-f]+250Goroutine [0-9] \(running\) created at:251  main\.main\(\)252      .+/main\.go:8 \+0x[0-9,a-f]+253==================254Found 1 data race\(s\)255exit status 66256`}},257	// Test for https://golang.org/issue/17190258	{"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `259package main260/*261#include <pthread.h>262typedef struct cb {263        int foo;264} cb;265extern void goCallback();266static inline void *threadFunc(void *p) {267	goCallback();268	return 0;269}270static inline void startThread(cb* c) {271	pthread_t th;272	pthread_create(&th, 0, threadFunc, 0);273}274*/275import "C"276var done chan bool277var racy int278//export goCallback279func goCallback() {280	racy++281	done <- true282}283func main() {284	done = make(chan bool)285	var c C.cb286	C.startThread(&c)287	racy++288	<- done289}290`, []string{`==================291WARNING: DATA RACE292Read at 0x[0-9,a-f]+ by main goroutine:293  main\.main\(\)294      .*/main\.go:34 \+0x[0-9,a-f]+295Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:296  main\.goCallback\(\)297      .*/main\.go:27 \+0x[0-9,a-f]+298  _cgoexp_[0-9a-z]+_goCallback\(\)299      .*_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+300  _cgoexp_[0-9a-z]+_goCallback\(\)301      <autogenerated>:1 \+0x[0-9,a-f]+302Goroutine [0-9] \(running\) created at:303  runtime\.newextram\(\)304      .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+305==================`,306		`==================307WARNING: DATA RACE308Read at 0x[0-9,a-f]+ by .*:309  main\..*310      .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*311Previous write at 0x[0-9,a-f]+ by .*:312  main\..*313      .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*314Goroutine [0-9] \(running\) created at:315  runtime\.newextram\(\)316      .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+317==================`}},318	{"second_test_passes", "test", "", "atexit_sleep_ms=0", `319package main_test320import "testing"321func TestFail(t *testing.T) {322	done := make(chan bool)323	x := 0324	_ = x325	go func() {326		x = 42327		done <- true328	}()329	x = 43330	<-done331}332func TestPass(t *testing.T) {333}334`, []string{`335==================336--- FAIL: TestFail \(0...s\)337.*testing.go:.*: race detected during execution of test338FAIL`}},339	{"mutex", "run", "", "atexit_sleep_ms=0", `340package main341import (342	"sync"343	"fmt"344)345func main() {346	c := make(chan bool, 1)347	threads := 1348	iterations := 20000349	data := 0350	var wg sync.WaitGroup351	for i := 0; i < threads; i++ {352		wg.Add(1)353		go func() {354			defer wg.Done()355			for i := 0; i < iterations; i++ {356				c <- true357				data += 1358				<- c359			}360		}()361	}362	for i := 0; i < iterations; i++ {363		c <- true364		data += 1365		<- c366	}367	wg.Wait()368	if (data == iterations*(threads+1)) { fmt.Println("pass") }369}`, []string{`pass`}},370	// Test for https://github.com/golang/go/issues/37355371	{"chanmm", "run", "", "atexit_sleep_ms=0", `372package main373import (374	"sync"375	"time"376)377func main() {378	c := make(chan bool, 1)379	var data uint64380	var wg sync.WaitGroup381	wg.Add(2)382	c <- true383	go func() {384		defer wg.Done()385		c <- true386	}()387	go func() {388		defer wg.Done()389		time.Sleep(time.Second)390		<-c391		data = 2392	}()393	data = 1394	<-c395	wg.Wait()396	_ = data397}398`, []string{`==================399WARNING: DATA RACE400Write at 0x[0-9,a-f]+ by goroutine [0-9]:401  main\.main\.func2\(\)402      .*/main\.go:21 \+0x[0-9,a-f]+403Previous write at 0x[0-9,a-f]+ by main goroutine:404  main\.main\(\)405      .*/main\.go:23 \+0x[0-9,a-f]+406Goroutine [0-9] \(running\) created at:407  main\.main\(\)408      .*/main.go:[0-9]+ \+0x[0-9,a-f]+409==================`}},410}...

Full Screen

Full Screen

main.go

Source:main.go Github

copy

Full Screen

2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4// Check correctness of various closure corner cases5// that are expected to be inlined6package main7var ok bool8var sink int9func main() {10	{11		if x := func() int { // ERROR "can inline main.func1"12			return 113		}(); x != 1 { // ERROR "inlining call to main.func1"14			ppanic("x != 1")15		}16		if x := func() int { // ERROR "can inline main.func2" "func literal does not escape"17			return 118		}; x() != 1 { // ERROR "inlining call to main.func2"19			ppanic("x() != 1")20		}21	}22	{23		if y := func(x int) int { // ERROR "can inline main.func3"24			return x + 225		}(40); y != 42 { // ERROR "inlining call to main.func3"26			ppanic("y != 42")27		}28		if y := func(x int) int { // ERROR "can inline main.func4" "func literal does not escape"29			return x + 230		}; y(40) != 42 { // ERROR "inlining call to main.func4"31			ppanic("y(40) != 42")32		}33	}34	{35		y := func(x int) int { // ERROR "can inline main.func5" "func literal does not escape"36			return x + 237		}38		y = func(x int) int { // ERROR "can inline main.func6" "func literal does not escape"39			return x + 140		}41		if y(40) != 41 {42			ppanic("y(40) != 41")43		}44	}45	{46		func() { // ERROR "func literal does not escape"47			y := func(x int) int { // ERROR "can inline main.func7.1" "func literal does not escape"48				return x + 249			}50			y = func(x int) int { // ERROR "can inline main.func7.2" "func literal does not escape"51				return x + 152			}53			if y(40) != 41 {54				ppanic("y(40) != 41")55			}56		}()57	}58	{59		y := func(x int) int { // ERROR "can inline main.func8" "func literal does not escape"60			return x + 261		}62		y, sink = func(x int) int { // ERROR "can inline main.func9" "func literal does not escape"63			return x + 164		}, 4265		if y(40) != 41 {66			ppanic("y(40) != 41")67		}68	}69	{70		func() { // ERROR "func literal does not escape"71			y := func(x int) int { // ERROR "can inline main.func10.1" "func literal does not escape"72				return x + 273			}74			y, sink = func(x int) int { // ERROR "can inline main.func10.2" "func literal does not escape"75				return x + 176			}, 4277			if y(40) != 41 {78				ppanic("y(40) != 41")79			}80		}()81	}82	{83		y := func(x int) int { // ERROR "can inline main.func11" "func literal does not escape"84			return x + 285		}86		y, sink = func() (func(int) int, int) { // ERROR "can inline main.func12"87			return func(x int) int { // ERROR "can inline main.func12"88				return x + 189			}, 4290		}() // ERROR "func literal does not escape" "inlining call to main.func12"91		if y(40) != 41 {92			ppanic("y(40) != 41")93		}94	}95	{96		func() { // ERROR "func literal does not escape"97			y := func(x int) int { // ERROR "func literal does not escape" "can inline main.func13.1"98				return x + 299			}100			y, sink = func() (func(int) int, int) { // ERROR "can inline main.func13.2"101				return func(x int) int { // ERROR "can inline main.func13.2"102					return x + 1103				}, 42104			}() // ERROR "inlining call to main.func13.2" "func literal does not escape"105			if y(40) != 41 {106				ppanic("y(40) != 41")107			}108		}()109	}110	{111		y := func(x int) int { // ERROR "can inline main.func14" "func literal does not escape"112			return x + 2113		}114		y, ok = map[int]func(int) int{ // ERROR "does not escape"115			0: func(x int) int { return x + 1 }, // ERROR "can inline main.func15" "func literal escapes"116		}[0]117		if y(40) != 41 {118			ppanic("y(40) != 41")119		}120	}121	{122		func() { // ERROR "func literal does not escape"123			y := func(x int) int { // ERROR "can inline main.func16.1" "func literal does not escape"124				return x + 2125			}126			y, ok = map[int]func(int) int{ // ERROR "does not escape"127				0: func(x int) int { return x + 1 }, // ERROR "can inline main.func16.2" "func literal escapes"128			}[0]129			if y(40) != 41 {130				ppanic("y(40) != 41")131			}132		}()133	}134	{135		y := func(x int) int { // ERROR "can inline main.func17" "func literal does not escape"136			return x + 2137		}138		y, ok = interface{}(func(x int) int { // ERROR "can inline main.func18" "does not escape"139			return x + 1140		}).(func(int) int)141		if y(40) != 41 {142			ppanic("y(40) != 41")143		}144	}145	{146		func() { // ERROR "func literal does not escape"147			y := func(x int) int { // ERROR "can inline main.func19.1" "func literal does not escape"148				return x + 2149			}150			y, ok = interface{}(func(x int) int { // ERROR "can inline main.func19.2" "does not escape"151				return x + 1152			}).(func(int) int)153			if y(40) != 41 {154				ppanic("y(40) != 41")155			}156		}()157	}158	{159		x := 42160		if y := func() int { // ERROR "can inline main.func20"161			return x162		}(); y != 42 { // ERROR "inlining call to main.func20"163			ppanic("y != 42")164		}165		if y := func() int { // ERROR "can inline main.func21" "func literal does not escape"166			return x167		}; y() != 42 { // ERROR "inlining call to main.func21"168			ppanic("y() != 42")169		}170	}171	{172		x := 42173		if z := func(y int) int { // ERROR "can inline main.func22"174			return func() int { // ERROR "can inline main.func22.1" "can inline main.func30"175				return x + y176			}() // ERROR "inlining call to main.func22.1"177		}(1); z != 43 { // ERROR "inlining call to main.func22" "inlining call to main.func30"178			ppanic("z != 43")179		}180		if z := func(y int) int { // ERROR "func literal does not escape" "can inline main.func23"181			return func() int { // ERROR "can inline main.func23.1" "can inline main.func31"182				return x + y183			}() // ERROR "inlining call to main.func23.1"184		}; z(1) != 43 { // ERROR "inlining call to main.func23" "inlining call to main.func31"185			ppanic("z(1) != 43")186		}187	}188	{189		a := 1190		func() { // ERROR "can inline main.func24"191			func() { // ERROR "can inline main.func24" "can inline main.func32"192				a = 2193			}() // ERROR "inlining call to main.func24"194		}() // ERROR "inlining call to main.func24" "inlining call to main.func32"195		if a != 2 {196			ppanic("a != 2")197		}198	}199	{200		b := 2201		func(b int) { // ERROR "func literal does not escape"202			func() { // ERROR "can inline main.func25.1"203				b = 3204			}() // ERROR "inlining call to main.func25.1"205			if b != 3 {206				ppanic("b != 3")207			}208		}(b)209		if b != 2 {210			ppanic("b != 2")211		}212	}213	{214		c := 3215		func() { // ERROR "func literal does not escape"216			c = 4217			func() { // ERROR "func literal does not escape"218				if c != 4 {219					ppanic("c != 4")220				}221				recover() // prevent inlining222			}()223		}()224		if c != 4 {225			ppanic("c != 4")226		}227	}228	{229		a := 2230		if r := func(x int) int { // ERROR "func literal does not escape"231			b := 3232			return func(y int) int { // ERROR "can inline main.func27.1"233				c := 5234				return func(z int) int { // ERROR "can inline main.func27.1.1" "can inline main.func27.2"235					return a*x + b*y + c*z236				}(10) // ERROR "inlining call to main.func27.1.1"237			}(100) // ERROR "inlining call to main.func27.1" "inlining call to main.func27.2"238		}(1000); r != 2350 {239			ppanic("r != 2350")240		}241	}242	{243		a := 2244		if r := func(x int) int { // ERROR "func literal does not escape"245			b := 3246			return func(y int) int { // ERROR "can inline main.func28.1"247				c := 5248				func(z int) { // ERROR "can inline main.func28.1.1" "can inline main.func28.2"249					a = a * x250					b = b * y251					c = c * z252				}(10) // ERROR "inlining call to main.func28.1.1"253				return a + c254			}(100) + b // ERROR "inlining call to main.func28.1" "inlining call to main.func28.2"255		}(1000); r != 2350 {256			ppanic("r != 2350")257		}258		if a != 2000 {259			ppanic("a != 2000")260		}261	}262}263//go:noinline264func ppanic(s string) { // ERROR "leaking param: s"265	panic(s) // ERROR "s escapes to heap"266}...

Full Screen

Full Screen

import_test.go

Source:import_test.go Github

copy

Full Screen

1// Copyright 2011 The Go Authors.  All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4package main5import "go/ast"6func init() {7	addTestCases(importTests, nil)8}9var importTests = []testCase{10	{11		Name: "import.0",12		Fn:   addImportFn("os"),13		In: `package main14import (15	"os"16)17`,18		Out: `package main19import (20	"os"21)22`,23	},24	{25		Name: "import.1",26		Fn:   addImportFn("os"),27		In: `package main28`,29		Out: `package main30import "os"31`,32	},33	{34		Name: "import.2",35		Fn:   addImportFn("os"),36		In: `package main37// Comment38import "C"39`,40		Out: `package main41// Comment42import "C"43import "os"44`,45	},46	{47		Name: "import.3",48		Fn:   addImportFn("os"),49		In: `package main50// Comment51import "C"52import (53	"io"54	"utf8"55)56`,57		Out: `package main58// Comment59import "C"60import (61	"io"62	"os"63	"utf8"64)65`,66	},67	{68		Name: "import.4",69		Fn:   deleteImportFn("os"),70		In: `package main71import (72	"os"73)74`,75		Out: `package main76`,77	},78	{79		Name: "import.5",80		Fn:   deleteImportFn("os"),81		In: `package main82// Comment83import "C"84import "os"85`,86		Out: `package main87// Comment88import "C"89`,90	},91	{92		Name: "import.6",93		Fn:   deleteImportFn("os"),94		In: `package main95// Comment96import "C"97import (98	"io"99	"os"100	"utf8"101)102`,103		Out: `package main104// Comment105import "C"106import (107	"io"108	"utf8"109)110`,111	},112	{113		Name: "import.7",114		Fn:   deleteImportFn("io"),115		In: `package main116import (117	"io"   // a118	"os"   // b119	"utf8" // c120)121`,122		Out: `package main123import (124	// a125	"os"   // b126	"utf8" // c127)128`,129	},130	{131		Name: "import.8",132		Fn:   deleteImportFn("os"),133		In: `package main134import (135	"io"   // a136	"os"   // b137	"utf8" // c138)139`,140		Out: `package main141import (142	"io" // a143	// b144	"utf8" // c145)146`,147	},148	{149		Name: "import.9",150		Fn:   deleteImportFn("utf8"),151		In: `package main152import (153	"io"   // a154	"os"   // b155	"utf8" // c156)157`,158		Out: `package main159import (160	"io" // a161	"os" // b162	// c163)164`,165	},166	{167		Name: "import.10",168		Fn:   deleteImportFn("io"),169		In: `package main170import (171	"io"172	"os"173	"utf8"174)175`,176		Out: `package main177import (178	"os"179	"utf8"180)181`,182	},183	{184		Name: "import.11",185		Fn:   deleteImportFn("os"),186		In: `package main187import (188	"io"189	"os"190	"utf8"191)192`,193		Out: `package main194import (195	"io"196	"utf8"197)198`,199	},200	{201		Name: "import.12",202		Fn:   deleteImportFn("utf8"),203		In: `package main204import (205	"io"206	"os"207	"utf8"208)209`,210		Out: `package main211import (212	"io"213	"os"214)215`,216	},217	{218		Name: "import.13",219		Fn:   rewriteImportFn("utf8", "encoding/utf8"),220		In: `package main221import (222	"io"223	"os"224	"utf8" // thanks ken225)226`,227		Out: `package main228import (229	"encoding/utf8" // thanks ken230	"io"231	"os"232)233`,234	},235	{236		Name: "import.14",237		Fn:   rewriteImportFn("asn1", "encoding/asn1"),238		In: `package main239import (240	"asn1"241	"crypto"242	"crypto/rsa"243	_ "crypto/sha1"244	"crypto/x509"245	"crypto/x509/pkix"246	"time"247)248var x = 1249`,250		Out: `package main251import (252	"crypto"253	"crypto/rsa"254	_ "crypto/sha1"255	"crypto/x509"256	"crypto/x509/pkix"257	"encoding/asn1"258	"time"259)260var x = 1261`,262	},263	{264		Name: "import.15",265		Fn:   rewriteImportFn("url", "net/url"),266		In: `package main267import (268	"bufio"269	"net"270	"path"271	"url"272)273var x = 1 // comment on x, not on url274`,275		Out: `package main276import (277	"bufio"278	"net"279	"net/url"280	"path"281)282var x = 1 // comment on x, not on url283`,284	},285	{286		Name: "import.16",287		Fn:   rewriteImportFn("http", "net/http", "template", "text/template"),288		In: `package main289import (290	"flag"291	"http"292	"log"293	"template"294)295var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18296`,297		Out: `package main298import (299	"flag"300	"log"301	"net/http"302	"text/template"303)304var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18305`,306	},307	{308		Name: "import.17",309		Fn:   addImportFn("x/y/z", "x/a/c"),310		In: `package main311// Comment312import "C"313import (314	"a"315	"b"316	"x/w"317	"d/f"318)319`,320		Out: `package main321// Comment322import "C"323import (324	"a"325	"b"326	"x/a/c"327	"x/w"328	"x/y/z"329	"d/f"330)331`,332	},333	{334		Name: "import.18",335		Fn:   addDelImportFn("e", "o"),336		In: `package main337import (338	"f"339	"o"340	"z"341)342`,343		Out: `package main344import (345	"e"346	"f"347	"z"348)349`,350	},351}352func addImportFn(path ...string) func(*ast.File) bool {353	return func(f *ast.File) bool {354		fixed := false355		for _, p := range path {356			if !imports(f, p) {357				addImport(f, p)...

Full Screen

Full Screen

func.go

Source:func.go Github

copy

Full Screen

1// +build ignore2package main3var a, b, c int4var unknown bool // defeat dead-code elimination5func func1() {6	var h int // @line f1h7	f := func(x *int) *int {8		if unknown {9			return &b10		}11		return x12	}13	// FV(g) = {f, h}14	g := func(x *int) *int {15		if unknown {16			return &h17		}18		return f(x)19	}20	print(g(&a)) // @pointsto main.a | main.b | h@f1h:621	print(f(&a)) // @pointsto main.a | main.b22	print(&a)    // @pointsto main.a23}24// @calls main.func1 -> main.func1$225// @calls main.func1 -> main.func1$126// @calls main.func1$2 ->  main.func1$127func func2() {28	var x, y *int29	defer func() {30		x = &a31	}()32	go func() {33		y = &b34	}()35	print(x) // @pointsto main.a36	print(y) // @pointsto main.b37}38func func3() {39	x, y := func() (x, y *int) {40		x = &a41		y = &b42		if unknown {43			return nil, &c44		}45		return46	}()47	print(x) // @pointsto main.a48	print(y) // @pointsto main.b | main.c49}50func swap(x, y *int) (*int, *int) { // @line swap51	print(&x) // @pointsto x@swap:1152	print(x)  // @pointsto makeslice[*]@func4make:1153	print(&y) // @pointsto y@swap:1454	print(y)  // @pointsto j@f4j:555	return y, x56}57func func4() {58	a := make([]int, 10) // @line func4make59	i, j := 123, 456     // @line f4j60	_ = i61	p, q := swap(&a[3], &j)62	print(p) // @pointsto j@f4j:563	print(q) // @pointsto makeslice[*]@func4make:1164	f := &b65	print(f) // @pointsto main.b66}67type T int68func (t *T) f(x *int) *int {69	print(t) // @pointsto main.a70	print(x) // @pointsto main.c71	return &b72}73func (t *T) g(x *int) *int {74	print(t) // @pointsto main.a75	print(x) // @pointsto main.b76	return &c77}78func (t *T) h(x *int) *int {79	print(t) // @pointsto main.a80	print(x) // @pointsto main.b81	return &c82}83var h func(*T, *int) *int84func func5() {85	// Static call of method.86	t := (*T)(&a)87	print(t.f(&c)) // @pointsto main.b88	// Static call of method as function89	print((*T).g(t, &b)) // @pointsto main.c90	// Dynamic call (not invoke) of method.91	h = (*T).h92	print(h(t, &b)) // @pointsto main.c93}94// @calls main.func5 -> (*main.T).f95// @calls main.func5 -> (*main.T).g$thunk96// @calls main.func5 -> (*main.T).h$thunk97func func6() {98	A := &a99	f := func() *int {100		return A // (free variable)101	}102	print(f()) // @pointsto main.a103}104// @calls main.func6 -> main.func6$1105type I interface {106	f()107}108type D struct{}109func (D) f() {}110func func7() {111	var i I = D{}112	imethodClosure := i.f113	imethodClosure()114	// @calls main.func7 -> (main.I).f$bound115	// @calls (main.I).f$bound -> (main.D).f116	var d D117	cmethodClosure := d.f118	cmethodClosure()119	// @calls main.func7 -> (main.D).f$bound120	// @calls (main.D).f$bound ->(main.D).f121	methodExpr := D.f122	methodExpr(d)123	// @calls main.func7 -> (main.D).f$thunk124}125func func8(x ...int) {126	print(&x[0]) // @pointsto varargs[*]@varargs:15127}128type E struct {129	x1, x2, x3, x4, x5 *int130}131func (e E) f() {}132func func9() {133	// Regression test for bug reported by Jon Valdes on golang-dev, Jun 19 2014.134	// The receiver of a bound method closure may be of a multi-node type, E.135	// valueNode was reserving only a single node for it, so the136	// nodes used by the immediately following constraints137	// (e.g. param 'i') would get clobbered.138	var e E139	e.x1 = &a140	e.x2 = &a141	e.x3 = &a142	e.x4 = &a143	e.x5 = &a144	_ = e.f // form a closure---must reserve sizeof(E) nodes145	func(i I) {146		i.f() // must not crash the solver147	}(new(D))148	print(e.x1) // @pointsto main.a149	print(e.x2) // @pointsto main.a150	print(e.x3) // @pointsto main.a151	print(e.x4) // @pointsto main.a152	print(e.x5) // @pointsto main.a153}154func main() {155	func1()156	func2()157	func3()158	func4()159	func5()160	func6()161	func7()162	func8(1, 2, 3) // @line varargs163	func9()164}165// @calls <root> -> main.main166// @calls <root> -> main.init...

Full Screen

Full Screen

interfaces.go

Source:interfaces.go Github

copy

Full Screen

1// +build ignore2package main3type I interface {4	f()5}6type C int7func (*C) f() {}8type D struct{ ptr *int }9func (D) f() {}10type E struct{}11func (*E) f() {}12var a, b int13var unknown bool // defeat dead-code elimination14func interface1() {15	var i interface{} = &a16	var j interface{} = D{&b}17	k := j18	if unknown {19		k = i20	}21	print(i) // @types *int22	print(j) // @types D23	print(k) // @types *int | D24	print(i.(*int)) // @pointsto main.a25	print(j.(*int)) // @pointsto26	print(k.(*int)) // @pointsto main.a27	print(i.(D).ptr) // @pointsto28	print(j.(D).ptr) // @pointsto main.b29	print(k.(D).ptr) // @pointsto main.b30}31func interface2() {32	var i I = (*C)(&a)33	var j I = D{&a}34	k := j35	if unknown {36		k = i37	}38	print(i) // @types *C39	print(j) // @types D40	print(k) // @types *C | D41	print(k) // @pointsto makeinterface:main.D | makeinterface:*main.C42	k.f()43	// @calls main.interface2 -> (*main.C).f44	// @calls main.interface2 -> (main.D).f45	print(i.(*C))    // @pointsto main.a46	print(j.(D).ptr) // @pointsto main.a47	print(k.(*C))    // @pointsto main.a48	switch x := k.(type) {49	case *C:50		print(x) // @pointsto main.a51	case D:52		print(x.ptr) // @pointsto main.a53	case *E:54		print(x) // @pointsto55	}56}57func interface3() {58	// There should be no backflow of concrete types from the type-switch to x.59	var x interface{} = 060	print(x) // @types int61	switch x.(type) {62	case int:63	case string:64	}65}66func interface4() {67	var i interface{} = D{&a}68	if unknown {69		i = 12370	}71	print(i) // @types int | D72	j := i.(I)       // interface narrowing type-assertion73	print(j)         // @types D74	print(j.(D).ptr) // @pointsto main.a75	var l interface{} = j // interface widening assignment.76	print(l)              // @types D77	print(l.(D).ptr)      // @pointsto main.a78	m := j.(interface{}) // interface widening type-assertion.79	print(m)             // @types D80	print(m.(D).ptr)     // @pointsto main.a81}82// Interface method calls and value flow:83type J interface {84	f(*int) *int85}86type P struct {87	x int88}89func (p *P) f(pi *int) *int {90	print(p)  // @pointsto p@i5p:691	print(pi) // @pointsto i@i5i:692	return &p.x93}94func interface5() {95	var p P // @line i5p96	var j J = &p97	var i int      // @line i5i98	print(j.f(&i)) // @pointsto p.x@i5p:699	print(&i)      // @pointsto i@i5i:6100	print(j) // @pointsto makeinterface:*main.P101}102// @calls main.interface5 -> (*main.P).f103func interface6() {104	f := I.f105	print(f) // @pointsto (main.I).f$thunk106	f(new(struct{ D }))107}108// @calls main.interface6 -> (main.I).f$thunk109// @calls (main.I).f$thunk -> (*struct{main.D}).f110func main() {111	interface1()112	interface2()113	interface3()114	interface4()115	interface5()116	interface6()117}...

Full Screen

Full Screen

inline_callers.go

Source:inline_callers.go Github

copy

Full Screen

1// run -gcflags=-l=42// Copyright 2017 The Go Authors. All rights reserved.3// Use of this source code is governed by a BSD-style4// license that can be found in the LICENSE file.5package main6import (7	"fmt"8	"runtime"9)10var skip int11var npcs int12var pcs = make([]uintptr, 32)13func f() {14	g()15}16func g() {17	h()18}19func h() {20	npcs = runtime.Callers(skip, pcs)21}22func testCallers(skp int) (frames []string) {23	skip = skp24	f()25	for i := 0; i < npcs; i++ {26		fn := runtime.FuncForPC(pcs[i] - 1)27		frames = append(frames, fn.Name())28		if fn.Name() == "main.main" {29			break30		}31	}32	return33}34func testCallersFrames(skp int) (frames []string) {35	skip = skp36	f()37	callers := pcs[:npcs]38	ci := runtime.CallersFrames(callers)39	for {40		frame, more := ci.Next()41		frames = append(frames, frame.Function)42		if !more || frame.Function == "main.main" {43			break44		}45	}46	return47}48var expectedFrames [][]string = [][]string{49	0: {"runtime.Callers", "main.h", "main.g", "main.f", "main.testCallers", "main.main"},50	1: {"main.h", "main.g", "main.f", "main.testCallers", "main.main"},51	2: {"main.g", "main.f", "main.testCallers", "main.main"},52	3: {"main.f", "main.testCallers", "main.main"},53	4: {"main.testCallers", "main.main"},54	5: {"main.main"},55}56var allFrames = []string{"runtime.Callers", "main.h", "main.g", "main.f", "main.testCallersFrames", "main.main"}57func same(xs, ys []string) bool {58	if len(xs) != len(ys) {59		return false60	}61	for i := range xs {62		if xs[i] != ys[i] {63			return false64		}65	}66	return true67}68func main() {69	for i := 0; i <= 5; i++ {70		frames := testCallers(i)71		expected := expectedFrames[i]72		if !same(frames, expected) {73			fmt.Printf("testCallers(%d):\n got %v\n want %v\n", i, frames, expected)74		}75		frames = testCallersFrames(i)76		expected = allFrames[i:]77		if !same(frames, expected) {78			fmt.Printf("testCallersFrames(%d):\n got %v\n want %v\n", i, frames, expected)79		}80	}81}...

Full Screen

Full Screen

main

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3    fmt.Println("Hello, World!")4}5import "fmt"6func main() {7    fmt.Println("Hello, World!")8}9import "fmt"10func main() {11    fmt.Println("Hello, World!")12}13import "fmt"14func main() {15    fmt.Println("Hello, World!")16}17import "fmt"18func main() {19    fmt.Println("Hello, World!")20}21import "fmt"22func main() {23    fmt.Println("Hello, World!")24}25import "fmt"26func main() {27    fmt.Println("Hello, World!")28}29import "fmt"30func main() {31    fmt.Println("Hello, World!")32}33import "fmt"34func main() {35    fmt.Println("Hello, World!")36}37import "fmt"38func main() {39    fmt.Println("Hello, World!")40}41import "fmt"42func main() {43    fmt.Println("Hello, World!")44}45import "fmt"46func main() {47    fmt.Println("Hello, World!")48}49import "fmt"50func main() {51    fmt.Println("Hello, World!")52}53import "fmt"54func main() {55    fmt.Println("Hello,

Full Screen

Full Screen

main

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3    fmt.Println("Hello World")4}5import "fmt"6func main() {7    fmt.Println("Hello World")8}9import "fmt"10func main() {11    fmt.Println("Hello World")12}13import "fmt"14func main() {15    fmt.Println("Hello World")16}17import "fmt"18func main() {19    fmt.Println("Hello World")20}21import "fmt"22func main() {23    fmt.Println("Hello World")24}25import "fmt"26func main() {27    fmt.Println("Hello World")28}29import "fmt"30func main() {31    fmt.Println("Hello World")32}33import "fmt"34func main() {35    fmt.Println("Hello World")36}37import "fmt"38func main() {39    fmt.Println("Hello World")40}41import "fmt"42func main() {43    fmt.Println("Hello World")44}45import "fmt"46func main() {47    fmt.Println("Hello World")48}49import "fmt"50func main() {51    fmt.Println("Hello World")52}53import "fmt"54func main() {55    fmt.Println("Hello World")56}

Full Screen

Full Screen

main

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3    fmt.Println("Hello World!")4}5import "fmt"6func main() {7    fmt.Println("Hello World!")8}9import "fmt"10func main() {11    fmt.Println("Hello World!")12}13import "fmt"14func main() {15    fmt.Println("Hello World!")16}17import "fmt"18func main() {19    fmt.Println("Hello World!")20}21import "fmt"22func main() {23    fmt.Println("Hello World!")24}25import "fmt"26func main() {27    fmt.Println("Hello World!")28}29import "fmt"30func main() {31    fmt.Println("Hello World!")32}33import "fmt"34func main() {35    fmt.Println("Hello World!")36}37import "fmt"38func main() {39    fmt.Println("Hello World!")40}41import "fmt"42func main() {43    fmt.Println("Hello World!")44}45import "fmt"46func main() {47    fmt.Println("Hello World!")48}49import "fmt"50func main() {51    fmt.Println("Hello World!")52}53import "fmt"54func main() {55    fmt.Println("Hello World!")56}

Full Screen

Full Screen

main

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3    fmt.Println("Hello, world.")4}5import "fmt"6func main() {7    fmt.Println("Hello, world.")8}9import "fmt"10func main() {11    fmt.Println("Hello, world.")12}13import "fmt"14func main() {15    fmt.Println("Hello, world.")16}17import "fmt"18func main() {19    fmt.Println("Hello, world.")20}21import "fmt"22func main() {23    fmt.Println("Hello, world.")24}25import "fmt"26func main() {27    fmt.Println("Hello, world.")28}29import "fmt"30func main() {31    fmt.Println("Hello, world.")32}33import "fmt"34func main() {35    fmt.Println("Hello, world.")36}37import "fmt"38func main() {39    fmt.Println("Hello, world.")40}41import "fmt"42func main() {43    fmt.Println("Hello, world.")44}45import "fmt"46func main() {47    fmt.Println("Hello, world.")48}49import "fmt"50func main() {51    fmt.Println("Hello, world.")52}53import "fmt"54func main() {55    fmt.Println("Hello,

Full Screen

Full Screen

main

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3    fmt.Println("Hello World")4}5import "fmt"6func main() {7    fmt.Println("Hello World")8}9import "fmt"10func main() {11    fmt.Println("Hello World")12}13import "fmt"14func main() {15    fmt.Println("Hello World")16}17import "fmt"18func main() {19    fmt.Println("Hello World")20}21import "fmt"22func main() {23    fmt.Println("Hello World")24}25import "fmt"26func main() {27    fmt.Println("Hello World")28}29import "fmt"30func main() {31    fmt.Println("Hello World")32}33import "fmt"34func main() {35    fmt.Println("Hello World")36}37import "fmt"38func main() {39    fmt.Println("Hello World")40}41import "fmt"42func main() {43    fmt.Println("Hello World")44}45import "fmt"46func main() {47    fmt.Println("Hello World")48}49import "fmt"50func main() {51    fmt.Println("Hello World")52}53import "fmt"54func main() {55    fmt.Println("Hello World")56}57import "fmt"58func main() {59    fmt.Println("Hello World")60}61import "fmt"62func main() {63    fmt.Println("Hello World")64}65import "fmt"66func main() {67    fmt.Println("Hello World")68}69import "fmt"70func main() {71    fmt.Println("Hello World")72}73import "fmt"74func main() {75    fmt.Println("Hello World")76}77import

Full Screen

Full Screen

main

Using AI Code Generation

copy

Full Screen

1func main() {2    println("Hello, World!")3}4func main() {5    println("Hello, World!")6}7func main() {8    println("Hello, World!")9}10func main() {11    println("Hello, World!")12}13func main() {14    println("Hello, World!")15}16func main() {17    println("Hello, World!")18}19func main() {20    println("Hello, World!")21}22func main() {23    println("Hello, World!")24}25func main() {26    println("Hello, World!")27}28func main() {29    println("Hello, World!")30}31func main() {32    println("Hello, World!")33}34func main() {35    println("Hello, World!")36}37func main() {38    println("Hello, World!")39}40func main() {41    println("Hello, World!")42}43func main() {44    println("Hello, World!")45}46func main() {47    println("Hello, World!")48}

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful