Copilot commented on code in PR #2551:
URL: 
https://github.com/apache/apisix-ingress-controller/pull/2551#discussion_r2335197670


##########
test/e2e/scaffold/scaffold.go:
##########
@@ -63,23 +63,41 @@ type Scaffold struct {
        dataplaneService *corev1.Service
        httpbinService   *corev1.Service
 
-       finalizers []func()
-
-       apisixHttpTunnel  *k8s.Tunnel
-       apisixHttpsTunnel *k8s.Tunnel
+       finalizers    []func()
+       apisixTunnels *Tunnels
 
        additionalGateways map[string]*GatewayResources
 
        runtimeOpts Options
        Deployer    Deployer
 }
 
+type Tunnels struct {
+       HTTP  *k8s.Tunnel
+       HTTPS *k8s.Tunnel
+       TCP   *k8s.Tunnel
+}
+
+func (t *Tunnels) Close() {
+       if t.HTTP != nil {
+               t.HTTP.Close()
+               t.HTTP = nil
+       }
+       if t.HTTPS != nil {
+               t.HTTPS.Close()
+               t.HTTPS = nil
+       }
+       if t.TCP != nil {
+               t.TCP.Close()
+               t.TCP = nil
+       }
+}

Review Comment:
   [nitpick] The Close method should handle panic scenarios. Consider using 
defer or recover to ensure all tunnels are closed even if one Close() call 
panics.



