Skip to content
Snippets Groups Projects
Commit c754102a authored by Manuel Kieweg's avatar Manuel Kieweg
Browse files

basic tests for grpc client

parent 94504d80
No related branches found
No related tags found
1 merge request!155Northbound Interface
Pipeline #71958 failed
...@@ -34,19 +34,13 @@ func Init(addr string) error { ...@@ -34,19 +34,13 @@ func Init(addr string) error {
return nil return nil
} }
func GetIds(addr string) error { func GetIds(addr string) ([]*ppb.PrincipalNetworkDomain,error) {
ctx := context.Background() ctx := context.Background()
resp, err := getAllCore(ctx, addr) resp, err := getAllCore(ctx, addr)
if err != nil { if err != nil {
return err return nil, err
}
for i, pnd := range resp.Pnd {
log.Infof("PND %v: %v", i+1, pnd.Id)
for j, sbi := range pnd.Sbi {
log.Infof("\tSBI %v: %v", j+1, sbi.Id)
}
} }
return nil return resp.Pnd, nil
} }
func getAllCore(ctx context.Context, addr string) (*pb.GetResponse, error) { func getAllCore(ctx context.Context, addr string) (*pb.GetResponse, error) {
...@@ -61,6 +55,99 @@ func getAllCore(ctx context.Context, addr string) (*pb.GetResponse, error) { ...@@ -61,6 +55,99 @@ func getAllCore(ctx context.Context, addr string) (*pb.GetResponse, error) {
return coreClient.Get(ctx, req) return coreClient.Get(ctx, req)
} }
func AddPnd(addr, name, description, sbi string) error {
coreClient, err := nbi.CoreClient(addr, grpcWithInsecure)
if err != nil {
return err
}
ctx := context.Background()
req := &pb.SetRequest{
Timestamp: time.Now().UnixNano(),
Pnd: []*pb.SetPnd{
{
Name: name,
Description: description,
Sbi: sbi,
},
},
}
resp, err := coreClient.Set(ctx, req)
if err != nil {
return err
}
log.Info(resp.Status.String())
return nil
}
func GetPnd(addr string, args ...string) (*pb.GetResponse, error) {
coreClient, err := nbi.CoreClient(addr, grpcWithInsecure)
if err != nil {
return nil,err
}
ctx := context.Background()
req := &pb.GetRequest{
Timestamp: time.Now().UnixNano(),
All: false,
Pid: args,
}
return coreClient.Get(ctx, req)
}
func GetChanges(addr, pnd string) (*ppb.GetResponse, error) {
ctx := context.Background()
client, err := nbi.PndClient(addr, grpcWithInsecure)
if err != nil {
return nil, err
}
req := &ppb.GetRequest{
Timestamp: time.Now().UnixNano(),
Request: &ppb.GetRequest_Change{
Change: &ppb.GetChange{
All: true,
},
},
Pid: pnd,
}
return client.Get(ctx, req)
}
func Commit(addr, pnd string, cuids ...string) (*ppb.SetResponse,error) {
changes := make([]*ppb.SetChange, len(cuids))
for i, arg := range cuids {
changes[i] = &ppb.SetChange{
Cuid: arg,
Op: ppb.SetChange_COMMIT,
}
}
return commitConfirm(addr, pnd, changes)
}
func Confirm(addr, pnd string, cuids ...string) (*ppb.SetResponse,error) {
changes := make([]*ppb.SetChange, len(cuids))
for i, arg := range cuids {
changes[i] = &ppb.SetChange{
Cuid: arg,
Op: ppb.SetChange_CONFIRM,
}
}
return commitConfirm(addr, pnd, changes)
}
func commitConfirm(addr, pnd string, changes []*ppb.SetChange) (*ppb.SetResponse,error) {
ctx := context.Background()
client, err := nbi.PndClient(addr, grpcWithInsecure)
if err != nil {
return nil, err
}
req := &ppb.SetRequest{
Timestamp: time.Now().UnixNano(),
Change: changes,
Pid: pnd,
}
return client.Set(ctx, req)
}
func AddDevice(addr, username, password, sbi, pnd, deviceAddress string) error { func AddDevice(addr, username, password, sbi, pnd, deviceAddress string) error {
pndClient, err := nbi.PndClient(addr, grpcWithInsecure) pndClient, err := nbi.PndClient(addr, grpcWithInsecure)
if err != nil { if err != nil {
...@@ -90,10 +177,10 @@ func AddDevice(addr, username, password, sbi, pnd, deviceAddress string) error { ...@@ -90,10 +177,10 @@ func AddDevice(addr, username, password, sbi, pnd, deviceAddress string) error {
return nil return nil
} }
func GetDevice(addr, pid, path string, did ...string) error { func GetDevice(addr, pid, path string, did ...string) (*ppb.GetResponse,error) {
pndClient, err := nbi.PndClient(addr, grpcWithInsecure) pndClient, err := nbi.PndClient(addr, grpcWithInsecure)
if err != nil { if err != nil {
return err return nil, err
} }
var all bool var all bool
...@@ -112,15 +199,10 @@ func GetDevice(addr, pid, path string, did ...string) error { ...@@ -112,15 +199,10 @@ func GetDevice(addr, pid, path string, did ...string) error {
Pid: pid, Pid: pid,
} }
ctx := context.Background() ctx := context.Background()
resp, err := pndClient.Get(ctx, req) return pndClient.Get(ctx, req)
if err != nil {
return err
}
log.Info(resp.String())
return nil
} }
func Update(addr, did, pid, path, value string) error { func Update(addr, did, pid, path, value string) (*ppb.SetResponse, error) {
req := &ppb.ChangeRequest{ req := &ppb.ChangeRequest{
Id: did, Id: did,
Path: path, Path: path,
...@@ -130,7 +212,7 @@ func Update(addr, did, pid, path, value string) error { ...@@ -130,7 +212,7 @@ func Update(addr, did, pid, path, value string) error {
return sendChangeRequest(addr, pid, req) return sendChangeRequest(addr, pid, req)
} }
func Replace(addr, did, pid, path, value string) error { func Replace(addr, did, pid, path, value string) (*ppb.SetResponse, error) {
req := &ppb.ChangeRequest{ req := &ppb.ChangeRequest{
Id: did, Id: did,
Path: path, Path: path,
...@@ -140,7 +222,7 @@ func Replace(addr, did, pid, path, value string) error { ...@@ -140,7 +222,7 @@ func Replace(addr, did, pid, path, value string) error {
return sendChangeRequest(addr, pid, req) return sendChangeRequest(addr, pid, req)
} }
func Delete(addr, did, pid, path string) error { func Delete(addr, did, pid, path string) (*ppb.SetResponse, error) {
req := &ppb.ChangeRequest{ req := &ppb.ChangeRequest{
Id: did, Id: did,
Path: path, Path: path,
...@@ -149,10 +231,10 @@ func Delete(addr, did, pid, path string) error { ...@@ -149,10 +231,10 @@ func Delete(addr, did, pid, path string) error {
return sendChangeRequest(addr, pid, req) return sendChangeRequest(addr, pid, req)
} }
func sendChangeRequest(addr, pid string, req *ppb.ChangeRequest) error { func sendChangeRequest(addr, pid string, req *ppb.ChangeRequest) (*ppb.SetResponse, error) {
pndClient, err := nbi.PndClient(addr, grpcWithInsecure) pndClient, err := nbi.PndClient(addr, grpcWithInsecure)
if err != nil { if err != nil {
return err return nil, err
} }
ctx := context.Background() ctx := context.Background()
r := &ppb.SetRequest{ r := &ppb.SetRequest{
...@@ -160,10 +242,5 @@ func sendChangeRequest(addr, pid string, req *ppb.ChangeRequest) error { ...@@ -160,10 +242,5 @@ func sendChangeRequest(addr, pid string, req *ppb.ChangeRequest) error {
ChangeRequest: []*ppb.ChangeRequest{req}, ChangeRequest: []*ppb.ChangeRequest{req},
Pid: pid, Pid: pid,
} }
resp, err := pndClient.Set(ctx, r) return pndClient.Set(ctx, r)
if err != nil {
return err
} }
log.Info(resp.String())
return nil
}
package cli
import (
pb "code.fbi.h-da.de/cocsn/api/go/gosdn/core"
ppb "code.fbi.h-da.de/cocsn/api/go/gosdn/pnd"
nbi "code.fbi.h-da.de/cocsn/gosdn/northbound/server"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
"context"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"k8s.io/apimachinery/pkg/util/rand"
"net"
"reflect"
"strconv"
"testing"
"time"
)
const unreachable = "203.0.113.10:6030"
const testPath = "/system/config/hostname"
const testUser = "admin"
const testPassword = "admin"
const testPid = "06aa4994-80f7-4751-99a4-6826b72d0057"
const testCuid = "cf628f4b-393d-44a5-affb-949dfe5c3c27"
const testDid = "1c37ff20-0169-44e0-bf37-b64787a979d5"
func startGrpcServer() (*grpc.Server, string, error) {
port := rand.IntnRange(1025, 65536)
sock := "localhost:" + strconv.Itoa(port)
pndc := nucleus.NewPndStore()
lis, err := net.Listen("tcp", sock)
if err != nil {
return nil, "", err
}
grpcServer := grpc.NewServer()
northbound := nbi.NewNBI(pndc)
pb.RegisterCoreServer(grpcServer, northbound.Core)
ppb.RegisterPndServer(grpcServer, northbound.Pnd)
go func() {
log.Fatal(grpcServer.Serve(lis))
}()
return grpcServer, sock, nil
}
func TestAddDevice(t *testing.T) {
type args struct {
username string
password string
sbi string
pnd string
deviceAddress string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "default",
args: args{
username: testUser,
password: testPassword,
sbi: "openconfig",
pnd: testPid,
deviceAddress: "",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
if err := AddDevice(sock, tt.args.username, tt.args.password, tt.args.sbi, tt.args.pnd, tt.args.deviceAddress); (err != nil) != tt.wantErr {
t.Errorf("AddDevice() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestAddPnd(t *testing.T) {
type args struct {
name string
description string
sbi string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "default",
args: args{
name: "test",
description: "test",
sbi: "openconfig",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
if err := AddPnd(sock, tt.args.name, tt.args.description, tt.args.sbi); (err != nil) != tt.wantErr {
t.Errorf("AddPnd() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestCommit(t *testing.T) {
type args struct {
pnd string
cuids []string
}
tests := []struct {
name string
args args
want ppb.SetResponseStatus
wantErr bool
}{
{
name: "default",
args: args{
pnd: testPid,
cuids: []string{
testCuid,
},
},
want: ppb.SetResponse_OK,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := Commit(sock, tt.args.pnd, tt.args.cuids...)
if err != nil {
if !tt.wantErr {
t.Errorf("Commit() error = %v, wantErr %v", err, tt.wantErr)
}
return
}
if !reflect.DeepEqual(got.Status, tt.want) {
t.Errorf("Commit() got = %v, want %v", got, tt.want)
}
})
}
}
func TestConfirm(t *testing.T) {
type args struct {
pnd string
cuids []string
}
tests := []struct {
name string
args args
want ppb.SetResponseStatus
wantErr bool
}{
{
name: "default",
args: args{
pnd: testPid,
cuids: []string{
testCuid,
},
},
want: ppb.SetResponse_OK,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := Confirm(sock, tt.args.pnd, tt.args.cuids...)
if err != nil {
if !tt.wantErr {
t.Errorf("Confirm() error = %v, wantErr %v", err, tt.wantErr)
}
return
}
if !reflect.DeepEqual(got.Status, tt.want) {
t.Errorf("Confirm() got = %v, want %v", got, tt.want)
}
})
}
}
func TestDelete(t *testing.T) {
type args struct {
did string
pid string
path string
}
tests := []struct {
name string
args args
want ppb.SetResponseStatus
wantErr bool
}{
{
name: "default",
args: args{
did: "",
pid: "",
path: "",
},
want: ppb.SetResponse_OK,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := Delete(sock, tt.args.did, tt.args.pid, tt.args.path)
if (err != nil) != tt.wantErr {
t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Delete() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGetChanges(t *testing.T) {
type args struct {
pnd string
}
tests := []struct {
name string
args args
want *ppb.GetResponse
wantErr bool
}{
{
name: "default",
args: args{
pnd: testPid,
},
want: &ppb.GetResponse{
Timestamp: time.Now().UnixNano(),
Pnd: &ppb.PrincipalNetworkDomain{},
Ond: nil,
Sbi: nil,
Change: nil,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := GetChanges(sock, tt.args.pnd)
if (err != nil) != tt.wantErr {
t.Errorf("GetChanges() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetChanges() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGetDevice(t *testing.T) {
type args struct {
pid string
path string
did []string
}
tests := []struct {
name string
args args
want *ppb.GetResponse
wantErr bool
}{
{
name: "default",
args: args{
pid: testPid,
path: testPath,
did: []string{testDid},
},
want: &ppb.GetResponse{
Timestamp: time.Now().UnixNano(),
Ond: []*ppb.OrchestratedNetworkingDevice{
{
Id: testDid,
Name: "testOnd",
Device: nil,
Sbi: nil,
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := GetDevice(sock, tt.args.pid, tt.args.path, tt.args.did...)
if (err != nil) != tt.wantErr {
t.Errorf("GetDevice() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetDevice() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGetIds(t *testing.T) {
tests := []struct {
name string
want []*ppb.PrincipalNetworkDomain
wantErr bool
}{
{
name: "default",
want: []*ppb.PrincipalNetworkDomain{
{
Id: testPid,
Name: "testPnd",
Description: "testPnd",
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := GetIds(sock)
if (err != nil) != tt.wantErr {
t.Errorf("GetIds() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetIds() got = %v, want %v", got, tt.want)
}
})
}
}
func TestGetPnd(t *testing.T) {
type args struct {
args []string
}
tests := []struct {
name string
args args
want *pb.GetResponse
wantErr bool
}{
{
name: "default",
args: args{args: []string{testPid}},
want: &pb.GetResponse{
Timestamp: time.Now().UnixNano(),
Pnd: []*ppb.PrincipalNetworkDomain{
{
Id: testPid,
Name: "testPnd",
Description: "testPnd",
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := GetPnd(sock, tt.args.args...)
if (err != nil) != tt.wantErr {
t.Errorf("GetPnd() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetPnd() got = %v, want %v", got, tt.want)
}
})
}
}
func TestInit(t *testing.T) {
tests := []struct {
name string
wantErr bool
}{
{
name: "default",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
if err := Init(sock); (err != nil) != tt.wantErr {
t.Errorf("Init() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestReplace(t *testing.T) {
type args struct {
did string
pid string
path string
value string
}
tests := []struct {
name string
args args
want *ppb.SetResponse
wantErr bool
}{
{
name: "default",
args: args{
did: testDid,
pid: testPid,
path: testPath,
value: "ceos3000",
},
want: &ppb.SetResponse{
Timestamp: time.Now().UnixNano(),
Status: ppb.SetResponse_OK,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := Replace(sock, tt.args.did, tt.args.pid, tt.args.path, tt.args.value)
if (err != nil) != tt.wantErr {
t.Errorf("Replace() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Replace() got = %v, want %v", got, tt.want)
}
})
}
}
func TestUpdate(t *testing.T) {
type args struct {
did string
pid string
path string
value string
}
tests := []struct {
name string
args args
want *ppb.SetResponse
wantErr bool
}{
{
name: "default",
args: args{
did: testDid,
pid: testPid,
path: testPath,
value: "ceos3000",
},
want: &ppb.SetResponse{
Timestamp: time.Now().UnixNano(),
Status: ppb.SetResponse_OK,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := Update(sock, tt.args.did, tt.args.pid, tt.args.path, tt.args.value)
if (err != nil) != tt.wantErr {
t.Errorf("Update() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Update() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_commitConfirm(t *testing.T) {
type args struct {
pnd string
changes []*ppb.SetChange
}
tests := []struct {
name string
args args
want *ppb.SetResponse
wantErr bool
}{
{
name: "default",
args: args{
pnd: testPid,
changes: []*ppb.SetChange{
{
Cuid: testCuid,
Op: ppb.SetChange_COMMIT,
},
},
},
want: &ppb.SetResponse{
Timestamp: time.Now().UnixNano(),
Status: ppb.SetResponse_OK,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := commitConfirm(sock, tt.args.pnd, tt.args.changes)
if (err != nil) != tt.wantErr {
t.Errorf("commitConfirm() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("commitConfirm() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_getAllCore(t *testing.T) {
tests := []struct {
name string
want *pb.GetResponse
wantErr bool
}{
{
name: "default",
want: &pb.GetResponse{
Timestamp: time.Now().UnixNano(),
Pnd: []*ppb.PrincipalNetworkDomain{
{
Id: testPid,
Name: "testPnd",
Description: "testPnd",
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
ctx := context.Background()
got, err := getAllCore(ctx, sock)
if (err != nil) != tt.wantErr {
t.Errorf("getAllCore() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("getAllCore() got = %v, want %v", got, tt.want)
}
})
}
}
func Test_sendChangeRequest(t *testing.T) {
type args struct {
pid string
req *ppb.ChangeRequest
}
tests := []struct {
name string
args args
want *ppb.SetResponse
wantErr bool
}{
{
name: "update",
args: args{
pid: testPid,
req: &ppb.ChangeRequest{
Id: testCuid,
Path: testPath,
Value: "ceos3000",
ApiOp: ppb.ChangeRequest_UPDATE,
},
},
want: nil,
wantErr: false,
},
{
name: "replace",
args: args{
pid: testPid,
req: &ppb.ChangeRequest{
Id: testCuid,
Path: testPath,
Value: "ceos3000",
ApiOp: ppb.ChangeRequest_REPLACE,
},
},
want: nil,
wantErr: false,
},
{
name: "delete",
args: args{
pid: testPid,
req: &ppb.ChangeRequest{
Id: testCuid,
Path: testPath,
ApiOp: ppb.ChangeRequest_DELETE,
},
},
want: nil,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, sock, err := startGrpcServer()
if err != nil {
if !tt.wantErr {
t.Error("startGrpcServer() error = cannot start grpc server")
}
return
}
defer server.Stop()
if tt.name == "unreachable" {
sock = unreachable
}
got, err := sendChangeRequest(sock, tt.args.pid, tt.args.req)
if (err != nil) != tt.wantErr {
t.Errorf("sendChangeRequest() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("sendChangeRequest() got = %v, want %v", got, tt.want)
}
})
}
}
package cli
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
const apiRoot = "?"
var builder *strings.Builder
func init() {
builder = &strings.Builder{}
}
// HTTPGet sends sends requests from the CLI to the gosdn HTTP API and processes any response data
func HTTPGet(apiEndpoint, f string, args ...string) error {
for _, p := range args {
builder.WriteString("&")
builder.WriteString(p)
}
resp, err := http.Get(apiEndpoint + apiRoot + "q=" + f + builder.String())
if err != nil {
log.Info(fmt.Sprintf("Err: %s", err))
return err
}
builder.Reset()
switch resp.StatusCode {
case http.StatusOK:
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
switch f {
case "init":
pnd := string(bytes[9:45])
sbi := string(bytes[55:91])
viper.Set("CLI_PND", pnd)
viper.Set("CLI_SBI", sbi)
err := viper.WriteConfig()
if err != nil {
log.Error(err)
}
default:
fmt.Println(string(bytes))
}
case http.StatusCreated:
defer resp.Body.Close()
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
uuid := string(bytes[19:55])
viper.Set("LAST_DEVICE_UUID", uuid)
fmt.Println(string(bytes))
case http.StatusAccepted:
default:
log.WithFields(log.Fields{
"status code": resp.StatusCode,
}).Error("operation unsuccessful")
return errors.New(resp.Status)
}
return nil
}
/*
Copyright © 2021 da/net research group <danet.fbi.h-da.de>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
package cmd
import (
"code.fbi.h-da.de/cocsn/gosdn/cli"
"github.com/spf13/cobra"
)
// addCmd represents the add command
var addCmd = &cobra.Command{
Use: "add",
Short: "adds a new principal network domain to the controller",
Long: `A principal network domain is a main networking entity. This can be a
campus building or site.
A description must be passed as positional argument. A name and default SBI can be
passed using flags`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return cli.AddPnd(apiEndpoint, pndName, args[0], pndDefaultSbi)
},
}
var pndName string
var pndDefaultSbi string
func init() {
pndCmd.AddCommand(addCmd)
addCmd.Flags().StringVar(&pndName, "name", "", "the name of the pnd")
addCmd.Flags().StringVar(&pndDefaultSbi, "sbi", "openconfig", "the default SBI of the pnd")
}
...@@ -46,15 +46,12 @@ only one value supported for now. ...@@ -46,15 +46,12 @@ only one value supported for now.
Use "set replace" or "set delete" respectively`, Use "set replace" or "set delete" respectively`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet( return cli.Update(
apiEndpoint, apiEndpoint,
"update", uuid,
"uuid="+uuid, cliPnd,
"cliSbi="+cliSbi, args[0],
"cliPnd="+cliPnd, args[1],
"path="+args[0],
"address="+address,
"value="+args[1],
) )
}, },
} }
......
...@@ -43,11 +43,10 @@ var commitCmd = &cobra.Command{ ...@@ -43,11 +43,10 @@ var commitCmd = &cobra.Command{
Short: "Commit the given change for the active PND", Short: "Commit the given change for the active PND",
Long: ``, Long: ``,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet( return cli.Commit(
apiEndpoint, apiEndpoint,
"change-commit", cliPnd,
"pnd="+cliPnd, args[0],
"cuid="+args[0],
) )
}, },
} }
......
...@@ -43,11 +43,10 @@ var confirmCmd = &cobra.Command{ ...@@ -43,11 +43,10 @@ var confirmCmd = &cobra.Command{
Short: "Confirms the given change for the active PND", Short: "Confirms the given change for the active PND",
Long: ``, Long: ``,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet( return cli.Confirm(
apiEndpoint, apiEndpoint,
"change-confirm", cliPnd,
"pnd="+cliPnd, args[0],
"cuid="+args[0],
) )
}, },
} }
......
...@@ -33,6 +33,7 @@ package cmd ...@@ -33,6 +33,7 @@ package cmd
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/cli" "code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
...@@ -42,7 +43,20 @@ var getIdsCmd = &cobra.Command{ ...@@ -42,7 +43,20 @@ var getIdsCmd = &cobra.Command{
Short: "gets device IDs from the controller", Short: "gets device IDs from the controller",
Long: `Gets device IDs from the controller and lists them.`, Long: `Gets device IDs from the controller and lists them.`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.GetIds(apiEndpoint) resp, err := cli.GetIds(apiEndpoint)
if err != nil {
return err
}
for i, pnd := range resp {
log.Infof("PND %v: %v\n\tuuid: %v", i+1, pnd.Name, pnd.Id)
for j, ond := range pnd.Ond {
log.Infof("\tSBI %v: %v\n\tuuid: %v", j+1, ond.Name, ond.Id)
}
for k, sbi := range pnd.Sbi {
log.Infof("\tSBI %v: %v", k+1, sbi.Id)
}
}
return nil
}, },
} }
......
/*
Copyright © 2021 da/net research group <danet.fbi.h-da.de>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
package cmd
import (
"code.fbi.h-da.de/cocsn/gosdn/cli"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
// getCmd represents the get command
var getCmd = &cobra.Command{
Use: "get",
Short: "get one or multiple pnds by uuid or name and print them to stdout",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
resp, err := cli.GetPnd(apiEndpoint, args...)
if err != nil {
return err
}
for i, pnd := range resp {
log.Infof("PND %v: %v\n\tuuid: %v", i+1, pnd.Name, pnd.Id)
if verbose {
for j, ond := range pnd.Ond {
log.Infof("\tSBI %v: %v\n\tuuid: %v", j+1, ond.Name, ond.Id)
}
for k, sbi := range pnd.Sbi {
log.Infof("\tSBI %v: %v", k+1, sbi.Id)
}
}
}
return nil
},
}
var verbose bool
func init() {
pndCmd.AddCommand(getCmd)
pndCmd.Flags().BoolVar(&verbose, "verbose", false, "show ond and sbi info")
}
...@@ -42,11 +42,7 @@ var listCmd = &cobra.Command{ ...@@ -42,11 +42,7 @@ var listCmd = &cobra.Command{
Short: "Lists all committed changes", Short: "Lists all committed changes",
Long: ``, Long: ``,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return cli.HTTPGet( return cli.ListChanges(apiEndpoint, cliPnd)
apiEndpoint,
"change-list",
"pnd="+cliPnd,
)
}, },
} }
......
/*
Copyright © 2021 da/net research group <danet.fbi.h-da.de>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
// pndCmd represents the pnd command
var pndCmd = &cobra.Command{
Use: "pnd",
Short: "A brief description of your command",
Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("pnd called")
},
}
func init() {
cliCmd.AddCommand(pndCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// pndCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// pndCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
...@@ -184,5 +184,61 @@ func fillChanges(pnd nucleus.PrincipalNetworkDomain) ([]*ppb.Change, error) { ...@@ -184,5 +184,61 @@ func fillChanges(pnd nucleus.PrincipalNetworkDomain) ([]*ppb.Change, error) {
} }
func (p pnd) Set(ctx context.Context, request *ppb.SetRequest) (*ppb.SetResponse, error) { func (p pnd) Set(ctx context.Context, request *ppb.SetRequest) (*ppb.SetResponse, error) {
panic("implement me") pid, err := uuid.Parse(request.Pid)
if err != nil {
return nil, err
}
ondResp, err := handleSetOnd(pid, request.Ond)
if err != nil {
return nil, err
}
sbiResp, err := handleSetSbi(pid, request.Sbi)
if err != nil {
return nil, err
}
changeResp, err := handleSetChange(pid, request.Change)
if err != nil {
return nil, err
}
changeRequestResp, err := handleChangeRequest(pid, request.ChangeRequest)
if err != nil {
return nil, err
}
return &ppb.SetResponse{
Timestamp: time.Now().UnixNano(),
Status: ppb.SetResponse_OK,
Responses: []*ppb.SetResponse{
ondResp,
sbiResp,
changeResp,
changeRequestResp,
},
}, nil
}
func handleSetOnd(pid uuid.UUID, req []*ppb.SetOnd) (*ppb.SetResponse, error) {
pndLock.Lock()
defer pndLock.Unlock()
pnd, err := pndc.Get(pid)
if err != nil {
return nil, err
}
for _,r := range req {
d, err := nucleus.NewDevice()
if err != nil {
return nil, err
}
}
}
func handleSetSbi(pid uuid.UUID, req []*ppb.SetSbi) (*ppb.SetResponse, error) {
}
func handleSetChange(pid uuid.UUID, change []*ppb.SetChange) (*ppb.SetResponse, error) {
}
func handleChangeRequest(pid uuid.UUID, req []*ppb.ChangeRequest) (*ppb.SetResponse, error) {
} }
...@@ -48,51 +48,6 @@ func TestCapabilities(t *testing.T) { ...@@ -48,51 +48,6 @@ func TestCapabilities(t *testing.T) {
} }
} }
func TestGet(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
type args struct {
a string
u string
p string
args []string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "default",
args: args{
a: testAddress,
u: testUsername,
p: testPassword,
args: defaultPath,
},
wantErr: false,
},
{
name: "destination unreachable",
args: args{
a: unreachable,
u: testUsername,
p: testPassword,
args: defaultPath,
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if _, err := cli.Get(tt.args.a, tt.args.u, tt.args.p, tt.args.args...); (err != nil) != tt.wantErr {
t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestHttpGet(t *testing.T) { func TestHttpGet(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("skipping integration test") t.Skip("skipping integration test")
...@@ -134,62 +89,3 @@ func TestHttpGet(t *testing.T) { ...@@ -134,62 +89,3 @@ func TestHttpGet(t *testing.T) {
}) })
} }
} }
func TestSet(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
type args struct {
a string
u string
p string
typ string
args []string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "default",
args: args{
a: testAddress,
u: testUsername,
p: testPassword,
typ: "update",
args: []string{"/system/config/hostname", "ceos3000"},
},
wantErr: false,
},
{
name: "destination unreachable",
args: args{
a: unreachable,
u: testUsername,
p: testPassword,
typ: "update",
args: []string{"/system/config/hostname", "ceos3000"},
},
wantErr: true,
},
{
name: "invalid path",
args: args{
a: testAddress,
u: testUsername,
p: testPassword,
typ: "update",
args: []string{"invalid/path", "ceos3000"},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := cli.Set(tt.args.a, tt.args.u, tt.args.p, tt.args.typ, tt.args.args...); (err != nil) != tt.wantErr {
t.Errorf("Set() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
...@@ -16,12 +16,12 @@ import ( ...@@ -16,12 +16,12 @@ import (
) )
const unreachable = "203.0.113.10:6030" const unreachable = "203.0.113.10:6030"
const testPath = "/system/config/hostname"
var testAddress = "141.100.70.171:6030" var testAddress = "141.100.70.171:6030"
var testAPIEndpoint = "http://gosdn-latest.apps.ocp.fbi.h-da.de/api" var testAPIEndpoint = "http://gosdn-latest.apps.ocp.fbi.h-da.de/api"
var testUsername = "admin" var testUsername = "admin"
var testPassword = "arista" var testPassword = "arista"
var defaultPath = []string{"/system/config/hostname"}
var opt *nucleus.GnmiTransportOptions var opt *nucleus.GnmiTransportOptions
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
...@@ -102,7 +102,7 @@ func TestCmdIntegration(t *testing.T) { ...@@ -102,7 +102,7 @@ func TestCmdIntegration(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
defer viper.Reset() defer viper.Reset()
if err := cli.HTTPGet(testAPIEndpoint, "init"); (err != nil) != tt.wantErr { if err := cli.Init(testAPIEndpoint); (err != nil) != tt.wantErr {
switch err.(type) { switch err.(type) {
case viper.ConfigFileNotFoundError: case viper.ConfigFileNotFoundError:
default: default:
...@@ -113,65 +113,67 @@ func TestCmdIntegration(t *testing.T) { ...@@ -113,65 +113,67 @@ func TestCmdIntegration(t *testing.T) {
cliPnd := viper.GetString("CLI_PND") cliPnd := viper.GetString("CLI_PND")
cliSbi := viper.GetString("CLI_SBI") cliSbi := viper.GetString("CLI_SBI")
if err := cli.HTTPGet( if err := cli.AddDevice(
testAPIEndpoint, testAPIEndpoint,
"addDevice", testUsername,
"address="+testAddress, testPassword,
"password="+testPassword, cliSbi,
"username="+testUsername, cliPnd,
"sbi="+cliSbi, testAddress,
"pnd="+cliPnd,
); (err != nil) != tt.wantErr { ); (err != nil) != tt.wantErr {
t.Errorf("gosdn cli add-device error = %v, wantErr %v", err, tt.wantErr) t.Errorf("gosdn cli add-device error = %v, wantErr %v", err, tt.wantErr)
return return
} }
did := viper.GetString("LAST_DEVICE_UUID") did := viper.GetString("LAST_DEVICE_UUID")
if err := cli.HTTPGet( _, err := cli.GetDevice(
testAPIEndpoint, testAPIEndpoint,
"request", cliPnd,
"uuid="+did, testPath,
"sbi="+cliSbi, did,
"pnd="+cliPnd, )
"path=/system/config/hostname", if (err != nil) != tt.wantErr {
); (err != nil) != tt.wantErr {
t.Errorf("gosdn cli request error = %v, wantErr %v", err, tt.wantErr) t.Errorf("gosdn cli request error = %v, wantErr %v", err, tt.wantErr)
return return
} }
if err := cli.HTTPGet( _, err = cli.GetDevice(
testAPIEndpoint, testAPIEndpoint,
"getDevice", cliPnd,
"address="+testAddress, "",
"uuid="+did, did,
"sbi="+cliSbi, )
"pnd="+cliPnd, if (err != nil) != tt.wantErr {
); (err != nil) != tt.wantErr {
t.Errorf("gosdn cli get-device error = %v, wantErr %v", err, tt.wantErr) t.Errorf("gosdn cli get-device error = %v, wantErr %v", err, tt.wantErr)
return return
} }
hostname := guuid.New().String() hostname := guuid.New().String()
if err := cli.HTTPGet( _, err = cli.Update(
testAPIEndpoint, testAPIEndpoint,
"update", did,
"address="+testAddress, cliPnd,
"uuid="+did, testPath,
"sbi="+cliSbi, hostname,
"pnd="+cliPnd, )
"path=/system/config/hostname", if (err != nil) != tt.wantErr {
"value="+hostname,
); (err != nil) != tt.wantErr {
t.Errorf("gosdn cli set error = %v, wantErr %v", err, tt.wantErr) t.Errorf("gosdn cli set error = %v, wantErr %v", err, tt.wantErr)
return return
} }
resp, err := cli.Get(testAddress, testUsername, testPassword, "/system/config/hostname") resp, err := cli.GetDevice(testAddress, testUsername, testPassword, testPath)
if (err != nil) != tt.wantErr { if err != nil {
t.Errorf("cli.Get() error = %v, wantErr %v", err, tt.wantErr) if !tt.wantErr {
t.Errorf("cli.Get() error = %v, wantErr %v", err, tt.wantErr)
}
return return
} }
got := resp.Notification[0].Update[0].Val.GetStringVal() var got string
if resp != nil {
got = resp.Ond[0].Name
} else {
t.Errorf("integration test failed got cannot be nil")
}
if got != hostname { if got != hostname {
t.Errorf("integration test failed = got: %v, want: %v", got, hostname) t.Errorf("integration test failed = got: %v, want: %v", got, hostname)
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment