2 // ========================LICENSE_START=================================
5 // Copyright (C) 2022: Nordix Foundation
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 // ========================LICENSE_END===================================
35 "github.com/deepmap/oapi-codegen/pkg/middleware"
36 "github.com/deepmap/oapi-codegen/pkg/testutil"
37 "github.com/labstack/echo/v4"
38 echomiddleware "github.com/labstack/echo/v4/middleware"
39 "github.com/stretchr/testify/assert"
40 "oransc.org/nonrtric/capifcore/internal/common29122"
41 "oransc.org/nonrtric/capifcore/internal/eventsapi"
42 "oransc.org/nonrtric/capifcore/internal/publishserviceapi"
43 "oransc.org/nonrtric/capifcore/internal/restclient"
46 func TestRegisterSubscriptions(t *testing.T) {
47 subscription1 := eventsapi.EventSubscription{
48 Events: []eventsapi.CAPIFEvent{
49 eventsapi.CAPIFEventSERVICEAPIAVAILABLE,
51 NotificationDestination: common29122.Uri("notificationUrl"),
53 serviceUnderTest, requestHandler := getEcho(nil)
54 subscriberId := "subscriberId"
56 result := testutil.NewRequest().Post("/"+subscriberId+"/subscriptions").WithJsonBody(subscription1).Go(t, requestHandler)
57 assert.Equal(t, http.StatusCreated, result.Code())
58 var resultEvent eventsapi.EventSubscription
59 err := result.UnmarshalBodyToObject(&resultEvent)
60 assert.NoError(t, err, "error unmarshaling response")
61 assert.Equal(t, resultEvent, subscription1)
62 assert.Regexp(t, "http://example.com/"+subscriberId+"/subscriptions/"+subscriberId+"[0-9]+", result.Recorder.Header().Get(echo.HeaderLocation))
63 subscriptionId1 := path.Base(result.Recorder.Header().Get(echo.HeaderLocation))
65 subscription2 := subscription1
66 subscription2.Events = []eventsapi.CAPIFEvent{
67 eventsapi.CAPIFEventAPIINVOKERUPDATED,
69 result = testutil.NewRequest().Post("/"+subscriberId+"/subscriptions").WithJsonBody(subscription2).Go(t, requestHandler)
70 assert.Regexp(t, "http://example.com/"+subscriberId+"/subscriptions/"+subscriberId+"[0-9]+", result.Recorder.Header().Get(echo.HeaderLocation))
71 subscriptionId2 := path.Base(result.Recorder.Header().Get(echo.HeaderLocation))
73 assert.NotEqual(t, subscriptionId1, subscriptionId2)
74 registeredSub1 := serviceUnderTest.getSubscription(subscriptionId1)
75 assert.Equal(t, subscription1, *registeredSub1)
76 registeredSub2 := serviceUnderTest.getSubscription(subscriptionId2)
77 assert.Equal(t, subscription2, *registeredSub2)
80 func TestDeregisterSubscription(t *testing.T) {
81 subscription := eventsapi.EventSubscription{
82 Events: []eventsapi.CAPIFEvent{
83 eventsapi.CAPIFEventSERVICEAPIAVAILABLE,
85 NotificationDestination: common29122.Uri(""),
87 serviceUnderTest, requestHandler := getEcho(nil)
89 serviceUnderTest.addSubscription(subId, subscription)
91 result := testutil.NewRequest().Delete("/subscriberId/subscriptions/"+subId).Go(t, requestHandler)
92 assert.Equal(t, http.StatusNoContent, result.Code())
93 assert.Nil(t, serviceUnderTest.getSubscription(subId))
96 func TestSendEvent(t *testing.T) {
97 notificationUrl := "url"
98 apiIds := []string{"apiId"}
100 newEvent := eventsapi.EventNotification{
101 EventDetail: &eventsapi.CAPIFEventDetail{
104 Events: eventsapi.CAPIFEventSERVICEAPIAVAILABLE,
106 wg := sync.WaitGroup{}
107 clientMock := NewTestClient(func(req *http.Request) *http.Response {
108 if req.URL.String() == notificationUrl {
109 assert.Equal(t, req.Method, "PUT")
110 assert.Equal(t, "application/json", req.Header.Get("Content-Type"))
111 newEvent.SubscriptionId = subId
112 assert.Equal(t, newEvent, getBodyAsEvent(req, t))
114 return &http.Response{
116 Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)),
117 Header: make(http.Header), // Must be set to non-nil value or it panics
120 t.Error("Wrong call to client: ", req)
124 serviceUnderTest, _ := getEcho(clientMock)
126 serviceUnderTest.addSubscription(subId, eventsapi.EventSubscription{
127 Events: []eventsapi.CAPIFEvent{
128 eventsapi.CAPIFEventSERVICEAPIAVAILABLE,
130 NotificationDestination: common29122.Uri(notificationUrl),
132 sub2 := eventsapi.EventSubscription{
133 Events: []eventsapi.CAPIFEvent{
134 eventsapi.CAPIFEventACCESSCONTROLPOLICYUNAVAILABLE,
136 NotificationDestination: common29122.Uri(notificationUrl),
138 serviceUnderTest.addSubscription("other", sub2)
142 serviceUnderTest.GetNotificationChannel() <- newEvent
145 if waitTimeout(&wg, 1*time.Second) {
146 t.Error("Not all calls to server were made")
151 func TestMatchEventType(t *testing.T) {
152 notificationUrl := "url"
154 serviceUnderTest := NewEventService(nil)
155 serviceUnderTest.addSubscription(subId, eventsapi.EventSubscription{
156 Events: []eventsapi.CAPIFEvent{
157 eventsapi.CAPIFEventSERVICEAPIAVAILABLE,
159 NotificationDestination: common29122.Uri(notificationUrl),
160 EventFilters: &[]eventsapi.CAPIFEventFilter{},
162 serviceUnderTest.addSubscription("other", eventsapi.EventSubscription{
163 Events: []eventsapi.CAPIFEvent{
164 eventsapi.CAPIFEventACCESSCONTROLPOLICYUNAVAILABLE,
166 NotificationDestination: common29122.Uri(notificationUrl),
169 event := eventsapi.EventNotification{
170 SubscriptionId: subId,
171 Events: eventsapi.CAPIFEventSERVICEAPIAVAILABLE,
174 matchingSubs := serviceUnderTest.filterOnEventType(event)
175 assert.Len(t, matchingSubs, 1)
176 assert.Equal(t, subId, matchingSubs[0])
179 func TestMatchEventTypeAndFilters(t *testing.T) {
181 apiIds := []string{"apiId"}
182 invokerIds := []string{"invokerId"}
184 aefIds := []string{aefId}
185 serviceUnderTest := NewEventService(nil)
186 serviceUnderTest.addSubscription(subId, eventsapi.EventSubscription{
187 Events: []eventsapi.CAPIFEvent{
188 eventsapi.CAPIFEventSERVICEAPIAVAILABLE,
190 EventFilters: &[]eventsapi.CAPIFEventFilter{
193 ApiInvokerIds: &invokerIds,
198 serviceUnderTest.addSubscription("otherSameType", eventsapi.EventSubscription{
199 Events: []eventsapi.CAPIFEvent{
200 eventsapi.CAPIFEventACCESSCONTROLPOLICYUNAVAILABLE,
203 serviceUnderTest.addSubscription("other", eventsapi.EventSubscription{
204 Events: []eventsapi.CAPIFEvent{
205 eventsapi.CAPIFEventACCESSCONTROLPOLICYUNAVAILABLE,
209 event := eventsapi.EventNotification{
210 Events: eventsapi.CAPIFEventACCESSCONTROLPOLICYUNAVAILABLE,
214 matchingSubs := serviceUnderTest.getMatchingSubs(event)
215 assert.Len(t, matchingSubs, 2)
217 // Match with all filter ids
218 aefProfiles := []publishserviceapi.AefProfile{
223 serviceDescriptions := []publishserviceapi.ServiceAPIDescription{
225 AefProfiles: &aefProfiles,
228 event.Events = eventsapi.CAPIFEventSERVICEAPIAVAILABLE
229 event.EventDetail = &eventsapi.CAPIFEventDetail{
231 ApiInvokerIds: &invokerIds,
232 ServiceAPIDescriptions: &serviceDescriptions,
234 matchingSubs = serviceUnderTest.getMatchingSubs(event)
235 assert.Len(t, matchingSubs, 1)
236 assert.Equal(t, subId, matchingSubs[0])
239 otherApiIds := []string{"otherApiId"}
240 (*serviceUnderTest.subscriptions[subId].EventFilters)[0].ApiIds = &otherApiIds
241 matchingSubs = serviceUnderTest.getMatchingSubs(event)
242 assert.Len(t, matchingSubs, 0)
244 // Un match invokerId
245 otherInvokerIds := []string{"otherInvokerId"}
246 (*serviceUnderTest.subscriptions[subId].EventFilters)[0].ApiIds = nil
247 (*serviceUnderTest.subscriptions[subId].EventFilters)[0].ApiInvokerIds = &otherInvokerIds
248 matchingSubs = serviceUnderTest.getMatchingSubs(event)
249 assert.Len(t, matchingSubs, 0)
252 otherAefIds := []string{"otherAefId"}
253 (*serviceUnderTest.subscriptions[subId].EventFilters)[0].ApiInvokerIds = nil
254 (*serviceUnderTest.subscriptions[subId].EventFilters)[0].AefIds = &otherAefIds
255 matchingSubs = serviceUnderTest.getMatchingSubs(event)
256 assert.Len(t, matchingSubs, 0)
258 // Match with empty subscription filter id list
259 (*serviceUnderTest.subscriptions[subId].EventFilters)[0].AefIds = &[]string{}
260 matchingSubs = serviceUnderTest.getMatchingSubs(event)
261 assert.Len(t, matchingSubs, 1)
263 // Match with empty event id list
264 event.EventDetail.ApiIds = nil
265 event.EventDetail.ApiInvokerIds = nil
266 event.EventDetail.ServiceAPIDescriptions = &[]publishserviceapi.ServiceAPIDescription{}
267 matchingSubs = serviceUnderTest.getMatchingSubs(event)
268 assert.Len(t, matchingSubs, 1)
271 func getEcho(client restclient.HTTPClient) (*EventService, *echo.Echo) {
272 swagger, err := eventsapi.GetSwagger()
274 fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
278 swagger.Servers = nil
280 es := NewEventService(client)
283 e.Use(echomiddleware.Logger())
284 e.Use(middleware.OapiRequestValidator(swagger))
286 eventsapi.RegisterHandlers(e, es)
290 type RoundTripFunc func(req *http.Request) *http.Response
292 func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
296 // NewTestClient returns *http.Client with Transport replaced to avoid making real calls
297 func NewTestClient(fn RoundTripFunc) *http.Client {
299 Transport: RoundTripFunc(fn),
303 // waitTimeout waits for the waitgroup for the specified max timeout.
304 // Returns true if waiting timed out.
305 func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
306 c := make(chan struct{})
313 return false // completed normally
314 case <-time.After(timeout):
315 return true // timed out
319 func getBodyAsEvent(req *http.Request, t *testing.T) eventsapi.EventNotification {
320 buf := new(bytes.Buffer)
321 if _, err := buf.ReadFrom(req.Body); err != nil {
324 var event eventsapi.EventNotification
325 err := json.Unmarshal(buf.Bytes(), &event)