Best Syzkaller code snippet using main.compile
compile_test.go
Source:compile_test.go
...5 "github.com/hashicorp/consul/agent/connect"6 "github.com/hashicorp/consul/agent/structs"7 "github.com/stretchr/testify/require"8)9type compileTestCase struct {10 entries *structs.DiscoveryChainConfigEntries11 setup func(req *CompileRequest)12 expect *structs.CompiledDiscoveryChain13 // expectIsDefault tests behavior of CompiledDiscoveryChain.IsDefault()14 expectIsDefault bool15 expectCustom bool16 expectErr string17 expectGraphErr bool18}19func TestCompile(t *testing.T) {20 t.Parallel()21 cases := map[string]compileTestCase{22 "router with defaults": testcase_JustRouterWithDefaults(),23 "router with defaults and resolver": testcase_RouterWithDefaults_NoSplit_WithResolver(),24 "router with defaults and noop split": testcase_RouterWithDefaults_WithNoopSplit_DefaultResolver(),25 "router with defaults and noop split and resolver": testcase_RouterWithDefaults_WithNoopSplit_WithResolver(),26 "router with no destination": testcase_JustRouterWithNoDestination(),27 "route bypasses splitter": testcase_RouteBypassesSplit(),28 "noop split": testcase_NoopSplit_DefaultResolver(),29 "noop split with protocol from proxy defaults": testcase_NoopSplit_DefaultResolver_ProtocolFromProxyDefaults(),30 "noop split with resolver": testcase_NoopSplit_WithResolver(),31 "subset split": testcase_SubsetSplit(),32 "service split": testcase_ServiceSplit(),33 "split bypasses next splitter": testcase_SplitBypassesSplit(),34 "service redirect": testcase_ServiceRedirect(),35 "service and subset redirect": testcase_ServiceAndSubsetRedirect(),36 "datacenter redirect": testcase_DatacenterRedirect(),37 "datacenter redirect with mesh gateways": testcase_DatacenterRedirect_WithMeshGateways(),38 "service failover": testcase_ServiceFailover(),39 "service failover through redirect": testcase_ServiceFailoverThroughRedirect(),40 "circular resolver failover": testcase_Resolver_CircularFailover(),41 "service and subset failover": testcase_ServiceAndSubsetFailover(),42 "datacenter failover": testcase_DatacenterFailover(),43 "datacenter failover with mesh gateways": testcase_DatacenterFailover_WithMeshGateways(),44 "noop split to resolver with default subset": testcase_NoopSplit_WithDefaultSubset(),45 "resolver with default subset": testcase_Resolve_WithDefaultSubset(),46 "default resolver with external sni": testcase_DefaultResolver_ExternalSNI(),47 "resolver with no entries and inferring defaults": testcase_DefaultResolver(),48 "default resolver with proxy defaults": testcase_DefaultResolver_WithProxyDefaults(),49 "loadbalancer splitter and resolver": testcase_LBSplitterAndResolver(),50 "loadbalancer resolver": testcase_LBResolver(),51 "service redirect to service with default resolver is not a default chain": testcase_RedirectToDefaultResolverIsNotDefaultChain(),52 "all the bells and whistles": testcase_AllBellsAndWhistles(),53 "multi dc canary": testcase_MultiDatacenterCanary(),54 // various errors55 "splitter requires valid protocol": testcase_SplitterRequiresValidProtocol(),56 "router requires valid protocol": testcase_RouterRequiresValidProtocol(),57 "split to unsplittable protocol": testcase_SplitToUnsplittableProtocol(),58 "route to unroutable protocol": testcase_RouteToUnroutableProtocol(),59 "failover crosses protocols": testcase_FailoverCrossesProtocols(),60 "redirect crosses protocols": testcase_RedirectCrossesProtocols(),61 "redirect to missing subset": testcase_RedirectToMissingSubset(),62 "resolver with failover and external sni": testcase_Resolver_ExternalSNI_FailoverNotAllowed(),63 "resolver with subsets and external sni": testcase_Resolver_ExternalSNI_SubsetsNotAllowed(),64 "resolver with redirect and external sni": testcase_Resolver_ExternalSNI_RedirectNotAllowed(),65 // overrides66 "resolver with protocol from override": testcase_ResolverProtocolOverride(),67 "resolver with protocol from override ignored": testcase_ResolverProtocolOverrideIgnored(),68 "router ignored due to protocol override": testcase_RouterIgnored_ResolverProtocolOverride(),69 // circular references70 "circular resolver redirect": testcase_Resolver_CircularRedirect(),71 "circular split": testcase_CircularSplit(),72 }73 for name, tc := range cases {74 tc := tc75 t.Run(name, func(t *testing.T) {76 t.Parallel()77 // sanity check entries are normalized and valid78 for _, entry := range tc.entries.Routers {79 require.NoError(t, entry.Normalize())80 require.NoError(t, entry.Validate())81 }82 for _, entry := range tc.entries.Splitters {83 require.NoError(t, entry.Normalize())84 require.NoError(t, entry.Validate())85 }86 for _, entry := range tc.entries.Resolvers {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) {...
mocks_test.go
Source:mocks_test.go
1package rpc_test2import (3 "encoding/json"4 "io/ioutil"5 "net/http"6 "regexp"7 "testing"8 "github.com/bakingbacon/go-tezos/v4/rpc"9 "github.com/stretchr/testify/assert"10)11type responseKey string12func (r *responseKey) String() string {13 return string(*r)14}15const (16 activechains responseKey = ".test-fixtures/active_chains.json"17 bakingrights responseKey = ".test-fixtures/baking_rights.json"18 balance responseKey = ".test-fixtures/balance.json"19 ballotList responseKey = ".test-fixtures/ballot_list.json"20 ballots responseKey = ".test-fixtures/ballots.json"21 block responseKey = ".test-fixtures/block.json"22 blocks responseKey = ".test-fixtures/blocks.json"23 chainid responseKey = ".test-fixtures/chain_id.json"24 contract responseKey = ".test-fixtures/contract.json"25 connections responseKey = ".test-fixtures/connections.json"26 constants responseKey = ".test-fixtures/constants.json"27 contractEntrypoints responseKey = ".test-fixtures/entrypoints.json"28 counter responseKey = ".test-fixtures/counter.json"29 currentLevel responseKey = ".test-fixtures/current_level.json"30 cycle responseKey = ".test-fixtures/cycle.json"31 delegate responseKey = ".test-fixtures/delegate.json"32 delegatedcontracts responseKey = ".test-fixtures/delegated_contracts.json"33 endorsingrights responseKey = ".test-fixtures/endorsing_rights.json"34 frozenbalance responseKey = ".test-fixtures/frozen_balance.json"35 frozenbalanceByCycle responseKey = ".test-fixtures/frozen_balance_by_cycle.json"36 header responseKey = ".test-fixtures/header.json"37 headerShell responseKey = ".test-fixtures/header_shell.json"38 liveBlocks responseKey = ".test-fixtures/live_blocks.json"39 metadata responseKey = ".test-fixtures/metadata.json"40 operations responseKey = ".test-fixtures/operations.json"41 operationhashes responseKey = ".test-fixtures/operation_hashes.json"42 operationMetaDataHashes responseKey = ".test-fixtures/operation_metadata_hashes.json"43 parseOperations responseKey = ".test-fixtures/parse_operations.json"44 preapplyOperations responseKey = ".test-fixtures/preapply_operations.json"45 proposals responseKey = ".test-fixtures/proposals.json"46 protocols responseKey = ".test-fixtures/protocols.json"47 protocolData responseKey = ".test-fixtures/protocol_data.json"48 rpcerrors responseKey = ".test-fixtures/rpc_errors.json"49 voteListings responseKey = ".test-fixtures/vote_listings.json"50)51func readResponse(key responseKey) []byte {52 f, _ := ioutil.ReadFile(key.String())53 return f54}55func getResponse(key responseKey) interface{} {56 switch key {57 case activechains:58 f := readResponse(key)59 var out rpc.ActiveChains60 json.Unmarshal(f, &out)61 return out62 case bakingrights:63 f := readResponse(key)64 var out []rpc.BakingRights65 json.Unmarshal(f, &out)66 return out67 case balance:68 f := readResponse(key)69 var out int70 json.Unmarshal(f, &out)71 return &out72 case ballotList:73 f := readResponse(key)74 var out rpc.BallotList75 json.Unmarshal(f, &out)76 return &out77 case ballots:78 f := readResponse(key)79 var out rpc.Ballots80 json.Unmarshal(f, &out)81 return &out82 case block:83 f := readResponse(key)84 var out rpc.Block85 json.Unmarshal(f, &out)86 return &out87 case blocks:88 f := readResponse(key)89 var out [][]string90 json.Unmarshal(f, &out)91 return out92 case chainid:93 f := readResponse(key)94 var out string95 json.Unmarshal(f, &out)96 return out97 case contract:98 f := readResponse(key)99 var out rpc.Contract100 json.Unmarshal(f, &out)101 return out102 case connections:103 f := readResponse(key)104 var out rpc.Connections105 json.Unmarshal(f, &out)106 return out107 case constants:108 f := readResponse(key)109 var out rpc.Constants110 json.Unmarshal(f, &out)111 return out112 case counter:113 f := readResponse(key)114 var out int115 json.Unmarshal(f, &out)116 return out117 case currentLevel:118 f := readResponse(key)119 var out rpc.CurrentLevel120 json.Unmarshal(f, &out)121 return out122 case cycle:123 f := readResponse(key)124 var out rpc.Cycle125 json.Unmarshal(f, &out)126 return out127 case delegate:128 f := readResponse(key)129 var out rpc.Delegate130 json.Unmarshal(f, &out)131 return out132 case delegatedcontracts:133 f := readResponse(key)134 var out []string135 json.Unmarshal(f, &out)136 return out137 case endorsingrights:138 f := readResponse(key)139 var out []rpc.EndorsingRights140 json.Unmarshal(f, &out)141 return out142 case frozenbalanceByCycle:143 f := readResponse(key)144 var out []rpc.FrozenBalanceByCycle145 json.Unmarshal(f, &out)146 return out147 case header:148 f := readResponse(key)149 var out rpc.Header150 json.Unmarshal(f, &out)151 return out152 case headerShell:153 f := readResponse(key)154 var out rpc.HeaderShell155 json.Unmarshal(f, &out)156 return out157 case liveBlocks:158 f := readResponse(key)159 var out []string160 json.Unmarshal(f, &out)161 return out162 case metadata:163 f := readResponse(key)164 var out rpc.Metadata165 json.Unmarshal(f, &out)166 return out167 case operations:168 f := readResponse(key)169 var out rpc.FlattenedOperations170 json.Unmarshal(f, &out)171 return out172 case operationhashes:173 f := readResponse(key)174 var out rpc.OperationHashes175 json.Unmarshal(f, &out)176 return out177 case operationMetaDataHashes:178 f := readResponse(key)179 var out rpc.OperationMetadataHashes180 json.Unmarshal(f, &out)181 return out182 case parseOperations:183 f := readResponse(key)184 var out []rpc.Operations185 json.Unmarshal(f, &out)186 return out187 case preapplyOperations:188 f := readResponse(key)189 var out []rpc.Operations190 json.Unmarshal(f, &out)191 return out192 case proposals:193 f := readResponse(key)194 var out rpc.Proposals195 json.Unmarshal(f, &out)196 return out197 case protocols:198 f := readResponse(key)199 var out rpc.Protocols200 json.Unmarshal(f, &out)201 return out202 case protocolData:203 f := readResponse(key)204 var out rpc.ProtocolData205 json.Unmarshal(f, &out)206 return out207 case rpcerrors:208 f := readResponse(key)209 var out rpc.Errors210 json.Unmarshal(f, &out)211 return out212 case voteListings:213 f := readResponse(key)214 var out rpc.Listings215 json.Unmarshal(f, &out)216 return out217 default:218 return nil219 }220}221// The below variables contain mocks that are unmarshaled.222var (223 mockAddressTz1 = "tz1SUgyRB8T5jXgXAwS33pgRHAKrafyg87Yc"224 mockBlockHash = "BLzGD63HA4RP8Fh5xEtvdQSMKa2WzJMZjQPNVUc4Rqy8Lh5BEY1"225)226// Regexes to allow the capture of custom handlers for unit testing.227var (228 regActiveChains = regexp.MustCompile(`\/monitor\/active_chains`)229 regBakingRights = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/baking_rights`)230 regContractBalance = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/balance`)231 regBallotList = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/ballot_list`)232 regBallots = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/ballots`)233 regBlock = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+`)234 regBigMap = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/big_maps\/[0-9]+\/[A-z0-9]+`)235 regContracts = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts`)236 regContract = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+`)237 regConnections = regexp.MustCompile(`\/network\/connections`)238 regConstants = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/constants`)239 regContractDelegate = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/delegate`)240 regContractEntrypoints = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/entrypoints`)241 regContractEntrypoint = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/entrypoints\/[A-z]+`)242 regContractManagerKey = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/manager_key`)243 regContractScript = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/script`)244 regContractCounter = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/counter`)245 regCurrentPeriodKind = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/current_period_kind`)246 regCurrentPeriod = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/current_period_kind`)247 regSuccessorPeriod = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/successor_period`)248 regCurrentLevel = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/current_level`)249 regCurrentProposal = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/current_proposal`)250 regCurrentQuorum = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/current_quorum`)251 regTotalVotingPower = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/total_voting_power`)252 regCycle = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/raw\/json\/cycle\/[0-9]+`)253 regDelegate = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+`)254 regDelegates = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates`)255 regDelegateDelegatedContracts = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/delegated_contracts`)256 regDelegateBalance = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/balance`)257 regDelegateDeactivated = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/deactivated`)258 regDelegateDelegatedBalance = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/delegated_balance`)259 regDelegateFrozenBalance = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/frozen_balance`)260 regDelegateFrozenBalanceByCycle = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/frozen_balance_by_cycle`)261 regDelegateGracePeriod = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/grace_period`)262 regDelegateVotingPower = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/voting_power`)263 regEndorsingRights = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/endorsing_rights`)264 regEndorsingPower = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/endorsing_power`)265 regEntrypoint = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers/scripts/entrypoint`)266 regEntrypoints = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers/scripts/entrypoints`)267 regForgeOperationWithRPC = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/forge\/operations`)268 regForgeBlockHeader = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/forge_block_header`)269 regHash = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/hash`)270 regHeader = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/header`)271 regHeaderRaw = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/header\/raw`)272 regHeaderShell = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/header\/shell`)273 regHeaderProtocolData = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/header\/protocol_data`)274 regHeaderProtocolDataRaw = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/header\/protocol_data/raw`)275 regLiveBlocks = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/live_blocks`)276 regInjectionBlock = regexp.MustCompile(`\/injection\/block`)277 regInjectionOperation = regexp.MustCompile(`\/injection\/operation`)278 regLevelsInCurrentCycle = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/levels_in_current_cycle`)279 regMetadata = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/metadata`)280 regMetadataHash = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/metadata_hash`)281 regMinimalValidTime = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/minimal_valid_time`)282 regNonces = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/nonces\/[0-9]+`)283 regOperations = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/operations`)284 regOperationsMetadataHash = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/operations_metadata_hash`)285 regOperationHashes = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/operation_hashes`)286 regOperationMetadataHashes = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/operation_metadata_hashes`)287 regPackData = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers/scripts/pack_data`)288 regParseBlock = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/parse\/block`)289 regParseOperations = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/parse\/operations`)290 regPreapplyBlock = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/preapply\/block`)291 regPreapplyOperations = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/preapply\/operations`)292 regProposals = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/proposals`)293 regProtocols = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/protocols`)294 regRawBytes = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/raw\/bytes`)295 regRunCode = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers/scripts/run_code`)296 regRunOperation = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/scripts\/run_operation`)297 regRequiredEndorsements = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/required_endorsements`)298 regSeed = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/seed`)299 regTraceCode = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/scripts\/trace_code`)300 regTypecheckCode = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/scripts\/typecheck_code`)301 regTypecheckData = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/helpers\/scripts\/typecheck_data`)302 regDelegateStakingBalance = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/delegates\/[A-z0-9]+\/staking_balance`)303 regContractStorage = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/context\/contracts\/[A-z0-9]+\/storage`)304 regVoteListings = regexp.MustCompile(`\/chains\/main\/blocks\/[A-z0-9]+\/votes\/listings`)305)306// blankHandler handles the end of a http test handler chain307var blankHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})308// ----------------------------------------- //309// Mock Handlers310// The below handlers are to simulate the Tezos RPC server for unit testing.311// ----------------------------------------- //312type requestResultPair struct {313 requestPath *regexp.Regexp314 resp []byte315}316func mockHandler(pair *requestResultPair, next http.Handler) http.Handler {317 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {318 if pair.requestPath.MatchString(r.URL.String()) {319 w.Write(pair.resp)320 return321 }322 next.ServeHTTP(w, r)323 })324}325type blockHandlerMock struct {326 used bool327}328func newBlockMock() *blockHandlerMock {329 return &blockHandlerMock{}330}331func (b *blockHandlerMock) handler(resp []byte, next http.Handler) http.Handler {332 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {333 if regBlock.MatchString(r.URL.String()) && !b.used {334 w.Write(resp)335 b.used = true336 return337 }338 next.ServeHTTP(w, r)339 })340}341type constantsHandlerMock struct {342 used bool343}344func newConstantsMock() *constantsHandlerMock {345 return &constantsHandlerMock{}346}347func (c *constantsHandlerMock) handler(resp []byte, next http.Handler) http.Handler {348 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {349 if regConstants.MatchString(r.URL.String()) && !c.used {350 w.Write(resp)351 c.used = true352 return353 }354 next.ServeHTTP(w, r)355 })356}357func cycleHandlerMock(resp []byte, next http.Handler) http.Handler {358 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {359 if regCycle.MatchString(r.URL.String()) {360 w.Write(resp)361 return362 }363 next.ServeHTTP(w, r)364 })365}366func runOperationHandlerMock(resp []byte, next http.Handler) http.Handler {367 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {368 if regRunOperation.MatchString(r.URL.String()) {369 w.Write(resp)370 return371 }372 next.ServeHTTP(w, r)373 })374}375func checkErr(t *testing.T, wantErr bool, errContains string, err error) {376 if wantErr {377 assert.Error(t, err)378 if err != nil {379 assert.Contains(t, err.Error(), errContains)380 }381 } else {382 assert.Nil(t, err)383 }384}...
util.go
Source:util.go
...11 problemID := fmt.Sprint(req.ProblemID)12 codeName := ""13 execName := ""14 runName := ""15 compileArgs := make([]string, 0)16 runArgs := make([]string, 0)17 javaRedundancy := int64(0)18 switch req.Language {19 case config.C:20 codeName, execName, runName = "main.c", "gcc", "main"21 compileArgs = append(compileArgs, "gcc", "main.c", "-o", "main", "-std=c11", "-O2", "-DONLINE_JUDGE", "-lm")22 runArgs = append(runArgs, "./main")23 case config.CPP:24 codeName, execName, runName = "main.cpp", "g++", "main"25 compileArgs = append(compileArgs, "g++", "main.cpp", "-o", "main", "-std=c++17", "-O2", "-DONLINE_JUDGE")26 runArgs = append(runArgs, "./main")27 case config.Java:28 codeName, execName, runName = "Main.java", "javac", "java"29 javaRedundancy = 6430 compileArgs = append(compileArgs, "javac", "-encoding", "UTF-8", "-sourcepath", ".", "-d", ".", "Main.java")31 javaXss := fmt.Sprintf("-Xss%dm", limit.MemoryLimit)32 javaXms := fmt.Sprintf("-Xms%dm", limit.MemoryLimit)33 javaXmx := fmt.Sprintf("-Xmx%dm", limit.MemoryLimit)34 runArgs = append(runArgs, "java", "-Dfile.encoding=UTF-8", "-XX:+UseSerialGC", javaXss, javaXms, javaXmx, "Main")35 case config.Python3:36 codeName, execName, runName = "main.py", "python3", "python3"37 compileArgs = append(compileArgs, "python3", "-m", "py_compile", "main.py")38 runArgs = append(runArgs, "python3", "__pycache__/main.cpython-38.pyc")39 default:40 return workermodel.ExecRequest{}, errors.New("unknown language code")41 }42 return workermodel.ExecRequest{43 CompilePhases: workermodel.CompilePhase{44 Compile: workermodel.Phase{45 Exec: execName,46 RunArgs: compileArgs,47 Limits: workermodel.Limitation{48 Time: 5000,49 Memory: 1024 << 20,50 },51 },52 SourceCode: workermodel.SourceCodeDescriptor{53 Name: codeName,54 Content: req.Code,55 },56 ExecName: execName,57 },58 RunPhases: workermodel.RunPhase{59 Run: workermodel.Phase{60 Exec: runName,...
compile
Using AI Code Generation
1import (2func main() {3 var re *regexp.Regexp = regexp.MustCompile(`am(.*)lang(.*)`)4 var str2 string = re.ReplaceAllString(str, "was$1programming$2")5 fmt.Println(str2)6}7import (8func main() {9 var re *regexp.Regexp = regexp.MustCompile(`am(.*)lang(.*)`)10 var str2 string = re.ReplaceAllString(str, "was${1}programming${2}")11 fmt.Println(str2)12}13import (14func main() {15 var re *regexp.Regexp = regexp.MustCompile(`am(.*)lang(.*)`)16 var str2 string = re.ReplaceAllString(str, "was${1}programming${2}")17 fmt.Println(str2)18}19import (20func main() {21 var re *regexp.Regexp = regexp.MustCompile(`am(.*)lang(.*)`)22 var str2 string = re.ReplaceAllString(str, "was${1}programming${2}")23 fmt.Println(str2)24}25import (26func main() {27 var re *regexp.Regexp = regexp.MustCompile(`am(.*)lang(.*)`)28 var str2 string = re.ReplaceAllString(str, "was${1}programming${2}")29 fmt.Println(str2)30}31import (32func main() {33 var re *regexp.Regexp = regexp.MustCompile(`am(.*)lang(.*)`)34 var str2 string = re.ReplaceAllString(str, "was${
compile
Using AI Code Generation
1import (2func main() {3 var regex, err = regexp.Compile(`hello`)4 if err != nil {5 fmt.Println(err.Error())6 }7 var result = regex.MatchString(str)8 fmt.Println(result)9}10import (11func main() {12 var regex, err = regexp.Compile(`how`)13 if err != nil {14 fmt.Println(err.Error())15 }16 var result = regex.FindString(str)17 fmt.Println(result)18}19import (20func main() {21 var regex, err = regexp.Compile(`how`)22 if err != nil {23 fmt.Println(err.Error())24 }25 var result = regex.FindStringIndex(str)26 fmt.Println(result)27}28import (29func main() {30 var regex, err = regexp.Compile(`how`)31 if err != nil {32 fmt.Println(err.Error())33 }34 var result = regex.FindStringSubmatch(str)35 fmt.Println(result)36}37import (38func main() {39 var regex, err = regexp.Compile(`how`)40 if err != nil {41 fmt.Println(err.Error())42 }43 var result = regex.FindStringSubmatchIndex(str)44 fmt.Println(result)45}46import (47func main() {48 var regex, err = regexp.Compile(`how`)49 if err != nil {50 fmt.Println(err.Error())51 }52 var result = regex.FindAllString(str, -1)53 fmt.Println(result)54}
compile
Using AI Code Generation
1import (2func main() {3 var regex, _ = regexp.Compile(`world`)4 var result = regex.MatchString(str)5 fmt.Println(result)6}
compile
Using AI Code Generation
1import (2func main() {3 var pattern = regexp.MustCompile("world")4 match := pattern.MatchString(str)5 fmt.Println(match)6}
compile
Using AI Code Generation
1import (2func main() {3 re, err := regexp.Compile("a([a-z]+)e")4 if err != nil {5 fmt.Println(err)6 }7 fmt.Println(re)8}
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!!