/*
* Copyright 2017 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.server.dao;
import com.thoughtworks.go.config.CaseInsensitiveString;
import com.thoughtworks.go.domain.*;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.exceptions.UserEnabledException;
import com.thoughtworks.go.server.exceptions.UserNotFoundException;
import org.hamcrest.Matchers;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.ExpectedException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.matchers.JUnitMatchers.hasItems;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:WEB-INF/applicationContext-global.xml",
"classpath:WEB-INF/applicationContext-dataLocalAccess.xml",
"classpath:WEB-INF/applicationContext-acegi-security.xml"
})
public class UserSqlMapDaoIntegrationTest {
@Autowired private UserSqlMapDao userDao;
@Autowired private DatabaseAccessHelper dbHelper;
@Autowired private SessionFactory sessionFactory;
@Before
public void setup() throws Exception {
dbHelper.onSetUp();
userDao.deleteAll();
}
@After
public void teardown() throws Exception {
userDao.deleteAll();
dbHelper.onTearDown();
}
@Test
public void shouldSaveUsersIntoDatabase() throws Exception {
User user = anUser();
userDao.saveOrUpdate(user);
User savedUser = userDao.findUser("user");
assertThat(savedUser, is(user));
assertThat(userDao.load(savedUser.getId()), is(user));
}
@Test
public void shouldSaveLoginAsDisplayNameIfDisplayNameIsNotPresent(){
User user = new User("loser");
userDao.saveOrUpdate(user);
assertThat(userDao.findUser("loser").getDisplayName(), is("loser"));
}
@Test
public void shouldNotUpdateDisplayNameToNullOrBlank(){
User user = new User("loser", "moocow", "moocow@example.com");
userDao.saveOrUpdate(user);
user.setDisplayName("");
userDao.saveOrUpdate(user);
assertThat(userDao.findUser("loser").getDisplayName(), is("loser"));
}
@Test
public void findUserShouldNotFailForNonExistentUser() {
assertThat(userDao.findUser("first"), is(new NullUser()));
User first = user("first");
userDao.saveOrUpdate(first);
assertThat(userDao.findUser("first"), is(first));
}
@Test
public void shouldFailWhenAttemptingToSaveAnonymousUser() {
User user = user(CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()));
try {
userDao.saveOrUpdate(user);
fail("should not allow saving of anonymous user");
} catch (Exception e) {
assertThat(e.getMessage(), is("User name 'anonymous' is not permitted."));
}
}
@Test
public void shouldFailWhenAttemptingToUpdateAnonymousUser() {
User user = user("foo");
userDao.saveOrUpdate(user);
user.setName("anonymous");
try {
userDao.saveOrUpdate(user);
fail("should not allow updating anonymous user");
} catch (Exception e) {
assertThat(e.getMessage(), is("User name 'anonymous' is not permitted."));
}
}
@Test
public void shouldFindUserAgnosticOfCase() {
userDao.saveOrUpdate(user("first"));
User lowerFirst = userDao.findUser("first");
assertThat(lowerFirst.getName(), is("first"));
User upperFirst = userDao.findUser("FIRST");
assertThat(upperFirst.getName(), is("first"));
assertThat(upperFirst.getId(), is(lowerFirst.getId()));
}
@Test
public void shouldDeleteAllUsers() {
User firstUser = user("first");
User secondUser = user("second");
userDao.saveOrUpdate(firstUser);
userDao.saveOrUpdate(secondUser);
userDao.deleteAll();
assertThat(userDao.allUsers().size(), is(0));
}
@Test
public void shouldDisableUsers() {
User firstUser = user("first");
User secondUser = user("second");
User thirdUser = user("third");
userDao.saveOrUpdate(firstUser);
userDao.saveOrUpdate(secondUser);
userDao.saveOrUpdate(thirdUser);
userDao.disableUsers(Arrays.asList("first", "second"));
assertThat(userDao.findUser(firstUser.getName()).isEnabled(), is(false));
assertThat(userDao.findUser(secondUser.getName()).isEnabled(), is(false));
assertThat(userDao.findUser(thirdUser.getName()).isEnabled(), is(true));
}
@Test
public void shouldReturnOnlyEnabledUsers() throws Exception {
userDao.saveOrUpdate(user("first"));
userDao.saveOrUpdate(user("second"));
User disabled = user("disabled");
disabled.disable();
userDao.saveOrUpdate(disabled);
List<User> enabledUsers = userDao.enabledUsers();
assertThat(enabledUsers.size(), is(2));
assertThat(enabledUsers, hasItem(user("first")));
assertThat(enabledUsers, hasItem(user("second")));
}
@Test
public void shouldUpdateUserWhenUserExist() throws Exception {
User user = anUser();
userDao.saveOrUpdate(user);
user = userDao.findUser(user.getName());
user.setEmail("user2@mail.com");
user.setMatcher("abc");
user.setEmailMe(false);
userDao.saveOrUpdate(user);
assertThat(userDao.findUser("user"), is(user));
assertThat(user.getNotificationFilters().size(), is(0));
}
@Test
public void shouldUpdateUserWithEnabledStatusWhenUserExist(){
User user = new User("user", "my name", "user2@mail.com");
userDao.saveOrUpdate(user);
final User foundUser = userDao.findUser("user");
assertThat(foundUser.isEnabled(), is(true));
foundUser.disable();
userDao.saveOrUpdate(foundUser);
assertThat(userDao.findUser("user").isEnabled(), is(false));
}
@Test
public void shouldFindUserWhenExist() throws Exception {
User user = anUser();
userDao.saveOrUpdate(user);
User settingFromDb = userDao.findUser("user");
assertThat(settingFromDb.getName(), is(user.getName()));
assertThat(settingFromDb.getMatcher(), is(user.getMatcher()));
assertThat(settingFromDb.getEmail(), is(user.getEmail()));
}
@Test
public void shouldFindAllUsers() throws Exception {
User user = new User("user", new String[]{"*.*,user"}, "user@mail.com", true);
User loser = new User("loser", new String[]{"loser", "user"}, "loser@mail.com", true);
User boozer = new User("boozer", new String[]{"boozer"}, "boozer@mail.com", true);
userDao.saveOrUpdate(user);
userDao.saveOrUpdate(loser);
userDao.saveOrUpdate(boozer);
List<User> allUsers = userDao.allUsers();
assertThat(allUsers, hasItems(user, loser, boozer));
assertThat(allUsers.size(), is(3));
}
@Test
public void shouldSaveAndLoadNotificationFilterInOrder() {
User user = anUser();
NotificationFilter filter1 = new NotificationFilter("PipelineName", "StageName", StageEvent.Fixed, false);
NotificationFilter filter2 = new NotificationFilter("PipelineName", "StageName", StageEvent.Fails, false);
user.setNotificationFilters(Arrays.asList(filter1, filter2));
userDao.saveOrUpdate(user);
user = userDao.findUser("user");
assertThat(user.getNotificationFilters().size(), is(2));
assertThat(user.getNotificationFilters().get(0), is(filter1));
assertThat(user.getNotificationFilters().get(1).getId(), is(filter2.getId()));
}
@Test
public void shouldGetCountForEnabledUsersOnly() {
User user = new User("user", new String[]{"*.*,user"}, "user@mail.com", true);
User loser = new User("loser", new String[]{"loser", "user"}, "loser@mail.com", true);
User boozer = new User("boozer", new String[]{"boozer"}, "boozer@mail.com", true);
userDao.saveOrUpdate(user);
userDao.saveOrUpdate(loser);
userDao.saveOrUpdate(boozer);
assertThat(userDao.enabledUserCount(), is(3));
userDao.disableUsers(Arrays.asList("loser"));
assertThat(userDao.enabledUserCount(), is(2));
userDao.enableUsers(Arrays.asList("loser"));
assertThat(userDao.enabledUserCount(), is(3));
}
@Test
public void shouldClearCountCacheOnSaveOrStatusChange() {
User user = new User("user", new String[]{"*.*,user"}, "user@mail.com", true);
userDao.saveOrUpdate(user);
assertThat(userDao.enabledUserCount(), is(1));
User loser = new User("loser", "Loser", "loser@mail.com");
loser.disable();
User foo = new User("foo", "Foo", "foo@mail.com");
userDao.saveOrUpdate(loser);
userDao.saveOrUpdate(foo);
userDao.saveOrUpdate(user);
assertThat(userDao.enabledUserCount(), is(2));
userDao.enableUsers(Arrays.asList(loser.getName()));
assertThat(userDao.enabledUserCount(), is(3));
userDao.disableUsers(Arrays.asList(user.getName()));
assertThat(userDao.enabledUserCount(), is(2));
userDao.saveOrUpdate(new User("bozer", "Bozer", "bozer@emai.com"));
assertThat(userDao.enabledUserCount(), is(3));
}
@Test
public void shouldFetchEnabledUsersCount() {
User user = new User("user", new String[]{"*.*,user"}, "user@mail.com", true);
userDao.saveOrUpdate(user);
assertThat(userDao.enabledUserCount(), is(1));
userDao.saveOrUpdate(new User("loser", new String[]{"loser", "user"}, "loser@mail.com", true));
assertThat(userDao.enabledUserCount(), is(2));
}
private User saveUser(final String user) {
User user1 = user(user);
userDao.saveOrUpdate(user1);
return user1;
}
@Test
public void findUserShouldIgnoreCaseOfUserName() {
String userName = "USER";
saveUser(userName.toLowerCase());
User found = userDao.findUser(userName);
found.disable();
userDao.saveOrUpdate(found);
assertThat(userDao.findUser(userName).isEnabled(), is(false));
assertThat(userDao.findUser(userName.toLowerCase()).isEnabled(), is(false));
}
@Test
public void shouldLoadSubscribersOfNotification(){
User user1 = new User("user1");
user1.addNotificationFilter(new NotificationFilter("pipeline", "stage", StageEvent.Fails, true));
userDao.saveOrUpdate(user1);
User user2 = new User("user2");
user2.addNotificationFilter(new NotificationFilter("pipeline", "stage", StageEvent.Fails, true));
user2.addNotificationFilter(new NotificationFilter("pipeline", "stage", StageEvent.Breaks, true));
user2.addNotificationFilter(new NotificationFilter("pipeline", "stage", StageEvent.Passes, true));
userDao.saveOrUpdate(user2);
User user3 = new User("user3");
user3.addNotificationFilter(new NotificationFilter("p1", "s1", StageEvent.Fails, true));
userDao.saveOrUpdate(user3);
User user4 = new User("user4");
userDao.saveOrUpdate(user4);
Users subscribedUsers = userDao.findNotificationSubscribingUsers();
userDao.findNotificationSubscribingUsers();
assertThat(subscribedUsers.size(), is(3));
assertThat(subscribedUsers.containsAll(Arrays.asList(user1, user2, user3)), is(true));
Collections.sort(subscribedUsers, new Comparator<User>() {
@Override
public int compare(User user1, User user2) {
return user1.getName().compareTo(user2.getName());
}
});
assertThat(subscribedUsers.get(0).getNotificationFilters().size(), is(1));
assertThat(subscribedUsers.get(1).getNotificationFilters().size(), is(3));
assertThat(subscribedUsers.get(2).getNotificationFilters().size(), is(1));
}
@Test
public void shouldDeleteNotificationOnAUser(){
User user = new User("user1");
user.addNotificationFilter(new NotificationFilter("pipeline1", "stage", StageEvent.Fails, true));
user.addNotificationFilter(new NotificationFilter("pipeline2", "stage", StageEvent.Fails, true));
userDao.saveOrUpdate(user);
user = userDao.findUser(user.getName());
NotificationFilter filter1 = user.getNotificationFilters().get(0);
long filter1Id = filter1.getId();
NotificationFilter filter2 = user.getNotificationFilters().get(1);
user.removeNotificationFilter(filter1.getId());
userDao.saveOrUpdate(user);
user = userDao.findUser(user.getName());
assertThat(user.getNotificationFilters().size(), is(1));
assertThat(user.getNotificationFilters().contains(filter2), is(true));
assertThat(sessionFactory.openSession().get(NotificationFilter.class, filter1Id), is(Matchers.nullValue()));
}
@Test
public void shouldDeleteUser() {
String userName = "user1";
User user = new User(userName);
user.disable();
userDao.saveOrUpdate(user);
boolean result = userDao.deleteUser(userName);
assertThat(result, is(true));
}
@Test
public void shouldDeleteNotificationsAlongWithUser() {
User user = new User("user1");
user.addNotificationFilter(new NotificationFilter("pipelineName", "stageName", StageEvent.All, true));
user.disable();
userDao.saveOrUpdate(user);
Users users = userDao.findNotificationSubscribingUsers();
assertThat(users, hasItem(user));
boolean result = userDao.deleteUser(user.getName());
assertThat(result, is(true));
users = userDao.findNotificationSubscribingUsers();
assertThat(users, is(empty()));
}
@Test
@ExpectedException(UserNotFoundException.class)
public void shouldThrowExceptionWhenUserIsNotFound() {
String userName = "invaliduser";
userDao.deleteUser(userName);
}
@Test
@ExpectedException(UserEnabledException.class)
public void shouldThrowExceptionWhenUserIsNotDisabled() {
String userName = "enabledUser";
User user = new User(userName);
userDao.saveOrUpdate(user);
userDao.deleteUser(userName);
}
@Test
public void shouldAddNewUserWhenDeleteQueryForTheUserHasCachedANullUser() {
String userName = "invalidForNowUser";
try {
userDao.deleteUser(userName);
fail("should have failed");
} catch (Exception e) {
assertThat(e instanceof UserNotFoundException, is(true));
}
User addingTheUserNow = new User(userName);
addingTheUserNow.disable();
userDao.saveOrUpdate(addingTheUserNow);
User retrievedUser = userDao.findUser(userName);
assertThat(retrievedUser instanceof NullUser, is(false));
assertThat(retrievedUser, is(addingTheUserNow));
assertThat(userDao.deleteUser(userName), is(true));
}
private User anUser() {
return user("user");
}
private User user(String username) {
return new User(username, username, new String[]{"*.*"}, username + "@mail.com", true);
}
}