package internal import ( "context" "testing" ) // NOTE: Assume MockLogger and SnapshotManager are defined for the test to run. // The actual implementation of LoadFilterChainFromYAML is assumed to be available // to the test file. // TestLoadFilterChainFromYAML_ComplexInput tests the functionality of LoadFilterChainFromYAML func TestLoadFilterChainFromYAML_ComplexInput(t *testing.T) { sm := &SnapshotManager{} ctx := context.Background() // The user's provided, valid YAML for a single FilterChain object validComplexYAML := ` filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http codec_type: AUTO upgrade_configs: - upgrade_type: websocket stream_idle_timeout: 0s normalize_path: true merge_slashes: true route_config: virtual_hosts: - name: printer_service domains: ["printer.jerxie.com"] routes: - match: { prefix: "/webcam" } route: { prefix_rewrite: "/", cluster: "_3d_printer_camera", max_stream_duration: {grpc_timeout_header_max: 0s} } - match: { prefix: "/" } route: { cluster: "_3d_printer_console"} http_filters: - name: envoy.filters.http.oauth2 typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.oauth2.v3.OAuth2 config: token_endpoint: cluster: _auth_server uri: auth.jerxie.com/token timeout: 3s authorization_endpoint: https://auth.jerxie.com/auth redirect_uri: "%REQ(x-forwarded-proto)%://%REQ(:authority)%/callback" redirect_path_matcher: path: exact: /callback signout_path: path: exact: /signout forward_bearer_token: true credentials: client_id: octoprint-portal token_secret: name: token sds_config: path: "/etc/envoy/token-secret.yaml" hmac_secret: name: hmac sds_config: path: "/etc/envoy/hmac-secret.yaml" auth_scopes: - openid - email - name: envoy.filters.http.jwt_authn typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication providers: provider1: remote_jwks: http_uri: uri: "https://auth.jerxie.com/keys" cluster: _auth_server timeout: 5s cache_duration: 600s from_headers: - name: Authorization value_prefix: "Bearer " payload_in_metadata: jwt_payload rules: - match: prefix: / requires: provider_name: provider1 - name: envoy.filters.http.lua typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua inline_code: | email = "" function envoy_on_request(request_handle) email = "" local meta = request_handle:streamInfo():dynamicMetadata() for key, value in pairs(meta:get("envoy.filters.http.jwt_authn")) do if key == "jwt_payload" then for k, v in pairs(value) do if k == "email" then print("login octoprint: "..v) email = v request_handle:headers():add("ENVOY_AUTHENTICATED_USER", v) end end end end end function envoy_on_response(response_handle) if email ~="" and email ~= "axieyangb@gmail.com" then response_handle:logInfo("Got unauthorized user, return 403 for user " ..email) response_handle:headers():add("set-cookie", "BearerToken=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT") response_handle:headers():add("set-cookie", "OauthHMAC=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT") response_handle:headers():add("set-cookie", "IdToken=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT") response_handle:headers():add("set-cookie", "OauthExpires=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT") end email = "" end - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router filter_chain_match: server_names: ["printer.jerxie.com", "printer.local"] transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_certificates: - certificate_chain: { filename: "/etc/certs/downstream/printer.jerxie.com/fullchain.pem" } private_key: { filename: "/etc/certs/downstream/printer.jerxie.com/privkey.pem" } ` tests := []struct { name string yamlStr string expectError bool expectedLen int // Expected number of network filters (top-level filters array) }{ { name: "Success_ComplexSingleFilterChain", yamlStr: validComplexYAML, expectError: false, expectedLen: 1, // Only one top-level network filter: http_connection_manager }, // Re-include sanity checks for robust testing { name: "Error_NoFiltersInChain", yamlStr: `filter_chain_match: { server_names: ["empty"] }`, expectError: true, expectedLen: 0, }, { name: "Error_InputIsAList", yamlStr: `- filters: []`, expectError: true, // Should fail unmarshaling a list into a single struct expectedLen: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { chain, err := sm.LoadFilterChainFromYAML(ctx, tt.yamlStr) if tt.expectError { if err == nil { t.Errorf("Expected an error but got nil") } if chain != nil { t.Errorf("Expected nil chain on error, but got non-nil") } } else { if err != nil { t.Fatalf("Expected no error but got: %v", err) } if chain == nil { t.Fatal("Expected non-nil filter chain, but got nil") } // 1. Check top-level filter count if len(chain.Filters) != tt.expectedLen { t.Errorf("Top-level filter count mismatch. Got %d, want %d", len(chain.Filters), tt.expectedLen) } // 2. Check a deeply nested value to ensure complex unmarshaling worked if len(chain.FilterChainMatch.ServerNames) == 0 || chain.FilterChainMatch.ServerNames[0] != "printer.jerxie.com" { t.Errorf("FilterChainMatch assertion failed. Expected server name 'printer.jerxie.com'") } // 3. Check the name of the top-level filter if chain.Filters[0].Name != "envoy.filters.network.http_connection_manager" { t.Errorf("Top-level filter name mismatch. Got %s", chain.Filters[0].Name) } } }) } }