github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/config_check_test.go (about) 1 // Copyright 2018 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package server 15 16 import ( 17 "errors" 18 "fmt" 19 "strings" 20 "testing" 21 ) 22 23 func TestConfigCheck(t *testing.T) { 24 tests := []struct { 25 // name is the name of the test. 26 name string 27 28 // config is content of the configuration file. 29 config string 30 31 // warningErr is an error that does not prevent server from starting. 32 warningErr error 33 34 // errorLine is the location of the error. 35 errorLine int 36 37 // errorPos is the position of the error. 38 errorPos int 39 40 // warning errors also include a reason optionally. 41 reason string 42 43 // newDefaultErr is a configuration error that includes source of error. 44 err error 45 }{ 46 { 47 name: "when unknown field is used at top level", 48 config: ` 49 monitor = "127.0.0.1:4442" 50 `, 51 err: errors.New(`unknown field "monitor"`), 52 errorLine: 2, 53 errorPos: 17, 54 }, 55 { 56 name: "when default permissions are used at top level", 57 config: ` 58 "default_permissions" { 59 publish = ["_SANDBOX.>"] 60 subscribe = ["_SANDBOX.>"] 61 } 62 `, 63 err: errors.New(`unknown field "default_permissions"`), 64 errorLine: 2, 65 errorPos: 18, 66 }, 67 { 68 name: "when authorization config is empty", 69 config: ` 70 authorization = { 71 } 72 `, 73 err: nil, 74 }, 75 { 76 name: "when authorization config has unknown fields", 77 config: ` 78 authorization = { 79 foo = "bar" 80 } 81 `, 82 err: errors.New(`unknown field "foo"`), 83 errorLine: 3, 84 errorPos: 5, 85 }, 86 { 87 name: "when authorization config has unknown fields", 88 config: ` 89 port = 4222 90 91 authorization = { 92 user = "hello" 93 foo = "bar" 94 password = "world" 95 } 96 97 `, 98 err: errors.New(`unknown field "foo"`), 99 errorLine: 6, 100 errorPos: 5, 101 }, 102 { 103 name: "when user authorization config has unknown fields", 104 config: ` 105 authorization = { 106 users = [ 107 { 108 user = "foo" 109 pass = "bar" 110 token = "quux" 111 } 112 ] 113 } 114 `, 115 err: errors.New(`unknown field "token"`), 116 errorLine: 7, 117 errorPos: 9, 118 }, 119 { 120 name: "when user authorization permissions config has unknown fields", 121 config: ` 122 authorization { 123 permissions { 124 subscribe = {} 125 inboxes = {} 126 publish = {} 127 } 128 } 129 `, 130 err: errors.New(`Unknown field "inboxes" parsing permissions`), 131 errorLine: 5, 132 errorPos: 7, 133 }, 134 { 135 name: "when user authorization permissions config has unknown fields within allow or deny", 136 config: ` 137 authorization { 138 permissions { 139 subscribe = { 140 allow = ["hello", "world"] 141 deny = ["foo", "bar"] 142 denied = "_INBOX.>" 143 } 144 publish = {} 145 } 146 } 147 `, 148 err: errors.New(`Unknown field name "denied" parsing subject permissions, only 'allow' or 'deny' are permitted`), 149 errorLine: 7, 150 errorPos: 9, 151 }, 152 { 153 name: "when user authorization permissions config has unknown fields within allow or deny", 154 config: ` 155 authorization { 156 permissions { 157 publish = { 158 allow = ["hello", "world"] 159 deny = ["foo", "bar"] 160 allowed = "_INBOX.>" 161 } 162 subscribe = {} 163 } 164 } 165 `, 166 err: errors.New(`Unknown field name "allowed" parsing subject permissions, only 'allow' or 'deny' are permitted`), 167 errorLine: 7, 168 errorPos: 9, 169 }, 170 { 171 name: "when user authorization permissions config has unknown fields using arrays", 172 config: ` 173 authorization { 174 175 default_permissions { 176 subscribe = ["a"] 177 publish = ["b"] 178 inboxes = ["c"] 179 } 180 181 users = [ 182 { 183 user = "foo" 184 pass = "bar" 185 } 186 ] 187 } 188 `, 189 err: errors.New(`Unknown field "inboxes" parsing permissions`), 190 errorLine: 7, 191 errorPos: 6, 192 }, 193 { 194 name: "when user authorization permissions config has unknown fields using strings", 195 config: ` 196 authorization { 197 198 default_permissions { 199 subscribe = "a" 200 requests = "b" 201 publish = "c" 202 } 203 204 users = [ 205 { 206 user = "foo" 207 pass = "bar" 208 } 209 ] 210 } 211 `, 212 err: errors.New(`Unknown field "requests" parsing permissions`), 213 errorLine: 6, 214 errorPos: 6, 215 }, 216 { 217 name: "when user authorization permissions config is empty", 218 config: ` 219 authorization = { 220 users = [ 221 { 222 user = "foo", pass = "bar", permissions = { 223 } 224 } 225 ] 226 } 227 `, 228 err: nil, 229 }, 230 { 231 name: "when unknown permissions are included in user config", 232 config: ` 233 authorization = { 234 users = [ 235 { 236 user = "foo", pass = "bar", permissions { 237 inboxes = true 238 } 239 } 240 ] 241 } 242 `, 243 err: errors.New(`Unknown field "inboxes" parsing permissions`), 244 errorLine: 6, 245 errorPos: 11, 246 }, 247 { 248 name: "when clustering config is empty", 249 config: ` 250 cluster = { 251 } 252 `, 253 254 err: nil, 255 }, 256 { 257 name: "when unknown option is in clustering config", 258 config: ` 259 # NATS Server Configuration 260 port = 4222 261 262 cluster = { 263 264 port = 6222 265 266 foo = "bar" 267 268 authorization { 269 user = "hello" 270 pass = "world" 271 } 272 273 } 274 `, 275 276 err: errors.New(`unknown field "foo"`), 277 errorLine: 9, 278 errorPos: 5, 279 }, 280 { 281 name: "when unknown option is in clustering authorization config", 282 config: ` 283 cluster = { 284 authorization { 285 foo = "bar" 286 } 287 } 288 `, 289 290 err: errors.New(`unknown field "foo"`), 291 errorLine: 4, 292 errorPos: 7, 293 }, 294 { 295 name: "when unknown option is in tls config", 296 config: ` 297 tls = { 298 hello = "world" 299 } 300 `, 301 err: errors.New(`error parsing tls config, unknown field "hello"`), 302 errorLine: 3, 303 errorPos: 5, 304 }, 305 { 306 name: "when unknown option is in cluster tls config", 307 config: ` 308 cluster { 309 tls = { 310 foo = "bar" 311 } 312 } 313 `, 314 err: errors.New(`error parsing tls config, unknown field "foo"`), 315 errorLine: 4, 316 errorPos: 7, 317 }, 318 { 319 name: "when using cipher suites in the TLS config", 320 config: ` 321 tls = { 322 cipher_suites: [ 323 "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 324 "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" 325 ] 326 preferences = [] 327 } 328 `, 329 err: errors.New(`error parsing tls config, unknown field "preferences"`), 330 errorLine: 7, 331 errorPos: 7, 332 }, 333 { 334 name: "when using curve preferences in the TLS config", 335 config: ` 336 tls = { 337 curve_preferences: [ 338 "CurveP256", 339 "CurveP384", 340 "CurveP521" 341 ] 342 suites = [] 343 } 344 `, 345 err: errors.New(`error parsing tls config, unknown field "suites"`), 346 errorLine: 8, 347 errorPos: 7, 348 }, 349 { 350 name: "when using curve preferences in the TLS config", 351 config: ` 352 tls = { 353 curve_preferences: [ 354 "CurveP5210000" 355 ] 356 } 357 `, 358 err: errors.New(`unrecognized curve preference CurveP5210000`), 359 errorLine: 4, 360 errorPos: 5, 361 }, 362 { 363 name: "verify_cert_and_check_known_urls not support for clients", 364 config: ` 365 tls = { 366 cert_file: "configs/certs/server.pem" 367 key_file: "configs/certs/key.pem" 368 verify_cert_and_check_known_urls: true 369 } 370 `, 371 err: errors.New("verify_cert_and_check_known_urls not supported in this context"), 372 errorLine: 5, 373 errorPos: 10, 374 }, 375 { 376 name: "when unknown option is in cluster config with defined routes", 377 config: ` 378 cluster { 379 port = 6222 380 routes = [ 381 nats://127.0.0.1:6222 382 ] 383 peers = [] 384 } 385 `, 386 err: errors.New(`unknown field "peers"`), 387 errorLine: 7, 388 errorPos: 5, 389 }, 390 { 391 name: "when used as variable in authorization block it should not be considered as unknown field", 392 config: ` 393 # listen: 127.0.0.1:-1 394 listen: 127.0.0.1:4222 395 396 authorization { 397 # Superuser can do anything. 398 super_user = { 399 publish = ">" 400 subscribe = ">" 401 } 402 403 # Can do requests on foo or bar, and subscribe to anything 404 # that is a response to an _INBOX. 405 # 406 # Notice that authorization filters can be singletons or arrays. 407 req_pub_user = { 408 publish = ["req.foo", "req.bar"] 409 subscribe = "_INBOX.>" 410 } 411 412 # Setup a default user that can subscribe to anything, but has 413 # no publish capabilities. 414 default_user = { 415 subscribe = "PUBLIC.>" 416 } 417 418 unused = "hello" 419 420 # Default permissions if none presented. e.g. susan below. 421 default_permissions: $default_user 422 423 # Users listed with persmissions. 424 users = [ 425 {user: alice, password: foo, permissions: $super_user} 426 {user: bob, password: bar, permissions: $req_pub_user} 427 {user: susan, password: baz} 428 ] 429 } 430 `, 431 err: errors.New(`unknown field "unused"`), 432 errorLine: 27, 433 errorPos: 5, 434 }, 435 { 436 name: "when used as variable in top level config it should not be considered as unknown field", 437 config: ` 438 monitoring_port = 8222 439 440 http_port = $monitoring_port 441 442 port = 4222 443 `, 444 err: nil, 445 }, 446 { 447 name: "when used as variable in cluster config it should not be considered as unknown field", 448 config: ` 449 cluster { 450 clustering_port = 6222 451 port = $clustering_port 452 } 453 `, 454 err: nil, 455 }, 456 { 457 name: "when setting permissions within cluster authorization block", 458 config: ` 459 cluster { 460 authorization { 461 permissions = { 462 publish = { allow = ["foo", "bar"] } 463 } 464 } 465 466 permissions = { 467 publish = { deny = ["foo", "bar"] } 468 } 469 } 470 `, 471 warningErr: errors.New(`invalid use of field "authorization"`), 472 errorLine: 3, 473 errorPos: 5, 474 reason: `setting "permissions" within cluster authorization block is deprecated`, 475 }, 476 { 477 name: "when write deadline is used with deprecated usage", 478 config: ` 479 write_deadline = 100 480 `, 481 warningErr: errors.New(`invalid use of field "write_deadline"`), 482 errorLine: 2, 483 errorPos: 17, 484 reason: `write_deadline should be converted to a duration`, 485 }, 486 ///////////////////// 487 // ACCOUNTS // 488 ///////////////////// 489 { 490 name: "when accounts block is correctly configured", 491 config: ` 492 http_port = 8222 493 494 accounts { 495 496 # 497 # synadia > nats.io, cncf 498 # 499 synadia { 500 # SAADJL5XAEM6BDYSWDTGVILJVY54CQXZM5ZLG4FRUAKB62HWRTPNSGXOHA 501 nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL" 502 503 users [ 504 { 505 # SUAEL6RU3BSDAFKOHNTEOK5Q6FTM5FTAMWVIKBET6FHPO4JRII3CYELVNM 506 nkey = "UCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3" 507 } 508 ] 509 510 exports = [ 511 { service: "synadia.requests", accounts: [nats, cncf] } 512 ] 513 } 514 515 # 516 # nats < synadia 517 # 518 nats { 519 # SUAJTM55JH4BNYDA22DMDZJSRBRKVDGSLYK2HDIOCM3LPWCDXIDV5Q4CIE 520 nkey = "ADRZ42QBM7SXQDXXTSVWT2WLLFYOQGAFC4TO6WOAXHEKQHIXR4HFYJDS" 521 522 users [ 523 { 524 # SUADZTYQAKTY5NQM7XRB5XR3C24M6ROGZLBZ6P5HJJSSOFUGC5YXOOECOM 525 nkey = "UD6AYQSOIN2IN5OGC6VQZCR4H3UFMIOXSW6NNS6N53CLJA4PB56CEJJI" 526 } 527 ] 528 529 imports = [ 530 # This account has to send requests to 'nats.requests' subject 531 { service: { account: "synadia", subject: "synadia.requests" }, to: "nats.requests" } 532 ] 533 } 534 535 # 536 # cncf < synadia 537 # 538 cncf { 539 # SAAFHDZX7SGZ2SWHPS22JRPPK5WX44NPLNXQHR5C5RIF6QRI3U65VFY6C4 540 nkey = "AD4YRVUJF2KASKPGRMNXTYKIYSCB3IHHB4Y2ME6B2PDIV5QJ23C2ZRIT" 541 542 users [ 543 { 544 # SUAKINP3Z2BPUXWOFSW2FZC7TFJCMMU7DHKP2C62IJQUDASOCDSTDTRMJQ 545 nkey = "UB57IEMPG4KOTPFV5A66QKE2HZ3XBXFHVRCCVMJEWKECMVN2HSH3VTSJ" 546 } 547 ] 548 549 imports = [ 550 # This account has to send requests to 'synadia.requests' subject 551 { service: { account: "synadia", subject: "synadia.requests" } } 552 ] 553 } 554 } 555 `, 556 err: nil, 557 }, 558 { 559 name: "when nkey is invalid within accounts block", 560 config: ` 561 accounts { 562 563 # 564 # synadia > nats.io, cncf 565 # 566 synadia { 567 # SAADJL5XAEM6BDYSWDTGVILJVY54CQXZM5ZLG4FRUAKB62HWRTPNSGXOHA 568 nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL" 569 570 users [ 571 { 572 # SUAEL6RU3BSDAFKOHNTEOK5Q6FTM5FTAMWVIKBET6FHPO4JRII3CYELVNM 573 nkey = "SCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3" 574 } 575 ] 576 577 exports = [ 578 { service: "synadia.requests", accounts: [nats, cncf] } 579 ] 580 } 581 582 # 583 # nats < synadia 584 # 585 nats { 586 # SUAJTM55JH4BNYDA22DMDZJSRBRKVDGSLYK2HDIOCM3LPWCDXIDV5Q4CIE 587 nkey = "ADRZ42QBM7SXQDXXTSVWT2WLLFYOQGAFC4TO6WOAXHEKQHIXR4HFYJDS" 588 589 users [ 590 { 591 # SUADZTYQAKTY5NQM7XRB5XR3C24M6ROGZLBZ6P5HJJSSOFUGC5YXOOECOM 592 nkey = "UD6AYQSOIN2IN5OGC6VQZCR4H3UFMIOXSW6NNS6N53CLJA4PB56CEJJI" 593 } 594 ] 595 596 imports = [ 597 # This account has to send requests to 'nats.requests' subject 598 { service: { account: "synadia", subject: "synadia.requests" }, to: "nats.requests" } 599 ] 600 } 601 602 # 603 # cncf < synadia 604 # 605 cncf { 606 # SAAFHDZX7SGZ2SWHPS22JRPPK5WX44NPLNXQHR5C5RIF6QRI3U65VFY6C4 607 nkey = "AD4YRVUJF2KASKPGRMNXTYKIYSCB3IHHB4Y2ME6B2PDIV5QJ23C2ZRIT" 608 609 users [ 610 { 611 # SUAKINP3Z2BPUXWOFSW2FZC7TFJCMMU7DHKP2C62IJQUDASOCDSTDTRMJQ 612 nkey = "UB57IEMPG4KOTPFV5A66QKE2HZ3XBXFHVRCCVMJEWKECMVN2HSH3VTSJ" 613 } 614 ] 615 616 imports = [ 617 # This account has to send requests to 'synadia.requests' subject 618 { service: { account: "synadia", subject: "synadia.requests" } } 619 ] 620 } 621 } 622 `, 623 err: errors.New(`Not a valid public nkey for a user`), 624 errorLine: 14, 625 errorPos: 11, 626 }, 627 { 628 name: "when accounts block has unknown fields", 629 config: ` 630 http_port = 8222 631 632 accounts { 633 foo = "bar" 634 }`, 635 err: errors.New(`Expected map entries for accounts`), 636 errorLine: 5, 637 errorPos: 19, 638 }, 639 { 640 name: "when accounts has a referenced config variable within same block", 641 config: ` 642 accounts { 643 PERMISSIONS = { 644 publish = { 645 allow = ["foo","bar"] 646 deny = ["quux"] 647 } 648 } 649 650 synadia { 651 nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL" 652 653 users [ 654 { 655 nkey = "UCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3" 656 permissions = $PERMISSIONS 657 } 658 ] 659 exports = [ 660 { stream: "synadia.>" } 661 ] 662 } 663 }`, 664 err: nil, 665 }, 666 { 667 name: "when accounts has an unreferenced config variables within same block", 668 config: ` 669 accounts { 670 PERMISSIONS = { 671 publish = { 672 allow = ["foo","bar"] 673 deny = ["quux"] 674 } 675 } 676 677 synadia { 678 nkey = "AC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL" 679 680 users [ 681 { 682 nkey = "UCARKS2E3KVB7YORL2DG34XLT7PUCOL2SVM7YXV6ETHLW6Z46UUJ2VZ3" 683 } 684 ] 685 exports = [ 686 { stream: "synadia.>" } 687 ] 688 } 689 }`, 690 err: errors.New(`unknown field "publish"`), 691 errorLine: 4, 692 errorPos: 5, 693 }, 694 { 695 name: "when accounts block defines a global account", 696 config: ` 697 http_port = 8222 698 699 accounts { 700 $G = { 701 } 702 } 703 `, 704 err: errors.New(`"$G" is a Reserved Account`), 705 errorLine: 5, 706 errorPos: 19, 707 }, 708 { 709 name: "when accounts block uses an invalid public key", 710 config: ` 711 accounts { 712 synadia = { 713 nkey = "invalid" 714 } 715 } 716 `, 717 err: errors.New(`Not a valid public nkey for an account: "invalid"`), 718 errorLine: 4, 719 errorPos: 21, 720 }, 721 { 722 name: "when accounts list includes reserved account", 723 config: ` 724 port = 4222 725 726 accounts = [foo, bar, "$G"] 727 728 http_port = 8222 729 `, 730 err: errors.New(`"$G" is a Reserved Account`), 731 errorLine: 4, 732 errorPos: 26, 733 }, 734 { 735 name: "when accounts list includes a dupe entry", 736 config: ` 737 port = 4222 738 739 accounts = [foo, bar, bar] 740 741 http_port = 8222 742 `, 743 err: errors.New(`Duplicate Account Entry: bar`), 744 errorLine: 4, 745 errorPos: 25, 746 }, 747 { 748 name: "when accounts block includes a dupe user", 749 config: ` 750 port = 4222 751 752 accounts = { 753 nats { 754 users = [ 755 { user: "foo", pass: "bar" }, 756 { user: "hello", pass: "world" }, 757 { user: "foo", pass: "bar" } 758 ] 759 } 760 } 761 762 http_port = 8222 763 `, 764 err: errors.New(`Duplicate user "foo" detected`), 765 errorLine: 6, 766 errorPos: 21, 767 }, 768 { 769 name: "when accounts block imports are not a list", 770 config: ` 771 port = 4222 772 773 accounts = { 774 nats { 775 imports = true 776 } 777 } 778 779 http_port = 8222 780 `, 781 err: errors.New(`Imports should be an array, got bool`), 782 errorLine: 6, 783 errorPos: 21, 784 }, 785 { 786 name: "when accounts block exports are not a list", 787 config: ` 788 port = 4222 789 790 accounts = { 791 nats { 792 exports = true 793 } 794 } 795 796 http_port = 8222 797 `, 798 err: errors.New(`Exports should be an array, got bool`), 799 errorLine: 6, 800 errorPos: 21, 801 }, 802 { 803 name: "when accounts block imports items are not a map", 804 config: ` 805 port = 4222 806 807 accounts = { 808 nats { 809 imports = [ 810 false 811 ] 812 } 813 } 814 815 http_port = 8222 816 `, 817 err: errors.New(`Import Items should be a map with type entry, got bool`), 818 errorLine: 7, 819 errorPos: 23, 820 }, 821 { 822 name: "when accounts block export items are not a map", 823 config: ` 824 port = 4222 825 826 accounts = { 827 nats { 828 exports = [ 829 false 830 ] 831 } 832 } 833 834 http_port = 8222 835 `, 836 err: errors.New(`Export Items should be a map with type entry, got bool`), 837 errorLine: 7, 838 errorPos: 23, 839 }, 840 { 841 name: "when accounts exports has a stream name that is not a string", 842 config: ` 843 port = 4222 844 845 accounts = { 846 nats { 847 exports = [ 848 { 849 stream: false 850 } 851 ] 852 } 853 } 854 855 http_port = 8222 856 `, 857 err: errors.New(`Expected stream name to be string, got bool`), 858 errorLine: 8, 859 errorPos: 25, 860 }, 861 { 862 name: "when accounts exports has a service name that is not a string", 863 config: ` 864 accounts = { 865 nats { 866 exports = [ 867 { 868 service: false 869 } 870 ] 871 } 872 } 873 `, 874 err: errors.New(`Expected service name to be string, got bool`), 875 errorLine: 6, 876 errorPos: 25, 877 }, 878 { 879 name: "when accounts imports stream without name", 880 config: ` 881 port = 4222 882 883 accounts = { 884 nats { 885 imports = [ 886 { stream: { }} 887 ] 888 } 889 } 890 891 http_port = 8222 892 `, 893 err: errors.New(`Expect an account name and a subject`), 894 errorLine: 7, 895 errorPos: 25, 896 }, 897 { 898 name: "when accounts imports service without name", 899 config: ` 900 port = 4222 901 902 accounts = { 903 nats { 904 imports = [ 905 { service: { }} 906 ] 907 } 908 } 909 910 http_port = 8222 911 `, 912 err: errors.New(`Expect an account name and a subject`), 913 errorLine: 7, 914 errorPos: 25, 915 }, 916 { 917 name: "when account trace destination is of the wrong type", 918 config: ` 919 accounts { 920 A { trace_dest: 123 } 921 } 922 `, 923 err: errors.New(`Expected account message trace "trace_dest" to be a string or a map/struct, got int64`), 924 errorLine: 3, 925 errorPos: 23, 926 }, 927 { 928 name: "when account trace destination is not a valid destination", 929 config: ` 930 accounts { 931 A { trace_dest: "invalid..dest" } 932 } 933 `, 934 err: errors.New(`Trace destination "invalid..dest" is not valid`), 935 errorLine: 3, 936 errorPos: 23, 937 }, 938 { 939 name: "when account trace destination is not a valid publish subject", 940 config: ` 941 accounts { 942 A { trace_dest: "invalid.publish.*.subject" } 943 } 944 `, 945 err: errors.New(`Trace destination "invalid.publish.*.subject" is not valid`), 946 errorLine: 3, 947 errorPos: 23, 948 }, 949 { 950 name: "when account message trace dest is wrong type", 951 config: ` 952 accounts { 953 A { msg_trace: {dest: 123} } 954 } 955 `, 956 err: errors.New(`Field "dest" should be a string, got int64`), 957 errorLine: 3, 958 errorPos: 35, 959 }, 960 { 961 name: "when account message trace dest is invalid", 962 config: ` 963 accounts { 964 A { msg_trace: {dest: "invalid..dest"} } 965 } 966 `, 967 err: errors.New(`Trace destination "invalid..dest" is not valid`), 968 errorLine: 3, 969 errorPos: 35, 970 }, 971 { 972 name: "when account message trace sampling is wrong type", 973 config: ` 974 accounts { 975 A { msg_trace: {dest: "acc.dest", sampling: {wront: "type"}} } 976 } 977 `, 978 err: errors.New(`Trace destination sampling field "sampling" should be an integer or a percentage, got map[string]interface {}`), 979 errorLine: 3, 980 errorPos: 53, 981 }, 982 { 983 name: "when account message trace sampling is wrong string", 984 config: ` 985 accounts { 986 A { msg_trace: {dest: "acc.dest", sampling: abc%} } 987 } 988 `, 989 err: errors.New(`Invalid trace destination sampling value "abc%"`), 990 errorLine: 3, 991 errorPos: 53, 992 }, 993 { 994 name: "when account message trace sampling is negative", 995 config: ` 996 accounts { 997 A { msg_trace: {dest: "acc.dest", sampling: -1} } 998 } 999 `, 1000 err: errors.New(`Ttrace destination sampling value -1 is invalid, needs to be [1..100]`), 1001 errorLine: 3, 1002 errorPos: 53, 1003 }, 1004 { 1005 name: "when account message trace sampling is zero", 1006 config: ` 1007 accounts { 1008 A { msg_trace: {dest: "acc.dest", sampling: 0} } 1009 } 1010 `, 1011 err: errors.New(`Ttrace destination sampling value 0 is invalid, needs to be [1..100]`), 1012 errorLine: 3, 1013 errorPos: 53, 1014 }, 1015 { 1016 name: "when account message trace sampling is more than 100", 1017 config: ` 1018 accounts { 1019 A { msg_trace: {dest: "acc.dest", sampling: 101} } 1020 } 1021 `, 1022 err: errors.New(`Ttrace destination sampling value 101 is invalid, needs to be [1..100]`), 1023 errorLine: 3, 1024 errorPos: 53, 1025 }, 1026 { 1027 name: "when account message trace has unknown field", 1028 config: ` 1029 accounts { 1030 A { msg_trace: {wrong: "field"} } 1031 } 1032 `, 1033 err: errors.New(`Unknown field "wrong" parsing account message trace map/struct "msg_trace"`), 1034 errorLine: 3, 1035 errorPos: 35, 1036 }, 1037 { 1038 name: "when user authorization config has both token and users", 1039 config: ` 1040 authorization = { 1041 token = "s3cr3t" 1042 users = [ 1043 { 1044 user = "foo" 1045 pass = "bar" 1046 } 1047 ] 1048 } 1049 `, 1050 err: errors.New(`Can not have a token and a users array`), 1051 errorLine: 2, 1052 errorPos: 3, 1053 }, 1054 { 1055 name: "when user authorization config has both token and user", 1056 config: ` 1057 authorization = { 1058 user = "foo" 1059 pass = "bar" 1060 token = "baz" 1061 } 1062 `, 1063 err: errors.New(`Cannot have a user/pass and token`), 1064 errorLine: 2, 1065 errorPos: 3, 1066 }, 1067 { 1068 name: "when user authorization config has both user and users array", 1069 config: ` 1070 authorization = { 1071 user = "user1" 1072 pass = "pwd1" 1073 users = [ 1074 { 1075 user = "user2" 1076 pass = "pwd2" 1077 } 1078 ] 1079 } 1080 `, 1081 err: errors.New(`Can not have a single user/pass and a users array`), 1082 errorLine: 2, 1083 errorPos: 3, 1084 }, 1085 { 1086 name: "when user authorization has duplicate users", 1087 config: ` 1088 authorization = { 1089 users = [ 1090 {user: "user1", pass: "pwd"} 1091 {user: "user2", pass: "pwd"} 1092 {user: "user1", pass: "pwd"} 1093 ] 1094 } 1095 `, 1096 err: fmt.Errorf(`Duplicate user %q detected`, "user1"), 1097 errorLine: 2, 1098 errorPos: 3, 1099 }, 1100 { 1101 name: "when user authorization has duplicate nkeys", 1102 config: ` 1103 authorization = { 1104 users = [ 1105 {nkey: UC6NLCN7AS34YOJVCYD4PJ3QB7QGLYG5B5IMBT25VW5K4TNUJODM7BOX } 1106 {nkey: UBAAQWTW6CG2G6ANGNKB5U2B7HRWHSGMZEZX3AQSAJOQDAUGJD46LD2E } 1107 {nkey: UC6NLCN7AS34YOJVCYD4PJ3QB7QGLYG5B5IMBT25VW5K4TNUJODM7BOX } 1108 ] 1109 } 1110 `, 1111 err: fmt.Errorf(`Duplicate nkey %q detected`, "UC6NLCN7AS34YOJVCYD4PJ3QB7QGLYG5B5IMBT25VW5K4TNUJODM7BOX"), 1112 errorLine: 2, 1113 errorPos: 3, 1114 }, 1115 { 1116 name: "when user authorization config has users not as a list", 1117 config: ` 1118 authorization = { 1119 users = false 1120 } 1121 `, 1122 err: errors.New(`Expected users field to be an array, got false`), 1123 errorLine: 3, 1124 errorPos: 5, 1125 }, 1126 { 1127 name: "when user authorization config has users not as a map", 1128 config: ` 1129 authorization = { 1130 users = [false] 1131 } 1132 `, 1133 err: errors.New(`Expected user entry to be a map/struct, got false`), 1134 errorLine: 3, 1135 errorPos: 14, 1136 }, 1137 { 1138 name: "when user authorization config has permissions not as a map", 1139 config: ` 1140 authorization = { 1141 users = [{user: hello, pass: world}] 1142 permissions = false 1143 } 1144 `, 1145 err: errors.New(`Expected permissions to be a map/struct, got false`), 1146 errorLine: 4, 1147 errorPos: 19, 1148 }, 1149 { 1150 name: "when user authorization permissions config has invalid fields within allow", 1151 config: ` 1152 authorization { 1153 permissions { 1154 publish = { 1155 allow = [false, "hello", "world"] 1156 deny = ["foo", "bar"] 1157 } 1158 subscribe = {} 1159 } 1160 } 1161 `, 1162 err: errors.New(`Subject in permissions array cannot be cast to string`), 1163 errorLine: 5, 1164 errorPos: 18, 1165 }, 1166 { 1167 name: "when user authorization permissions config has invalid fields within deny", 1168 config: ` 1169 authorization { 1170 permissions { 1171 publish = { 1172 allow = ["hello", "world"] 1173 deny = [true, "foo", "bar"] 1174 } 1175 subscribe = {} 1176 } 1177 } 1178 `, 1179 err: errors.New(`Subject in permissions array cannot be cast to string`), 1180 errorLine: 6, 1181 errorPos: 17, 1182 }, 1183 { 1184 name: "when user authorization permissions config has invalid type", 1185 config: ` 1186 authorization { 1187 permissions { 1188 publish = { 1189 allow = false 1190 } 1191 subscribe = {} 1192 } 1193 } 1194 `, 1195 err: errors.New(`Expected subject permissions to be a subject, or array of subjects, got bool`), 1196 errorLine: 5, 1197 errorPos: 9, 1198 }, 1199 { 1200 name: "when user authorization permissions subject is invalid", 1201 config: ` 1202 authorization { 1203 permissions { 1204 publish = { 1205 allow = ["foo..bar"] 1206 } 1207 subscribe = {} 1208 } 1209 } 1210 `, 1211 err: errors.New(`subject "foo..bar" is not a valid subject`), 1212 errorLine: 5, 1213 errorPos: 9, 1214 }, 1215 { 1216 name: "when cluster config listen is invalid", 1217 config: ` 1218 cluster { 1219 listen = "0.0.0.0:XXXX" 1220 } 1221 `, 1222 err: errors.New(`could not parse port "XXXX"`), 1223 errorLine: 3, 1224 errorPos: 5, 1225 }, 1226 { 1227 name: "when cluster config includes multiple users", 1228 config: ` 1229 cluster { 1230 authorization { 1231 users = [] 1232 } 1233 } 1234 `, 1235 err: errors.New(`Cluster authorization does not allow multiple users`), 1236 errorLine: 3, 1237 errorPos: 5, 1238 }, 1239 { 1240 name: "when cluster routes are invalid", 1241 config: ` 1242 cluster { 1243 routes = [ 1244 "0.0.0.0:XXXX" 1245 # "0.0.0.0:YYYY" 1246 # "0.0.0.0:ZZZZ" 1247 ] 1248 } 1249 `, 1250 err: errors.New(`error parsing route url ["0.0.0.0:XXXX"]`), 1251 errorLine: 4, 1252 errorPos: 22, 1253 }, 1254 { 1255 name: "when setting invalid TLS config within cluster block", 1256 config: ` 1257 cluster { 1258 tls { 1259 } 1260 } 1261 `, 1262 err: nil, 1263 errorLine: 0, 1264 errorPos: 0, 1265 }, 1266 { 1267 name: "invalid lame_duck_duration type", 1268 config: ` 1269 lame_duck_duration: abc 1270 `, 1271 err: errors.New(`error parsing lame_duck_duration: time: invalid duration`), 1272 errorLine: 2, 1273 errorPos: 5, 1274 }, 1275 { 1276 name: "lame_duck_duration too small", 1277 config: ` 1278 lame_duck_duration: "5s" 1279 `, 1280 err: errors.New(`invalid lame_duck_duration of 5s, minimum is 30 seconds`), 1281 errorLine: 2, 1282 errorPos: 5, 1283 }, 1284 { 1285 name: "invalid lame_duck_grace_period type", 1286 config: ` 1287 lame_duck_grace_period: abc 1288 `, 1289 err: errors.New(`error parsing lame_duck_grace_period: time: invalid duration`), 1290 errorLine: 2, 1291 errorPos: 5, 1292 }, 1293 { 1294 name: "lame_duck_grace_period should be positive", 1295 config: ` 1296 lame_duck_grace_period: "-5s" 1297 `, 1298 err: errors.New(`invalid lame_duck_grace_period, needs to be positive`), 1299 errorLine: 2, 1300 errorPos: 5, 1301 }, 1302 { 1303 name: "when only setting TLS timeout for a leafnode remote", 1304 config: ` 1305 leafnodes { 1306 remotes = [ 1307 { 1308 url: "tls://nats:7422" 1309 tls { 1310 timeout: 0.01 1311 } 1312 } 1313 ] 1314 }`, 1315 err: nil, 1316 errorLine: 0, 1317 errorPos: 0, 1318 }, 1319 { 1320 name: "verify_cert_and_check_known_urls do not work for leaf nodes", 1321 config: ` 1322 leafnodes { 1323 remotes = [ 1324 { 1325 url: "tls://nats:7422" 1326 tls { 1327 timeout: 0.01 1328 verify_cert_and_check_known_urls: true 1329 } 1330 } 1331 ] 1332 }`, 1333 //Unexpected error after processing config: /var/folders/9h/6g_c9l6n6bb8gp331d_9y0_w0000gn/T/057996446:8:5: 1334 err: errors.New("verify_cert_and_check_known_urls not supported in this context"), 1335 errorLine: 8, 1336 errorPos: 5, 1337 }, 1338 { 1339 name: "when leafnode remotes use wrong type", 1340 config: ` 1341 leafnodes { 1342 remotes: { 1343 url: "tls://nats:7422" 1344 } 1345 }`, 1346 err: errors.New(`Expected remotes field to be an array, got map[string]interface {}`), 1347 errorLine: 3, 1348 errorPos: 5, 1349 }, 1350 { 1351 name: "when leafnode remotes url uses wrong type", 1352 config: ` 1353 leafnodes { 1354 remotes: [ 1355 { urls: 1234 } 1356 ] 1357 }`, 1358 err: errors.New(`Expected remote leafnode url to be an array or string, got 1234`), 1359 errorLine: 4, 1360 errorPos: 18, 1361 }, 1362 { 1363 name: "when leafnode min_version is wrong type", 1364 config: ` 1365 leafnodes { 1366 port: -1 1367 min_version = 123 1368 }`, 1369 err: errors.New(`interface conversion: interface {} is int64, not string`), 1370 errorLine: 4, 1371 errorPos: 6, 1372 }, 1373 { 1374 name: "when leafnode min_version has parsing error", 1375 config: ` 1376 leafnodes { 1377 port: -1 1378 min_version = bad.version 1379 }`, 1380 err: errors.New(`invalid leafnode's minimum version: invalid semver`), 1381 errorLine: 4, 1382 errorPos: 6, 1383 }, 1384 { 1385 name: "when leafnode min_version is too low", 1386 config: ` 1387 leafnodes { 1388 port: -1 1389 min_version = 2.7.9 1390 }`, 1391 err: errors.New(`the minimum version should be at least 2.8.0`), 1392 errorLine: 4, 1393 errorPos: 6, 1394 }, 1395 { 1396 name: "when setting latency tracking with a system account", 1397 config: ` 1398 system_account: sys 1399 1400 accounts { 1401 sys { users = [ {user: sys, pass: "" } ] } 1402 1403 nats.io: { 1404 users = [ { user : bar, pass: "" } ] 1405 1406 exports = [ 1407 { service: "nats.add" 1408 response: singleton 1409 latency: { 1410 sampling: 100% 1411 subject: "latency.tracking.add" 1412 } 1413 } 1414 1415 ] 1416 } 1417 } 1418 `, 1419 err: nil, 1420 errorLine: 0, 1421 errorPos: 0, 1422 }, 1423 { 1424 name: "when setting latency tracking with an invalid publish subject", 1425 config: ` 1426 system_account = sys 1427 accounts { 1428 sys { users = [ {user: sys, pass: "" } ] } 1429 1430 nats.io: { 1431 users = [ { user : bar, pass: "" } ] 1432 1433 exports = [ 1434 { service: "nats.add" 1435 response: singleton 1436 latency: "*" 1437 } 1438 ] 1439 } 1440 } 1441 `, 1442 err: errors.New(`Error adding service latency sampling for "nats.add" on subject "*": invalid publish subject`), 1443 errorLine: 3, 1444 errorPos: 17, 1445 }, 1446 { 1447 name: "when setting latency tracking on a stream", 1448 config: ` 1449 system_account = sys 1450 accounts { 1451 sys { users = [ {user: sys, pass: "" } ] } 1452 1453 nats.io: { 1454 users = [ { user : bar, pass: "" } ] 1455 1456 exports = [ 1457 { stream: "nats.add" 1458 latency: "foo" 1459 } 1460 ] 1461 } 1462 } 1463 `, 1464 err: errors.New(`Detected latency directive on non-service`), 1465 errorLine: 11, 1466 errorPos: 25, 1467 }, 1468 { 1469 name: "when setting allow_trace on a stream export (after)", 1470 config: ` 1471 system_account = sys 1472 accounts { 1473 sys { users = [ {user: sys, pass: "" } ] } 1474 1475 nats.io: { 1476 users = [ { user : bar, pass: "" } ] 1477 exports = [ { stream: "nats.add", allow_trace: true } ] 1478 } 1479 } 1480 `, 1481 err: errors.New(`Detected allow_trace directive on non-service`), 1482 errorLine: 8, 1483 errorPos: 55, 1484 }, 1485 { 1486 name: "when setting allow_trace on a stream export (before)", 1487 config: ` 1488 system_account = sys 1489 accounts { 1490 sys { users = [ {user: sys, pass: "" } ] } 1491 1492 nats.io: { 1493 users = [ { user : bar, pass: "" } ] 1494 exports = [ { allow_trace: true, stream: "nats.add" } ] 1495 } 1496 } 1497 `, 1498 err: errors.New(`Detected allow_trace directive on non-service`), 1499 errorLine: 8, 1500 errorPos: 35, 1501 }, 1502 { 1503 name: "when setting allow_trace on a service import (after)", 1504 config: ` 1505 accounts { 1506 A: { 1507 users = [ {user: user1, pass: ""} ] 1508 exports = [{service: "foo"}] 1509 } 1510 B: { 1511 users = [ {user: user2, pass: ""} ] 1512 imports = [ { service: {account: "A", subject: "foo"}, allow_trace: true } ] 1513 } 1514 } 1515 `, 1516 err: errors.New(`Detected allow_trace directive on a non-stream`), 1517 errorLine: 9, 1518 errorPos: 76, 1519 }, 1520 { 1521 name: "when setting allow_trace on a service import (before)", 1522 config: ` 1523 accounts { 1524 A: { 1525 users = [ {user: user1, pass: ""} ] 1526 exports = [{service: "foo"}] 1527 } 1528 B: { 1529 users = [ {user: user2, pass: ""} ] 1530 imports = [ { allow_trace: true, service: {account: "A", subject: "foo"} } ] 1531 } 1532 } 1533 `, 1534 err: errors.New(`Detected allow_trace directive on a non-stream`), 1535 errorLine: 9, 1536 errorPos: 35, 1537 }, 1538 { 1539 name: "when using duplicate service import subject", 1540 config: ` 1541 accounts { 1542 A: { 1543 users = [ {user: user1, pass: ""} ] 1544 exports = [ 1545 {service: "remote1"} 1546 {service: "remote2"} 1547 ] 1548 } 1549 B: { 1550 users = [ {user: user2, pass: ""} ] 1551 imports = [ 1552 {service: {account: "A", subject: "remote1"}, to: "local"} 1553 {service: {account: "A", subject: "remote2"}, to: "local"} 1554 ] 1555 } 1556 } 1557 `, 1558 err: errors.New(`Duplicate service import subject "local", previously used in import for account "A", subject "remote1"`), 1559 errorLine: 14, 1560 errorPos: 71, 1561 }, 1562 { 1563 name: "mixing single and multi users in leafnode authorization", 1564 config: ` 1565 leafnodes { 1566 authorization { 1567 user: user1 1568 password: pwd 1569 users = [{user: user2, password: pwd}] 1570 } 1571 } 1572 `, 1573 err: errors.New("can not have a single user/pass and a users array"), 1574 errorLine: 3, 1575 errorPos: 20, 1576 }, 1577 { 1578 name: "duplicate usernames in leafnode authorization", 1579 config: ` 1580 leafnodes { 1581 authorization { 1582 users = [ 1583 {user: user, password: pwd} 1584 {user: user, password: pwd} 1585 ] 1586 } 1587 } 1588 `, 1589 err: errors.New(`duplicate user "user" detected in leafnode authorization`), 1590 errorLine: 3, 1591 errorPos: 21, 1592 }, 1593 { 1594 name: "mqtt bad type", 1595 config: ` 1596 mqtt [ 1597 "wrong" 1598 ] 1599 `, 1600 err: errors.New(`Expected mqtt to be a map, got []interface {}`), 1601 errorLine: 2, 1602 errorPos: 17, 1603 }, 1604 { 1605 name: "mqtt bad listen", 1606 config: ` 1607 mqtt { 1608 listen: "xxxxxxxx" 1609 } 1610 `, 1611 err: errors.New(`could not parse address string "xxxxxxxx"`), 1612 errorLine: 3, 1613 errorPos: 21, 1614 }, 1615 { 1616 name: "mqtt bad host", 1617 config: ` 1618 mqtt { 1619 host: 1234 1620 } 1621 `, 1622 err: errors.New(`interface conversion: interface {} is int64, not string`), 1623 errorLine: 3, 1624 errorPos: 21, 1625 }, 1626 { 1627 name: "mqtt bad port", 1628 config: ` 1629 mqtt { 1630 port: "abc" 1631 } 1632 `, 1633 err: errors.New(`interface conversion: interface {} is string, not int64`), 1634 errorLine: 3, 1635 errorPos: 21, 1636 }, 1637 { 1638 name: "mqtt bad TLS", 1639 config: ` 1640 mqtt { 1641 port: -1 1642 tls { 1643 cert_file: "./configs/certs/server.pem" 1644 } 1645 } 1646 `, 1647 err: errors.New(`missing 'key_file' in TLS configuration`), 1648 errorLine: 4, 1649 errorPos: 21, 1650 }, 1651 { 1652 name: "connection types wrong type", 1653 config: ` 1654 authorization { 1655 users [ 1656 {user: a, password: pwd, allowed_connection_types: 123} 1657 ] 1658 } 1659 `, 1660 err: errors.New(`error parsing allowed connection types: unsupported type int64`), 1661 errorLine: 4, 1662 errorPos: 53, 1663 }, 1664 { 1665 name: "connection types content wrong type", 1666 config: ` 1667 authorization { 1668 users [ 1669 {user: a, password: pwd, allowed_connection_types: [ 1670 123 1671 WEBSOCKET 1672 ]} 1673 ] 1674 } 1675 `, 1676 err: errors.New(`error parsing allowed connection types: unsupported type in array int64`), 1677 errorLine: 5, 1678 errorPos: 32, 1679 }, 1680 { 1681 name: "connection types type unknown", 1682 config: ` 1683 authorization { 1684 users [ 1685 {user: a, password: pwd, allowed_connection_types: [ "UNKNOWN" ]} 1686 ] 1687 } 1688 `, 1689 err: fmt.Errorf("invalid connection types [%q]", "UNKNOWN"), 1690 errorLine: 4, 1691 errorPos: 53, 1692 }, 1693 { 1694 name: "websocket auth unknown var", 1695 config: ` 1696 websocket { 1697 authorization { 1698 unknown: "field" 1699 } 1700 } 1701 `, 1702 err: fmt.Errorf("unknown field %q", "unknown"), 1703 errorLine: 4, 1704 errorPos: 25, 1705 }, 1706 { 1707 name: "websocket bad tls", 1708 config: ` 1709 websocket { 1710 tls { 1711 cert_file: "configs/certs/server.pem" 1712 } 1713 } 1714 `, 1715 err: fmt.Errorf("missing 'key_file' in TLS configuration"), 1716 errorLine: 3, 1717 errorPos: 21, 1718 }, 1719 { 1720 name: "verify_cert_and_check_known_urls not support for websockets", 1721 config: ` 1722 websocket { 1723 tls { 1724 cert_file: "configs/certs/server.pem" 1725 key_file: "configs/certs/key.pem" 1726 verify_cert_and_check_known_urls: true 1727 } 1728 } 1729 `, 1730 err: fmt.Errorf("verify_cert_and_check_known_urls not supported in this context"), 1731 errorLine: 6, 1732 errorPos: 10, 1733 }, 1734 { 1735 name: "ambiguous store dir", 1736 config: ` 1737 store_dir: "foo" 1738 jetstream { 1739 store_dir: "bar" 1740 } 1741 `, 1742 err: fmt.Errorf(`Duplicate 'store_dir' configuration`), 1743 }, 1744 { 1745 name: "token not supported in cluster", 1746 config: ` 1747 cluster { 1748 port: -1 1749 authorization { 1750 token: "my_token" 1751 } 1752 } 1753 `, 1754 err: fmt.Errorf("Cluster authorization does not support tokens"), 1755 errorLine: 4, 1756 errorPos: 6, 1757 }, 1758 { 1759 name: "token not supported in gateway", 1760 config: ` 1761 gateway { 1762 port: -1 1763 name: "A" 1764 authorization { 1765 token: "my_token" 1766 } 1767 } 1768 `, 1769 err: fmt.Errorf("Gateway authorization does not support tokens"), 1770 errorLine: 5, 1771 errorPos: 6, 1772 }, 1773 { 1774 name: "wrong type for cluster pool size", 1775 config: ` 1776 cluster { 1777 port: -1 1778 pool_size: "abc" 1779 } 1780 `, 1781 err: fmt.Errorf("interface conversion: interface {} is string, not int64"), 1782 errorLine: 4, 1783 errorPos: 6, 1784 }, 1785 { 1786 name: "wrong type for cluster accounts", 1787 config: ` 1788 cluster { 1789 port: -1 1790 accounts: 123 1791 } 1792 `, 1793 err: fmt.Errorf("error parsing accounts: unsupported type int64"), 1794 errorLine: 4, 1795 errorPos: 6, 1796 }, 1797 { 1798 name: "wrong type for cluster compression", 1799 config: ` 1800 cluster { 1801 port: -1 1802 compression: 123 1803 } 1804 `, 1805 err: fmt.Errorf("field %q should be a boolean or a structure, got int64", "compression"), 1806 errorLine: 4, 1807 errorPos: 6, 1808 }, 1809 { 1810 name: "wrong type for cluster compression mode", 1811 config: ` 1812 cluster { 1813 port: -1 1814 compression: { 1815 mode: 123 1816 } 1817 } 1818 `, 1819 err: fmt.Errorf("interface conversion: interface {} is int64, not string"), 1820 errorLine: 5, 1821 errorPos: 7, 1822 }, 1823 { 1824 name: "wrong type for cluster compression rtt thresholds", 1825 config: ` 1826 cluster { 1827 port: -1 1828 compression: { 1829 mode: "s2_auto" 1830 rtt_thresholds: 123 1831 } 1832 } 1833 `, 1834 err: fmt.Errorf("interface conversion: interface {} is int64, not []interface {}"), 1835 errorLine: 6, 1836 errorPos: 7, 1837 }, 1838 { 1839 name: "invalid durations for cluster compression rtt thresholds", 1840 config: ` 1841 cluster { 1842 port: -1 1843 compression: { 1844 mode: "s2_auto" 1845 rtt_thresholds: [abc] 1846 } 1847 } 1848 `, 1849 err: fmt.Errorf("time: invalid duration %q", "abc"), 1850 errorLine: 6, 1851 errorPos: 7, 1852 }, 1853 { 1854 name: "invalid durations for cluster ping interval", 1855 config: ` 1856 cluster { 1857 port: -1 1858 ping_interval: -1 1859 ping_max: 6 1860 } 1861 `, 1862 err: fmt.Errorf(`invalid use of field "ping_interval": ping_interval should be converted to a duration`), 1863 errorLine: 4, 1864 errorPos: 6, 1865 }, 1866 { 1867 name: "invalid durations for cluster ping interval", 1868 config: ` 1869 cluster { 1870 port: -1 1871 ping_interval: '2m' 1872 ping_max: 6 1873 } 1874 `, 1875 warningErr: fmt.Errorf(`Cluster 'ping_interval' will reset to 30s which is the max for routes`), 1876 errorLine: 4, 1877 errorPos: 6, 1878 }, 1879 { 1880 name: "wrong type for leafnodes compression", 1881 config: ` 1882 leafnodes { 1883 port: -1 1884 compression: 123 1885 } 1886 `, 1887 err: fmt.Errorf("field %q should be a boolean or a structure, got int64", "compression"), 1888 errorLine: 4, 1889 errorPos: 6, 1890 }, 1891 { 1892 name: "wrong type for leafnodes compression mode", 1893 config: ` 1894 leafnodes { 1895 port: -1 1896 compression: { 1897 mode: 123 1898 } 1899 } 1900 `, 1901 err: fmt.Errorf("interface conversion: interface {} is int64, not string"), 1902 errorLine: 5, 1903 errorPos: 7, 1904 }, 1905 { 1906 name: "wrong type for leafnodes compression rtt thresholds", 1907 config: ` 1908 leafnodes { 1909 port: -1 1910 compression: { 1911 mode: "s2_auto" 1912 rtt_thresholds: 123 1913 } 1914 } 1915 `, 1916 err: fmt.Errorf("interface conversion: interface {} is int64, not []interface {}"), 1917 errorLine: 6, 1918 errorPos: 7, 1919 }, 1920 { 1921 name: "invalid durations for leafnodes compression rtt thresholds", 1922 config: ` 1923 leafnodes { 1924 port: -1 1925 compression: { 1926 mode: "s2_auto" 1927 rtt_thresholds: [abc] 1928 } 1929 } 1930 `, 1931 err: fmt.Errorf("time: invalid duration %q", "abc"), 1932 errorLine: 6, 1933 errorPos: 7, 1934 }, 1935 { 1936 name: "wrong type for remote leafnodes compression", 1937 config: ` 1938 leafnodes { 1939 port: -1 1940 remotes [ 1941 { 1942 url: "nats://127.0.0.1:123" 1943 compression: 123 1944 } 1945 ] 1946 } 1947 `, 1948 err: fmt.Errorf("field %q should be a boolean or a structure, got int64", "compression"), 1949 errorLine: 7, 1950 errorPos: 8, 1951 }, 1952 { 1953 name: "wrong type for remote leafnodes compression mode", 1954 config: ` 1955 leafnodes { 1956 port: -1 1957 remotes [ 1958 { 1959 url: "nats://127.0.0.1:123" 1960 compression: { 1961 mode: 123 1962 } 1963 } 1964 ] 1965 } 1966 `, 1967 err: fmt.Errorf("interface conversion: interface {} is int64, not string"), 1968 errorLine: 8, 1969 errorPos: 9, 1970 }, 1971 { 1972 name: "wrong type for remote leafnodes compression rtt thresholds", 1973 config: ` 1974 leafnodes { 1975 port: -1 1976 remotes [ 1977 { 1978 url: "nats://127.0.0.1:123" 1979 compression: { 1980 mode: "s2_auto" 1981 rtt_thresholds: 123 1982 } 1983 } 1984 ] 1985 } 1986 `, 1987 err: fmt.Errorf("interface conversion: interface {} is int64, not []interface {}"), 1988 errorLine: 9, 1989 errorPos: 9, 1990 }, 1991 { 1992 name: "invalid durations for remote leafnodes compression rtt thresholds", 1993 config: ` 1994 leafnodes { 1995 port: -1 1996 remotes [ 1997 { 1998 url: "nats://127.0.0.1:123" 1999 compression: { 2000 mode: "s2_auto" 2001 rtt_thresholds: [abc] 2002 } 2003 } 2004 ] 2005 } 2006 `, 2007 err: fmt.Errorf("time: invalid duration %q", "abc"), 2008 errorLine: 9, 2009 errorPos: 9, 2010 }, 2011 { 2012 name: "show warnings on empty configs without values", 2013 config: ``, 2014 warningErr: errors.New(`config has no values or is empty`), 2015 errorLine: 0, 2016 errorPos: 0, 2017 reason: "", 2018 }, 2019 { 2020 name: "show warnings on empty configs without values and only comments", 2021 config: `# Valid file but has no usable values. 2022 `, 2023 warningErr: errors.New(`config has no values or is empty`), 2024 errorLine: 0, 2025 errorPos: 0, 2026 reason: "", 2027 }, 2028 { 2029 name: "TLS handshake first, wrong type", 2030 config: ` 2031 port: -1 2032 tls { 2033 first: 123 2034 } 2035 `, 2036 err: fmt.Errorf("field %q should be a boolean or a string, got int64", "first"), 2037 errorLine: 4, 2038 errorPos: 6, 2039 }, 2040 { 2041 name: "TLS handshake first, wrong value", 2042 config: ` 2043 port: -1 2044 tls { 2045 first: "123" 2046 } 2047 `, 2048 err: fmt.Errorf("field %q's value %q is invalid", "first", "123"), 2049 errorLine: 4, 2050 errorPos: 6, 2051 }, 2052 { 2053 name: "TLS multiple certs", 2054 config: ` 2055 port: -1 2056 tls { 2057 certs: [ 2058 { cert_file: "configs/certs/server.pem", key_file: "configs/certs/key.pem"}, 2059 { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"}, 2060 ] 2061 } 2062 `, 2063 err: nil, 2064 }, 2065 { 2066 name: "TLS multiple certs, bad type", 2067 config: ` 2068 port: -1 2069 tls { 2070 certs: [ 2071 { cert_file: "configs/certs/server.pem", key_file: 123 }, 2072 { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"}, 2073 ] 2074 } 2075 `, 2076 err: fmt.Errorf("error parsing certificates config: unsupported type int64"), 2077 errorLine: 5, 2078 errorPos: 49, 2079 }, 2080 { 2081 name: "TLS multiple certs, missing key_file", 2082 config: ` 2083 port: -1 2084 tls { 2085 certs: [ 2086 { cert_file: "configs/certs/server.pem" } 2087 { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"} 2088 ] 2089 } 2090 `, 2091 err: fmt.Errorf("error parsing certificates config: both 'cert_file' and 'cert_key' options are required"), 2092 errorLine: 5, 2093 errorPos: 10, 2094 }, 2095 { 2096 name: "TLS multiple certs and single cert options at the same time", 2097 config: ` 2098 port: -1 2099 tls { 2100 cert_file: "configs/certs/server.pem" 2101 key_file: "configs/certs/key.pem" 2102 certs: [ 2103 { cert_file: "configs/certs/server.pem", key_file: "configs/certs/key.pem"}, 2104 { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"}, 2105 ] 2106 } 2107 `, 2108 err: fmt.Errorf("error parsing tls config, cannot combine 'cert_file' option with 'certs' option"), 2109 errorLine: 3, 2110 errorPos: 5, 2111 }, 2112 { 2113 name: "TLS multiple certs used but not configured, but cert_file configured", 2114 config: ` 2115 port: -1 2116 tls { 2117 cert_file: "configs/certs/server.pem" 2118 key_file: "configs/certs/key.pem" 2119 certs: [] 2120 } 2121 `, 2122 err: nil, 2123 }, 2124 { 2125 name: "TLS multiple certs, missing bad path", 2126 config: ` 2127 port: -1 2128 tls { 2129 certs: [ 2130 { cert_file: "configs/certs/cert.new.pem", key_file: "configs/certs/key.new.pem"} 2131 { cert_file: "configs/certs/server.pem", key_file: "configs/certs/key.new.pom" } 2132 ] 2133 } 2134 `, 2135 err: fmt.Errorf("error parsing X509 certificate/key pair 2/2: open configs/certs/key.new.pom: no such file or directory"), 2136 errorLine: 3, 2137 errorPos: 5, 2138 }, 2139 } 2140 2141 checkConfig := func(config string) error { 2142 opts := &Options{ 2143 CheckConfig: true, 2144 } 2145 return opts.ProcessConfigFile(config) 2146 } 2147 2148 checkErr := func(t *testing.T, err, expectedErr error) { 2149 t.Helper() 2150 switch { 2151 case err == nil && expectedErr == nil: 2152 // OK 2153 case err != nil && expectedErr == nil: 2154 t.Errorf("Unexpected error after processing config: %s", err) 2155 case err == nil && expectedErr != nil: 2156 t.Errorf("Expected %q error after processing invalid config but got nothing", expectedErr) 2157 } 2158 } 2159 for _, test := range tests { 2160 t.Run(test.name, func(t *testing.T) { 2161 conf := createConfFile(t, []byte(test.config)) 2162 err := checkConfig(conf) 2163 var expectedErr error 2164 2165 // Check for either warnings or errors. 2166 if test.err != nil { 2167 expectedErr = test.err 2168 } else if test.warningErr != nil { 2169 expectedErr = test.warningErr 2170 } 2171 2172 if err != nil && expectedErr != nil { 2173 var msg string 2174 2175 if test.errorPos > 0 { 2176 msg = fmt.Sprintf("%s:%d:%d: %s", conf, test.errorLine, test.errorPos, expectedErr.Error()) 2177 if test.reason != "" { 2178 msg += ": " + test.reason 2179 } 2180 } else if test.warningErr != nil { 2181 msg = expectedErr.Error() 2182 } else { 2183 msg = test.reason 2184 } 2185 2186 if !strings.Contains(err.Error(), msg) { 2187 t.Errorf("Expected:\n%q\ngot:\n%q", msg, err.Error()) 2188 } 2189 } 2190 2191 checkErr(t, err, expectedErr) 2192 }) 2193 } 2194 } 2195 2196 func TestConfigCheckIncludes(t *testing.T) { 2197 // Check happy path first. 2198 opts := &Options{ 2199 CheckConfig: true, 2200 } 2201 err := opts.ProcessConfigFile("./configs/include_conf_check_a.conf") 2202 if err != nil { 2203 t.Errorf("Unexpected error processing include files with configuration check enabled: %v", err) 2204 } 2205 2206 opts = &Options{ 2207 CheckConfig: true, 2208 } 2209 err = opts.ProcessConfigFile("./configs/include_bad_conf_check_a.conf") 2210 if err == nil { 2211 t.Errorf("Expected error processing include files with configuration check enabled: %v", err) 2212 } 2213 expectedErr := `include_bad_conf_check_b.conf:10:19: unknown field "monitoring_port"` + "\n" 2214 if err != nil && !strings.HasSuffix(err.Error(), expectedErr) { 2215 t.Errorf("Expected: \n%q, got\n: %q", expectedErr, err.Error()) 2216 } 2217 } 2218 2219 func TestConfigCheckMultipleErrors(t *testing.T) { 2220 opts := &Options{ 2221 CheckConfig: true, 2222 } 2223 err := opts.ProcessConfigFile("./configs/multiple_errors.conf") 2224 if err == nil { 2225 t.Errorf("Expected error processing config files with multiple errors check enabled: %v", err) 2226 } 2227 cerr, ok := err.(*processConfigErr) 2228 if !ok { 2229 t.Fatalf("Expected a configuration process error") 2230 } 2231 got := len(cerr.Warnings()) 2232 expected := 1 2233 if got != expected { 2234 t.Errorf("Expected a %d warning, got: %d", expected, got) 2235 } 2236 got = len(cerr.Errors()) 2237 // Could be 7 or 8 errors depending on internal ordering of the parsing. 2238 if got != 7 && got != 8 { 2239 t.Errorf("Expected 7 or 8 errors, got: %d", got) 2240 } 2241 2242 errMsg := err.Error() 2243 2244 errs := []string{ 2245 `./configs/multiple_errors.conf:12:1: invalid use of field "write_deadline": write_deadline should be converted to a duration`, 2246 `./configs/multiple_errors.conf:2:1: Cannot have a user/pass and token`, 2247 `./configs/multiple_errors.conf:10:1: unknown field "monitoring"`, 2248 `./configs/multiple_errors.conf:67:3: Cluster authorization does not allow multiple users`, 2249 `./configs/multiple_errors.conf:21:5: Not a valid public nkey for an account: "OC5GRL36RQV7MJ2GT6WQSCKDKJKYTK4T2LGLWJ2SEJKRDHFOQQWGGFQL"`, 2250 `./configs/multiple_errors.conf:26:9: Not a valid public nkey for a user`, 2251 `./configs/multiple_errors.conf:36:5: Not a valid public nkey for an account: "ODRZ42QBM7SXQDXXTSVWT2WLLFYOQGAFC4TO6WOAXHEKQHIXR4HFYJDS"`, 2252 `./configs/multiple_errors.conf:41:9: Not a valid public nkey for a user`, 2253 } 2254 for _, msg := range errs { 2255 found := strings.Contains(errMsg, msg) 2256 if !found { 2257 t.Fatalf("Expected to find error %q", msg) 2258 } 2259 } 2260 if got == 8 { 2261 extra := "./configs/multiple_errors.conf:54:5: Can not have a single user/pass and accounts" 2262 if !strings.Contains(errMsg, extra) { 2263 t.Fatalf("Expected to find error %q (%s)", extra, errMsg) 2264 } 2265 } 2266 }