Best Mock code snippet using main.main
compile_test.go
Source:compile_test.go
...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}...
imports_test.go
Source:imports_test.go
...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)...
output_test.go
Source:output_test.go
...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}...
main.go
Source:main.go
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}...
import_test.go
Source:import_test.go
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)...
func.go
Source:func.go
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...
interfaces.go
Source:interfaces.go
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}...
inline_callers.go
Source:inline_callers.go
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}...
main
Using AI Code Generation
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,
main
Using AI Code Generation
1import "fmt"2func main() {3fmt.Println("Hello World")4}5import "fmt"6func main() {7fmt.Println("Hello World")8}9import "fmt"10func main() {11fmt.Println("Hello World")12}13import "fmt"14func main() {15fmt.Println("Hello World")16}17import "fmt"18func main() {19fmt.Println("Hello World")20}21import "fmt"22func main() {23fmt.Println("Hello World")24}25import "fmt"26func main() {27fmt.Println("Hello World")28}29import "fmt"30func main() {31fmt.Println("Hello World")32}33import "fmt"34func main() {35fmt.Println("Hello World")36}37import "fmt"38func main() {39fmt.Println("Hello World")40}41import "fmt"42func main() {43fmt.Println("Hello World")44}45import "fmt"46func main() {47fmt.Println("Hello World")48}49import "fmt"50func main() {51fmt.Println("Hello World")52}53import "fmt"54func main() {55fmt.Println("Hello World")56}57import "fmt"
main
Using AI Code Generation
1import (2func main() {3 fmt.Println("Hello, World!")4}5import (6func main() {7 fmt.Println("Hello, World!")8}9import (10func main() {11 fmt.Println("Hello, World!")12}13import (14func main() {15 fmt.Println("Hello, World!")16}17import (18func main() {19 fmt.Println("Hello, World!")20}21import (22func main() {23 fmt.Println("Hello, World!")24}25import (26func main() {27 fmt.Println("Hello, World!")28}29import (30func main() {31 fmt.Println("Hello, World!")32}33import (34func main() {35 fmt.Println("Hello, World!")36}37import (38func main() {39 fmt.Println("Hello, World!")40}41import (42func main() {43 fmt.Println("Hello, World!")44}45import (46func main() {47 fmt.Println("Hello, World!")48}49import (50func main() {51 fmt.Println("
main
Using AI Code Generation
1import "fmt"2func main() {3}4import "fmt"5func main() {6}7import "fmt"8func main() {9}10import "fmt"11func main() {12}13import "fmt"14func main() {15}16import "fmt"17func main() {18}19import "fmt"20func main() {21}22import "fmt"23func main() {24}25import "fmt"26func main() {27}28import "fmt"29func main() {30}31import "fmt"32func main() {33}34import "fmt"35func main() {36}37import "fmt"38func main() {39}40import
main
Using AI Code Generation
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}
main
Using AI Code Generation
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}
main
Using AI Code Generation
1import (2func main() {3 fmt.Println("Hello World!")4 main.Main()5}6import (7func main() {8 fmt.Println("Hello World!")9 main.Main()10}11import (12func Main() {13 fmt.Println("Main method of main class")14}15import (16func Main() {17 fmt.Println("Main method of main class")18}19import (20func Main() {21 fmt.Println("Main method of main class")22}23import (24func Main() {25 fmt.Println("Main method of main class")26}27import (28func Main() {29 fmt.Println("Main method of main class")30}31import (32func Main() {33 fmt.Println("Main method of main class")34}35import (36func Main() {37 fmt.Println("Main method of main class")38}39import (40func Main() {41 fmt.Println("Main method of main class")42}43import (44func Main() {45 fmt.Println("Main method of main class")46}47import (48func Main() {49 fmt.Println("Main method of main class")50}51import (
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.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!