2 * ============LICENSE_START=======================================================
3 * Copyright (c) 2021-2022 Bell Canada.
4 * Modifications Copyright (c) 2022-2023 Nordix Foundation
5 * Modifications Copyright (C) 2023 TechMahindra Ltd.
6 * ================================================================================
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.
19 * SPDX-License-Identifier: Apache-2.0
20 * ============LICENSE_END=========================================================
23 package org.onap.cps.notification
25 import org.onap.cps.spi.model.DataNode
27 import java.time.OffsetDateTime
28 import java.time.format.DateTimeFormatter
29 import org.onap.cps.utils.DateTimeUtility
30 import org.onap.cps.utils.PrefixResolver
31 import org.onap.cps.api.CpsDataService
32 import org.onap.cps.event.model.Content
33 import org.onap.cps.event.model.Data
34 import org.onap.cps.spi.FetchDescendantsOption
35 import org.onap.cps.spi.model.Anchor
36 import org.onap.cps.spi.model.DataNodeBuilder
37 import org.springframework.util.StringUtils
38 import spock.lang.Specification
40 class CpsDataUpdatedEventFactorySpec extends Specification {
42 def mockCpsDataService = Mock(CpsDataService)
44 def mockPrefixResolver = Mock(PrefixResolver)
46 def objectUnderTest = new CpsDataUpdatedEventFactory(mockCpsDataService, mockPrefixResolver)
48 def dateTimeFormat = 'yyyy-MM-dd\'T\'HH:mm:ss.SSSZ'
50 def 'Create a CPS data updated event successfully: #scenario'() {
51 given: 'an anchor which has been updated'
52 def anchor = new Anchor('my-anchorname', 'my-dataspace', 'my-schemaset-name')
53 and: 'cps data service returns the data node details'
55 def dataNode = new DataNodeBuilder().withXpath(xpath).withLeaves(['leafName': 'leafValue']).build()
56 mockCpsDataService.getDataNodes(
57 'my-dataspace', 'my-anchorname', '/', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode]
58 when: 'CPS data updated event is created'
59 def cpsDataUpdatedEvent = objectUnderTest.createCpsDataUpdatedEvent(anchor,
60 DateTimeUtility.toOffsetDateTime(inputObservedTimestamp), Operation.CREATE)
61 then: 'CPS data updated event is created with correct envelope'
62 with(cpsDataUpdatedEvent) {
63 type == 'org.onap.cps.data-updated-event'
64 source == new URI('urn:cps:org.onap.cps')
65 schema == new URI('urn:cps:org.onap.cps:data-updated-event-schema:v1')
66 StringUtils.hasText(id)
69 and: 'correct content'
70 with(cpsDataUpdatedEvent.content) {
71 assert isExpectedDateTimeFormat(observedTimestamp): "$observedTimestamp is not in $dateTimeFormat format"
72 if (inputObservedTimestamp != null)
73 assert observedTimestamp == inputObservedTimestamp
75 assert OffsetDateTime.now().minusSeconds(20).isBefore(
76 DateTimeUtility.toOffsetDateTime(observedTimestamp))
77 assert anchorName == 'my-anchorname'
78 assert dataspaceName == 'my-dataspace'
79 assert schemaSetName == 'my-schemaset-name'
80 assert operation == Content.Operation.CREATE
81 assert data == new Data().withAdditionalProperty('xpath', ['leafName': 'leafValue'])
84 scenario | inputObservedTimestamp
85 'with observed timestamp -0400' | '2021-01-01T23:00:00.345-0400'
86 'with observed timestamp +0400' | '2021-01-01T23:00:00.345+0400'
87 'missing observed timestamp' | null
90 def 'Create a delete CPS data updated event successfully'() {
91 given: 'an anchor which has been deleted'
92 def anchor = new Anchor('my-anchorname', 'my-dataspace', 'my-schemaset-name')
93 def deletionTimestamp = '2021-01-01T23:00:00.345-0400'
94 when: 'a delete root data node event is created'
95 def cpsDataUpdatedEvent = objectUnderTest.createCpsDataUpdatedEvent(anchor,
96 DateTimeUtility.toOffsetDateTime(deletionTimestamp), Operation.DELETE)
97 then: 'CPS data updated event is created with correct envelope'
98 with(cpsDataUpdatedEvent) {
99 type == 'org.onap.cps.data-updated-event'
100 source == new URI('urn:cps:org.onap.cps')
101 schema == new URI('urn:cps:org.onap.cps:data-updated-event-schema:v1')
102 StringUtils.hasText(id)
105 and: 'correct content'
106 with(cpsDataUpdatedEvent.content) {
107 assert isExpectedDateTimeFormat(observedTimestamp): "$observedTimestamp is not in $dateTimeFormat format"
108 assert observedTimestamp == deletionTimestamp
109 assert anchorName == 'my-anchorname'
110 assert dataspaceName == 'my-dataspace'
111 assert schemaSetName == 'my-schemaset-name'
112 assert operation == Content.Operation.DELETE
117 def 'Create CPS Data Event with URI Syntax Exception'() {
119 def anchor = new Anchor('my-anchorname', 'my-dataspace', 'my-schemaset-name')
120 and: 'a mocked data Node (collection)'
121 def mockDataNode = Mock(DataNode)
122 mockCpsDataService.getDataNodes(*_) >> [ mockDataNode ]
123 and: 'a URI syntax exception is thrown somewhere (using datanode as cannot manipulate hardcoded URIs'
124 def originalException = new URISyntaxException('input', 'reason', 0)
125 mockDataNode.getXpath() >> { throw originalException }
126 when: 'attempt to create data updated event'
127 objectUnderTest.createCpsDataUpdatedEvent(anchor, OffsetDateTime.now(), Operation.UPDATE)
128 then: 'the same exception is thrown up'
129 def thrownUp = thrown(URISyntaxException)
130 assert thrownUp == originalException
133 def isExpectedDateTimeFormat(String observedTimestamp) {
135 DateTimeFormatter.ofPattern(dateTimeFormat).parse(observedTimestamp)
136 } catch (DateTimeParseException) {