blob: db1b28bdad3fc0e56c8980a2fca72fb3a57e0dad [file] [log] [blame]
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001/*
Joey Armstrong7a9af442024-01-03 19:26:36 -05002 * Copyright 2020-2024 Open Networking Foundation (ONF) and the ONF Contributors
Mahir Gunyel03de0d32020-06-03 01:36:59 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// Package core Common Logger initialization
18package test
19
20import (
khenaidood948f772021-08-11 17:49:24 -040021 "bufio"
Rohan Agrawal31f21802020-06-12 05:38:46 +000022 "context"
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +053023 "crypto/rand"
khenaidood948f772021-08-11 17:49:24 -040024 "encoding/json"
25 "fmt"
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +053026 "io"
khenaidood948f772021-08-11 17:49:24 -040027 "os"
28 "path/filepath"
29 "strings"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070030 "testing"
khenaidood948f772021-08-11 17:49:24 -040031
khenaidoo9beaaf12021-10-19 17:32:01 -040032 ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
khenaidood948f772021-08-11 17:49:24 -040033
Mahir Gunyel03de0d32020-06-03 01:36:59 -070034 "github.com/opencord/voltha-go/rw_core/config"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070035 cm "github.com/opencord/voltha-go/rw_core/mocks"
khenaidood948f772021-08-11 17:49:24 -040036 "github.com/opencord/voltha-lib-go/v7/pkg/db/kvstore"
37 "github.com/opencord/voltha-lib-go/v7/pkg/log"
38 mock_etcd "github.com/opencord/voltha-lib-go/v7/pkg/mocks/etcd"
39 "github.com/opencord/voltha-lib-go/v7/pkg/version"
40 "github.com/opencord/voltha-protos/v5/go/voltha"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070041 "github.com/phayes/freeport"
42 "github.com/stretchr/testify/assert"
43 "google.golang.org/grpc/codes"
44 "google.golang.org/grpc/status"
45)
46
47const (
48 OltAdapter = iota
49 OnuAdapter
50)
51
khenaidood948f772021-08-11 17:49:24 -040052type AdapterInfo struct {
khenaidood948f772021-08-11 17:49:24 -040053 Vendor string
54 DeviceType string
55 ChildDeviceType string
56 ChildVendor string
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +053057 TotalReplica int32
khenaidood948f772021-08-11 17:49:24 -040058}
59
60// prettyPrintDeviceUpdateLog is used just for debugging and exploring the Core logs
61func prettyPrintDeviceUpdateLog(inputFile string, deviceID string) {
62 file, err := os.Open(filepath.Clean(inputFile))
63 if err != nil {
64 logger.Fatal(context.Background(), err)
65 }
66 defer func() {
67 if err := file.Close(); err != nil {
68 logger.Errorw(context.Background(), "file-close-error", log.Fields{"error": err})
69 }
70 }()
71
72 var logEntry struct {
73 Level string `json:"level"`
74 Ts string `json:"ts"`
75 Caller string `json:"caller"`
76 Msg string `json:"msg"`
77 RPC string `json:"rpc"`
78 DeviceID string `json:"device-id"`
79 RequestedBy string `json:"requested-by"`
80 StateChange string `json:"state-change"`
81 Status string `json:"status"`
82 Description string `json:"description"`
83 }
84
85 scanner := bufio.NewScanner(file)
86 fmt.Println("Timestamp\t\t\tDeviceId\t\t\t\tStatus\t\t\tRPC\t\t\tRequestedBy\t\t\tStateChange\t\t\tDescription")
87 for scanner.Scan() {
88 input := scanner.Text()
89 // Look for device update logs only
90 if !strings.Contains(input, "device-operation") || !strings.Contains(input, "requested-by") {
91 continue
92 }
93 // Check if deviceID is required
94 if deviceID != "" {
95 if !strings.Contains(input, deviceID) {
96 continue
97 }
98 }
99 if err := json.Unmarshal([]byte(input), &logEntry); err != nil {
100 logger.Fatal(context.Background(), err)
101 }
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530102 fmt.Printf("%s\t%s\t%s\t%-30.30q\t%-16.16s\t%-25.25s\t%s",
103 logEntry.Ts,
104 logEntry.DeviceID,
105 logEntry.Status,
106 logEntry.RPC,
107 logEntry.RequestedBy,
108 logEntry.StateChange,
109 logEntry.Description)
khenaidood948f772021-08-11 17:49:24 -0400110 }
111}
112
113func omciLog(inputFile string, deviceID string) {
114 file, err := os.Open(filepath.Clean(inputFile))
115 if err != nil {
116 logger.Fatal(context.Background(), err)
117 }
118 defer func() {
119 if err := file.Close(); err != nil {
120 logger.Errorw(context.Background(), "file-close-error", log.Fields{"error": err})
121 }
122 }()
123
124 var logEntry struct {
125 Level string `json:"level"`
126 Ts string `json:"ts"`
127 Caller string `json:"caller"`
128 Msg string `json:"msg"`
129 InstanceID string `json:"instanceId"`
130 ChildDeviceID string `json:"child-device-id"`
131 OmciMsg string `json:"omciMsg"`
132 IntfID string `json:"intf-id"`
133 OnuID string `json:"onu-id"`
134 OmciTrns int `json:"omciTransactionID"`
135 }
136
137 scanner := bufio.NewScanner(file)
138 uniqueTnsIDs := map[int]int{}
139 for scanner.Scan() {
140 input := scanner.Text()
141 // Look for device update logs only
142 if !strings.Contains(input, "sent-omci-msg") {
143 continue
144 }
145 // Check if deviceID is required
146 if deviceID != "" {
147 if !strings.Contains(input, deviceID) {
148 continue
149 }
150 }
151 if err := json.Unmarshal([]byte(input), &logEntry); err != nil {
152 logger.Fatal(context.Background(), err)
153 }
154 uniqueTnsIDs[logEntry.OmciTrns]++
155 }
156 repeatedTrnsID := []int{}
157 for k, v := range uniqueTnsIDs {
158 if v != 1 {
159 repeatedTrnsID = append(repeatedTrnsID, k)
160 }
161 }
162 fmt.Println("RepeatedIDs", repeatedTrnsID, "TransID:", len(uniqueTnsIDs))
163}
164
Joey Armstrong393daca2023-07-06 08:47:54 -0400165// CreateMockAdapter creates mock OLT and ONU adapters - this will automatically the grpc service hosted by that
khenaidood948f772021-08-11 17:49:24 -0400166// adapter
167func CreateMockAdapter(
168 ctx context.Context,
169 adapterType int,
170 coreEndpoint string,
171 deviceType string,
172 vendor string,
173 childDeviceType string,
174 childVendor string,
175) (interface{}, error) {
176
177 var adpt interface{}
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700178 switch adapterType {
179 case OltAdapter:
khenaidood948f772021-08-11 17:49:24 -0400180 adpt = cm.NewOLTAdapter(ctx, coreEndpoint, deviceType, vendor, childDeviceType, childVendor)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700181 case OnuAdapter:
khenaidood948f772021-08-11 17:49:24 -0400182 adpt = cm.NewONUAdapter(ctx, coreEndpoint, deviceType, vendor)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700183 default:
Rohan Agrawal31f21802020-06-12 05:38:46 +0000184 logger.Fatalf(ctx, "invalid-adapter-type-%d", adapterType)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700185 }
khenaidood948f772021-08-11 17:49:24 -0400186 return adpt, nil
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700187}
188
Joey Armstrong393daca2023-07-06 08:47:54 -0400189// CreateAndRegisterAdapters creates mock ONU and OLT adapters and registers them to rw-core
khenaidood948f772021-08-11 17:49:24 -0400190func CreateAndRegisterAdapters(
191 ctx context.Context,
192 t *testing.T,
193 oltAdapters map[string]*AdapterInfo,
194 onuAdapters map[string]*AdapterInfo,
195 coreEndpoint string,
196) (map[string][]*cm.OLTAdapter, map[string][]*cm.ONUAdapter) {
197 // Setup the ONU adapter first in this unit test environment. This makes it easier to test whether the
198 // Core is ready to send grpc requests to the adapters. The unit test uses grpc to communicate with the
199 // Core and as such it does not have inside knowledge when the adapters are ready.
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700200
khenaidood948f772021-08-11 17:49:24 -0400201 // Setup the ONU Adapters
202 onuAdaptersMap := make(map[string][]*cm.ONUAdapter)
203 for adapterType, adapterInfo := range onuAdapters {
204 for replica := int32(1); replica <= adapterInfo.TotalReplica; replica++ {
205 adpt, err := CreateMockAdapter(ctx, OnuAdapter, coreEndpoint, adapterInfo.DeviceType, adapterInfo.Vendor, adapterInfo.ChildDeviceType, adapterInfo.ChildVendor)
206 assert.Nil(t, err)
207 onuAdapter, ok := adpt.(*cm.ONUAdapter)
208 assert.True(t, ok)
209 assert.NotNil(t, onuAdapter)
210 // Register the adapter
211 adapterID := fmt.Sprintf("%s-%d", adapterType, replica)
212 adapterToRegister := &voltha.Adapter{
213 Id: adapterID,
214 Vendor: adapterInfo.Vendor,
215 Version: version.VersionInfo.Version,
216 Type: adapterType,
217 CurrentReplica: replica,
218 TotalReplicas: adapterInfo.TotalReplica,
219 Endpoint: onuAdapter.GetEndPoint(),
220 }
221 types := []*voltha.DeviceType{{Id: adapterInfo.DeviceType, AdapterType: adapterType, AcceptsAddRemoveFlowUpdates: true}}
222 deviceTypes := &voltha.DeviceTypes{Items: types}
223 coreClient, err := onuAdapter.GetCoreClient()
224 assert.Nil(t, err)
225 assert.NotNil(t, coreClient)
khenaidoo9beaaf12021-10-19 17:32:01 -0400226 if _, err := coreClient.RegisterAdapter(ctx, &ca.AdapterRegistration{
khenaidood948f772021-08-11 17:49:24 -0400227 Adapter: adapterToRegister,
228 DTypes: deviceTypes}); err != nil {
229 logger.Errorw(ctx, "failed-to-register-adapter", log.Fields{"error": err, "adapter": adapterToRegister.Id})
230 assert.NotNil(t, err)
231 }
232 if _, ok := onuAdaptersMap[adapterType]; !ok {
233 onuAdaptersMap[adapterType] = []*cm.ONUAdapter{}
234 }
235 onuAdaptersMap[adapterType] = append(onuAdaptersMap[adapterType], onuAdapter)
236 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700237 }
238
khenaidood948f772021-08-11 17:49:24 -0400239 // Setup the OLT Adapters
240 oltAdaptersMap := make(map[string][]*cm.OLTAdapter)
241 for adapterType, adapterInfo := range oltAdapters {
242 for replica := int32(1); replica <= adapterInfo.TotalReplica; replica++ {
243 adpt, err := CreateMockAdapter(ctx, OltAdapter, coreEndpoint, adapterInfo.DeviceType, adapterInfo.Vendor, adapterInfo.ChildDeviceType, adapterInfo.ChildVendor)
244 assert.Nil(t, err)
245 oltAdapter, ok := adpt.(*cm.OLTAdapter)
246 assert.True(t, ok)
247 assert.NotNil(t, oltAdapter)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700248
khenaidood948f772021-08-11 17:49:24 -0400249 // Register the adapter
250 adapterID := fmt.Sprintf("%s-%d", adapterType, replica)
251 adapterToRegister := &voltha.Adapter{
252 Id: adapterID,
253 Vendor: adapterInfo.Vendor,
254 Version: version.VersionInfo.Version,
255 Type: adapterType,
256 CurrentReplica: replica,
257 TotalReplicas: adapterInfo.TotalReplica,
258 Endpoint: oltAdapter.GetEndPoint(),
259 }
260 types := []*voltha.DeviceType{{Id: adapterInfo.DeviceType, AdapterType: adapterType, AcceptsAddRemoveFlowUpdates: true}}
261 deviceTypes := &voltha.DeviceTypes{Items: types}
262 coreClient, err := oltAdapter.GetCoreClient()
263 assert.Nil(t, err)
264 assert.NotNil(t, coreClient)
265
khenaidoo9beaaf12021-10-19 17:32:01 -0400266 if _, err := coreClient.RegisterAdapter(ctx, &ca.AdapterRegistration{
khenaidood948f772021-08-11 17:49:24 -0400267 Adapter: adapterToRegister,
268 DTypes: deviceTypes}); err != nil {
269 logger.Errorw(ctx, "failed-to-register-adapter", log.Fields{"error": err, "adapter": adapterToRegister.Id})
270 assert.NotNil(t, err)
271 }
272 if _, ok := oltAdaptersMap[adapterType]; !ok {
273 oltAdaptersMap[adapterType] = []*cm.OLTAdapter{}
274 }
275 oltAdaptersMap[adapterType] = append(oltAdaptersMap[adapterType], oltAdapter)
276 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700277 }
khenaidood948f772021-08-11 17:49:24 -0400278
279 return oltAdaptersMap, onuAdaptersMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700280}
281
Joey Armstrong393daca2023-07-06 08:47:54 -0400282// StartEmbeddedEtcdServer creates and starts an Embedded etcd server locally.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000283func StartEmbeddedEtcdServer(ctx context.Context, configName, storageDir, logLevel string) (*mock_etcd.EtcdServer, int, error) {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700284 kvClientPort, err := freeport.GetFreePort()
285 if err != nil {
286 return nil, 0, err
287 }
288 peerPort, err := freeport.GetFreePort()
289 if err != nil {
290 return nil, 0, err
291 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000292 etcdServer := mock_etcd.StartEtcdServer(ctx, mock_etcd.MKConfig(ctx, configName, kvClientPort, peerPort, storageDir, logLevel))
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700293 if etcdServer == nil {
294 return nil, 0, status.Error(codes.Internal, "Embedded server failed to start")
295 }
296 return etcdServer, kvClientPort, nil
297}
298
Joey Armstrong393daca2023-07-06 08:47:54 -0400299// StopEmbeddedEtcdServer stops the embedded etcd server
Rohan Agrawal31f21802020-06-12 05:38:46 +0000300func StopEmbeddedEtcdServer(ctx context.Context, server *mock_etcd.EtcdServer) {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700301 if server != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000302 server.Stop(ctx)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700303 }
304}
305
Joey Armstrong393daca2023-07-06 08:47:54 -0400306// SetupKVClient creates a new etcd client
Rohan Agrawal31f21802020-06-12 05:38:46 +0000307func SetupKVClient(ctx context.Context, cf *config.RWCoreFlags, coreInstanceID string) kvstore.Client {
308 client, err := kvstore.NewEtcdClient(ctx, cf.KVStoreAddress, cf.KVStoreTimeout, log.FatalLevel)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700309 if err != nil {
310 panic("no kv client")
311 }
312 return client
313}
khenaidood948f772021-08-11 17:49:24 -0400314
Joey Armstrong393daca2023-07-06 08:47:54 -0400315// getRandomMacAddress returns a random mac address
khenaidood948f772021-08-11 17:49:24 -0400316func getRandomMacAddress() string {
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530317 mac := make([]byte, 6)
318 if _, err := io.ReadFull(rand.Reader, mac); err != nil {
319 fmt.Println("Error", err)
320 }
321
322 // Ensure the locally administered bit is set and the unicast bit is cleared
323 mac[0] = (mac[0] & 0xfe) | 0x02
324
khenaidood948f772021-08-11 17:49:24 -0400325 return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
Akash Reddy Kankanala929cc002025-04-08 15:05:21 +0530326 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])
khenaidood948f772021-08-11 17:49:24 -0400327}