##########
test/e2e/crds/v2/streamroute.go:
##########
@@ -0,0 +1,222 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package v2
+
+import (
+       "fmt"
+       "time"
+
+       mqtt "github.com/eclipse/paho.mqtt.golang"
+       . "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+
+       "github.com/apache/apisix-ingress-controller/test/e2e/framework"
+       "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = Describe("Test ApisixRoute With StreamRoute", 
Label("apisix.apache.org", "v2", "apisixroute"), func() {
+       s := scaffold.NewDefaultScaffold()
+
+       BeforeEach(func() {
+               if framework.ProviderType != framework.ProviderTypeAPISIX {
+                       Skip("only support APISIX provider")
+               }
+               By("create GatewayProxy")
+               gatewayProxy := s.GetGatewayProxyYaml()
+               err := s.CreateResourceFromString(gatewayProxy)
+               Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy")
+               time.Sleep(5 * time.Second)
+
+               By("create IngressClass")
+               err = 
s.CreateResourceFromStringWithNamespace(s.GetIngressClassYaml(), "")
+               Expect(err).NotTo(HaveOccurred(), "creating IngressClass")
+               time.Sleep(5 * time.Second)
+       })
+
+       Context("TCP Proxy", func() {
+               apisixRoute := `
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  name: httpbin-tcp-route
+spec:
+  ingressClassName: %s
+  stream:
+  - name: rule1
+    protocol: TCP
+    match:
+      ingressPort: 9100
+    backend:
+      serviceName: httpbin-service-e2e-test
+      servicePort: 80
+`
+               It("stream tcp proxy", func() {
+                       err := 
s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace()))
+                       Expect(err).NotTo(HaveOccurred(), "creating 
ApisixRoute")
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Client: s.NewAPISIXClientWithTCPProxy(),
+                               Method: "GET",
+                               Path:   "/ip",
+                               Checks: []scaffold.ResponseCheckFunc{
+                                       scaffold.WithExpectedStatus(200),
+                                       
scaffold.WithExpectedBodyContains("origin"),
+                               },
+                       })
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Client: s.NewAPISIXClientWithTCPProxy(),
+                               Method: "GET",
+                               Path:   "/get",
+                               Headers: map[string]string{
+                                       "x-my-header": "x-my-value",
+                               },
+                               Checks: []scaffold.ResponseCheckFunc{
+                                       scaffold.WithExpectedStatus(200),
+                                       
scaffold.WithExpectedBodyContains("x-my-value"),
+                               },
+                       })
+               })
+       })
+
+       Context("UDP Proxy", func() {
+               apisixRoute := `
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  name: httpbin-udp-route
+spec:
+  ingressClassName: %s
+  stream:
+  - name: rule1
+    protocol: UDP
+    match:
+      ingressPort: 9200
+    backend:
+      serviceName: %s
+      servicePort: %d
+`
+               It("stream udp proxy", func() {
+                       dnsSvc := s.NewCoreDNSService()
+                       err := 
s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace(), dnsSvc.Name, 
dnsSvc.Spec.Ports[0].Port))
+                       Expect(err).NotTo(HaveOccurred(), "creating 
ApisixRoute")
+                       time.Sleep(20 * time.Second)
+
+                       svc := s.GetDataplaneService()
+
+                       // test dns query
+                       output, err := 
s.RunDigDNSClientFromK8s(fmt.Sprintf("@%s", svc.Name), "-p", "9200", 
"github.com")

Review Comment:
   [nitpick] Consider using a constant for the UDP port number (9200) instead 
of hardcoding it, since it's also used in the APISIX configuration and route 
definition.



##########
test/e2e/crds/v2/streamroute.go:
##########
@@ -0,0 +1,222 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package v2
+
+import (
+       "fmt"
+       "time"
+
+       mqtt "github.com/eclipse/paho.mqtt.golang"
+       . "github.com/onsi/ginkgo/v2"
+       . "github.com/onsi/gomega"
+
+       "github.com/apache/apisix-ingress-controller/test/e2e/framework"
+       "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
+)
+
+var _ = Describe("Test ApisixRoute With StreamRoute", 
Label("apisix.apache.org", "v2", "apisixroute"), func() {
+       s := scaffold.NewDefaultScaffold()
+
+       BeforeEach(func() {
+               if framework.ProviderType != framework.ProviderTypeAPISIX {
+                       Skip("only support APISIX provider")
+               }
+               By("create GatewayProxy")
+               gatewayProxy := s.GetGatewayProxyYaml()
+               err := s.CreateResourceFromString(gatewayProxy)
+               Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy")
+               time.Sleep(5 * time.Second)
+
+               By("create IngressClass")
+               err = 
s.CreateResourceFromStringWithNamespace(s.GetIngressClassYaml(), "")
+               Expect(err).NotTo(HaveOccurred(), "creating IngressClass")
+               time.Sleep(5 * time.Second)
+       })
+
+       Context("TCP Proxy", func() {
+               apisixRoute := `
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  name: httpbin-tcp-route
+spec:
+  ingressClassName: %s
+  stream:
+  - name: rule1
+    protocol: TCP
+    match:
+      ingressPort: 9100
+    backend:
+      serviceName: httpbin-service-e2e-test
+      servicePort: 80
+`
+               It("stream tcp proxy", func() {
+                       err := 
s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace()))
+                       Expect(err).NotTo(HaveOccurred(), "creating 
ApisixRoute")
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Client: s.NewAPISIXClientWithTCPProxy(),
+                               Method: "GET",
+                               Path:   "/ip",
+                               Checks: []scaffold.ResponseCheckFunc{
+                                       scaffold.WithExpectedStatus(200),
+                                       
scaffold.WithExpectedBodyContains("origin"),
+                               },
+                       })
+
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Client: s.NewAPISIXClientWithTCPProxy(),
+                               Method: "GET",
+                               Path:   "/get",
+                               Headers: map[string]string{
+                                       "x-my-header": "x-my-value",
+                               },
+                               Checks: []scaffold.ResponseCheckFunc{
+                                       scaffold.WithExpectedStatus(200),
+                                       
scaffold.WithExpectedBodyContains("x-my-value"),
+                               },
+                       })
+               })
+       })
+
+       Context("UDP Proxy", func() {
+               apisixRoute := `
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  name: httpbin-udp-route
+spec:
+  ingressClassName: %s
+  stream:
+  - name: rule1
+    protocol: UDP
+    match:
+      ingressPort: 9200
+    backend:
+      serviceName: %s
+      servicePort: %d
+`
+               It("stream udp proxy", func() {
+                       dnsSvc := s.NewCoreDNSService()
+                       err := 
s.CreateResourceFromString(fmt.Sprintf(apisixRoute, s.Namespace(), dnsSvc.Name, 
dnsSvc.Spec.Ports[0].Port))
+                       Expect(err).NotTo(HaveOccurred(), "creating 
ApisixRoute")
+                       time.Sleep(20 * time.Second)
+
+                       svc := s.GetDataplaneService()
+
+                       // test dns query
+                       output, err := 
s.RunDigDNSClientFromK8s(fmt.Sprintf("@%s", svc.Name), "-p", "9200", 
"github.com")
+                       Expect(err).NotTo(HaveOccurred(), "dig github.com via 
apisix udp proxy")
+                       Expect(output).To(ContainSubstring("ADDITIONAL 
SECTION"))
+
+                       time.Sleep(3 * time.Second)
+                       output = s.GetDeploymentLogs(scaffold.CoreDNSDeployment)
+                       Expect(output).To(ContainSubstring("github.com. udp"))
+               })
+       })
+
+       Context("Plugins", func() {
+               It("MQTT", func() {
+                       //nolint:misspell // eclipse-mosquitto is the correct 
image name
+                       mqttDeploy := `
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: mosquito

Review Comment:
   The deployment name should be 'mosquitto' (with double 't') to match the 
correct spelling of the Eclipse Mosquitto MQTT broker.



##########
internal/adc/translator/apisixroute.go:
##########
@@ -341,6 +349,20 @@ func (t *Translator) 
translateApisixRouteBackendResolveGranularityService(tctx *
        }, nil
 }
 
+func (t *Translator) translateApisixRouteStreamBackendResolveGranularity(tctx 
*provider.TranslateContext, arNN types.NamespacedName, backend 
apiv2.ApisixRouteStreamBackend) (adc.UpstreamNodes, error) {
+       tsBakcnd := apiv2.ApisixRouteHTTPBackend{

Review Comment:
   Variable name 'tsBakcnd' contains a typo. It should be 'tsBackend' for 
better readability.



##########
api/adc/types.go:
##########
@@ -195,15 +195,14 @@ type Timeout struct {
 
 // +k8s:deepcopy-gen=true
 type StreamRoute struct {
-       Description string            `json:"description,omitempty"`
-       ID          string            `json:"id,omitempty"`
-       Labels      map[string]string `json:"labels,omitempty"`
-       Name        string            `json:"name"`
-       Plugins     Plugins           `json:"plugins,omitempty"`
-       RemoteAddr  string            `json:"remote_addr,omitempty"`
-       ServerAddr  string            `json:"server_addr,omitempty"`
-       ServerPort  *int64            `json:"server_port,omitempty"`
-       Sni         string            `json:"sni,omitempty"`
+       Metadata `json:",inline" yaml:",inline"`
+
+       Labels     map[string]string `json:"labels,omitempty"`
+       Plugins    Plugins           `json:"plugins,omitempty"`
+       RemoteAddr string            `json:"remote_addr,omitempty"`
+       ServerAddr string            `json:"server_addr,omitempty"`
+       ServerPort int32             `json:"server_port,omitempty"`

Review Comment:
   [nitpick] The ServerPort field type changed from *int64 to int32. This could 
be a breaking change if existing code expects the pointer type or int64 range. 
Consider documenting this change or using the same type for consistency.



##########
test/e2e/scaffold/assertion.go:
##########
@@ -194,8 +212,10 @@ func (s *Scaffold) RequestAssert(r *RequestAssert) bool {
                r.Checks = append(r.Checks, r.Check)
        }
 
-       return EventuallyWithOffset(1, func() error {
-               req := r.request(r.Method, r.Path, r.Body)
+       return EventuallyWithOffset(1, func() (err error) {
+               reporter := &ErrorReporter{}
+
+               req := r.request(r.Method, r.Path, 
r.Body).WithReporter(reporter)

Review Comment:
   [nitpick] The ErrorReporter is created inside the retry loop. Consider 
creating it once outside the loop and resetting its error state in each 
iteration to avoid unnecessary allocations.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to