/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Andreas Alanko, Emil Nilsson, Sony Mobile Communications AB.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.sonymobile.jenkins.plugins.gitlab.gitlabauth.folder;
import com.cloudbees.hudson.plugins.folder.Folder;
import com.sonymobile.gitlab.exceptions.GitLabApiException;
import com.sonymobile.gitlab.model.GitLabGroupInfo;
import com.sonymobile.jenkins.plugins.gitlab.gitlabauth.GitLab;
import com.sonymobile.jenkins.plugins.gitlab.gitlabauth.authorization.GitLabFolderAuthorization;
import com.sonymobile.jenkins.plugins.gitlab.gitlabauth.exceptions.ItemNameCollisionException;
import hudson.model.TopLevelItem;
import hudson.model.TopLevelItemDescriptor;
import jenkins.model.ModifiableTopLevelItemGroup;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import static com.sonymobile.jenkins.plugins.gitlab.gitlabauth.helpers.GitLabMatchers.hasGroupId;
import static com.sonymobile.jenkins.plugins.gitlab.gitlabauth.helpers.MockDataCreators.expectNewFolderAuthorization;
import static com.sonymobile.jenkins.plugins.gitlab.gitlabauth.helpers.MockDataCreators.mockFolderAuthorization;
import static com.sonymobile.jenkins.plugins.gitlab.gitlabauth.helpers.MockDataCreators.mockGroupInfo;
import static com.sonymobile.jenkins.plugins.gitlab.gitlabauth.helpers.MockFolderBuilder.folder;
import static com.sonymobile.jenkins.plugins.gitlab.gitlabauth.helpers.MockFolderBuilder.mockFolder;
import static com.sonymobile.jenkins.plugins.gitlab.gitlabauth.helpers.MockFreeStyleProjectBuilder.freeStyleProject;
import static java.util.Arrays.asList;
import static org.apache.commons.lang.StringUtils.EMPTY;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.contains;
import static org.junit.Assert.assertThat;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.api.easymock.PowerMock.replay;
import static org.powermock.api.easymock.PowerMock.verify;
/**
* Tests for {@link GroupFolderManager}.
*
* @author Emil Nilsson
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ GitLabFolderAuthorization.class, GroupFolderManager.class, GitLab.class })
public class GroupFolderManagerTest implements GroupFolderManager.ManagesGroupPredicate {
/** A rule for catching expected exceptions. */
@Rule
public ExpectedException thrown = ExpectedException.none();
/** The descriptor for a folder item. */
private static final TopLevelItemDescriptor folderDescriptor = new Folder.DescriptorImpl();
/** The target item group. */
private ModifiableTopLevelItemGroup itemGroup;
/** Items in the target item group. */
private List<TopLevelItem> items;
/** The GitLab groups. */
private List<GitLabGroupInfo> groups;
/**
* The folder manager instance.
*
* This folder manager only manages group with a group ID less than 10.
*
* @see #shouldManageGroup(GitLabGroupInfo)
*/
private GroupFolderManager folderManager;
@Before
public void setUp() throws Exception {
items = new LinkedList<TopLevelItem>();
groups = new LinkedList<GitLabGroupInfo>();
// mock itemGroup#getGetItems() returning the items list
itemGroup = createMock(ModifiableTopLevelItemGroup.class);
expect(itemGroup.getItems()).andReturn(items).anyTimes();
// mock creating new GitLabFolderAuthorization folder properties
expectNewFolderAuthorization();
mockStatic(GitLab.class);
folderManager = new GroupFolderManager(this, itemGroup, folderDescriptor);
}
/**
* Tests getting the existing GitLab group folders.
*/
@Test
public void getFolders() throws Exception {
// group1 and group2 are managed by the folder manager, everything else should be excluded
addItems(
gitLabFolder(1, "Group 1", "group1"),
gitLabFolder(2, "Group 2", "group2"),
gitLabFolder(10, "Group 10", "group10"),
folder("folder"),
freeStyleProject("item"));
replay(itemGroup);
List<GroupFolderInfo> existingFolders = new ArrayList<GroupFolderInfo>(folderManager.getFolders());
verify(itemGroup);
assertThat(existingFolders, contains(hasGroupId(1), hasGroupId(2)));
}
/**
* Tests getting all the existing GitLab group folders.
*/
@Test
public void getAllFolders() throws Exception {
// group1 and group2 are managed by the folder manager, group10 should still be included
addItems(
gitLabFolder(1, "Group 1", "group1"),
gitLabFolder(2, "Group 2", "group2"),
gitLabFolder(10, "Group 10", "group10"),
folder("folder"),
freeStyleProject("item"));
replay(itemGroup);
List<GroupFolderInfo> existingFolders = new ArrayList<GroupFolderInfo>(folderManager.getAllFolders());
verify(itemGroup);
assertThat(existingFolders, contains(hasGroupId(1), hasGroupId(2), hasGroupId(10)));
}
/**
* Tests getting available GitLab groups.
*/
@Test
public void getAvailableGroups() throws Exception {
// existing groups are group1, group2 and group 10 (group 10 is not managed)
addGroups(
mockGroupInfo(1, "Group 1", "group1"),
mockGroupInfo(2, "Group 2", "group2"),
mockGroupInfo(10, "Group 10", "group10"));
// group1 is already created
addItems(
gitLabFolder(1, "Group 1", "group1"),
folder("folder"),
freeStyleProject("item"));
replay(itemGroup);
Collection<GitLabGroupInfo> availableGroups = folderManager.getAvailableGroups(groups);
assertThat(availableGroups, contains(hasGroupId(2)));
verify(itemGroup);
}
/**
* Tests creating new GitLab group folders.
*/
@Test
public void createFolders() throws Exception {
// attempt to create group1, group2 and group 10 (group 10 is not managed)
addGroups(
mockGroupInfo(1, "Group 1", "group1"),
mockGroupInfo(2, "Group 2", "group2"),
mockGroupInfo(10, "Group 10", "group10")
);
// group1 is already created
addItems(
gitLabFolder(1, "Group 1", "group1"),
folder("folder"),
freeStyleProject("item"));
// return group2 when creating a new folder
Folder group2 = folder("group2");
expect(itemGroup.createProject(folderDescriptor, "group2", true))
.andReturn(group2);
replay(itemGroup);
folderManager.createFolders(groups);
verify(itemGroup);
// get property for group2
GitLabFolderAuthorization folderProperty = group2.getProperties().get(GitLabFolderAuthorization.class);
assertThat("name not set correctly", group2.getName(), is("group2"));
assertThat("folder property not set", folderProperty, is(notNullValue()));
assertThat("group ID not set correctly", folderProperty, hasGroupId(2));
}
/**
* Tests creating new GitLab group folders when the item name collides with another item.
*/
@Test
public void createFoldersWithNameCollisions() throws Exception {
// attempt to create group1, group2, group3 and group4
addGroups(
mockGroupInfo(1, "Group 1", "group1"),
mockGroupInfo(2, "Group 2", "group2"),
mockGroupInfo(3, "Group 3", "group3"),
mockGroupInfo(3, "Group 4", "group4")
);
// group1 is already created, group3 and group4 collides with existing items
addItems(
gitLabFolder(1, "Group 1", "group1"),
freeStyleProject("group3"),
folder("group4"));
expect(itemGroup.createProject(folderDescriptor, "group2", true))
.andReturn(folder("group2"));
expect(itemGroup.createProject(folderDescriptor, "group3", true))
.andThrow(new IllegalArgumentException(EMPTY));
expect(itemGroup.createProject(folderDescriptor, "group4", true))
.andThrow(new IllegalArgumentException(EMPTY));
replay(itemGroup);
// should throw an exception because the item names collides
thrown.expect(ItemNameCollisionException.class);
thrown.expectMessage(containsString("group3, group4"));
folderManager.createFolders(groups);
verify(itemGroup);
}
/**
* Creates a mock of a GitLab group folder
*
* @param name the name of the item
* @param groupId the group ID of the group
* @return a GitLab group folder
*/
private Folder gitLabFolder(int groupId, String name, String path) {
return mockFolder().name(name).addProperty(mockFolderAuthorization(groupId, name, path)).build();
}
/**
* Adds items to the target item group.
*
* @param items the items
*/
private void addItems(TopLevelItem... items) {
this.items.addAll(asList(items));
}
private void addGroups(GitLabGroupInfo... groups) {
this.groups.addAll(asList(groups));
}
/**
* Checks whether a group should be included by the folder manager.
*
* Used to exclude groups with a group ID greater than 9.
*
* @param group the group
* @return true if the group should be included
* @throws GitLabApiException
*/
public boolean shouldManageGroup(GitLabGroupInfo group) throws GitLabApiException {
return group.getId() < 10;
}
}