blob: f2bf3e0a6b60082fe38a2ede53d1bdccc13ac42a [file] [log] [blame]
Mahir Gunyel03de0d32020-06-03 01:36:59 -07001/*
Joey Armstrong5f51f2e2023-01-17 17:06:26 -05002 * Copyright 2020-2023 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"
khenaidood948f772021-08-11 17:49:24 -040023 "encoding/json"
24 "fmt"
25 "os"
26 "path/filepath"
27 "strings"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070028 "testing"
khenaidood948f772021-08-11 17:49:24 -040029 "time"
30
khenaidoo9beaaf12021-10-19 17:32:01 -040031 ca "github.com/opencord/voltha-protos/v5/go/core_adapter"
khenaidood948f772021-08-11 17:49:24 -040032
33 "math/rand"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070034
35 "github.com/opencord/voltha-go/rw_core/config"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070036 cm "github.com/opencord/voltha-go/rw_core/mocks"
khenaidood948f772021-08-11 17:49:24 -040037 "github.com/opencord/voltha-lib-go/v7/pkg/db/kvstore"
38 "github.com/opencord/voltha-lib-go/v7/pkg/log"
39 mock_etcd "github.com/opencord/voltha-lib-go/v7/pkg/mocks/etcd"
40 "github.com/opencord/voltha-lib-go/v7/pkg/version"
41 "github.com/opencord/voltha-protos/v5/go/voltha"
Mahir Gunyel03de0d32020-06-03 01:36:59 -070042 "github.com/phayes/freeport"
43 "github.com/stretchr/testify/assert"
44 "google.golang.org/grpc/codes"
45 "google.golang.org/grpc/status"
46)
47
48const (
49 OltAdapter = iota
50 OnuAdapter
51)
52
khenaidood948f772021-08-11 17:49:24 -040053type AdapterInfo struct {
54 TotalReplica int32
55 Vendor string
56 DeviceType string
57 ChildDeviceType string
58 ChildVendor string
59}
60
61// prettyPrintDeviceUpdateLog is used just for debugging and exploring the Core logs
62func prettyPrintDeviceUpdateLog(inputFile string, deviceID string) {
63 file, err := os.Open(filepath.Clean(inputFile))
64 if err != nil {
65 logger.Fatal(context.Background(), err)
66 }
67 defer func() {
68 if err := file.Close(); err != nil {
69 logger.Errorw(context.Background(), "file-close-error", log.Fields{"error": err})
70 }
71 }()
72
73 var logEntry struct {
74 Level string `json:"level"`
75 Ts string `json:"ts"`
76 Caller string `json:"caller"`
77 Msg string `json:"msg"`
78 RPC string `json:"rpc"`
79 DeviceID string `json:"device-id"`
80 RequestedBy string `json:"requested-by"`
81 StateChange string `json:"state-change"`
82 Status string `json:"status"`
83 Description string `json:"description"`
84 }
85
86 scanner := bufio.NewScanner(file)
87 fmt.Println("Timestamp\t\t\tDeviceId\t\t\t\tStatus\t\t\tRPC\t\t\tRequestedBy\t\t\tStateChange\t\t\tDescription")
88 for scanner.Scan() {
89 input := scanner.Text()
90 // Look for device update logs only
91 if !strings.Contains(input, "device-operation") || !strings.Contains(input, "requested-by") {
92 continue
93 }
94 // Check if deviceID is required
95 if deviceID != "" {
96 if !strings.Contains(input, deviceID) {
97 continue
98 }
99 }
100 if err := json.Unmarshal([]byte(input), &logEntry); err != nil {
101 logger.Fatal(context.Background(), err)
102 }
103 fmt.Println(
104 fmt.Sprintf(
105 "%s\t%s\t%s\t%-30.30q\t%-16.16s\t%-25.25s\t%s",
106 logEntry.Ts,
107 logEntry.DeviceID,
108 logEntry.Status,
109 logEntry.RPC,
110 logEntry.RequestedBy,
111 logEntry.StateChange,
112 logEntry.Description))
113 }
114}
115
116func omciLog(inputFile string, deviceID string) {
117 file, err := os.Open(filepath.Clean(inputFile))
118 if err != nil {
119 logger.Fatal(context.Background(), err)
120 }
121 defer func() {
122 if err := file.Close(); err != nil {
123 logger.Errorw(context.Background(), "file-close-error", log.Fields{"error": err})
124 }
125 }()
126
127 var logEntry struct {
128 Level string `json:"level"`
129 Ts string `json:"ts"`
130 Caller string `json:"caller"`
131 Msg string `json:"msg"`
132 InstanceID string `json:"instanceId"`
133 ChildDeviceID string `json:"child-device-id"`
134 OmciMsg string `json:"omciMsg"`
135 IntfID string `json:"intf-id"`
136 OnuID string `json:"onu-id"`
137 OmciTrns int `json:"omciTransactionID"`
138 }
139
140 scanner := bufio.NewScanner(file)
141 uniqueTnsIDs := map[int]int{}
142 for scanner.Scan() {
143 input := scanner.Text()
144 // Look for device update logs only
145 if !strings.Contains(input, "sent-omci-msg") {
146 continue
147 }
148 // Check if deviceID is required
149 if deviceID != "" {
150 if !strings.Contains(input, deviceID) {
151 continue
152 }
153 }
154 if err := json.Unmarshal([]byte(input), &logEntry); err != nil {
155 logger.Fatal(context.Background(), err)
156 }
157 uniqueTnsIDs[logEntry.OmciTrns]++
158 }
159 repeatedTrnsID := []int{}
160 for k, v := range uniqueTnsIDs {
161 if v != 1 {
162 repeatedTrnsID = append(repeatedTrnsID, k)
163 }
164 }
165 fmt.Println("RepeatedIDs", repeatedTrnsID, "TransID:", len(uniqueTnsIDs))
166}
167
168//CreateMockAdapter creates mock OLT and ONU adapters - this will automatically the grpc service hosted by that
169// adapter
170func CreateMockAdapter(
171 ctx context.Context,
172 adapterType int,
173 coreEndpoint string,
174 deviceType string,
175 vendor string,
176 childDeviceType string,
177 childVendor string,
178) (interface{}, error) {
179
180 var adpt interface{}
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700181 switch adapterType {
182 case OltAdapter:
khenaidood948f772021-08-11 17:49:24 -0400183 adpt = cm.NewOLTAdapter(ctx, coreEndpoint, deviceType, vendor, childDeviceType, childVendor)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700184 case OnuAdapter:
khenaidood948f772021-08-11 17:49:24 -0400185 adpt = cm.NewONUAdapter(ctx, coreEndpoint, deviceType, vendor)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700186 default:
Rohan Agrawal31f21802020-06-12 05:38:46 +0000187 logger.Fatalf(ctx, "invalid-adapter-type-%d", adapterType)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700188 }
khenaidood948f772021-08-11 17:49:24 -0400189 return adpt, nil
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700190}
191
khenaidood948f772021-08-11 17:49:24 -0400192//CreateAndRegisterAdapters creates mock ONU and OLT adapters and registers them to rw-core
193func CreateAndRegisterAdapters(
194 ctx context.Context,
195 t *testing.T,
196 oltAdapters map[string]*AdapterInfo,
197 onuAdapters map[string]*AdapterInfo,
198 coreEndpoint string,
199) (map[string][]*cm.OLTAdapter, map[string][]*cm.ONUAdapter) {
200 // Setup the ONU adapter first in this unit test environment. This makes it easier to test whether the
201 // Core is ready to send grpc requests to the adapters. The unit test uses grpc to communicate with the
202 // Core and as such it does not have inside knowledge when the adapters are ready.
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700203
khenaidood948f772021-08-11 17:49:24 -0400204 // Setup the ONU Adapters
205 onuAdaptersMap := make(map[string][]*cm.ONUAdapter)
206 for adapterType, adapterInfo := range onuAdapters {
207 for replica := int32(1); replica <= adapterInfo.TotalReplica; replica++ {
208 adpt, err := CreateMockAdapter(ctx, OnuAdapter, coreEndpoint, adapterInfo.DeviceType, adapterInfo.Vendor, adapterInfo.ChildDeviceType, adapterInfo.ChildVendor)
209 assert.Nil(t, err)
210 onuAdapter, ok := adpt.(*cm.ONUAdapter)
211 assert.True(t, ok)
212 assert.NotNil(t, onuAdapter)
213 // Register the adapter
214 adapterID := fmt.Sprintf("%s-%d", adapterType, replica)
215 adapterToRegister := &voltha.Adapter{
216 Id: adapterID,
217 Vendor: adapterInfo.Vendor,
218 Version: version.VersionInfo.Version,
219 Type: adapterType,
220 CurrentReplica: replica,
221 TotalReplicas: adapterInfo.TotalReplica,
222 Endpoint: onuAdapter.GetEndPoint(),
223 }
224 types := []*voltha.DeviceType{{Id: adapterInfo.DeviceType, AdapterType: adapterType, AcceptsAddRemoveFlowUpdates: true}}
225 deviceTypes := &voltha.DeviceTypes{Items: types}
226 coreClient, err := onuAdapter.GetCoreClient()
227 assert.Nil(t, err)
228 assert.NotNil(t, coreClient)
khenaidoo9beaaf12021-10-19 17:32:01 -0400229 if _, err := coreClient.RegisterAdapter(ctx, &ca.AdapterRegistration{
khenaidood948f772021-08-11 17:49:24 -0400230 Adapter: adapterToRegister,
231 DTypes: deviceTypes}); err != nil {
232 logger.Errorw(ctx, "failed-to-register-adapter", log.Fields{"error": err, "adapter": adapterToRegister.Id})
233 assert.NotNil(t, err)
234 }
235 if _, ok := onuAdaptersMap[adapterType]; !ok {
236 onuAdaptersMap[adapterType] = []*cm.ONUAdapter{}
237 }
238 onuAdaptersMap[adapterType] = append(onuAdaptersMap[adapterType], onuAdapter)
239 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700240 }
241
khenaidood948f772021-08-11 17:49:24 -0400242 // Setup the OLT Adapters
243 oltAdaptersMap := make(map[string][]*cm.OLTAdapter)
244 for adapterType, adapterInfo := range oltAdapters {
245 for replica := int32(1); replica <= adapterInfo.TotalReplica; replica++ {
246 adpt, err := CreateMockAdapter(ctx, OltAdapter, coreEndpoint, adapterInfo.DeviceType, adapterInfo.Vendor, adapterInfo.ChildDeviceType, adapterInfo.ChildVendor)
247 assert.Nil(t, err)
248 oltAdapter, ok := adpt.(*cm.OLTAdapter)
249 assert.True(t, ok)
250 assert.NotNil(t, oltAdapter)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700251
khenaidood948f772021-08-11 17:49:24 -0400252 // Register the adapter
253 adapterID := fmt.Sprintf("%s-%d", adapterType, replica)
254 adapterToRegister := &voltha.Adapter{
255 Id: adapterID,
256 Vendor: adapterInfo.Vendor,
257 Version: version.VersionInfo.Version,
258 Type: adapterType,
259 CurrentReplica: replica,
260 TotalReplicas: adapterInfo.TotalReplica,
261 Endpoint: oltAdapter.GetEndPoint(),
262 }
263 types := []*voltha.DeviceType{{Id: adapterInfo.DeviceType, AdapterType: adapterType, AcceptsAddRemoveFlowUpdates: true}}
264 deviceTypes := &voltha.DeviceTypes{Items: types}
265 coreClient, err := oltAdapter.GetCoreClient()
266 assert.Nil(t, err)
267 assert.NotNil(t, coreClient)
268
khenaidoo9beaaf12021-10-19 17:32:01 -0400269 if _, err := coreClient.RegisterAdapter(ctx, &ca.AdapterRegistration{
khenaidood948f772021-08-11 17:49:24 -0400270 Adapter: adapterToRegister,
271 DTypes: deviceTypes}); err != nil {
272 logger.Errorw(ctx, "failed-to-register-adapter", log.Fields{"error": err, "adapter": adapterToRegister.Id})
273 assert.NotNil(t, err)
274 }
275 if _, ok := oltAdaptersMap[adapterType]; !ok {
276 oltAdaptersMap[adapterType] = []*cm.OLTAdapter{}
277 }
278 oltAdaptersMap[adapterType] = append(oltAdaptersMap[adapterType], oltAdapter)
279 }
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700280 }
khenaidood948f772021-08-11 17:49:24 -0400281
282 return oltAdaptersMap, onuAdaptersMap
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700283}
284
285//StartEmbeddedEtcdServer creates and starts an Embedded etcd server locally.
Rohan Agrawal31f21802020-06-12 05:38:46 +0000286func StartEmbeddedEtcdServer(ctx context.Context, configName, storageDir, logLevel string) (*mock_etcd.EtcdServer, int, error) {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700287 kvClientPort, err := freeport.GetFreePort()
288 if err != nil {
289 return nil, 0, err
290 }
291 peerPort, err := freeport.GetFreePort()
292 if err != nil {
293 return nil, 0, err
294 }
Rohan Agrawal31f21802020-06-12 05:38:46 +0000295 etcdServer := mock_etcd.StartEtcdServer(ctx, mock_etcd.MKConfig(ctx, configName, kvClientPort, peerPort, storageDir, logLevel))
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700296 if etcdServer == nil {
297 return nil, 0, status.Error(codes.Internal, "Embedded server failed to start")
298 }
299 return etcdServer, kvClientPort, nil
300}
301
302//StopEmbeddedEtcdServer stops the embedded etcd server
Rohan Agrawal31f21802020-06-12 05:38:46 +0000303func StopEmbeddedEtcdServer(ctx context.Context, server *mock_etcd.EtcdServer) {
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700304 if server != nil {
Rohan Agrawal31f21802020-06-12 05:38:46 +0000305 server.Stop(ctx)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700306 }
307}
308
309//SetupKVClient creates a new etcd client
Rohan Agrawal31f21802020-06-12 05:38:46 +0000310func SetupKVClient(ctx context.Context, cf *config.RWCoreFlags, coreInstanceID string) kvstore.Client {
311 client, err := kvstore.NewEtcdClient(ctx, cf.KVStoreAddress, cf.KVStoreTimeout, log.FatalLevel)
Mahir Gunyel03de0d32020-06-03 01:36:59 -0700312 if err != nil {
313 panic("no kv client")
314 }
315 return client
316}
khenaidood948f772021-08-11 17:49:24 -0400317
318//getRandomMacAddress returns a random mac address
319func getRandomMacAddress() string {
320 rand.Seed(time.Now().UnixNano() / int64(rand.Intn(255)+1))
321 return fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
322 rand.Intn(255),
323 rand.Intn(255),
324 rand.Intn(255),
325 rand.Intn(255),
326 rand.Intn(255),
327 rand.Intn(255),
328 )
329}