Fixes added and UT-coverage improved over 85%
[ric-plt/submgr.git] / pkg / control / sdl_test.go
1 /*
2 ==================================================================================
3   Copyright (c) 2019 AT&T Intellectual Property.
4   Copyright (c) 2019 Nokia
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 package control
21
22 import (
23         "encoding/json"
24         "fmt"
25         "gerrit.o-ran-sc.org/r/ric-plt/e2ap/pkg/e2ap"
26         "gerrit.o-ran-sc.org/r/ric-plt/submgr/pkg/teststube2ap"
27         "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
28         "github.com/stretchr/testify/assert"
29         "reflect"
30         "strconv"
31         "strings"
32         "testing"
33         "time"
34 )
35
36 var sdlShouldReturnError bool = false
37
38 const sdlTestErrorString string = "Test sdl returned error on purpose"
39
40 const (
41         subsResponse = 1
42         subsFailure  = 2
43         noResponse   = 3
44 )
45
46 type Mock struct {
47         subsDB             map[string]string // Store information as a string like real db does.
48         register           map[uint32]*Subscription
49         subIds             []uint32
50         lastAllocatedSubId uint32
51 }
52
53 var mock *Mock
54
55 func CreateMock() *Mock {
56         fmt.Println("Test CreateMock()")
57         mock = new(Mock)
58         mock.ResetTestSettings()
59         return mock
60 }
61
62 func (m *Mock) ResetTestSettings() {
63         m.subsDB = make(map[string]string)
64         m.register = make(map[uint32]*Subscription)
65         var i uint32
66         for i = 1; i < 65535; i++ {
67                 m.subIds = append(m.subIds, i)
68         }
69 }
70
71 func (m *Mock) AllocNextSubId() uint32 {
72         m.lastAllocatedSubId = m.subIds[0]
73         return m.lastAllocatedSubId
74 }
75
76 func TestWait(t *testing.T) {
77         // Wait to test settings to complete
78         <-time.After(1 * time.Second)
79 }
80
81 func GetSubscription(t *testing.T, e2SubId uint32, responseType int, srcEndPoint, ranName string, xId string) *Subscription {
82         t.Log("TEST: Getting subscription")
83
84         subs := &Subscription{}
85
86         // Create unpacked e2SubReqMsg
87         subReqParams := &teststube2ap.E2StubSubsReqParams{}
88         subReqParams.Init()
89
90         meid := xapp.RMRMeid{}
91         meid.RanName = ranName
92
93         params := &xapp.RMRParams{}
94         params.Src = srcEndPoint
95         params.Xid = xId
96         params.Meid = &meid
97
98         // Create xApp transaction
99         trans := mainCtrl.c.tracker.NewXappTransaction(xapp.NewRmrEndpoint(params.Src), params.Xid, subReqParams.Req.RequestId, params.Meid)
100         if trans == nil {
101                 t.Errorf("TEST: %s", idstring(fmt.Errorf("transaction not created"), params))
102                 return nil
103         }
104
105         // Allocate E2 instanceId/subId
106         subReqParams.Req.RequestId.InstanceId = e2SubId
107
108         subs.ReqId.Id = 123
109         subs.ReqId.InstanceId = subReqParams.Req.RequestId.InstanceId
110         subs.Meid = &meid
111         subs.EpList.AddEndpoint(trans.GetEndpoint())
112         subs.SubReqMsg = subReqParams.Req
113         // subs.SubRFMsg contains received/cached SubscriptionResponse or SubscriptionFailure, nil in no response received
114         if responseType == subsResponse {
115                 subs.SubRFMsg = GetSubsResponse(t, subReqParams.Req)
116                 subs.valid = true
117         } else if responseType == subsFailure {
118                 subs.SubRFMsg = GetSubsFailure(t, subReqParams.Req)
119                 subs.valid = false
120         } else if responseType == noResponse {
121                 subs.SubRFMsg = nil
122                 subs.valid = false
123         }
124         return subs
125 }
126
127 func GetSubsResponse(t *testing.T, req *e2ap.E2APSubscriptionRequest) *e2ap.E2APSubscriptionResponse {
128         t.Log("TEST: Getting ricSubscriptionResponse")
129
130         // Create e2SubRespMsg
131         resp := &e2ap.E2APSubscriptionResponse{}
132         resp.RequestId.Id = 123
133         resp.RequestId.InstanceId = req.RequestId.InstanceId
134         resp.FunctionId = req.FunctionId
135
136         resp.ActionAdmittedList.Items = make([]e2ap.ActionAdmittedItem, len(req.ActionSetups))
137         for index := int(0); index < len(req.ActionSetups); index++ {
138                 resp.ActionAdmittedList.Items[index].ActionId = req.ActionSetups[index].ActionId
139         }
140
141         for index := uint64(0); index < 1; index++ {
142                 item := e2ap.ActionNotAdmittedItem{}
143                 item.ActionId = index
144                 item.Cause.Content = 1
145                 item.Cause.Value = 1
146                 resp.ActionNotAdmittedList.Items = append(resp.ActionNotAdmittedList.Items, item)
147         }
148         return resp
149 }
150
151 func GetSubsFailure(t *testing.T, req *e2ap.E2APSubscriptionRequest) *e2ap.E2APSubscriptionFailure {
152         t.Log("TEST: Getting ricSubscriptionFailure")
153
154         fail := &e2ap.E2APSubscriptionFailure{}
155         fail.RequestId.Id = req.RequestId.Id
156         fail.RequestId.InstanceId = req.RequestId.InstanceId
157         fail.FunctionId = req.FunctionId
158         return fail
159 }
160
161 func PrintSubscriptionData(t *testing.T, subs *Subscription) {
162         t.Log("TEST: subscription data")
163         t.Logf("TEST: subs.mutex = %v", subs.mutex)
164         t.Logf("TEST: subs.ReqId.InstanceId = %v", subs.ReqId.InstanceId)
165         t.Logf("TEST: subs.ReqId.Id = %v", subs.ReqId.Id)
166         t.Logf("TEST: subs.EpList = %v", subs.EpList)
167         t.Logf("TEST: subs.Meid.RanName = %v", subs.Meid.RanName)
168         t.Logf("TEST: subs.SubReqMsg = %v", subs.SubReqMsg.String())
169         t.Logf("TEST: subs.valid = %v", subs.valid)
170
171         if subs.SubRFMsg != nil {
172                 switch typeofSubsMessage(subs.SubRFMsg) {
173                 case "SubResp":
174                         t.Logf("TEST: subs.SubRFMsg == SubResp")
175                         subResp := subs.SubRFMsg.(*e2ap.E2APSubscriptionResponse)
176                         t.Logf("TEST: subResp = %+v", subResp)
177                 case "SubFail":
178                         t.Logf("TEST: subs.SubRFMsg == SubFail")
179                         subFail := subs.SubRFMsg.(*e2ap.E2APSubscriptionFailure)
180                         t.Logf("TEST: subFail = %+v", subFail)
181                 }
182         } else {
183                 t.Logf("TEST: subs.SubRFMsg == nil")
184         }
185 }
186
187 func TestWriteSubscriptionToSdl(t *testing.T) {
188
189         // Write one subscription
190         subId := mock.AllocNextSubId()
191         subs := GetSubscription(t, subId, subsResponse, "localhost:13560", "RAN_NAME_1", "123456")
192         PrintSubscriptionData(t, subs)
193         t.Logf("TEST: Writing subId = %v\n", subId)
194         err := mainCtrl.c.WriteSubscriptionToSdl(subId, subs)
195         if err != nil {
196                 t.Errorf("TEST: %s", err.Error())
197         }
198 }
199
200 func TestReadSubscriptionFromSdl(t *testing.T) {
201
202         subId := mock.lastAllocatedSubId
203         t.Logf("Reading subId = %v\n", subId)
204         subs, err := mainCtrl.c.ReadSubscriptionFromSdl(subId)
205         if err != nil {
206                 t.Errorf("TEST: %s", err.Error())
207                 return
208         }
209         PrintSubscriptionData(t, subs)
210         assert.Equal(t, mock.register[subId].SubReqMsg, subs.SubReqMsg)
211 }
212
213 func TestRemoveSubscriptionFromSdl(t *testing.T) {
214
215         subId := mock.lastAllocatedSubId
216         err := mainCtrl.c.RemoveSubscriptionFromSdl(subId)
217         if err != nil {
218                 t.Errorf("TEST: %s", err.Error())
219                 return
220         }
221         delete(mock.register, subId)
222         mock.subIds = append(mock.subIds, subId)
223         t.Logf("TEST: subscription removed from db. subId = %v", subId)
224 }
225
226 func TestReadNotExistingSubscriptionFromSdl(t *testing.T) {
227
228         var subId uint32 = 0
229         subs, err := mainCtrl.c.ReadSubscriptionFromSdl(subId)
230         if err != nil {
231                 t.Logf("TEST: subscription not found from db. subId = %v", subId)
232                 return
233         }
234         t.Errorf("TEST: subscription read from db. %v", subs.String())
235         PrintSubscriptionData(t, subs)
236 }
237
238 func TestReadNotExistingSubscriptionFromSdl2(t *testing.T) {
239
240         var subId uint32 = 7
241         subs, err := mainCtrl.c.ReadSubscriptionFromSdl(subId)
242         if err != nil {
243                 t.Logf("TEST: subscription not found from db. subId = %v", subId)
244                 return
245         }
246         t.Errorf("TEST: subscription read from db. %v", subs.String())
247         PrintSubscriptionData(t, subs)
248 }
249
250 func TestRemoveNotExistingSubscriptionFromSdl(t *testing.T) {
251
252         var subId uint32 = 0
253         err := mainCtrl.c.RemoveSubscriptionFromSdl(subId)
254         if err != nil {
255                 t.Logf("TEST: %s", err.Error())
256                 return
257         }
258         t.Logf("TEST: subscription removed from db. subId = %v", subId)
259 }
260
261 func TestWriteSubscriptionsToSdl(t *testing.T) {
262
263         // Write 1st subscription
264         subId := mock.AllocNextSubId()
265         t.Logf("TEST: Writing subId = %v\n", subId)
266         subs := GetSubscription(t, subId, subsResponse, "localhost:13560", "RAN_NAME_1", "123456")
267         PrintSubscriptionData(t, subs)
268         err := mainCtrl.c.WriteSubscriptionToSdl(subId, subs)
269         if err != nil {
270                 t.Errorf("TEST: %s", err.Error())
271                 return
272         }
273         t.Logf("TEST: subscription written in db = %v", subs.String())
274
275         // Write 2nd subscription
276         subId = mock.AllocNextSubId()
277         t.Logf("TEST:Writing subId = %v\n", subId)
278         subs = GetSubscription(t, subId, subsFailure, "localhost:13560", "RAN_NAME_2", "123457")
279         PrintSubscriptionData(t, subs)
280         err = mainCtrl.c.WriteSubscriptionToSdl(subId, subs)
281         if err != nil {
282                 t.Errorf("TEST: %s", err.Error())
283                 return
284         }
285         t.Logf("TEST: subscription written in db = %v", subs.String())
286
287         // Write 3rd subscription
288         subId = mock.AllocNextSubId()
289         t.Logf("TEST:Writing subId = %v\n", subId)
290         subs = GetSubscription(t, subId, noResponse, "localhost:13560", "RAN_NAME_3", "123458")
291         PrintSubscriptionData(t, subs)
292         err = mainCtrl.c.WriteSubscriptionToSdl(subId, subs)
293         if err != nil {
294                 t.Errorf("TEST: %s", err.Error())
295                 return
296         }
297         t.Logf("TEST: subscription written in db = %v", subs.String())
298 }
299
300 func TestReadSubscriptionsFromSdl(t *testing.T) {
301
302         // Subscription with subId 1 was added and and removed above. Then subscriptions with subIds 2, 3 and 4 was added
303         // Db subscriptions should now contain subIDs 2, 3 and 4
304         var subId uint32
305         for subId = 2; subId <= 4; subId++ {
306                 subs, err := mainCtrl.c.ReadSubscriptionFromSdl(subId)
307                 if err != nil {
308                         t.Errorf("TEST: %s", err.Error())
309                         return
310                 }
311                 PrintSubscriptionData(t, subs)
312         }
313 }
314
315 func TestReadAllSubscriptionsFromSdl(t *testing.T) {
316
317         // This test cases simulates submgr restart. SubIds and subscriptions are restored from db
318         // after initializing mock.subIds and mock.register
319         //      var err error
320         subIds, register, err := mainCtrl.c.ReadAllSubscriptionsFromSdl()
321         if err != nil {
322                 t.Errorf("TEST: %s", err.Error())
323                 return
324         }
325         //      for _, subs := range mock.register {
326         for _, subs := range register {
327                 PrintSubscriptionData(t, subs)
328         }
329         // SubIds slices before and after restart can't be directly compared as original slice is not stored
330         // in the db. SubId values 1, 2, 3, 4 are already removed from the beginning of subIds slice above
331         // so far. Next free subId is 5 in the beginning of mock.subIds slice. The db contains now however only
332         // 3 subscriptions with subIds 2, 3 and 4, so only subId values 2, 3, 4 are removed from the returned
333         // subIds slice and there next free value is 1
334         assert.Equal(t, uint32(0x1), subIds[0])
335 }
336
337 func TestRemoveAllSubscriptionsFromSdl(t *testing.T) {
338
339         err := mainCtrl.c.RemoveAllSubscriptionsFromSdl()
340         if err != nil {
341                 t.Errorf("TEST: %s", err.Error())
342                 return
343         }
344         t.Log("TEST: All subscription removed from db")
345 }
346
347 func TestReadAllSubscriptionsFromSdl2(t *testing.T) {
348
349         // This test cases simulates submgr startup. SubIds and subscriptions are restored from empty db
350         // after initializing mock.subIds and mock.register
351         subIds, register, err := mainCtrl.c.ReadAllSubscriptionsFromSdl()
352         if err != nil {
353                 t.Errorf("TEST: %s", err.Error())
354                 return
355         }
356         for _, subs := range mock.register {
357                 PrintSubscriptionData(t, subs)
358         }
359         assert.Equal(t, len(subIds), 65534)
360         assert.Equal(t, len(register), 0)
361 }
362
363 func TestWriteSubscriptionToSdlFail(t *testing.T) {
364
365         // Try to write one subscription. Test db should return test error string
366         MakeNextSdlCallFail()
367         subId := mock.AllocNextSubId()
368         subs := GetSubscription(t, subId, subsResponse, "localhost:13560", "RAN_NAME_1", "123456")
369         PrintSubscriptionData(t, subs)
370         t.Logf("TEST: Writing subId = %v\n", subId)
371         err := mainCtrl.c.WriteSubscriptionToSdl(subId, subs)
372         if err != nil {
373                 if !strings.Contains(fmt.Sprintf("%s", err), sdlTestErrorString) {
374                         t.Errorf("TEST: %s", err.Error())
375                 }
376         } else {
377                 t.Errorf("TEST: This test case should return error")
378         }
379 }
380
381 func TestReadSubscriptionFromSdlFail(t *testing.T) {
382
383         // Try to read one subscription. Test db should return test error string
384         MakeNextSdlCallFail()
385         subId := mock.lastAllocatedSubId
386         t.Logf("Reading subId = %v\n", subId)
387         subs, err := mainCtrl.c.ReadSubscriptionFromSdl(subId)
388         if err != nil {
389                 if !strings.Contains(fmt.Sprintf("%s", err), sdlTestErrorString) {
390                         t.Errorf("TEST: %s", err.Error())
391                 }
392                 return
393         } else {
394                 t.Errorf("TEST: This test case should return error")
395         }
396         PrintSubscriptionData(t, subs)
397         assert.Equal(t, mock.register[subId].SubReqMsg, subs.SubReqMsg)
398 }
399
400 func TestRemoveSubscriptionFromSdlFail(t *testing.T) {
401
402         // Try to remove one subscription. Test db should return test error string
403         MakeNextSdlCallFail()
404         subId := mock.lastAllocatedSubId
405         err := mainCtrl.c.RemoveSubscriptionFromSdl(subId)
406         if err != nil {
407                 if !strings.Contains(fmt.Sprintf("%s", err), sdlTestErrorString) {
408                         t.Errorf("TEST: %s", err.Error())
409                 }
410                 return
411         } else {
412                 t.Errorf("TEST: This test case should return error")
413         }
414         delete(mock.register, subId)
415         mock.subIds = append(mock.subIds, subId)
416         t.Logf("TEST: subscription removed from db. subId = %v", subId)
417 }
418
419 func TestReadAllSubscriptionsFromSdlFail(t *testing.T) {
420
421         // Try to read all subscriptions. Test db should return test error string
422         MakeNextSdlCallFail()
423         // This test cases simulates submgr restart. SubIds and subscriptions are restored from db
424         // after initializing mock.subIds and mock.register
425         //      var err error
426         subIds, register, err := mainCtrl.c.ReadAllSubscriptionsFromSdl()
427         if err != nil {
428                 if !strings.Contains(fmt.Sprintf("%s", err), sdlTestErrorString) {
429                         t.Errorf("TEST: %s", err.Error())
430                 }
431                 return
432         } else {
433                 t.Errorf("TEST: This test case should return error")
434         }
435         //      for _, subs := range mock.register {
436         for _, subs := range register {
437                 PrintSubscriptionData(t, subs)
438         }
439         // SubIds slices before and after restart can't be directly compared as original slice is not stored
440         // in the db. SubId values 1, 2, 3, 4 are already removed from the beginning of subIds slice above
441         // so far. Next free subId is 5 in the beginning of mock.subIds slice. The db contains now however only
442         // 3 subscriptions with subIds 2, 3 and 4, so only subId values 2, 3, 4 are removed from the returned
443         // subIds slice and there next free value is 1
444         assert.Equal(t, uint32(0x1), subIds[0])
445 }
446
447 func TestRemoveAllSubscriptionsFromSdlFail(t *testing.T) {
448
449         // Try to remove all subscriptions. Test db should return test error string
450         MakeNextSdlCallFail()
451         err := mainCtrl.c.RemoveAllSubscriptionsFromSdl()
452         if err != nil {
453                 if !strings.Contains(fmt.Sprintf("%s", err), sdlTestErrorString) {
454                         t.Errorf("TEST: %s", err.Error())
455                 }
456                 return
457         } else {
458                 t.Errorf("TEST: This test case should return error")
459         }
460         t.Log("TEST: All subscription removed from db")
461 }
462
463 func (m *Mock) Set(pairs ...interface{}) error {
464         var key string
465         var val string
466
467         if sdlShouldReturnError == true {
468                 return GetSdlError()
469         }
470
471         for _, v := range pairs {
472                 reflectType := reflect.TypeOf(v)
473                 switch reflectType.Kind() {
474                 case reflect.Slice:
475                         val = fmt.Sprintf("%s", v.([]uint8))
476                 default:
477                         switch v.(type) {
478                         case string:
479                                 key = v.(string)
480                         default:
481                                 return fmt.Errorf("Set() error: Unexpected type\n")
482                         }
483                 }
484         }
485
486         if key != "" {
487                 m.subsDB[key] = val
488                 subId := m.subIds[0]
489                 subscriptionInfo := &SubscriptionInfo{}
490                 err := json.Unmarshal([]byte(val), subscriptionInfo)
491                 if err != nil {
492                         return fmt.Errorf("Set() json.unmarshal error: %s\n", err.Error())
493                 }
494
495                 subs := mainCtrl.c.CreateSubscription(subscriptionInfo, &val)
496                 m.register[subId] = subs
497                 m.subIds = m.subIds[1:]
498         } else {
499                 return fmt.Errorf("Set() error: key == ''\n")
500         }
501         return nil
502 }
503
504 func (m *Mock) Get(keys []string) (map[string]interface{}, error) {
505         retMap := make(map[string]interface{})
506         if len(keys) == 0 {
507                 return nil, fmt.Errorf("Get() error: len(key) == 0\n")
508         }
509
510         if sdlShouldReturnError == true {
511                 return nil, GetSdlError()
512         }
513
514         for _, key := range keys {
515                 if key != "" {
516                         retMap[key] = m.subsDB[key]
517                 } else {
518                         return nil, fmt.Errorf("Get() error: key == ''\n")
519                 }
520         }
521         return retMap, nil
522 }
523
524 func (m *Mock) GetAll() ([]string, error) {
525
526         if sdlShouldReturnError == true {
527                 return nil, GetSdlError()
528         }
529
530         keys := []string{}
531         for key, _ := range m.subsDB {
532                 keys = append(keys, key)
533         }
534         return keys, nil
535 }
536
537 func (m *Mock) Remove(keys []string) error {
538         if len(keys) == 0 {
539                 return fmt.Errorf("Remove() error: len(key) == 0\n")
540         }
541         subId64, err := strconv.ParseUint(keys[0], 10, 64)
542         if err != nil {
543                 return fmt.Errorf("Remove() ParseUint() error: %s\n", err.Error())
544         }
545
546         if sdlShouldReturnError == true {
547                 return GetSdlError()
548         }
549
550         subId := uint32(subId64)
551         delete(m.subsDB, keys[0])
552         delete(m.register, subId)
553         m.subIds = append(m.subIds, subId)
554         return nil
555 }
556
557 func (m *Mock) RemoveAll() error {
558
559         for key := range m.subsDB {
560                 subId64, err := strconv.ParseUint(key, 10, 64)
561                 if err != nil {
562                         return fmt.Errorf("RemoveAll() ParseUint() error: %s\n", err.Error())
563                 }
564
565                 subId := uint32(subId64)
566                 delete(m.subsDB, key)
567                 delete(m.register, subId)
568                 m.subIds = append(m.subIds, subId)
569         }
570
571         if sdlShouldReturnError == true {
572                 return GetSdlError()
573         }
574
575         return nil
576 }
577
578 func MakeNextSdlCallFail() {
579         sdlShouldReturnError = true
580 }
581
582 func GetSdlError() error {
583         sdlShouldReturnError = false
584         return fmt.Errorf(sdlTestErrorString)
585 }