package api import ( "context" "net" "os" "testing" "time" "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict" cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core" ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd" apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport" "code.fbi.h-da.de/danet/gosdn/controller/app" "code.fbi.h-da.de/danet/gosdn/controller/config" eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" "code.fbi.h-da.de/danet/gosdn/controller/mocks" nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/server" "code.fbi.h-da.de/danet/gosdn/controller/nucleus" "code.fbi.h-da.de/danet/gosdn/controller/nucleus/util/proto" rbacImpl "code.fbi.h-da.de/danet/gosdn/controller/rbac" "code.fbi.h-da.de/danet/gosdn/controller/topology" "code.fbi.h-da.de/danet/gosdn/controller/topology/links" "code.fbi.h-da.de/danet/gosdn/controller/topology/nodes" "code.fbi.h-da.de/danet/gosdn/controller/topology/ports" routingtables "code.fbi.h-da.de/danet/gosdn/controller/topology/routing-tables" "code.fbi.h-da.de/danet/gosdn/controller/topology/store" "code.fbi.h-da.de/danet/gosdn/models/generated/openconfig" "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/mock" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/test/bufconn" gpb "github.com/openconfig/gnmi/proto/gnmi" pb "google.golang.org/protobuf/proto" ) /* Based on this StackOverflow answer: https://stackoverflow.com/a/52080545/4378176 */ const bufSize = 1024 * 1024 const bufnet = "bufnet" const pndID = "2043519e-46d1-4963-9a8e-d99007e104b8" const changeID = "0992d600-f7d4-4906-9559-409b04d59a5f" const sbiID = "f6fd4b35-f039-4111-9156-5e4501bb8a5a" const mneID = "7e0ed8cc-ebf5-46fa-9794-741494914883" var pndStore networkdomain.PndStore var userService rbac.UserService var roleService rbac.RoleService var sbiStore southbound.Store var lis *bufconn.Listener var pndUUID uuid.UUID var sbiUUID uuid.UUID func bootstrapUnitTest() { dialOptions = []grpc.DialOption{ grpc.WithContextDialer(bufDialer), grpc.WithTransportCredentials(insecure.NewCredentials()), } lis = bufconn.Listen(bufSize) s := grpc.NewServer() changeUUID, err := uuid.Parse(changeID) if err != nil { log.Fatal(err) } pndUUID, err = uuid.Parse(pndID) if err != nil { log.Fatal(err) } sbiUUID, err = uuid.Parse(sbiID) if err != nil { log.Fatal(err) } mneUUID, err := uuid.Parse(mneID) if err != nil { log.Fatal(err) } eventService := eventservice.NewMockEventService() pndStore = nucleus.NewMemoryPndStore() sbiStore = nucleus.NewMemorySbiStore() userService = rbacImpl.NewUserService(rbacImpl.NewMemoryUserStore(), eventService) roleService = rbacImpl.NewRoleService(rbacImpl.NewMemoryRoleStore(), eventService) if err := clearAndCreateAuthTestSetup(); err != nil { log.Fatal(err) } previousHostname := "previousHostname" intendedHostname := "intendedHostname" mockChange := &mocks.Change{} mockChange.On("Age").Return(time.Hour) mockChange.On("State").Return(ppb.ChangeState_CHANGE_STATE_INCONSISTENT) mockChange.On("PreviousState").Return(&openconfig.Device{ System: &openconfig.OpenconfigSystem_System{ Config: &openconfig.OpenconfigSystem_System_Config{ Hostname: &previousHostname, }, }, }) mockChange.On("IntendedState").Return(&openconfig.Device{ System: &openconfig.OpenconfigSystem_System{ Config: &openconfig.OpenconfigSystem_System_Config{ Hostname: &intendedHostname, }, }, }) sbi := &nucleus.OpenConfig{} schema, err := sbi.Schema() if err != nil { log.Fatal(err) } mockNetworkElement := &mocks.NetworkElement{} mockNetworkElement.On("SBI").Return(sbi) mockNetworkElement.On("ID").Return(mneUUID) mockNetworkElement.On("GetModel").Return(schema.Root) mockNetworkElement.On("Name").Return("openconfig") mockNetworkElement.On("TransportAddress").Return("127.0.0.1:6030") mockNetworkElement.On("GetMetadata").Return(conflict.Metadata{ResourceVersion: 0}) mockPnd := mocks.NetworkDomain{} mockPnd.On("ID").Return(pndUUID) mockPnd.On("GetName").Return("test") mockPnd.On("GetDescription").Return("test") mockPnd.On("PendingChanges").Return([]uuid.UUID{changeUUID}) mockPnd.On("CommittedChanges").Return([]uuid.UUID{changeUUID}) mockPnd.On("GetChange", mock.Anything).Return(mockChange, nil) mockPnd.On("AddNetworkElement", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) mockPnd.On("GetNetworkElement", mock.Anything).Return(mockNetworkElement, nil) mockPnd.On("Commit", mock.Anything).Return(nil) mockPnd.On("Confirm", mock.Anything).Return(nil) mockPnd.On("NetworkElements").Return([]networkelement.NetworkElement{ &nucleus.CommonNetworkElement{ UUID: mneUUID, Model: &openconfig.Device{}, }, }) mockPnd.On("GetSBIs").Return([]mocks.SouthboundInterface{}) mockPnd.On("ChangeMNE", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, nil) if err := pndStore.Add(&mockPnd); err != nil { log.Fatal(err) } jwtManager := rbacImpl.NewJWTManager("", (10000 * time.Hour)) appService := app.NewMockAppService() nodeStore := store.NewGenericStore[nodes.Node]() nodeService := nodes.NewNodeService(nodeStore, eventService) portStore := store.NewGenericStore[ports.Port]() portService := ports.NewPortService(portStore, eventService) topoloyStore := store.NewGenericStore[links.Link]() topologyService := topology.NewTopologyService(topoloyStore, nodeService, portService, eventService) routeStore := store.NewGenericStore[routingtables.RoutingTable]() routeService := routingtables.NewRoutingTableService(routeStore, nodeService, portService, eventService) northbound := nbi.NewNBI( pndStore, userService, roleService, *jwtManager, topologyService, nodeService, portService, routeService, appService, &mockPnd, ) cpb.RegisterCoreServiceServer(s, northbound.Core) ppb.RegisterPndServiceServer(s, northbound.Pnd) apb.RegisterAuthServiceServer(s, northbound.Auth) apb.RegisterUserServiceServer(s, northbound.User) apb.RegisterRoleServiceServer(s, northbound.Role) go func() { if err := s.Serve(lis); err != nil { log.Fatalf("Server exited with error: %v", err) } }() } func bufDialer(context.Context, string) (net.Conn, error) { return lis.Dial() } const testPath = "/system/config/hostname" var testAddress = "10.254.254.105:6030" var testAPIEndpoint = "gosdn-latest.apps.ocp.fbi.h-da.de" var testUsername = "admin" var testPassword = "arista" var opt *tpb.TransportOption var gnmiMessages map[string]pb.Message func TestMain(m *testing.M) { bootstrapUnitTest() bootstrapIntegrationTest() os.Exit(m.Run()) } func bootstrapIntegrationTest() { log.SetLevel(config.LogLevel) addr := os.Getenv("CEOS_TEST_ENDPOINT") if addr != "" { testAddress = addr log.Infof("CEOS_TEST_ENDPOINT set to %v", testAddress) } api := os.Getenv("GOSDN_TEST_API_ENDPOINT") if api != "" { testAPIEndpoint = api log.Infof("GOSDN_TEST_API_ENDPOINT set to %v", testAPIEndpoint) } u := os.Getenv("GOSDN_TEST_USER") if u != "" { testUsername = u log.Infof("GOSDN_TEST_USER set to %v", testUsername) } p := os.Getenv("GOSDN_TEST_PASSWORD") if p != "" { testPassword = p log.Infof("GOSDN_TEST_PASSWORD set to %v", testPassword) } gnmiMessages = map[string]pb.Message{ "../test/proto/cap-resp-arista-ceos": &gpb.CapabilityResponse{}, "../test/proto/req-full-node": &gpb.GetRequest{}, "../test/proto/req-full-node-arista-ceos": &gpb.GetRequest{}, "../test/proto/req-interfaces-arista-ceos": &gpb.GetRequest{}, "../test/proto/req-interfaces-interface-arista-ceos": &gpb.GetRequest{}, "../test/proto/req-interfaces-wildcard": &gpb.GetRequest{}, "../test/proto/resp-full-node": &gpb.GetResponse{}, "../test/proto/resp-full-node-arista-ceos": &gpb.GetResponse{}, "../test/proto/resp-interfaces-arista-ceos": &gpb.GetResponse{}, "../test/proto/resp-interfaces-interface-arista-ceos": &gpb.GetResponse{}, "../test/proto/resp-interfaces-wildcard": &gpb.GetResponse{}, "../test/proto/resp-set-system-config-hostname": &gpb.SetResponse{}, } for k, v := range gnmiMessages { if err := proto.Read(k, v); err != nil { log.Fatalf("error parsing %v: %v", k, err) } } opt = &tpb.TransportOption{ Address: testAddress, Username: testUsername, Password: testPassword, } }