Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ used for mTLS.
| service-1.3 | gNSI client | gNSI authz Get works |
| service-1.4 | gRIBI client | gRIBI Get works |
| service-1.5 | p4rt client | P4RT Capabilities works |
| service-1.6 | gNMI PQC client | gNMI Get works |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add these to the testregistry.textproto at the root of the repo please?

| service-1.7 | gNOI PQC client | gNOI system Time works |
| service-1.8 | gNSI PQC client | gNSI authz Get works |
| service-1.9 | gRIBI PQC client | gRIBI Get works |
| service-1.10 | p4rt PQC client | P4RT Capabilities works |
Comment on lines +33 to +37
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the description here, can we call out that these are specifically for PQC-algorithms or just differentiate them somehow from the ones that above?


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be useful to have some verbiage in the README that describes what the PQC tests do differently to the base tests.

1. Configure DUT with service configurations for all required services
2. Each test will then create a client to those services and valid each service is properly
Expand All @@ -38,6 +43,8 @@ used for mTLS.

## OpenConfig Path and RPC Coverage

## OpenConfig Path and RPC Coverage
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this heading to be repeated?


```yaml
paths:
/system/state/motd-banner:
Expand All @@ -55,3 +62,19 @@ rpcs:
gribi:
gRIBI.Get:
```
## Canonical OC
```json
{
"system": {
"state": {
"motd-banner": "<string>",
"login-banner": "<string>",
"hostname": "<string>",
"current-datetime": "2022-01-01T00:00:00Z",
"boot-time": "0"
}
}
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
Copyright 2026 Google LLC

Licensed 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

https://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 system_g_protocol_test

import (
"context"
"crypto/tls"
"fmt"
"testing"

"github.com/openconfig/featureprofiles/internal/deviations"
"github.com/openconfig/ondatra"
"github.com/openconfig/ondatra/binding/introspect"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/status"

gpb "github.com/openconfig/gnmi/proto/gnmi"
spb "github.com/openconfig/gnoi/system"
authzpb "github.com/openconfig/gnsi/authz"
gribipb "github.com/openconfig/gribi/v1/proto/service"
p4rtpb "github.com/p4lang/p4runtime/go/p4/v1"
)

func dialPQCConn(t *testing.T, dut *ondatra.DUTDevice, svc introspect.Service, wantPort uint32, nonStandardPort bool) *grpc.ClientConn {
Comment thread
marcushines marked this conversation as resolved.
t.Helper()
if svc == introspect.GNOI || svc == introspect.GNSI {
// Renaming service name due to gnoi and gnsi always residing on same port as gnmi.
svc = introspect.GNMI
}
dialer := introspect.DUTDialer(t, dut, svc)
t.Logf("Dialing %s on %s (Port: %d) with PQC", svc, dialer.DialTarget, dialer.DevicePort)
if !nonStandardPort {
if dialer.DevicePort != int(wantPort) {
t.Fatalf("DUT is not listening on standard port for %q: got %d, want %d", svc, dialer.DevicePort, wantPort)
}
}

// Custom TLS config for PQC
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
CurvePreferences: []tls.CurveID{tls.X25519MLKEM768, tls.X25519, tls.CurveP256},
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider just adding a parameter to the existing dialConn in system_g_protocol_test.go that takes the CurvePreferences or the tls.Config so that we don't duplicate the whole fn?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you did this, you could probably make it such that you just have a table-driven test for each of the existing TestXXX functions with the different parameters.

}

target := fmt.Sprintf("%s:%d", dialer.DialTarget, dialer.DevicePort)
conn, err := grpc.NewClient(target, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)))
if err != nil {
t.Fatalf("grpc.NewClient failed to: %q, error: %v", target, err)
}
t.Logf("Successfully dialed %s on %s with PQC", svc, target)
return conn
}

// TestPQCGNMIClient validates that the DUT listens on standard gNMI Port and supports PQC.
func TestPQCGNMIClient(t *testing.T) {
dut := ondatra.DUT(t, "dut")
conn := dialPQCConn(t, dut, introspect.GNMI, 9339, deviations.NonStandardGRPCPort(dut))
defer conn.Close()
c := gpb.NewGNMIClient(conn)

var req *gpb.GetRequest
if deviations.GNMIGetOnRootUnsupported(dut) {
req = &gpb.GetRequest{
Path: []*gpb.Path{{
Elem: []*gpb.PathElem{}}},
Type: gpb.GetRequest_CONFIG,
Encoding: gpb.Encoding_JSON_IETF,
}

} else {
req = &gpb.GetRequest{Encoding: gpb.Encoding_JSON_IETF, Path: []*gpb.Path{{Elem: []*gpb.PathElem{}}}}
}

if _, err := c.Get(context.Background(), req); err != nil {
t.Fatalf("gnmi.Get failed: %v", err)
}
}

// TestPQCGNOIClient validates that the DUT listens on standard gNOI Port and supports PQC.
func TestPQCGNOIClient(t *testing.T) {
dut := ondatra.DUT(t, "dut")
conn := dialPQCConn(t, dut, introspect.GNOI, 9339, deviations.NonStandardGRPCPort(dut))
defer conn.Close()
c := spb.NewSystemClient(conn)
if _, err := c.Ping(context.Background(), &spb.PingRequest{}); err != nil {
t.Fatalf("gnoi.system.Ping failed: %v", err)
}
}

// TestPQCGNSIClient validates that the DUT listens on standard gNSI Port and supports PQC.
func TestPQCGNSIClient(t *testing.T) {
dut := ondatra.DUT(t, "dut")
conn := dialPQCConn(t, dut, introspect.GNSI, 9339, deviations.NonStandardGRPCPort(dut))
defer conn.Close()
c := authzpb.NewAuthzClient(conn)
rsp, err := c.Get(context.Background(), &authzpb.GetRequest{})
if err != nil {
statusError, _ := status.FromError(err)
if statusError.Code() == codes.FailedPrecondition {
t.Logf("Expected error FAILED_PRECONDITION seen for authz Get Request.")
return
}
t.Fatalf("Unexpected error during authz Get Request: %v", err)
}
t.Logf("gNSI authz get response is %s", rsp)
Comment thread
marcushines marked this conversation as resolved.
}

// TestPQCGRIBIClient validates that the DUT listens on standard gRIBI Port and supports PQC.
func TestPQCGRIBIClient(t *testing.T) {
dut := ondatra.DUT(t, "dut")
conn := dialPQCConn(t, dut, introspect.GRIBI, 9340, deviations.NonStandardGRPCPort(dut))
defer conn.Close()
c := gribipb.NewGRIBIClient(conn)
if _, err := c.Get(context.Background(), &gribipb.GetRequest{}); err != nil {
t.Fatalf("gribi.Get failed: %v", err)
}
}

// TestPQCP4RTClient validates that the DUT listens on standard P4RT Port and supports PQC.
func TestPQCP4RTClient(t *testing.T) {
dut := ondatra.DUT(t, "dut")
conn := dialPQCConn(t, dut, introspect.P4RT, 9559, deviations.NonStandardGRPCPort(dut))
defer conn.Close()
c := p4rtpb.NewP4RuntimeClient(conn)
if deviations.P4RTCapabilitiesUnsupported(dut) {
if _, err := c.Read(context.Background(), &p4rtpb.ReadRequest{
DeviceId: 1,
Entities: []*p4rtpb.Entity{
{
Entity: &p4rtpb.Entity_TableEntry{},
},
},
}); err != nil {
t.Fatalf("p4rt.Read failed: %v", err)
}
} else {
if _, err := c.Capabilities(context.Background(), &p4rtpb.CapabilitiesRequest{}); err != nil {
t.Fatalf("p4rt.Capabilites failed: %v", err)
}
}
}
Loading