From 3fb887a38c074405cdb7471f9fc19831c39352ed Mon Sep 17 00:00:00 2001 From: kamiljarmusik Date: Thu, 14 Sep 2023 20:41:29 +0200 Subject: [PATCH] #2698 Corrected cache pending events - - Update cached pending events for only logged user; (Limiting the number of database queries) - added spring bean org.scada_lts.login.LoggedUsers; corrected update permission without logout user; added test suite: LoggedUserTestsSuite (LoggedUsersMultiThreadTest, LoggedUsersTest), extends MultiThreadEngine and TestConcurrentUtils; removed deprecated methods: MangoEvent/EventService.getPendingSimpleEventsForDataSource, MangoEvent/EventService.getPendingSimpleEvents; removed deprecated class EventDao; added enum AlarmLevelType; refactor: PendingEventsDAO, PendingEventService; - The current limited event analysis to the number of events within the limit, this has been corrected for cache mode; (Information about events could be false, e.g. an event that should have been displayed could be missing, on Alarm List Component) - added parameter event.pending.update.limit to env.properties, corrected AlarmListComponent, added method getEventPendingUpdateLimit in SystemSettingsUtils; - By default, the Pending event cache is enabled; (This setting can be changed from SystemSettings) - set abilit.cacheEnable=true in env.properties --- WebContent/WEB-INF/applicationContext.xml | 2 + build.gradle | 1 + .../view/component/AlarmListComponent.java | 2 +- .../org/scadabr/web/dwr/UsersProfilesDwr.java | 3 + src/com/serotonin/mango/db/dao/EventDao.java | 221 -------- .../mango/rt/event/type/AlarmLevelType.java | 32 ++ src/com/serotonin/mango/vo/User.java | 28 +- src/com/serotonin/mango/web/dwr/UsersDwr.java | 7 +- src/org/scada_lts/dao/PendingEventsDAO.java | 17 +- src/org/scada_lts/login/ILoggedUsers.java | 15 + src/org/scada_lts/login/LoggedUsers.java | 122 ++++ .../scada_lts/mango/adapter/MangoEvent.java | 6 - .../scada_lts/mango/service/EventService.java | 40 +- .../mango/service/PendingEventService.java | 63 ++- .../scada_lts/utils/SystemSettingsUtils.java | 15 +- .../scada_lts/web/beans/ApplicationBeans.java | 6 + .../mango/vo/LoggedUserTestsSuite.java | 17 + .../mango/vo/LoggedUsersMultiThreadTest.java | 532 +++++++++++++++++ .../serotonin/mango/vo/LoggedUsersTest.java | 535 ++++++++++++++++++ .../MessagingChannelsMultiThreadTest.java | 28 +- test/utils/MultiThreadEngine.java | 20 +- test/utils/TestConcurrentUtils.java | 55 +- test/utils/mock/EventServiceMock.java | 10 - webapp-resources/env.properties | 3 +- 24 files changed, 1448 insertions(+), 332 deletions(-) delete mode 100644 src/com/serotonin/mango/db/dao/EventDao.java create mode 100644 src/com/serotonin/mango/rt/event/type/AlarmLevelType.java create mode 100644 src/org/scada_lts/login/ILoggedUsers.java create mode 100644 src/org/scada_lts/login/LoggedUsers.java create mode 100644 test/com/serotonin/mango/vo/LoggedUserTestsSuite.java create mode 100644 test/com/serotonin/mango/vo/LoggedUsersMultiThreadTest.java create mode 100644 test/com/serotonin/mango/vo/LoggedUsersTest.java diff --git a/WebContent/WEB-INF/applicationContext.xml b/WebContent/WEB-INF/applicationContext.xml index 57cbc58713..d0e68ab512 100644 --- a/WebContent/WEB-INF/applicationContext.xml +++ b/WebContent/WEB-INF/applicationContext.xml @@ -244,4 +244,6 @@ + + diff --git a/build.gradle b/build.gradle index e577577d05..6921d48ecb 100644 --- a/build.gradle +++ b/build.gradle @@ -197,5 +197,6 @@ test { includeTestsMatching "org.scada_lts.dao.IsEventDetectorXidUniqueTest" includeTestsMatching "com.serotonin.mango.view.export.CsvWriterTest" includeTestsMatching "com.serotonin.mango.util.EmailValidatorTest" + includeTestsMatching "com.serotonin.mango.vo.LoggedUserTestsSuite" } } \ No newline at end of file diff --git a/src/br/org/scadabr/view/component/AlarmListComponent.java b/src/br/org/scadabr/view/component/AlarmListComponent.java index 6241cf93af..b60cb78fc8 100644 --- a/src/br/org/scadabr/view/component/AlarmListComponent.java +++ b/src/br/org/scadabr/view/component/AlarmListComponent.java @@ -58,7 +58,7 @@ public String generateContent() { WebContext webContext = WebContextFactory.get(); HttpServletRequest request = webContext.getHttpServletRequest(); List toViewEvents = new EventService().getPendingEventsAlarmLevelMin(Common - .getUser().getId(), minAlarmLevel, maxListSize, true); + .getUser().getId(), minAlarmLevel, maxListSize); model.put("nome", "marlon"); model.put("events",toViewEvents); diff --git a/src/br/org/scadabr/web/dwr/UsersProfilesDwr.java b/src/br/org/scadabr/web/dwr/UsersProfilesDwr.java index f3426259a2..3c918d3f44 100644 --- a/src/br/org/scadabr/web/dwr/UsersProfilesDwr.java +++ b/src/br/org/scadabr/web/dwr/UsersProfilesDwr.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest; +import com.serotonin.mango.vo.User; import org.directwebremoting.WebContextFactory; import br.org.scadabr.api.exception.DAOException; @@ -33,6 +34,7 @@ import org.scada_lts.dao.model.ScadaObjectIdentifier; import org.scada_lts.mango.service.UsersProfileService; import org.scada_lts.mango.service.ViewService; +import org.scada_lts.web.beans.ApplicationBeans; public class UsersProfilesDwr { @@ -122,6 +124,7 @@ public DwrResponseI18n saveUserAdmin(int id, String name, try { usersProfileService.saveUsersProfile(profile); + ApplicationBeans.getLoggedUsersBean().updateUsers(profile); } catch (DAOException e) { response.addMessage(new LocalizableMessage( "userProfiles.validate.nameUnique")); diff --git a/src/com/serotonin/mango/db/dao/EventDao.java b/src/com/serotonin/mango/db/dao/EventDao.java deleted file mode 100644 index 9da777843c..0000000000 --- a/src/com/serotonin/mango/db/dao/EventDao.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * (c) 2016 Abil'I.T. http://abilit.eu/ - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.serotonin.mango.db.dao; - -import java.util.Date; -import java.util.List; -import java.util.ResourceBundle; - -import org.scada_lts.dao.DAO; -import org.scada_lts.mango.adapter.MangoEvent; -import org.scada_lts.mango.service.EventService; - -import com.serotonin.mango.rt.event.EventInstance; -import com.serotonin.mango.rt.event.type.EventType; -import com.serotonin.mango.vo.UserComment; -import com.serotonin.mango.vo.event.EventHandlerVO; -import com.serotonin.mango.vo.event.EventTypeVO; - -/** - * Rewrite (ultimately to remove) and only use EventService - * - * @author Grzesiek Bylica Abil'I.T. development team, sdt@abilit.eu - */ -@Deprecated -public class EventDao { - - private MangoEvent eventService = new EventService(); - - public void saveEvent(EventInstance event) { - eventService.saveEvent(event); - } - - public void ackEvent(int eventId, long time, int userId, - int alternateAckSource, boolean signalAlarmLevelChange) { - eventService.ackEvent(eventId, time, userId, alternateAckSource); - } - - public void ackEvent(int eventId, long time, int userId, - int alternateAckSource) { - eventService.ackEvent(eventId, time, userId, alternateAckSource); - } - - public void insertUserEvents(final int eventId, - final List userIds, final boolean alarm) { - eventService.insertUserEvents(eventId, userIds, alarm); - } - - public List getActiveEvents() { - return eventService.getActiveEvents(); - } - - public List getEventsForDataPoint(int dataPointId, int userId) { - return eventService.getEventsForDataPoint(dataPointId, userId); - } - - public List getPendingEventsForDataPoint(int dataPointId, - int userId) { - return eventService.getPendingEventsForDataPoint(dataPointId, userId); - } - - public List getPendingEventsForDataSource(int dataSourceId, - int userId) { - return eventService.getPendingEvents(EventType.EventSources.DATA_SOURCE, - dataSourceId, userId); - } - - public List getPendingEventsForPublisher(int publisherId, - int userId) { - return eventService.getPendingEvents(EventType.EventSources.PUBLISHER, publisherId, - userId); - } - - public List getPendingEvents(int userId) { - return eventService.getPendingEvents(userId); - } - - public void attachRelationalInfo(List list) { - eventService.attachRelationalInfo(list); - } - - public EventInstance insertEventComment(int eventId, UserComment comment) { - return eventService.insertEventComment(eventId, comment); - } - - public int purgeEventsBefore(final long time) { - return eventService.purgeEventsBefore(time); - } - - public int getEventCount() { - return eventService.getEventCount(); - } - - public List searchOld(int eventId, int eventSourceType, - String status, int alarmLevel, final String[] keywords, - final int maxResults, int userId, final ResourceBundle bundle) { - return eventService.searchOld(eventId, eventSourceType, status, alarmLevel, keywords, maxResults, userId, bundle); - - } - - public List search(int eventId, int eventSourceType, - String status, int alarmLevel, final String[] keywords, int userId, - final ResourceBundle bundle, final int from, final int to, - final Date date) { - return eventService.search(eventId, eventSourceType, status, alarmLevel, keywords, userId, bundle, from, to, date); - - } - - public List search(int eventId, int eventSourceType, - String status, int alarmLevel, final String[] keywords, - long dateFrom, long dateTo, int userId, - final ResourceBundle bundle, final int from, final int to, - final Date date) { - - return eventService.search(eventId, eventSourceType, status, alarmLevel, keywords, dateFrom, dateTo, userId, bundle, from, to, date); - } - - public int getSearchRowCount() { - return eventService.getSearchRowCount(); - } - - public int getStartRow() { - return eventService.getStartRow(); - } - - // - // / - // / Event handlers - // / - // - public String generateUniqueXid() { - return DAO.getInstance().generateUniqueXid(EventHandlerVO.XID_PREFIX, "eventHandlers"); - } - - public boolean isXidUnique(String xid, int excludeId) { - return DAO.getInstance().isXidUnique(xid, excludeId, "eventHandlers"); - } - - public EventType getEventHandlerType(int handlerId) { - return eventService.getEventHandlerType(handlerId); - } - - public List getEventHandlers(EventType type) { - return eventService.getEventHandlers(type); - } - - public List getEventHandlers(EventTypeVO type) { - return eventService.getEventHandlers(type); - } - - public List getEventHandlers() { - return eventService.getEventHandlers(); - } - - public EventHandlerVO getEventHandler(int eventHandlerId) { - return eventService.getEventHandler(eventHandlerId); - } - - public EventHandlerVO getEventHandler(String xid) { - return eventService.getEventHandler(xid); - } - - public EventHandlerVO saveEventHandler(final EventType type, - final EventHandlerVO handler) { - return eventService.saveEventHandler(type, handler); - } - - public EventHandlerVO saveEventHandler(final EventTypeVO type, - final EventHandlerVO handler) { - return eventService.saveEventHandler(type, handler); - } - - public void deleteEventHandler(final int handlerId) { - eventService.deleteEventHandler(handlerId); - } - - public boolean toggleSilence(int eventId, int userId) { - return eventService.toggleSilence(eventId, userId); - } - - @Deprecated - public int getHighestUnsilencedAlarmLevel(int userId) { - return eventService.getHighestUnsilencedAlarmLevel(userId); - } - - public static List getFromCache(int userId) { - return EventService.getFromCache(userId); - } - - public static void addToCache(int userId, List list) { - EventService.addToCache(userId, list); - } - - public static void updateCache(EventInstance event) { - EventService.updateCache(event); - } - - public static void removeUserIdFromCache(int userId) { - EventService.removeUserIdFromCache(userId); - } - - public static void clearCache() { - EventService.clearCache(); - } - - -} diff --git a/src/com/serotonin/mango/rt/event/type/AlarmLevelType.java b/src/com/serotonin/mango/rt/event/type/AlarmLevelType.java new file mode 100644 index 0000000000..4f6e9dfb32 --- /dev/null +++ b/src/com/serotonin/mango/rt/event/type/AlarmLevelType.java @@ -0,0 +1,32 @@ +package com.serotonin.mango.rt.event.type; + +import com.serotonin.mango.rt.event.AlarmLevels; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public enum AlarmLevelType { + + NONE(AlarmLevels.NONE), + INFORMATION(AlarmLevels.INFORMATION), + URGENT(AlarmLevels.URGENT), + CRITICAL(AlarmLevels.CRITICAL), + LIFE_SAFETY(AlarmLevels.LIFE_SAFETY); + private final int code; + AlarmLevelType(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public static List getAlarmLevels() { + return Stream.of(AlarmLevelType.values()).collect(Collectors.toList()); + } + + public static List getAlarmLevelsWithoutNone() { + return Stream.of(AlarmLevelType.values()).filter(a -> a != AlarmLevelType.NONE).collect(Collectors.toList()); + } +} diff --git a/src/com/serotonin/mango/vo/User.java b/src/com/serotonin/mango/vo/User.java index aeccfb4798..b89b766bdd 100644 --- a/src/com/serotonin/mango/vo/User.java +++ b/src/com/serotonin/mango/vo/User.java @@ -21,6 +21,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; import br.org.scadabr.vo.exporter.ZIPProjectManager; @@ -51,6 +52,7 @@ import com.serotonin.web.i18n.LocalizableMessage; import org.scada_lts.dao.UsersProfileDAO; import org.scada_lts.mango.service.UsersProfileService; +import org.scada_lts.web.beans.ApplicationBeans; @JsonRemoteEntity public class User implements SetPointSource, HttpSessionBindingListener, @@ -123,18 +125,6 @@ public class User implements SetPointSource, HttpSessionBindingListener, public User() { } - @Deprecated - public User(int id, String username, String email, String phone, boolean admin, boolean disabled, String homeUrl, long lastLogin) { - this.id = id; - this.username = username; - this.email = email; - this.phone = phone; - this.admin = admin; - this.disabled = disabled; - this.homeUrl = homeUrl; - this.lastLogin = lastLogin; - } - public User(int id, String username, String firstName, String lastName, String email, String phone, boolean admin, boolean disabled, String homeUrl, long lastLogin) { this.id = id; this.username = username; @@ -231,6 +221,16 @@ public void raiseRecursionFailureEvent() { throw new ShouldNeverHappenException(""); } + @Override + public void valueBound(HttpSessionBindingEvent event) { + ApplicationBeans.getLoggedUsersBean().addUser(this, event.getSession()); + } + + @Override + public void valueUnbound(HttpSessionBindingEvent event) { + ApplicationBeans.getLoggedUsersBean().removeUser(this, event.getSession()); + } + // Convenience method for JSPs @JsonIgnore public boolean isDataSourcePermission() { @@ -674,6 +674,10 @@ public int getUserProfile() { public void resetUserProfile() { this.userProfile = Common.NEW_ID; + this.dataPointProfilePermissions.clear(); + this.dataSourceProfilePermissions.clear(); + this.watchListProfilePermissions.clear(); + this.viewProfilePermissions.clear(); } @Override diff --git a/src/com/serotonin/mango/web/dwr/UsersDwr.java b/src/com/serotonin/mango/web/dwr/UsersDwr.java index 0e65e0f71e..f670587539 100644 --- a/src/com/serotonin/mango/web/dwr/UsersDwr.java +++ b/src/com/serotonin/mango/web/dwr/UsersDwr.java @@ -51,6 +51,7 @@ import org.scada_lts.mango.service.SystemSettingsService; import org.scada_lts.mango.service.UserService; import org.scada_lts.mango.service.UsersProfileService; +import org.scada_lts.web.beans.ApplicationBeans; import org.scada_lts.web.mvc.api.json.JsonSettingsMisc; import static com.serotonin.mango.util.LoggingUtils.userInfo; @@ -215,10 +216,10 @@ else if (dupUser != null && id != dupUser.getId()) // set permission on all watchlists } - if (currentUser.getId() == id) + /*if (currentUser.getId() == id) // Update the user object in session too. Why not? - Common.updateUserInSession(request, user); - + Common.updateUserInSession(request, user);*/ + ApplicationBeans.getLoggedUsersBean().updateUser(user); response.addData("userId", user.getId()); } diff --git a/src/org/scada_lts/dao/PendingEventsDAO.java b/src/org/scada_lts/dao/PendingEventsDAO.java index a23dfe6fab..14f19b659c 100644 --- a/src/org/scada_lts/dao/PendingEventsDAO.java +++ b/src/org/scada_lts/dao/PendingEventsDAO.java @@ -19,9 +19,11 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Collections; import java.util.List; import java.util.Map; +import com.serotonin.mango.rt.event.type.AlarmLevelType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.scada_lts.utils.EventTypeUtil; @@ -85,31 +87,32 @@ public class PendingEventsDAO { + "left join userEvents ue on e.id=ue.eventId " + "where " + "ue.userId=? and " - + "(e.ackTs is null or e.ackTs = 0) " + + "(e.ackTs is null or e.ackTs = 0) and " + + "e.alarmLevel >= ? " + "order by e.activeTs desc " - + "LIMIT ? "; + + "LIMIT ? OFFSET ?"; // @formatter:on - public List getPendingEvents(int userId, final Map> comments) { - return getPendingEvents(userId, comments, 100); + public List getPendingEvents(int userId, final Map> comments, AlarmLevelType minAlarmLevel) { + return getPendingEvents(userId, comments, minAlarmLevel, 100, 0); } - public List getPendingEvents(int userId, final Map> comments, int limit) { + public List getPendingEvents(int userId, final Map> comments, AlarmLevelType minAlarmLevel, int limit, int offset) { if (LOG.isTraceEnabled()) { LOG.trace("SQL PendingEvents userId:"+userId); } try { @SuppressWarnings({ "unchecked", "rawtypes" }) - List listEvents = DAO.getInstance().getJdbcTemp().query(SQL_EVENTS,new Integer[]{userId, limit}, + List listEvents = DAO.getInstance().getJdbcTemp().query(SQL_EVENTS,new Integer[]{userId, minAlarmLevel.getCode(), limit, offset}, (rs, rownumber) -> mapToEvent(comments, rs)); return listEvents; } catch (Exception e) { LOG.error(e); } - return null; + return Collections.emptyList(); } private EventInstance mapToEvent(Map> comments, ResultSet rs) throws SQLException { diff --git a/src/org/scada_lts/login/ILoggedUsers.java b/src/org/scada_lts/login/ILoggedUsers.java new file mode 100644 index 0000000000..90b32a2970 --- /dev/null +++ b/src/org/scada_lts/login/ILoggedUsers.java @@ -0,0 +1,15 @@ +package org.scada_lts.login; + +import br.org.scadabr.vo.usersProfiles.UsersProfileVO; +import com.serotonin.mango.vo.User; + +import javax.servlet.http.HttpSession; +import java.util.Set; + +public interface ILoggedUsers { + User addUser(User user, HttpSession session); + void updateUser(User user); + void updateUsers(UsersProfileVO profile); + User removeUser(User user, HttpSession session); + Set getUserIds(); +} diff --git a/src/org/scada_lts/login/LoggedUsers.java b/src/org/scada_lts/login/LoggedUsers.java new file mode 100644 index 0000000000..18eb58153e --- /dev/null +++ b/src/org/scada_lts/login/LoggedUsers.java @@ -0,0 +1,122 @@ +package org.scada_lts.login; + +import br.org.scadabr.vo.usersProfiles.UsersProfileVO; +import com.serotonin.mango.util.LoggingUtils; +import com.serotonin.mango.vo.User; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.security.core.GrantedAuthority; + +import javax.servlet.http.HttpSession; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import static com.serotonin.mango.Common.SESSION_USER; + +public class LoggedUsers implements ILoggedUsers { + + private static final Log LOG = LogFactory.getLog(LoggedUsers.class); + + public LoggedUsers() {} + + private final Map loggedUsers = new ConcurrentHashMap<>(); + private final Map> loggedSessions = new ConcurrentHashMap<>(); + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + private final ThreadLocal blocked = new ThreadLocal<>(); + + @Override + public User addUser(User user, HttpSession session) { + lock.writeLock().lock(); + try { + if("setAttribute".equals(blocked.get())) { + LOG.warn("blocked addUser: " + LoggingUtils.userInfo(user) + ", thread: " + Thread.currentThread().getName()); + return null; + } + loggedSessions.putIfAbsent(user.getId(), new CopyOnWriteArrayList<>()); + if(!loggedSessions.get(user.getId()).contains(session)) { + loggedSessions.get(user.getId()).add(session); + return loggedUsers.put(user.getId(), user); + } + LOG.warn("session exists for: " + LoggingUtils.userInfo(user) + ", thread: " + Thread.currentThread().getName()); + return null; + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public void updateUser(User user) { + lock.writeLock().lock(); + try { + update(user, loggedUsers, loggedSessions, blocked); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public void updateUsers(UsersProfileVO profile) { + lock.writeLock().lock(); + try { + for(User user: new ArrayList<>(loggedUsers.values())) { + if(user.getUserProfile() == profile.getId()) { + profile.apply(user); + update(user, loggedUsers, loggedSessions, blocked); + } + } + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public User removeUser(User user, HttpSession session) { + lock.writeLock().lock(); + try { + if("setAttribute".equals(blocked.get())) { + LOG.warn("blocked removeUser: " + LoggingUtils.userInfo(user) + ", thread: " + Thread.currentThread().getName()); + return null; + } + if (loggedSessions.get(user.getId()) == null || (loggedSessions.get(user.getId()).remove(session) + && loggedSessions.get(user.getId()).isEmpty())) { + loggedSessions.remove(user.getId()); + return loggedUsers.remove(user.getId()); + } + return null; + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public Set getUserIds() { + lock.readLock().lock(); + try { + return loggedUsers.keySet(); + } finally { + lock.readLock().unlock(); + } + } + + private static void update(User user, Map loggedUsers, + Map> loggedSessions, + ThreadLocal blocked) { + User loggedUser = loggedUsers.get(user.getId()); + if(loggedUser == null) { + LOG.warn("not logged user: " + LoggingUtils.userInfo(user) + ", thread: " + Thread.currentThread().getName()); + return; + } + List roles = loggedUser.getAttribute("roles"); + if(roles != null) + user.setAttribute("roles", roles); + loggedSessions.putIfAbsent(user.getId(), new CopyOnWriteArrayList<>()); + for(HttpSession session : loggedSessions.get(user.getId())) { + blocked.set("setAttribute"); + session.setAttribute(SESSION_USER, user); + blocked.set(""); + } + loggedUsers.put(user.getId(), user); + } +} diff --git a/src/org/scada_lts/mango/adapter/MangoEvent.java b/src/org/scada_lts/mango/adapter/MangoEvent.java index 2cf994a07e..cab5948e6e 100644 --- a/src/org/scada_lts/mango/adapter/MangoEvent.java +++ b/src/org/scada_lts/mango/adapter/MangoEvent.java @@ -66,16 +66,12 @@ public interface MangoEvent { List getEventsForDataPoint(int dataPointId, int userId); List getPendingEventsForDataPoint(int dataPointId, int userId); - - List getPendingSimpleEventsForDataSource(int dataSourceId, int userId); List getPendingEventsForDataSource(int dataSourceId, int userId); List getPendingEventsForPublisher(int publisherId, int userId); List getPendingEvents(int typeId, int typeRef1, int userId); - - List getPendingSimpleEvents(int typeId, int typeRef1, int userId); List getPendingEvents(int userId); @@ -132,6 +128,4 @@ public interface MangoEvent { boolean isXidUnique(String xid, int excludeId); List getPendingEventsAlarmLevelMin(int userId, int alarmLevelMin, int limit); - - List getPendingEventsAlarmLevelMin(int userId, int alarmLevelMin, int limit, boolean disabledCache); } diff --git a/src/org/scada_lts/mango/service/EventService.java b/src/org/scada_lts/mango/service/EventService.java index 67491f83f5..6509c6a3bc 100644 --- a/src/org/scada_lts/mango/service/EventService.java +++ b/src/org/scada_lts/mango/service/EventService.java @@ -185,20 +185,6 @@ public List getPendingEvents(int typeId, int typeRef1, int userId } - @Deprecated(since = "2.7.5.4") - @Override - public List getPendingSimpleEvents(int typeId, int typeRef1, int userId) { - - List lst; - if (typeRef1 == -1) { - lst = eventDAO.getPendingEvents(typeId, userId); - } else { - lst = eventDAO.getPendingEvents(typeId, typeRef1, userId); - } - return lst; - - } - @Override public List getEventsForDataPoint(int dataPointId, int userId) { int limit = systemSettingsService.getMiscSettings().getEventPendingLimit(); @@ -235,13 +221,6 @@ public List getPendingEventsForDataSource(int dataSourceId, int u return getPendingEvents(EventType.EventSources.DATA_SOURCE, dataSourceId, userId); } - @Deprecated - @Override - public List getPendingSimpleEventsForDataSource(int dataSourceId, int userId) { - return getPendingSimpleEvents(EventType.EventSources.DATA_SOURCE, dataSourceId, userId); - } - - @Override public List getPendingEventsForPublisher(int publisherId, int userId) { return getPendingEvents(EventType.EventSources.PUBLISHER, publisherId, @@ -251,29 +230,24 @@ public List getPendingEventsForPublisher(int publisherId, int use @Override public List getPendingEvents(int userId) { int limit = systemSettingsService.getMiscSettings().getEventPendingLimit(); - return getPendingEventsAlarmLevelMin(userId, -1, limit, false); + return getPendingEventsAlarmLevelMin(userId, -1, limit); } @Override public List getPendingEventsAlarmLevelMin(int userId, int alarmLevelMin, int limit) { - return getPendingEventsAlarmLevelMin(userId, alarmLevelMin, limit, false); - } - - @Override - public List getPendingEventsAlarmLevelMin(int userId, int alarmLevelMin, int limit, boolean forceDisabledCache) { List results = null; try { boolean cacheEnable = systemSettingsService.getMiscSettings().isEventPendingCacheEnabled(); - if (!forceDisabledCache && cacheEnable) { + int fromSystemSettingsLimit = systemSettingsService.getMiscSettings().getEventPendingLimit(); + int calcLimit = limit > -1 && limit <= fromSystemSettingsLimit ? limit : fromSystemSettingsLimit; + if (cacheEnable) { PendingEventsCache.getInstance().startUpdate(); results = PendingEventsCache.getInstance().getPendingEvents(userId).stream() - .sorted(Comparator.comparing(EventInstance::getActiveTimestamp)) + .sorted(Comparator.comparing(EventInstance::getActiveTimestamp).reversed()) .filter(a -> alarmLevelMin < 0 || a.getAlarmLevel() >= alarmLevelMin) + .limit(calcLimit) .collect(Collectors.toList()); } else { - if(!forceDisabledCache) - PendingEventsCache.getInstance().stopUpdate(); - int fromSystemSettingsLimit = systemSettingsService.getMiscSettings().getEventPendingLimit(); - int calcLimit = limit > -1 ? limit : fromSystemSettingsLimit; + PendingEventsCache.getInstance().stopUpdate(); if(alarmLevelMin > 0) { results = eventDAO.getPendingEventsLimitAlarmLevelMin(userId, alarmLevelMin, calcLimit); } else { diff --git a/src/org/scada_lts/mango/service/PendingEventService.java b/src/org/scada_lts/mango/service/PendingEventService.java index 97bd1dbef0..ea9557399e 100644 --- a/src/org/scada_lts/mango/service/PendingEventService.java +++ b/src/org/scada_lts/mango/service/PendingEventService.java @@ -18,18 +18,23 @@ package org.scada_lts.mango.service; +import com.serotonin.mango.rt.event.type.AlarmLevelType; import com.serotonin.mango.rt.event.EventInstance; +import org.scada_lts.login.ILoggedUsers; +import com.serotonin.mango.vo.User; import com.serotonin.mango.vo.UserComment; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.scada_lts.dao.IUserCommentDAO; -import org.scada_lts.dao.IUserDAO; import org.scada_lts.dao.PendingEventsDAO; +import org.scada_lts.service.IHighestAlarmLevelService; +import org.scada_lts.utils.SystemSettingsUtils; import org.scada_lts.web.beans.ApplicationBeans; import org.springframework.stereotype.Service; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; @Service public class PendingEventService { @@ -40,27 +45,47 @@ public class PendingEventService { private final PendingEventsDAO pendingEventsDAO; - private final IUserDAO userDAO; - private final SystemSettingsService systemSettingsService; + private final IHighestAlarmLevelService highestAlarmLevelService; + private final ILoggedUsers loggedUsers; + public PendingEventService() { userCommentDAO = ApplicationBeans.getUserCommentDaoBean(); + highestAlarmLevelService = ApplicationBeans.getHighestAlarmLevelServiceBean(); + loggedUsers = ApplicationBeans.getLoggedUsersBean(); pendingEventsDAO = new PendingEventsDAO(); - userDAO = ApplicationBeans.getUserDaoBean(); systemSettingsService = new SystemSettingsService(); } public Map> getPendingEvents() { - List users = userDAO.getAll(); + Set users = loggedUsers.getUserIds(); Map> comments = getCacheUserComments(userCommentDAO.getEventComments()); int limit = systemSettingsService.getMiscSettings().getEventPendingLimit(); Map> cacheEvents = new ConcurrentHashMap<>(); for (int userId: users) { - List events = new CopyOnWriteArrayList<>(pendingEventsDAO.getPendingEvents(userId, comments, limit)); - cacheEvents.put(userId, events); + Set events = pendingEventsDAO.getPendingEvents(userId, comments, AlarmLevelType.NONE, + SystemSettingsUtils.getEventPendingUpdateLimit(), 0).stream() + .map(EventInstanceEqualsById::new) + .collect(Collectors.toSet()); + if(!events.isEmpty()) { + int highestAlarmLevelForUser = highestAlarmLevelService.getAlarmLevel(User.onlyId(userId)); + for (AlarmLevelType alarmLevelType : AlarmLevelType.getAlarmLevelsWithoutNone()) { + if(alarmLevelType.getCode() <= highestAlarmLevelForUser) { + long count = events.stream() + .filter(a -> a.getEventInstance().getAlarmLevel() >= alarmLevelType.getCode()) + .count(); + if (count < limit) { + events.addAll(pendingEventsDAO.getPendingEvents(userId, comments, alarmLevelType, limit, 0).stream() + .map(EventInstanceEqualsById::new) + .collect(Collectors.toSet())); + } + } + } + } + cacheEvents.put(userId, events.stream().map(EventInstanceEqualsById::getEventInstance).collect(Collectors.toList())); } return cacheEvents; } @@ -82,4 +107,28 @@ private Map> getCacheUserComments(List c } return mappedUserCommentForEvent; } + + static class EventInstanceEqualsById { + private final EventInstance eventInstance; + public EventInstanceEqualsById(EventInstance eventInstance) { + this.eventInstance = eventInstance; + } + + public EventInstance getEventInstance() { + return eventInstance; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof EventInstanceEqualsById)) return false; + EventInstanceEqualsById byId = (EventInstanceEqualsById) o; + return eventInstance.getId() == byId.eventInstance.getId(); + } + + @Override + public int hashCode() { + return Objects.hash(eventInstance.getId()); + } + } } diff --git a/src/org/scada_lts/utils/SystemSettingsUtils.java b/src/org/scada_lts/utils/SystemSettingsUtils.java index cc0f80d285..dacf29b319 100644 --- a/src/org/scada_lts/utils/SystemSettingsUtils.java +++ b/src/org/scada_lts/utils/SystemSettingsUtils.java @@ -35,6 +35,7 @@ private SystemSettingsUtils() {} public static final String VIEW_FORCE_FULL_SCREEN_MODE = "view.forceFullScreen"; public static final String VIEW_HIDE_SHORTCUT_DISABLE_FULL_SCREEN = "view.hideShortcutDisableFullScreen"; public static final String EVENT_PENDING_LIMIT = "event.pending.limit"; + public static final String EVENT_PENDING_UPDATE_LIMIT = "event.pending.update.limit"; public static final String EVENT_PENDING_CACHE_ENABLED = "abilit.cacheEnable"; private static final org.apache.commons.logging.Log LOG = LogFactory.getLog(SystemSettingsUtils.class); @@ -215,13 +216,23 @@ public static int getEventPendingLimit() { } } + public static int getEventPendingUpdateLimit() { + try { + String eventPendingLimit = ScadaConfig.getInstance().getConf().getProperty(EVENT_PENDING_UPDATE_LIMIT, "1000"); + return Integer.parseInt(eventPendingLimit); + } catch (Exception e) { + LOG.error(e.getMessage()); + return 1000; + } + } + public static boolean isEventPendingCacheEnabled() { try { - String eventPendingCache = ScadaConfig.getInstance().getConf().getProperty(EVENT_PENDING_CACHE_ENABLED, "false"); + String eventPendingCache = ScadaConfig.getInstance().getConf().getProperty(EVENT_PENDING_CACHE_ENABLED, "true"); return Boolean.parseBoolean(eventPendingCache); } catch (Exception e) { LOG.error(e.getMessage()); - return false; + return true; } } } diff --git a/src/org/scada_lts/web/beans/ApplicationBeans.java b/src/org/scada_lts/web/beans/ApplicationBeans.java index c9de7e88a2..4507c8e373 100644 --- a/src/org/scada_lts/web/beans/ApplicationBeans.java +++ b/src/org/scada_lts/web/beans/ApplicationBeans.java @@ -5,6 +5,8 @@ import br.org.scadabr.vo.usersProfiles.UsersProfileVO; import com.serotonin.mango.Common; import com.serotonin.mango.view.View; +import org.scada_lts.login.ILoggedUsers; +import org.scada_lts.login.LoggedUsers; import com.serotonin.mango.vo.User; import com.serotonin.mango.vo.WatchList; import com.serotonin.mango.vo.permission.DataPointAccess; @@ -147,6 +149,10 @@ public static EventsServiceWebSocket getEventsServiceWebSocketBean() { return getBeanFromContext("eventsServiceWebSocket", EventsServiceWebSocket.class); } + public static ILoggedUsers getLoggedUsersBean() { + return getBeanFromContext("loggedUsers", LoggedUsers.class); + } + @Deprecated public static class Lazy { diff --git a/test/com/serotonin/mango/vo/LoggedUserTestsSuite.java b/test/com/serotonin/mango/vo/LoggedUserTestsSuite.java new file mode 100644 index 0000000000..2d34e47567 --- /dev/null +++ b/test/com/serotonin/mango/vo/LoggedUserTestsSuite.java @@ -0,0 +1,17 @@ +package com.serotonin.mango.vo; + +import com.serotonin.mango.rt.scripting.ScriptTest; +import com.serotonin.mango.rt.scripting.ScriptWithObjectContextEnableDisableDataPointTest; +import com.serotonin.mango.rt.scripting.ScriptWithObjectContextEnableDisableDataSourceTest; +import com.serotonin.mango.rt.scripting.ScriptWithObjectContextWriteDataPointTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + LoggedUsersTest.class, + LoggedUsersMultiThreadTest.class +}) +public class LoggedUserTestsSuite { +} \ No newline at end of file diff --git a/test/com/serotonin/mango/vo/LoggedUsersMultiThreadTest.java b/test/com/serotonin/mango/vo/LoggedUsersMultiThreadTest.java new file mode 100644 index 0000000000..e9a5be5047 --- /dev/null +++ b/test/com/serotonin/mango/vo/LoggedUsersMultiThreadTest.java @@ -0,0 +1,532 @@ +package com.serotonin.mango.vo; + +import br.org.scadabr.db.utils.TestUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.scada_lts.login.ILoggedUsers; +import org.scada_lts.login.LoggedUsers; +import org.scada_lts.web.beans.ApplicationBeans; +import org.springframework.mock.web.MockHttpSession; +import utils.TestConcurrentUtils; + +import javax.servlet.http.HttpSession; +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; + +import static com.serotonin.mango.Common.SESSION_USER; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ApplicationBeans.class}) +// resources/org/powermock/extensions/configuration.properties is not working +@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*", "com.sun.org.apache.xalan.*", + "javax.activation.*", "javax.management.*"}) +public class LoggedUsersMultiThreadTest { + + private final ILoggedUsers loggedUsers = new LoggedUsers(); + + @Before + public void config() { + mockStatic(ApplicationBeans.class); + when(ApplicationBeans.getLoggedUsersBean()).thenReturn(loggedUsers); + } + + @Test + public void when_addUser_for_one_user_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, httpSession1) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_one_removeUser_for_one_user_and_same_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_one_removeUser_for_one_user_and_other_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, new MockHttpSession()) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_one_removeUser_for_one_user_and_two_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_one_user_and_two_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_one_user_and_one_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, new MockHttpSession()) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_one_user_and_other_session_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.ConsumerAction<>(loggedUsers::updateUser, user), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_one_user_and_other_session_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, httpSession1), + new TestConcurrentUtils.ConsumerAction<>(loggedUsers::updateUser, user), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_two_user_and_same_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user2, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_addUser_for_two_user_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, httpSession1), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user2, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_four_addUser_for_two_user_then_logged_two_user() { + //given: + User user = TestUtils.newUser(1); + User user2 = TestUtils.newUser(2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user2, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user2, new MockHttpSession()) + )); + + //then: + Assert.assertEquals(2, loggedUsers.getUserIds().size()); + } + + @Test + public void when_six_addUser_for_two_user_then_logged_two_user() { + //given: + User user = TestUtils.newUser(1); + User user2 = TestUtils.newUser(2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user2, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user2, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, new MockHttpSession()), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user2, new MockHttpSession()) + )); + + //then: + Assert.assertEquals(2, loggedUsers.getUserIds().size()); + } + + @Test + public void when_two_removeUser_for_two_user_and_other_session_as_addUser_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, new MockHttpSession()) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_two_user_and_two_session_as_addUser_then_logged_one_user() { + + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_three_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession2), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user2, httpSession3) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_two_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_one_session_as_addUser_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_one_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + TestConcurrentUtils.biConsumer(10, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user2, httpSession3) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_two_user_and_one_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user2, new MockHttpSession()) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_two_user_and_other_session_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user, httpSession1), + new TestConcurrentUtils.ConsumerAction<>(loggedUsers::updateUser, user), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::removeUser, user2, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_two_user_and_other_session_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user, httpSession1), + new TestConcurrentUtils.ConsumerAction<>(loggedUsers::updateUser, user), + new TestConcurrentUtils.BiFunctionAction<>(loggedUsers::addUser, user2, httpSession2) + )); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_one_user_and_one_session_then_set_user_in_session() { + //given: + User user = TestUtils.newUser(123); + user.setFirstName("nonupdated"); + User updatedUser = TestUtils.newUser(123); + updatedUser.setFirstName("updated"); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.ConsumerAction<>(loggedUsers::updateUser, updatedUser) + )); + + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + + //then: + Assert.assertEquals(updatedUser.isAdmin(), result1.isAdmin()); + } + + @Test + public void when_updateUser_for_one_user_and_two_session_then_set_updated_user_in_two_session() { + //given: + User user = TestUtils.newUser(123); + user.setFirstName("nonupdated"); + User updatedUser = TestUtils.newUser(123); + updatedUser.setFirstName("updated"); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.ConsumerAction<>(loggedUsers::updateUser, updatedUser) + )); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + User result2 = (User) httpSession2.getAttribute(SESSION_USER); + + //then: + Assert.assertEquals(updatedUser.getFirstName(), result1.getFirstName()); + Assert.assertEquals(updatedUser.getFirstName(), result2.getFirstName()); + } + + @Test + public void when_updateUser_for_one_user_and_two_session_then_no_set_no_updated_user_in_two_session() { + //given: + User user = TestUtils.newUser(123); + user.setFirstName("nonupdated"); + User updatedUser = TestUtils.newUser(123); + updatedUser.setFirstName("updated"); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + TestConcurrentUtils.biConsumer(1, Arrays.asList( + new TestConcurrentUtils.ConsumerAction<>(loggedUsers::updateUser, updatedUser) + )); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + User result2 = (User) httpSession2.getAttribute(SESSION_USER); + + //then: + Assert.assertNotEquals(user.getFirstName(), result1.getFirstName()); + Assert.assertNotEquals(user.getFirstName(), result2.getFirstName()); + } +} \ No newline at end of file diff --git a/test/com/serotonin/mango/vo/LoggedUsersTest.java b/test/com/serotonin/mango/vo/LoggedUsersTest.java new file mode 100644 index 0000000000..b44bc49113 --- /dev/null +++ b/test/com/serotonin/mango/vo/LoggedUsersTest.java @@ -0,0 +1,535 @@ +package com.serotonin.mango.vo; + +import br.org.scadabr.db.utils.TestUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.scada_lts.login.ILoggedUsers; +import org.scada_lts.login.LoggedUsers; +import org.scada_lts.web.beans.ApplicationBeans; +import org.springframework.mock.web.MockHttpSession; +import utils.TestConcurrentUtils; + +import javax.servlet.http.HttpSession; +import java.util.*; + +import static com.serotonin.mango.Common.SESSION_USER; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ApplicationBeans.class}) +// resources/org/powermock/extensions/configuration.properties is not working +@PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*", "com.sun.org.apache.xalan.*", + "javax.activation.*", "javax.management.*"}) +public class LoggedUsersTest { + + private final ILoggedUsers loggedUsers = new LoggedUsers(); + + @Before + public void config() { + mockStatic(ApplicationBeans.class); + when(ApplicationBeans.getLoggedUsersBean()).thenReturn(loggedUsers); + } + + @Test + public void when_addUser_for_one_user_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + + //when: + loggedUsers.addUser(user, httpSession1); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_one_removeUser_for_one_user_and_same_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + loggedUsers.removeUser(user, httpSession1); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_one_removeUser_for_one_user_and_other_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + loggedUsers.removeUser(user, new MockHttpSession()); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_one_removeUser_for_one_user_and_two_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + loggedUsers.removeUser(user, httpSession1); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_one_user_and_two_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + loggedUsers.removeUser(user, httpSession1); + loggedUsers.removeUser(user, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_one_user_and_one_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + loggedUsers.removeUser(user, httpSession1); + loggedUsers.removeUser(user, new MockHttpSession()); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_one_user_and_other_session_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + loggedUsers.removeUser(user, httpSession1); + loggedUsers.updateUser(user); + loggedUsers.removeUser(user, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_one_user_and_other_session_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + + //when: + loggedUsers.addUser(user, httpSession1); + loggedUsers.updateUser(user); + loggedUsers.addUser(user, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_two_user_and_same_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + loggedUsers.removeUser(user, httpSession1); + loggedUsers.removeUser(user2, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_addUser_for_two_user_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + + //when: + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_two_user_and_other_session_as_addUser_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + loggedUsers.removeUser(user, new MockHttpSession()); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_two_user_and_two_session_as_addUser_then_logged_one_user() { + + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + loggedUsers.removeUser(user, httpSession1); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_three_session_as_addUser_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + loggedUsers.removeUser(user, httpSession1); + loggedUsers.removeUser(user, httpSession2); + loggedUsers.removeUser(user2, httpSession3); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_two_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + loggedUsers.removeUser(user, httpSession1); + loggedUsers.removeUser(user, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_one_session_as_addUser_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + loggedUsers.removeUser(user, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_three_removeUser_for_two_user_and_one_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + HttpSession httpSession3 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + loggedUsers.addUser(user2, httpSession3); + + //when: + loggedUsers.removeUser(user2, httpSession3); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_two_removeUser_for_two_user_and_one_session_as_addUser_then_logged_one_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + loggedUsers.removeUser(user, httpSession1); + loggedUsers.removeUser(user2, new MockHttpSession()); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_and_two_removeUser_for_two_user_then_logged_any_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Collections.emptySet(); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user2, httpSession2); + + //when: + loggedUsers.updateUser(user); + loggedUsers.removeUser(user, httpSession1); + loggedUsers.removeUser(user2, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_addUser_and_updateUser_and_addUser_for_two_user_then_logged_two_user() { + //given: + User user = TestUtils.newUser(123); + User user2 = TestUtils.newUser(345); + Set expected = Set.of(user.getId(), user2.getId()); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + + //when: + loggedUsers.addUser(user, httpSession1); + loggedUsers.updateUser(user); + loggedUsers.addUser(user2, httpSession2); + + //then: + Assert.assertEquals(expected, loggedUsers.getUserIds()); + } + + @Test + public void when_updateUser_for_updated_user_and_two_session_then_set_updated_user_in_two_session() { + //given: + User user = TestUtils.newUser(123); + user.setAdmin(false); + User updatedUser = TestUtils.newUser(123); + updatedUser.setAdmin(true); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + loggedUsers.updateUser(updatedUser); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + User result2 = (User) httpSession2.getAttribute(SESSION_USER); + + //then: + Assert.assertEquals(updatedUser.isAdmin(), result1.isAdmin()); + Assert.assertEquals(updatedUser.isAdmin(), result1.isAdmin()); + } + + @Test + public void when_updateUser_for_two_updated_user_and_two_session_then_set_second_updated_user_in_two_session() { + //given: + User user = TestUtils.newUser(123); + user.setAdmin(false); + user.setFirstName(""); + User firstUpdatedUser = TestUtils.newUser(123); + firstUpdatedUser.setAdmin(true); + User secondUpdatedUser = TestUtils.newUser(123); + secondUpdatedUser.setFirstName("firstName"); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + loggedUsers.updateUser(firstUpdatedUser); + loggedUsers.updateUser(secondUpdatedUser); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + User result2 = (User) httpSession2.getAttribute(SESSION_USER); + + //then: + Assert.assertEquals(secondUpdatedUser.getFirstName(), result1.getFirstName()); + Assert.assertEquals(secondUpdatedUser.getFirstName(), result2.getFirstName()); + } + + @Test + public void when_updateUser_for_updated_user_then_set_updated_user_in_session() { + //given: + User user = TestUtils.newUser(123); + user.setAdmin(false); + User updatedUser = TestUtils.newUser(123); + updatedUser.setAdmin(true); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + loggedUsers.updateUser(updatedUser); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + + //then: + Assert.assertEquals(updatedUser.isAdmin(), result1.isAdmin()); + } + + @Test + public void when_updateUser_for_updated_user_then_not_set_nonupdated_user_in_session() { + //given: + User user = TestUtils.newUser(123); + user.setAdmin(false); + User updatedUser = TestUtils.newUser(123); + updatedUser.setAdmin(true); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + loggedUsers.updateUser(updatedUser); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + + //then: + Assert.assertNotEquals(user.isAdmin(), result1.isAdmin()); + } + + @Test + public void when_updateUser_for_two_updated_user_then_set_second_updated_user_in_session() { + //given: + User user = TestUtils.newUser(123); + user.setAdmin(false); + user.setFirstName(""); + User fisrtUpdatedUser = TestUtils.newUser(123); + fisrtUpdatedUser.setAdmin(true); + User secondUpdatedUser = TestUtils.newUser(123); + secondUpdatedUser.setFirstName("firstName"); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + loggedUsers.updateUser(fisrtUpdatedUser); + loggedUsers.updateUser(secondUpdatedUser); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + + //then: + Assert.assertEquals(secondUpdatedUser.getFirstName(), result1.getFirstName()); + } + + @Test + public void when_updateUser_for_two_updated_user_then_set_not_first_updated_user_in_session() { + //given: + User user = TestUtils.newUser(123); + user.setAdmin(false); + user.setFirstName(""); + User firstUpdatedUser = TestUtils.newUser(123); + firstUpdatedUser.setAdmin(true); + User secondUpdatedUser = TestUtils.newUser(123); + secondUpdatedUser.setFirstName("firstName"); + HttpSession httpSession1 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + + //when: + loggedUsers.updateUser(firstUpdatedUser); + loggedUsers.updateUser(secondUpdatedUser); + User result = (User) httpSession1.getAttribute(SESSION_USER); + + //then: + Assert.assertNotEquals(firstUpdatedUser.getFirstName(), result.getFirstName()); + } + + @Test + public void when_updateUser_for_updated_user_then_not_set_nonupdated_user_in_two_session() { + //given: + User user = TestUtils.newUser(123); + user.setAdmin(false); + User updatedUser = TestUtils.newUser(123); + updatedUser.setAdmin(true); + HttpSession httpSession1 = new MockHttpSession(); + HttpSession httpSession2 = new MockHttpSession(); + loggedUsers.addUser(user, httpSession1); + loggedUsers.addUser(user, httpSession2); + + //when: + loggedUsers.updateUser(updatedUser); + User result1 = (User) httpSession1.getAttribute(SESSION_USER); + User result2 = (User) httpSession2.getAttribute(SESSION_USER); + + //then: + Assert.assertNotEquals(user.isAdmin(), result1.isAdmin()); + Assert.assertNotEquals(user.isAdmin(), result2.isAdmin()); + } +} \ No newline at end of file diff --git a/test/org/scada_lts/ds/messaging/channel/MessagingChannelsMultiThreadTest.java b/test/org/scada_lts/ds/messaging/channel/MessagingChannelsMultiThreadTest.java index 07f0cca158..e5bd0842d9 100644 --- a/test/org/scada_lts/ds/messaging/channel/MessagingChannelsMultiThreadTest.java +++ b/test/org/scada_lts/ds/messaging/channel/MessagingChannelsMultiThreadTest.java @@ -220,16 +220,16 @@ public void when_removeChannel_and_initChannel_on_other_dataPoints_then_one_size //given: messagingChannels.initChannel(dataPointRT2, () -> messagingChannelOpenned1); - TestConcurrentUtils.Action action1 = - new TestConcurrentUtils.Action<>((dp, timeout) -> { + TestConcurrentUtils.BiConsumerAction action1 = + new TestConcurrentUtils.BiConsumerAction<>((dp, timeout) -> { try { messagingChannels.initChannel(dp, () -> messagingChannelOpenned1); } catch (Exception e) { throw new RuntimeException(e); } }, dataPointRT1, 1000); - TestConcurrentUtils.Action action2 = - new TestConcurrentUtils.Action<>((dp, timeout) -> { + TestConcurrentUtils.BiConsumerAction action2 = + new TestConcurrentUtils.BiConsumerAction<>((dp, timeout) -> { try { messagingChannels.removeChannel(dp); } catch (Exception e) { @@ -250,16 +250,16 @@ public void when_removeChannel_and_initChannel_on_other_dataPoints_then_one_isOp //given: messagingChannels.initChannel(dataPointRT2, () -> messagingChannelOpenned1); - TestConcurrentUtils.Action action1 = - new TestConcurrentUtils.Action<>((dp, timeout) -> { + TestConcurrentUtils.BiConsumerAction action1 = + new TestConcurrentUtils.BiConsumerAction<>((dp, timeout) -> { try { messagingChannels.initChannel(dp, () -> messagingChannelOpenned1); } catch (Exception e) { throw new RuntimeException(e); } }, dataPointRT1, 1000); - TestConcurrentUtils.Action action2 = - new TestConcurrentUtils.Action<>((dp, timeout) -> { + TestConcurrentUtils.BiConsumerAction action2 = + new TestConcurrentUtils.BiConsumerAction<>((dp, timeout) -> { try { messagingChannels.removeChannel(dp); } catch (Exception e) { @@ -301,24 +301,24 @@ public void when_isOpenChannel_without_initChannel_then_false() { public void when_initChannel_with_three_dataPoints_then_size_three() throws Exception { //given: - TestConcurrentUtils.Action> action1 = - new TestConcurrentUtils.Action<>((a, b) -> { + TestConcurrentUtils.BiConsumerAction> action1 = + new TestConcurrentUtils.BiConsumerAction<>((a, b) -> { try { messagingChannels.initChannel(a, b); } catch (Exception e) { e.printStackTrace(); } }, dataPointRT1, () -> messagingChannelOpenned1); - TestConcurrentUtils.Action> action2 = - new TestConcurrentUtils.Action<>((a, b) -> { + TestConcurrentUtils.BiConsumerAction> action2 = + new TestConcurrentUtils.BiConsumerAction<>((a, b) -> { try { messagingChannels.initChannel(a, b); } catch (Exception e) { e.printStackTrace(); } }, dataPointRT2, () -> messagingChannelOpenned2); - TestConcurrentUtils.Action> action3 = - new TestConcurrentUtils.Action<>((a, b) -> { + TestConcurrentUtils.BiConsumerAction> action3 = + new TestConcurrentUtils.BiConsumerAction<>((a, b) -> { try { messagingChannels.initChannel(a, b); } catch (Exception e) { diff --git a/test/utils/MultiThreadEngine.java b/test/utils/MultiThreadEngine.java index e47c5a5323..784d9b2b8a 100644 --- a/test/utils/MultiThreadEngine.java +++ b/test/utils/MultiThreadEngine.java @@ -11,7 +11,7 @@ public class MultiThreadEngine { - private static Logger logger = LoggerFactory.getLogger(MultiThreadEngine.class); + private static Logger LOG = LoggerFactory.getLogger(MultiThreadEngine.class); public static void execute(final Executor executor, int concurrency, final Runnable action) { final CountDownLatch ready = new CountDownLatch(concurrency); @@ -24,7 +24,7 @@ public static void execute(final Executor executor, int concurrency, final Runna start.await(); action.run(); } catch (InterruptedException ex) { - logger.error(ex.getMessage(), ex); + LOG.error(ex.getMessage(), ex); } finally { done.countDown(); } @@ -35,9 +35,9 @@ public static void execute(final Executor executor, int concurrency, final Runna long startNanos = System.nanoTime(); start.countDown(); done.await(); - logger.info("time: {}", (System.nanoTime() - startNanos)/1000000000.0); + LOG.info("time: {}", (System.nanoTime() - startNanos)/1000000000.0); } catch (Exception ex) { - logger.error(ex.getMessage(), ex); + LOG.error(ex.getMessage(), ex); } } @@ -54,7 +54,7 @@ public static List execute(final Executor executor, int concurrency, fina R result = action.call(); results.add(result); } catch (Exception ex) { - logger.error(ex.getMessage(), ex); + LOG.error(ex.getMessage(), ex); } finally { done.countDown(); } @@ -65,9 +65,9 @@ public static List execute(final Executor executor, int concurrency, fina long startNanos = System.nanoTime(); start.countDown(); done.await(); - logger.info("time: {}", (System.nanoTime() - startNanos) / 1000000000.0); + LOG.info("time: {}", (System.nanoTime() - startNanos) / 1000000000.0); } catch (Exception ex) { - logger.error(ex.getMessage(), ex); + LOG.error(ex.getMessage(), ex); } return results; } @@ -84,7 +84,7 @@ public static void execute(final Executor executor, int concurrency, final List< start.await(); runnable.run(); } catch (InterruptedException ex) { - logger.error(ex.getMessage(), ex); + LOG.error(ex.getMessage(), ex); } finally { done.countDown(); } @@ -96,9 +96,9 @@ public static void execute(final Executor executor, int concurrency, final List< long startNanos = System.nanoTime(); start.countDown(); done.await(); - logger.info("time: {}", (System.nanoTime() - startNanos)/1000000000.0); + LOG.info("time: {}", (System.nanoTime() - startNanos)/1000000000.0); } catch (Exception ex) { - logger.error(ex.getMessage(), ex); + LOG.error(ex.getMessage(), ex); } } } \ No newline at end of file diff --git a/test/utils/TestConcurrentUtils.java b/test/utils/TestConcurrentUtils.java index 9bc8ef321d..d315839db1 100644 --- a/test/utils/TestConcurrentUtils.java +++ b/test/utils/TestConcurrentUtils.java @@ -32,10 +32,10 @@ public static void biConsumer(int numberOfLaunches, BiConsumer fun, executor.shutdownNow(); } - public static void biConsumer(int numberOfLaunches, List> actions) { + public static void biConsumer(int numberOfLaunches, List actions) { ExecutorService executor = Executors.newFixedThreadPool(numberOfLaunches * actions.size()); List runnables = new ArrayList<>(); - for(Action action: actions) { + for(SupplierVoid action: actions) { runnables.add(action::execute); } MultiThreadEngine.execute(executor, numberOfLaunches, runnables); @@ -92,19 +92,64 @@ public interface SupplierVoid { void execute(); } - public static class Action { - private BiConsumer fun; + public static class BiConsumerAction implements SupplierVoid { + private final BiConsumer fun; A keyA; B keyB; - public Action(BiConsumer fun, A keyA, B keyB) { + public BiConsumerAction(BiConsumer fun, A keyA, B keyB) { this.fun = fun; this.keyA = keyA; this.keyB = keyB; } + @Override public void execute() { fun.accept(keyA, keyB); } } + + public static class ConsumerAction implements SupplierVoid { + private final Consumer fun; + A keyA; + + public ConsumerAction(Consumer fun, A keyA) { + this.fun = fun; + this.keyA = keyA; + } + @Override + public void execute() { + fun.accept(keyA); + } + } + + public static class FunctionAction implements SupplierVoid { + private final Function fun; + A keyA; + + public FunctionAction(Function fun, A keyA) { + this.fun = fun; + this.keyA = keyA; + } + @Override + public void execute() { + fun.apply(keyA); + } + } + + public static class BiFunctionAction implements SupplierVoid { + private final BiFunction fun; + A keyA; + B keyB; + + public BiFunctionAction(BiFunction fun, A keyA, B keyB) { + this.fun = fun; + this.keyA = keyA; + this.keyB = keyB; + } + @Override + public void execute() { + fun.apply(keyA, keyB); + } + } } \ No newline at end of file diff --git a/test/utils/mock/EventServiceMock.java b/test/utils/mock/EventServiceMock.java index 246df5fa19..2b28d870ef 100644 --- a/test/utils/mock/EventServiceMock.java +++ b/test/utils/mock/EventServiceMock.java @@ -91,11 +91,6 @@ public List getPendingEvents(int typeId, int typeRef1, int userId return Collections.emptyList(); } - @Override - public List getPendingSimpleEvents(int typeId, int typeRef1, int userId) { - return Collections.emptyList(); - } - @Override public List getEventsForDataPoint(int dataPointId, int userId) { return Collections.emptyList(); @@ -111,11 +106,6 @@ public List getPendingEventsForDataSource(int dataSourceId, int u return Collections.emptyList(); } - @Override - public List getPendingSimpleEventsForDataSource(int dataSourceId, int userId) { - return Collections.emptyList(); - } - @Override public List getPendingEventsForPublisher(int publisherId, int userId) { return Collections.emptyList(); diff --git a/webapp-resources/env.properties b/webapp-resources/env.properties index 2c2c4b9b82..4a07896f29 100644 --- a/webapp-resources/env.properties +++ b/webapp-resources/env.properties @@ -57,7 +57,7 @@ abilit.disableDataSourcesOnServerStart=false abilit.api.replace.alert.onview=true -abilit.cacheEnable=false +abilit.cacheEnable=true abilit.START_UPDATE_UNSILENCED_ALARM_LEVEL=100000 abilit.START_UPDATE_EVENT_DETECTORS=100000 abilit.START_UPDATE_PENDING_EVENTS=100000 @@ -132,4 +132,5 @@ view.forceFullScreen=false view.hideShortcutDisableFullScreen=false eventdetector.cache.enabled=true event.pending.limit=101 +event.pending.update.limit=5001 thread.name.additional.length=255 \ No newline at end of file