2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2022 Nordix Foundation
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.spi.utils
23 import com.google.common.util.concurrent.TimeLimiter
24 import org.hibernate.HibernateException
25 import org.hibernate.Transaction
26 import org.onap.cps.spi.config.CpsSessionFactory
27 import org.onap.cps.spi.entities.AnchorEntity
28 import org.onap.cps.spi.exceptions.SessionManagerException
29 import org.onap.cps.spi.repository.AnchorRepository
30 import org.onap.cps.spi.repository.DataspaceRepository
31 import spock.lang.Specification
32 import org.hibernate.Session
33 import java.util.concurrent.ExecutionException
35 class SessionManagerSpec extends Specification {
37 def mockCpsSessionFactory = Mock(CpsSessionFactory)
38 def spiedTimeLimiterProvider = Spy(TimeLimiterProvider)
39 def mockDataspaceRepository = Mock(DataspaceRepository)
40 def mockAnchorRepository = Mock(AnchorRepository)
41 def mockSession1 = Mock(Session)
42 def mockSession2 = Mock(Session)
43 def mockTransaction1 = Mock(Transaction)
44 def mockTransaction2 = Mock(Transaction)
46 def objectUnderTest = new SessionManager(mockCpsSessionFactory, spiedTimeLimiterProvider, mockDataspaceRepository, mockAnchorRepository)
49 mockSession1.getTransaction() >> mockTransaction1
50 mockSession2.getTransaction() >> mockTransaction2
53 def 'Lock anchor entity with #exceptionDuringTest exception.'() {
54 given: 'a dummy session'
55 objectUnderTest.sessionMap.put('dummy-session', mockSession1)
56 and: 'the anchor name can be resolved'
57 def mockAnchorEntity = Mock(AnchorEntity)
58 mockAnchorEntity.getId() > 456
59 mockAnchorRepository.getByDataspaceAndName(_, _) >> mockAnchorEntity
60 and: 'timeLimiter throws an #exceptionDuringTest exception'
61 def mockTimeLimiter = Mock(TimeLimiter)
62 spiedTimeLimiterProvider.getTimeLimiter(_) >> mockTimeLimiter
63 mockTimeLimiter.callWithTimeout(*_) >> { throw exceptionDuringTest }
64 when: 'session tries to acquire anchor lock'
65 objectUnderTest.lockAnchor('dummy-session', 'some-dataspace', 'some-anchor', 123L)
66 then: 'a session manager exception is thrown with the expected detail'
67 def thrown = thrown(SessionManagerException)
68 thrown.details.contains(expectedExceptionDetail)
70 exceptionDuringTest || expectedExceptionDetail
71 new InterruptedException() || 'interrupted'
72 new ExecutionException() || 'aborted'
75 def 'Close a session' () {
76 given: 'a session in the session map'
77 objectUnderTest.sessionMap.putAll([testSessionId1:mockSession1])
78 when: 'the session manager closes session'
79 objectUnderTest.closeSession('testSessionId1', commit)
80 then: 'commit or rollback is called on the transaction as appropriate'
82 1 * mockTransaction1.commit()
84 1 * mockTransaction1.rollback()
86 and: 'the correct session is closed'
87 1 * mockSession1.close()
89 commit << [SessionManager.WITH_COMMIT, SessionManager.WITH_ROLLBACK]
92 def 'Close session that does not exist.'() {
93 when: 'attempt to close session that does not exist'
94 objectUnderTest.closeSession('unknown session id', SessionManager.WITH_COMMIT)
95 then: 'a session manager exception is thrown with the unknown id in the details'
96 def thrown = thrown(SessionManagerException)
97 assert thrown.details.contains('unknown session id')
100 def 'Hibernate exception while closing session.'() {
101 given: 'a test session in session map'
102 objectUnderTest.sessionMap.put('testSessionId', mockSession1)
103 and: 'an hibernate exception when closing that session'
104 def hibernateException = new HibernateException('test')
105 mockSession1.close() >> { throw hibernateException }
106 when: 'attempt to close session'
107 objectUnderTest.closeSession('testSessionId', SessionManager.WITH_COMMIT)
108 then: 'a session manager exception is thrown with the session id in the details'
109 def thrown = thrown(SessionManagerException)
110 assert thrown.details.contains('testSessionId')
111 and: 'the original exception as cause'
112 assert thrown.cause == hibernateException
115 def 'Attempt to lock anchor entity with session Id that does not exist'() {
116 when: 'attempt to acquire anchor lock with session that does not exist'
117 objectUnderTest.lockAnchor('unknown session id', '', '', 123L)
118 then: 'a session manager exception is thrown with the unknown id in the details'
119 def thrown = thrown(SessionManagerException)
120 thrown.details.contains('unknown session id')
123 def 'Close all sessions in shutdown.'() {
124 given: 'sessions that holds transactions in the session map'
125 objectUnderTest.sessionMap.putAll([testSessionId1:mockSession1, otherSessionId:mockSession2])
126 when: 'shutdown method to close all sessions is called'
127 objectUnderTest.closeAllSessionsInShutdown()
128 then: 'commit is called on each transaction'
129 1 * mockTransaction1.rollback()
130 1 * mockTransaction2.rollback()
131 and: 'each session is closed'
132 1 * mockSession1.close()
133 1 * mockSession2.close()
134 then: 'session factory is closed'
135 1 * mockCpsSessionFactory.closeSessionFactory()