• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmrs / openmrs-core / 36456271610

28 Sep 2026 04:53PM UTC coverage: 66.105% (+1.2%) from 64.906%
36456271610

push

github

ibacher
Clear leaked outbox rows before OutboxEventServiceTest tests (#6596)

Global property saves committed by earlier tests in the shared context
are persisted as outbox events via TestTransactionalEventAggregator.
When more than 100 are pending, getProcessingAndPendingEvents (ordered
by id, limit 100) no longer returns the test's own events, so the test
failed whenever the module tests ran before it, as on Linux CI.


Claude-Session: https://claude.ai/code/session_015sv8E9mrTQK5LBCaS5zqCn

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

25547 of 38646 relevant lines covered (66.11%)

0.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.41
/api/src/main/java/org/openmrs/api/impl/CohortServiceImpl.java
1
/**
2
 * This Source Code Form is subject to the terms of the Mozilla Public License,
3
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
4
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6
 *
7
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8
 * graphic logo is a trademark of OpenMRS Inc.
9
 */
10
package org.openmrs.api.impl;
11

12
import static org.openmrs.util.DateUtil.truncateToSeconds;
13

14
import java.util.Date;
15
import java.util.List;
16
import java.util.stream.Collectors;
17

18
import org.openmrs.Cohort;
19
import org.openmrs.CohortMembership;
20
import org.openmrs.Patient;
21
import org.openmrs.User;
22
import org.openmrs.api.APIException;
23
import org.openmrs.api.CohortService;
24
import org.openmrs.api.context.Context;
25
import org.openmrs.api.db.CohortDAO;
26
import org.openmrs.util.OpenmrsUtil;
27
import org.openmrs.util.PrivilegeConstants;
28
import org.slf4j.Logger;
29
import org.slf4j.LoggerFactory;
30
import org.springframework.transaction.annotation.Transactional;
31

32
/**
33
 * API functions related to Cohorts
34
 */
35
@Transactional
36
public class CohortServiceImpl extends BaseOpenmrsService implements CohortService {
1 ✔
37
        
38
        private static final Logger log = LoggerFactory.getLogger(CohortServiceImpl.class);
1 ✔
39
        
40
        private CohortDAO dao;
41
        
42
        /**
43
         * @see org.openmrs.api.CohortService#setCohortDAO(org.openmrs.api.db.CohortDAO)
44
         */
45
        @Override
46
        public void setCohortDAO(CohortDAO dao) {
47
                this.dao = dao;
1 ✔
48
        }
1 ✔
49
        
50
        /**
51
         * @see org.openmrs.api.CohortService#saveCohort(org.openmrs.Cohort)
52
         */
53
        @Override
54
        public Cohort saveCohort(Cohort cohort) throws APIException {
55
                if (cohort.getCohortId() == null) {
1 ✔
56
                        Context.requirePrivilege(PrivilegeConstants.ADD_COHORTS);
1 ✔
57
                } else {
58
                        Context.requirePrivilege(PrivilegeConstants.EDIT_COHORTS);
1 ✔
59
                }
60
                if (cohort.getName() == null) {
1 ✔
61
                        throw new APIException("Cohort.save.nameRequired", (Object[]) null);
×
62
                }
63
                if (cohort.getDescription() == null) {
1 ✔
64
                        throw new APIException("Cohort.save.descriptionRequired", (Object[]) null);
×
65
                }
66
                if (log.isInfoEnabled()) {
1 ✔
67
                        log.info("Saving cohort " + cohort);
×
68
                }
69
                
70
                return dao.saveCohort(cohort);
1 ✔
71
        }
72
        
73
        /**
74
         * @see org.openmrs.api.CohortService#getCohort(java.lang.Integer)
75
         */
76
        @Override
77
        @Transactional(readOnly = true)
78
        public Cohort getCohort(Integer id) {
79
                return dao.getCohort(id);
1 ✔
80
        }
81
        
82
        /**
83
         * @see org.openmrs.api.CohortService#voidCohort(org.openmrs.Cohort, java.lang.String)
84
         */
85
        @Override
86
        public Cohort voidCohort(Cohort cohort, String reason) {
87
                // other setters done by the save handlers
88
                return Context.getCohortService().saveCohort(cohort);
1 ✔
89
        }
90
        
91
        /**
92
         * @see org.openmrs.api.CohortService#getCohortByUuid(java.lang.String)
93
         */
94
        @Override
95
        @Transactional(readOnly = true)
96
        public Cohort getCohortByUuid(String uuid) {
97
                return dao.getCohortByUuid(uuid);
1 ✔
98
        }
99
        
100
        /**
101
         * @see org.openmrs.api.CohortService#getCohortMembershipByUuid(java.lang.String)
102
         */
103
        @Override
104
        @Transactional(readOnly = true)
105
        public CohortMembership getCohortMembershipByUuid(String uuid) {
106
                return dao.getCohortMembershipByUuid(uuid);
1 ✔
107
        }
108
        
109
        /**
110
         * @see org.openmrs.api.CohortService#addPatientToCohort(org.openmrs.Cohort,
111
         *      org.openmrs.Patient)
112
         */
113
        @Override
114
        public Cohort addPatientToCohort(Cohort cohort, Patient patient) {
115
                if (!cohort.contains(patient.getPatientId())) {
1 ✔
116
                        CohortMembership cohortMembership = new CohortMembership(patient.getPatientId());
1 ✔
117
                        cohort.addMembership(cohortMembership);
1 ✔
118
                        Context.getCohortService().saveCohort(cohort);
1 ✔
119
                }
120
                return cohort;
1 ✔
121
        }
122
        
123
        /**
124
         * @see org.openmrs.api.CohortService#removePatientFromCohort(org.openmrs.Cohort,
125
         *      org.openmrs.Patient)
126
         */
127
        @Override
128
        public Cohort removePatientFromCohort(Cohort cohort, Patient patient) {
129
                List<CohortMembership> memberships = getCohortMemberships(patient.getPatientId(), null, false);
1 ✔
130
                List<CohortMembership> toVoid = memberships.stream()
1 ✔
131
                                .filter(m -> m.getCohort().equals(cohort))
1 ✔
132
                                .collect(Collectors.toList());
1 ✔
133
                
134
                for (CohortMembership membership : toVoid) {
1 ✔
135
                        Context.getCohortService().voidCohortMembership(membership, "removePatientFromCohort");
1 ✔
136
                }
1 ✔
137
                return cohort;
1 ✔
138
        }
139
        
140
        @Override
141
        @Transactional(readOnly = true)
142
        public List<Cohort> getCohortsContainingPatient(Patient patient) {
143
                return getCohortsContainingPatientId(patient.getPatientId());
×
144
        }
145
        
146
        @Override
147
        @Transactional(readOnly = true)
148
        public List<Cohort> getCohortsContainingPatientId(Integer patientId) {
149
                return dao.getCohortsContainingPatientId(patientId, false, new Date());
1 ✔
150
        }
151
        
152
        /**
153
         * @see org.openmrs.api.CohortService#getCohorts(java.lang.String)
154
         */
155
        @Override
156
        @Transactional(readOnly = true)
157
        public List<Cohort> getCohorts(String nameFragment) throws APIException {
158
                return dao.getCohorts(nameFragment);
1 ✔
159
        }
160
        
161
        /**
162
         * @see org.openmrs.api.CohortService#getAllCohorts()
163
         */
164
        @Override
165
        @Transactional(readOnly = true)
166
        public List<Cohort> getAllCohorts() throws APIException {
167
                return Context.getCohortService().getAllCohorts(false);
1 ✔
168
        }
169
        
170
        /**
171
         * @see org.openmrs.api.CohortService#getAllCohorts(boolean)
172
         */
173
        @Override
174
        @Transactional(readOnly = true)
175
        public List<Cohort> getAllCohorts(boolean includeVoided) throws APIException {
176
                return dao.getAllCohorts(includeVoided);
1 ✔
177
        }
178
        
179
        /**
180
         * @see org.openmrs.api.CohortService#getCohortByName(java.lang.String)
181
         */
182
        @Override
183
        @Transactional(readOnly = true)
184
        public Cohort getCohortByName(String name) throws APIException {
185
                return dao.getCohort(name);
1 ✔
186
        }
187
        
188
        /**
189
         * @see org.openmrs.api.CohortService#getCohort(java.lang.String)
190
         */
191
        @Override
192
        @Transactional(readOnly = true)
193
        public Cohort getCohort(String name) throws APIException {
194
                return getCohortByName(name);
×
195
        }
196
        
197
        /**
198
         * @see org.openmrs.api.CohortService#purgeCohort(org.openmrs.Cohort)
199
         */
200
        @Override
201
        public Cohort purgeCohort(Cohort cohort) throws APIException {
202
                return dao.deleteCohort(cohort);
1 ✔
203
        }
204
        
205
        /**
206
         * @see CohortService#purgeCohortMembership(CohortMembership)
207
         */
208
        @Override
209
        public void purgeCohortMembership(CohortMembership cohortMembership) throws APIException {
210
                Cohort cohort = cohortMembership.getCohort();
1 ✔
211
                boolean removed = cohort.removeMembership(cohortMembership);
1 ✔
212
                if (removed) {
1 ✔
213
                        Context.getCohortService().saveCohort(cohort);
1 ✔
214
                }
215
        }
1 ✔
216
        
217
        /**
218
         * @see CohortService#voidCohortMembership(CohortMembership, String)
219
         */
220
        @Override
221
        public CohortMembership voidCohortMembership(CohortMembership cohortMembership, String reason) {
222
                Context.getCohortService().saveCohort(cohortMembership.getCohort());
1 ✔
223
                return cohortMembership;
1 ✔
224
        }
225
        
226
        /**
227
         * @see CohortService#endCohortMembership(CohortMembership, Date)
228
         */
229
        @Override
230
        public CohortMembership endCohortMembership(CohortMembership cohortMembership, Date onDate) {
231
                cohortMembership.setEndDate(onDate == null ? new Date() : onDate);
1 ✔
232
                Context.getCohortService().saveCohort(cohortMembership.getCohort());
1 ✔
233
                return cohortMembership;
1 ✔
234
        }
235
        
236
        /**
237
         * @see org.openmrs.api.CohortService#notifyPatientVoided(org.openmrs.Patient)
238
         */
239
        @Override
240
        public void notifyPatientVoided(Patient patient) throws APIException {
241
                // this membership read is internal bookkeeping done while a patient is being voided; acquire
242
                // the read privilege on the voiding user's behalf rather than requiring them to hold it
243
                List<CohortMembership> memberships;
244
                try {
245
                        Context.addProxyPrivilege(PrivilegeConstants.GET_PATIENT_COHORTS);
1 ✔
246
                        memberships = Context.getCohortService().getCohortMemberships(patient.getPatientId(), null, false);
1 ✔
247
                } finally {
248
                        Context.removeProxyPrivilege(PrivilegeConstants.GET_PATIENT_COHORTS);
1 ✔
249
                }
250
                memberships.forEach(m -> {
1 ✔
251
                        m.setVoided(patient.getVoided());
1 ✔
252
                        m.setDateVoided(patient.getDateVoided());
1 ✔
253
                        m.setVoidedBy(patient.getVoidedBy());
1 ✔
254
                        m.setVoidReason(patient.getVoidReason());
1 ✔
255
                        dao.saveCohortMembership(m);
1 ✔
256
                });
1 ✔
257
        }
1 ✔
258
        
259
        /**
260
         * @see org.openmrs.api.CohortService#notifyPatientUnvoided(Patient, User, Date)
261
         */
262
        @Override
263
        public void notifyPatientUnvoided(Patient patient, User originallyVoidedBy, Date originalDateVoided) throws APIException {
264
                List<CohortMembership> memberships = getCohortMemberships(patient.getPatientId(), null, true);
1 ✔
265
                List<CohortMembership> toUnvoid = memberships.stream().filter(
1 ✔
266
                                                m -> m.getVoided()
1 ✔
267
                                                                && m.getVoidedBy().equals(originallyVoidedBy)
1 ✔
268
                                                                && OpenmrsUtil.compare(
1 ✔
269
                                                                                truncateToSeconds(m.getDateVoided()),
1 ✔
270
                                                                                truncateToSeconds(originalDateVoided)) == 0)
1 ✔
271
                                .collect(Collectors.toList());
1 ✔
272
                
273
                for (CohortMembership member : toUnvoid) {
1 ✔
274
                        member.setVoided(false);
1 ✔
275
                        member.setDateVoided(null);
1 ✔
276
                        member.setVoidedBy(null);
1 ✔
277
                        member.setVoidReason(null);
1 ✔
278
                        dao.saveCohortMembership(member);
1 ✔
279
                }
1 ✔
280
        }
1 ✔
281
        
282
        @Override
283
        public List<CohortMembership> getCohortMemberships(Integer patientId, Date activeOnDate, boolean includeVoided) {
284
                if (patientId == null) {
1 ✔
285
                        throw new IllegalArgumentException("patientId is required");
×
286
                }
287
                return dao.getCohortMemberships(patientId, activeOnDate, includeVoided);
1 ✔
288
        }
289
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc