Add cli commands for users and groups (#1993)

Adds cli commands to manage users and groups.

Co-authored-by: Matthias Thieroff <matthias.thieroff@cloudogu.com>
This commit is contained in:
René Pfeuffer
2022-04-11 10:04:19 +02:00
committed by GitHub
parent edd972b1a8
commit d2e81ce121
51 changed files with 4640 additions and 12 deletions

View File

@@ -0,0 +1,117 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.cli;
import com.google.common.io.Resources;
import picocli.CommandLine;
import sonia.scm.template.MustacheTemplateTestEngine;
import sonia.scm.template.TemplateEngine;
import sonia.scm.template.TemplateEngineFactory;
import javax.servlet.ServletContext;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.ResourceBundle;
import static java.util.Collections.singleton;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* This is a helper to create a {@link TemplateRenderer} that can be used for
* command tests
*/
public class TemplateTestRenderer {
private final ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
private final ByteArrayOutputStream stdErr = new ByteArrayOutputStream();
private final CliContext context = mock(CliContext.class);
private final TemplateEngineFactory templateEngineFactory;
@SuppressWarnings("UnstableApiUsage")
public TemplateTestRenderer() {
lenient().when(context.getStdout()).thenReturn(new PrintWriter(stdOut));
lenient().when(context.getStderr()).thenReturn(new PrintWriter(stdErr));
lenient().doThrow(CliExitException.class).when(context).exit(anyInt());
ServletContext servletContext = mock(ServletContext.class);
lenient().when(servletContext.getResourceAsStream(any()))
.thenAnswer(invocation -> Resources.getResource(invocation.getArgument(0, String.class)).openStream());
TemplateEngine engine = new MustacheTemplateTestEngine().createEngine(servletContext);
when(context.getLocale()).thenReturn(new Locale("en"));
templateEngineFactory = new TemplateEngineFactory(singleton(engine), engine);
}
public TemplateRenderer createTemplateRenderer() {
return new TemplateRenderer(context, templateEngineFactory) {
@Override
protected ResourceBundle getBundle() {
return TemplateTestRenderer.this.getResourceBundle();
}
};
}
public ResourceBundle getResourceBundle() {
return ResourceBundle.getBundle("sonia.scm.cli.i18n", context.getLocale(), new ResourceBundle.Control() {
@Override
public Locale getFallbackLocale(String baseName, Locale locale) {
return Locale.ROOT;
}
});
}
public void setLocale(String locale) {
lenient().when(context.getLocale()).thenReturn(new Locale(locale));
}
public String getStdOut() {
return stdOut.toString();
}
public String getStdErr() {
return stdErr.toString();
}
public CliContext getContextMock() {
return context;
}
public TemplateEngineFactory getTemplateEngineFactory() {
return templateEngineFactory;
}
public CommandLine.Model.CommandSpec getMockedSpeck() {
ResourceBundle resourceBundle = getResourceBundle();
CommandLine.Model.CommandSpec mock = mock(CommandLine.Model.CommandSpec.class);
lenient().when(mock.resourceBundle()).thenReturn(resourceBundle);
return mock;
}
}

View File

@@ -0,0 +1,122 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class GroupAddMemberCommandTest {
private final GroupTemplateTestRenderer testRenderer = new GroupTemplateTestRenderer();
@Mock
private GroupManager manager;
private GroupAddMemberCommand command;
@BeforeEach
void initCommand() {
command = new GroupAddMemberCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulModificationTest {
private Group group;
@BeforeEach
void mockModification() {
group = new Group("test", "hog", "zaphod");
when(manager.get("hog")).thenAnswer(invocation -> group);
doAnswer(invocation -> {
Group modifiedGroup = invocation.getArgument(0, Group.class);
modifiedGroup.setLastModified(1649662000000L);
group = modifiedGroup;
return null;
}).when(manager).modify(any());
command.setName("hog");
command.setMembers(new String[]{"trillian", "arthur", "ford"});
}
@Test
void shouldModifyGroup() {
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("hog");
assertThat(argument.getMembers()).contains("zaphod", "trillian", "arthur", "ford");
return true;
}));
}
@Test
void shouldPrintGroupAfterModification() {
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Name: hog",
"Members: zaphod, trillian, arthur, ford",
"Last Modified: 2022-04-11T07:26:40Z"
);
assertThat(testRenderer.getStdErr())
.isEmpty();
}
}
@Test
void shouldFailIfGroupDoesNotExists() {
when(manager.get("hog")).thenReturn(null);
command.setName("hog");
Assertions.assertThrows(
CliExitException.class,
() -> command.run()
);
assertThat(testRenderer.getStdOut())
.isEmpty();
assertThat(testRenderer.getStdErr())
.isEqualTo("Could not find group");
}
}

View File

@@ -0,0 +1,103 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class GroupCreateCommandTest {
private final GroupTemplateTestRenderer testRenderer = new GroupTemplateTestRenderer();
@Mock
private GroupManager manager;
private GroupCreateCommand command;
@BeforeEach
void initCommand() {
command = new GroupCreateCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulCreationTest {
@BeforeEach
void mockCreation() {
when(manager.create(any()))
.thenAnswer(invocation -> {
Group createdGroup = invocation.getArgument(0, Group.class);
createdGroup.setCreationDate(1649262000000L);
return createdGroup;
});
command.setName("hog");
command.setDescription("Crew of the Heart of Gold");
command.setMembers(new String[]{"zaphod", "trillian"});
}
@Test
void shouldCreateGroup() {
command.run();
verify(manager).create(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("hog");
assertThat(argument.getDescription()).isEqualTo("Crew of the Heart of Gold");
assertThat(argument.getMembers()).contains("zaphod", "trillian");
return true;
}));
}
@Test
void shouldPrintGroupAfterCreation() {
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Name: hog",
"Description: Crew of the Heart of Gold",
"Members: zaphod, trillian",
"External: no",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: "
);
assertThat(testRenderer.getStdErr())
.isEmpty();
}
}
}

View File

@@ -0,0 +1,98 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class GroupDeleteCommandTest {
@Mock
private GroupManager manager;
private final GroupTemplateTestRenderer testRenderer = new GroupTemplateTestRenderer();
private GroupDeleteCommand command;
@BeforeEach
void initCommand() {
command = new GroupDeleteCommand(testRenderer.getTemplateRenderer(), manager);
}
@Test
void shouldRenderPromptWithoutYesFlag() {
command.setName("hog");
command.run();
assertThat(testRenderer.getStdOut())
.isEmpty();
assertThat(testRenderer.getStdErr())
.isEqualTo("If you really want to delete this group please pass --yes");
}
@Test
void shouldDeleteGroup() {
Group groupToDelete = new Group("test", "vogons");
when(manager.get("vogons")).thenReturn(groupToDelete);
command.setShouldDelete(true);
command.setName("vogons");
command.run();
verify(manager).delete(groupToDelete);
assertThat(testRenderer.getStdOut())
.isEmpty();
assertThat(testRenderer.getStdErr())
.isEmpty();
}
@Test
void shouldNotFailForNotExistingGroup() {
when(manager.get("vogons")).thenReturn(null);
command.setShouldDelete(true);
command.setName("vogons");
command.run();
verify(manager, never()).delete(any());
assertThat(testRenderer.getStdOut())
.isEmpty();
assertThat(testRenderer.getStdErr())
.isEmpty();
}
}

View File

@@ -0,0 +1,95 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class GroupGetCommandTest {
private final GroupTemplateTestRenderer testRenderer = new GroupTemplateTestRenderer();
@Mock
private GroupManager manager;
private GroupGetCommand command;
@BeforeEach
void initCommand() {
command = new GroupGetCommand(testRenderer.getTemplateRenderer(), manager);
}
@Test
void shouldGetGroup() {
Group group = new Group("test", "hog", "zaphod", "trillian");
group.setCreationDate(1649262000000L);
group.setLastModified(1649462000000L);
group.setDescription("Crew of the Heart of Gold");
when(manager.get("hog")).thenReturn(group);
command.setName("hog");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Name: hog",
"Description: Crew of the Heart of Gold",
"Members: zaphod, trillian",
"External: no",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-08T23:53:20Z"
);
assertThat(testRenderer.getStdErr())
.isEmpty();
}
@Test
void shouldFailForNotExistingGroup() {
command.setName("hog");
Assertions.assertThrows(
CliExitException.class,
() -> command.run()
);
assertThat(testRenderer.getStdOut())
.isEmpty();
assertThat(testRenderer.getStdErr())
.contains("Could not find group");
}
}

View File

@@ -0,0 +1,85 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.TemplateTestRenderer;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class GroupListCommandTest {
@Mock
private GroupManager manager;
private final GroupCommandBeanMapper beanMapper = new GroupCommandBeanMapperImpl();
private final TemplateTestRenderer testRenderer = new TemplateTestRenderer();
private GroupListCommand command;
@BeforeEach
void initCommand() {
command = new GroupListCommand(testRenderer.createTemplateRenderer(), manager, beanMapper);
command.setSpec(testRenderer.getMockedSpeck());
}
@BeforeEach
void mockGroups() {
Group internalGroup = new Group("test", "hog");
Group externalGroup = new Group("test", "vogons");
externalGroup.setExternal(true);
when(manager.getAll())
.thenReturn(
asList(
internalGroup,
externalGroup));
}
@Test
void shouldRenderShortTable() {
command.setUseShortTemplate(true);
command.run();
assertThat(testRenderer.getStdOut()).isEqualTo("hog\nvogons\n");
}
@Test
void shouldRenderLongTable() {
command.run();
assertThat(testRenderer.getStdOut())
.isEqualTo("NAME EXTERNAL\nhog no \nvogons yes \n");
}
}

View File

@@ -0,0 +1,180 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class GroupModifyCommandTest {
private final GroupTemplateTestRenderer testRenderer = new GroupTemplateTestRenderer();
@Mock
private GroupManager manager;
private GroupModifyCommand command;
@BeforeEach
void initCommand() {
command = new GroupModifyCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulModificationTest {
private Group group;
@BeforeEach
void mockModification() {
group = new Group("test", "hog", "zaphod", "trillian");
group.setCreationDate(1649262000000L);
group.setLastModified(1649462000000L);
group.setDescription("Crew of the Heart of Gold");
when(manager.get("hog")).thenAnswer(invocation -> group);
doAnswer(invocation -> {
Group modifiedGroup = invocation.getArgument(0, Group.class);
modifiedGroup.setLastModified(1649662000000L);
group = modifiedGroup;
return null;
}).when(manager).modify(any());
command.setName("hog");
}
@Test
void shouldModifyGroup() {
command.setDescription("Earthlings on the Heart of Gold");
command.setMembers(new String[]{"arthur", "trillian"});
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("hog");
assertThat(argument.getDescription()).isEqualTo("Earthlings on the Heart of Gold");
assertThat(argument.getMembers()).contains("arthur", "trillian");
assertThat(argument.isExternal()).isFalse();
return true;
}));
}
@Test
void shouldNotModifyDescriptionIfNotSet() {
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getDescription()).isEqualTo("Crew of the Heart of Gold");
return true;
}));
}
@Test
void shouldNotModifyExternalIfNotSet() {
group.setExternal(true);
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.isExternal()).isTrue();
return true;
}));
}
@Test
void shouldNotModifyMembersIfNotSet() {
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getMembers()).contains("zaphod", "trillian");
return true;
}));
}
@Test
void shouldSetGroupExternal() {
command.setExternal(true);
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getMembers()).isEmpty();
assertThat(argument.isExternal()).isTrue();
return true;
}));
}
@Test
void shouldPrintGroupAfterModification() {
command.setDescription("Earthlings on the Heart of Gold");
command.setMembers(new String[]{"arthur", "trillian"});
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Name: hog",
"Description: Earthlings on the Heart of Gold",
"Members: arthur, trillian",
"External: no",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-11T07:26:40Z"
);
assertThat(testRenderer.getStdErr())
.isEmpty();
}
}
@Test
void shouldFailIfGroupDoesNotExists() {
when(manager.get("hog")).thenReturn(null);
command.setName("hog");
Assertions.assertThrows(
CliExitException.class,
() -> command.run()
);
assertThat(testRenderer.getStdOut())
.isEmpty();
assertThat(testRenderer.getStdErr())
.isEqualTo("Could not find group");
}
}

View File

@@ -0,0 +1,122 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.group.Group;
import sonia.scm.group.GroupManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class GroupRemoveMemberCommandTest {
private final GroupTemplateTestRenderer testRenderer = new GroupTemplateTestRenderer();
@Mock
private GroupManager manager;
private GroupRemoveMemberCommand command;
@BeforeEach
void initCommand() {
command = new GroupRemoveMemberCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulModificationTest {
private Group group;
@BeforeEach
void mockModification() {
group = new Group("test", "hog", "zaphod", "marvin", "trillian");
when(manager.get("hog")).thenAnswer(invocation -> group);
doAnswer(invocation -> {
Group modifiedGroup = invocation.getArgument(0, Group.class);
modifiedGroup.setLastModified(1649662000000L);
group = modifiedGroup;
return null;
}).when(manager).modify(any());
command.setName("hog");
command.setMembers(new String[]{"zaphod", "marvin"});
}
@Test
void shouldModifyGroup() {
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("hog");
assertThat(argument.getMembers()).contains("trillian");
return true;
}));
}
@Test
void shouldPrintGroupAfterModification() {
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Name: hog",
"Members: trillian",
"Last Modified: 2022-04-11T07:26:40Z"
);
assertThat(testRenderer.getStdErr())
.isEmpty();
}
}
@Test
void shouldFailIfGroupDoesNotExists() {
when(manager.get("hog")).thenReturn(null);
command.setName("hog");
Assertions.assertThrows(
CliExitException.class,
() -> command.run()
);
assertThat(testRenderer.getStdOut())
.isEmpty();
assertThat(testRenderer.getStdErr())
.isEqualTo("Could not find group");
}
}

View File

@@ -0,0 +1,52 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.group.cli;
import sonia.scm.cli.TemplateTestRenderer;
import java.util.ResourceBundle;
class GroupTemplateTestRenderer {
private final TemplateTestRenderer testRenderer = new TemplateTestRenderer();
private final GroupCommandBeanMapper beanMapper = new GroupCommandBeanMapperImpl();
private final GroupTemplateRenderer templateRenderer = new GroupTemplateRenderer(testRenderer.getContextMock(), testRenderer.getTemplateEngineFactory(), beanMapper) {
@Override
protected ResourceBundle getBundle() {
return testRenderer.getResourceBundle();
}
};
GroupTemplateRenderer getTemplateRenderer() {
return templateRenderer;
}
String getStdOut() {
return testRenderer.getStdOut();
}
String getStdErr() {
return testRenderer.getStdErr();
}
}

View File

@@ -0,0 +1,54 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.template;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import sonia.scm.plugin.PluginLoader;
import javax.servlet.ServletContext;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* This class can be used to create a mustache renderer in unit test
*/
public class MustacheTemplateTestEngine {
public TemplateEngine createEngine(ServletContext context) {
PluginLoader loader = mock(PluginLoader.class);
when(loader.getUberClassLoader()).thenReturn(
Thread.currentThread().getContextClassLoader());
MustacheTemplateEngine.PluginLoaderHolder pluginLoaderHolder = new MustacheTemplateEngine.PluginLoaderHolder();
pluginLoaderHolder.pluginLoader = loader;
MustacheTemplateEngine.MeterRegistryHolder meterRegistryHolder = new MustacheTemplateEngine.MeterRegistryHolder();
meterRegistryHolder.registry = new SimpleMeterRegistry();
return new MustacheTemplateEngine(context, pluginLoaderHolder, meterRegistryHolder);
}
}

View File

@@ -0,0 +1,188 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserActivateCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private UserManager manager;
private UserActivateCommand command;
@BeforeEach
void initCommand() {
command = new UserActivateCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulActivationTest {
@BeforeEach
void mockGet() {
User user = new User("havelock", "Havelock Vetinari", "havelock.vetinari@discworld");
user.setPassword("patrician");
user.setExternal(false);
user.setActive(false);
user.setCreationDate(1649262000000L);
user.setLastModified(1649272000000L);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldActivateInternalUser() {
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("patrician");
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldPrintUserAfterActivationInEnglish() {
testRenderer.setLocale("en");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Username: havelock",
"Display Name: Havelock Vetinari",
"Email address: havelock.vetinari@discworld",
"External: no",
"Active: yes",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldPrintUserAfterActivationInGerman() {
testRenderer.setLocale("de");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Benutzername: havelock",
"Anzeigename: Havelock Vetinari ",
"E-Mail-Adresse: havelock.vetinari@discworld",
"Extern: nein",
"Aktiv: ja",
"Erstellt: 2022-04-06T16:20:00Z",
"Zuletzt bearbeitet: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
@Nested
class ForUnsuccessfulActivationTest {
@Test
void shouldFailWithEnglishMsgIfUserNotFound() {
testRenderer.setLocale("en");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Could not find user");
}
@Test
void shouldFailWithGermanMsgIfUserNotFound() {
testRenderer.setLocale("de");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Benutzer konnte nicht gefunden werden");
}
@Nested
class ForExternalUserTest {
@BeforeEach
void mockExternalUser() {
User user = new User();
user.setExternal(true);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldFailWithEnglishMsgIfUserIsExternal() {
testRenderer.setLocale("en");
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("External users cannot be activated");
}
@Test
void shouldFailWithGermanMsgIfUserIsExternal() {
testRenderer.setLocale("de");
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Externe Benutzer können nicht aktiviert werden");
}
}
}
}

View File

@@ -0,0 +1,155 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserConvertToExternalCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private UserManager manager;
private UserConvertToExternalCommand command;
@BeforeEach
void initCommand() {
command = new UserConvertToExternalCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulConversionTest {
@BeforeEach
void mockGet() {
User user = new User("havelock", "Havelock Vetinari", "havelock.vetinari@discworld");
user.setPassword("patrician");
user.setExternal(false);
user.setActive(true);
user.setCreationDate(1649262000000L);
user.setLastModified(1649272000000L);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldConvertToExternalUser() {
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isTrue();
assertThat(argument.getPassword()).isEqualTo("patrician");
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldPrintUserAfterConversionInEnglish() {
testRenderer.setLocale("en");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Username: havelock",
"Display Name: Havelock Vetinari",
"Email address: havelock.vetinari@discworld",
"External: yes",
"Active: yes",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldPrintUserAfterConversionInGerman() {
testRenderer.setLocale("de");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Benutzername: havelock",
"Anzeigename: Havelock Vetinari ",
"E-Mail-Adresse: havelock.vetinari@discworld",
"Extern: ja",
"Aktiv: ja",
"Erstellt: 2022-04-06T16:20:00Z",
"Zuletzt bearbeitet: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
@Nested
class ForUnsuccessfulConversionTest {
@Test
void shouldFailWithEnglishMsgIfUserNotFound() {
testRenderer.setLocale("en");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Could not find user");
}
@Test
void shouldFailWithGermanMsgIfUserNotFound() {
testRenderer.setLocale("de");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Benutzer konnte nicht gefunden werden");
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserConvertToInternalCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private UserManager manager;
private UserConvertToInternalCommand command;
@BeforeEach
void initCommand() {
command = new UserConvertToInternalCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulActivationTest {
@BeforeEach
void mockGet() {
User user = new User("havelock", "Havelock Vetinari", "havelock.vetinari@discworld");
user.setPassword("patrician");
user.setExternal(true);
user.setActive(true);
user.setCreationDate(1649262000000L);
user.setLastModified(1649272000000L);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldActivateInternalUser() {
command.setPassword("havelock123");
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("havelock123");
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldPrintUserAfterActivationInEnglish() {
testRenderer.setLocale("en");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Username: havelock",
"Display Name: Havelock Vetinari",
"Email address: havelock.vetinari@discworld",
"External: no",
"Active: yes",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldPrintUserAfterActivationInGerman() {
testRenderer.setLocale("de");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Benutzername: havelock",
"Anzeigename: Havelock Vetinari ",
"E-Mail-Adresse: havelock.vetinari@discworld",
"Extern: nein",
"Aktiv: ja",
"Erstellt: 2022-04-06T16:20:00Z",
"Zuletzt bearbeitet: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
@Nested
class ForUnsuccessfulConversionTest {
@Test
void shouldFailWithEnglishMsgIfUserNotFound() {
testRenderer.setLocale("en");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Could not find user");
}
@Test
void shouldFailWithGermanMsgIfUserNotFound() {
testRenderer.setLocale("de");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Benutzer konnte nicht gefunden werden");
}
}
}

View File

@@ -0,0 +1,237 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.cli.CommandValidator;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserCreateCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private CommandValidator validator;
@Mock
private UserManager manager;
private UserCreateCommand command;
@BeforeEach
void initCommand() {
command = new UserCreateCommand(testRenderer.getTemplateRenderer(), validator, manager);
}
@Nested
class ForSuccessfulCreationTest {
@BeforeEach
void mockCreation() {
when(manager.create(any()))
.thenAnswer(invocation -> {
User createdUser = invocation.getArgument(0, User.class);
createdUser.setCreationDate(1649262000000L);
return createdUser;
});
command.setUsername("havelock");
command.setDisplayName("Havelock Vetinari");
command.setEmail("havelock.vetinari@discworld");
}
@Test
void shouldCreateInternalUser() {
command.setPassword("patrician");
command.run();
verify(manager).create(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("patrician");
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldCreateExternalUser() {
command.setExternal(true);
command.run();
verify(manager).create(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isTrue();
assertThat(argument.getPassword()).isNull();
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldCreateInactiveUser() {
command.setPassword("patrician");
command.setInactive(true);
command.run();
verify(manager).create(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("patrician");
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isFalse();
return true;
}));
}
@Test
void shouldPrintUserAfterCreationInEnglish() {
testRenderer.setLocale("en");
command.setPassword("patrician");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Username: havelock",
"Display Name: Havelock Vetinari",
"Email address: havelock.vetinari@discworld",
"External: no",
"Active: yes",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified:"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldPrintUserAfterCreationInGerman() {
testRenderer.setLocale("de");
command.setPassword("patrician");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Benutzername: havelock",
"Anzeigename: Havelock Vetinari ",
"E-Mail-Adresse: havelock.vetinari@discworld",
"Extern: nein",
"Aktiv: ja",
"Erstellt: 2022-04-06T16:20:00Z",
"Zuletzt bearbeitet:"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
@Nested
class ForUnsuccessfulCreationTest {
@Test
void shouldFailIfValidatorFails() {
doThrow(picocli.CommandLine.ParameterException.class).when(validator).validate();
assertThrows(
picocli.CommandLine.ParameterException.class,
() -> command.run()
);
assertThat(testRenderer.getStdOut()).isEmpty();
}
@Test
void shouldFailWithEnglishMsgIfInternalUserWithoutPassword() {
testRenderer.setLocale("en");
assertThrows(CliExitException.class, () -> command.run());
verifyNoInteractions(manager);
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Password is required for internal users");
}
@Test
void shouldFailWithGermanMsgIfInternalUserWithoutPassword() {
testRenderer.setLocale("de");
assertThrows(CliExitException.class, () -> command.run());
verifyNoInteractions(manager);
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Für interne Benutzer muss ein Passwort gesetzt werden");
}
@Test
void shouldFailWithEnglishMsgIfExternalUserAndInactive() {
testRenderer.setLocale("en");
command.setExternal(true);
command.setInactive(true);
assertThrows(CliExitException.class, () -> command.run());
verifyNoInteractions(manager);
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("External users cannot be deactivated");
}
@Test
void shouldFailWithGermanMsgIfExternalUserWithInactive() {
testRenderer.setLocale("de");
command.setExternal(true);
command.setInactive(true);
assertThrows(CliExitException.class, () -> command.run());
verifyNoInteractions(manager);
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Externe Benutzer können nicht deaktiviert werden");
}
}
}

View File

@@ -0,0 +1,188 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserDeactivateCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private UserManager manager;
private UserDeactivateCommand command;
@BeforeEach
void initCommand() {
command = new UserDeactivateCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulDeactivationTest {
@BeforeEach
void mockGet() {
User user = new User("havelock", "Havelock Vetinari", "havelock.vetinari@discworld");
user.setPassword("patrician");
user.setExternal(false);
user.setActive(true);
user.setCreationDate(1649262000000L);
user.setLastModified(1649272000000L);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldDeactivateInternalUser() {
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("patrician");
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isFalse();
return true;
}));
}
@Test
void shouldPrintUserAfterDeactivationInEnglish() {
testRenderer.setLocale("en");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Username: havelock",
"Display Name: Havelock Vetinari",
"Email address: havelock.vetinari@discworld",
"External: no",
"Active: no",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldPrintUserAfterDeactivationInGerman() {
testRenderer.setLocale("de");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Benutzername: havelock",
"Anzeigename: Havelock Vetinari ",
"E-Mail-Adresse: havelock.vetinari@discworld",
"Extern: nein",
"Aktiv: nein",
"Erstellt: 2022-04-06T16:20:00Z",
"Zuletzt bearbeitet: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
@Nested
class ForUnsuccessfulActivationTest {
@Test
void shouldFailWithEnglishMsgIfUserNotFound() {
testRenderer.setLocale("en");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Could not find user");
}
@Test
void shouldFailWithGermanMsgIfUserNotFound() {
testRenderer.setLocale("de");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Benutzer konnte nicht gefunden werden");
}
@Nested
class ForExternalUserTest {
@BeforeEach
void mockExternalUser() {
User user = new User();
user.setExternal(true);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldFailWithEnglishMsgIfUserIsExternal() {
testRenderer.setLocale("en");
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("External users cannot be deactivated");
}
@Test
void shouldFailWithGermanMsgIfUserIsExternal() {
testRenderer.setLocale("de");
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Externe Benutzer können nicht deaktiviert werden");
}
}
}
}

View File

@@ -0,0 +1,132 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserDeleteCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private UserManager manager;
private UserDeleteCommand command;
@BeforeEach
void initCommand() {
command = new UserDeleteCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulDeletionTest {
private User user;
@BeforeEach
void mockGet() {
user = new User();
lenient().when(manager.get(any())).thenReturn(user);
}
@Test
void shouldRenderPromptInEnglishWithoutYesFlag() {
testRenderer.setLocale("en");
command.run();
verifyNoInteractions(manager);
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("If you really want to delete this user please pass --yes");
}
@Test
void shouldRenderPromptInGermanWithoutYesFlag() {
testRenderer.setLocale("de");
command.run();
verifyNoInteractions(manager);
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Wenn dieser Benutzer endgültig gelöscht werden soll, setzen Sie bitte --yes");
}
@Test
void shouldDeleteUserWithEnglishMsg() {
testRenderer.setLocale("en");
command.setShouldDelete(true);
command.run();
verify(manager).delete(user);
assertThat(testRenderer.getStdOut()).contains("Successfully deleted user");
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldDeleteUserWithGermanMsg() {
testRenderer.setLocale("de");
command.setShouldDelete(true);
command.run();
verify(manager).delete(user);
assertThat(testRenderer.getStdOut()).contains("Benutzer erfolgreich gelöscht");
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
@Nested
class ForUnsuccessfulDeletionTest {
@Test
void shouldFailSilentlyIfUserNotFound() {
when(manager.get(any())).thenReturn(null);
command.setShouldDelete(true);
command.run();
verify(manager, never()).delete(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
}

View File

@@ -0,0 +1,136 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserGetCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private UserManager manager;
private UserGetCommand command;
@BeforeEach
void initCommand() {
command = new UserGetCommand(testRenderer.getTemplateRenderer(), manager);
}
@Nested
class ForSuccessfulGetTest {
@BeforeEach
void mockGet() {
User user = new User("havelock", "Havelock Vetinari", "havelock.vetinari@discworld");
user.setPassword("patrician");
user.setExternal(true);
user.setActive(false);
user.setCreationDate(1649262000000L);
user.setLastModified(1649272000000L);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldPrintUserInEnglish() {
testRenderer.setLocale("en");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Username: havelock",
"Display Name: Havelock Vetinari",
"Email address: havelock.vetinari@discworld",
"External: yes",
"Active: no",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldPrintUserInGerman() {
testRenderer.setLocale("de");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Benutzername: havelock",
"Anzeigename: Havelock Vetinari ",
"E-Mail-Adresse: havelock.vetinari@discworld",
"Extern: ja",
"Aktiv: nein",
"Erstellt: 2022-04-06T16:20:00Z",
"Zuletzt bearbeitet: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr())
.isEmpty();
}
}
@Nested
class ForUnsuccessfulGetTest {
@Test
void shouldFailWithEnglishMsgIfUserNotFound() {
testRenderer.setLocale("en");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Could not find user");
}
@Test
void shouldFailWithGermanMsgIfUserNotFound() {
testRenderer.setLocale("de");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Benutzer konnte nicht gefunden werden");
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.TemplateTestRenderer;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserListCommandTest {
@Mock
private UserManager manager;
private final UserCommandBeanMapper beanMapper = new UserCommandBeanMapperImpl();
private final TemplateTestRenderer testRenderer = new TemplateTestRenderer();
private UserListCommand command;
@BeforeEach
void initCommand() {
command = new UserListCommand(testRenderer.createTemplateRenderer(), manager, beanMapper);
}
@BeforeEach
void mockGroups() {
User internalUser = new User("havelock", "Havelock Vetinari", "havelock.vetinari@discworld");
User externalUser = new User("mustrum", "Mustrum Ridcully", "mustrum.ridcully@discworld");
externalUser.setExternal(true);
externalUser.setActive(false);
when(manager.getAll())
.thenReturn(
asList(
internalUser,
externalUser));
}
@Test
void shouldRenderShortTableInEnglish() {
testRenderer.setLocale("en");
command.setSpec(testRenderer.getMockedSpeck());
command.setUseShortTemplate(true);
command.run();
assertThat(testRenderer.getStdOut()).isEqualTo("havelock\nmustrum\n");
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldRenderShortTableInGerman() {
testRenderer.setLocale("de");
command.setSpec(testRenderer.getMockedSpeck());
command.setUseShortTemplate(true);
command.run();
assertThat(testRenderer.getStdOut()).isEqualTo("havelock\nmustrum\n");
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldRenderLongTableInEnglish() {
testRenderer.setLocale("en");
command.setSpec(testRenderer.getMockedSpeck());
command.run();
assertThat(testRenderer.getStdOut())
.isEqualTo("USERNAME DISPLAY NAME EMAIL ADDRESS EXTERNAL ACTIVE\n" +
"havelock Havelock Vetinari havelock.vetinari@discworld no yes \n" +
"mustrum Mustrum Ridcully mustrum.ridcully@discworld yes no \n");
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldRenderLongTableInGerman() {
testRenderer.setLocale("de");
command.setSpec(testRenderer.getMockedSpeck());
command.run();
assertThat(testRenderer.getStdOut())
.isEqualTo("BENUTZERNAME ANZEIGENAME E-MAIL-ADRESSE EXTERN AKTIV\n" +
"havelock Havelock Vetinari havelock.vetinari@discworld nein ja \n" +
"mustrum Mustrum Ridcully mustrum.ridcully@discworld ja nein \n");
assertThat(testRenderer.getStdErr()).isEmpty();
}
}

View File

@@ -0,0 +1,233 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.cli.CliExitException;
import sonia.scm.cli.CommandValidator;
import sonia.scm.user.User;
import sonia.scm.user.UserManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class UserModifyCommandTest {
private final UserTemplateTestRenderer testRenderer = new UserTemplateTestRenderer();
@Mock
private CommandValidator validator;
@Mock
private UserManager manager;
private UserModifyCommand command;
@BeforeEach
void initCommand() {
command = new UserModifyCommand(testRenderer.getTemplateRenderer(), validator, manager);
}
@Nested
class ForSuccessfulModificationTest {
@BeforeEach
void mockGet() {
User user = new User("havelock", "Havelock Vetinari", "havelock.vetinari@discworld");
user.setPassword("patrician");
user.setExternal(false);
user.setActive(true);
user.setCreationDate(1649262000000L);
user.setLastModified(1649272000000L);
when(manager.get(any())).thenReturn(user);
}
@Test
void shouldModifyUser() {
command.setDisplayName("Lord Vetinari");
command.setEmail("patrician@discworld");
command.setPassword("havelock");
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Lord Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("havelock");
assertThat(argument.getMail()).isEqualTo("patrician@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldNotModifyDisplayNameIfNotSet() {
command.setEmail("patrician@discworld");
command.setPassword("havelock");
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Havelock Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("havelock");
assertThat(argument.getMail()).isEqualTo("patrician@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldNotModifyEmailIfNotSet() {
command.setDisplayName("Lord Vetinari");
command.setPassword("havelock");
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Lord Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("havelock");
assertThat(argument.getMail()).isEqualTo("havelock.vetinari@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldNotModifyPasswordIfNotSet() {
command.setEmail("patrician@discworld");
command.setDisplayName("Lord Vetinari");
command.run();
verify(manager).modify(argThat(argument -> {
assertThat(argument.getName()).isEqualTo("havelock");
assertThat(argument.getDisplayName()).isEqualTo("Lord Vetinari");
assertThat(argument.isExternal()).isFalse();
assertThat(argument.getPassword()).isEqualTo("patrician");
assertThat(argument.getMail()).isEqualTo("patrician@discworld");
assertThat(argument.isActive()).isTrue();
return true;
}));
}
@Test
void shouldPrintUserAfterModificationInEnglish() {
testRenderer.setLocale("en");
command.setDisplayName("Lord Vetinari");
command.setEmail("patrician@discworld");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Username: havelock",
"Display Name: Lord Vetinari",
"Email address: patrician@discworld",
"External: no",
"Active: yes",
"Creation Date: 2022-04-06T16:20:00Z",
"Last Modified: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
@Test
void shouldPrintUserAfterModificationInGerman() {
testRenderer.setLocale("de");
command.setDisplayName("Lord Vetinari");
command.setEmail("patrician@discworld");
command.run();
assertThat(testRenderer.getStdOut())
.contains(
"Benutzername: havelock",
"Anzeigename: Lord Vetinari ",
"E-Mail-Adresse: patrician@discworld",
"Extern: nein",
"Aktiv: ja",
"Erstellt: 2022-04-06T16:20:00Z",
"Zuletzt bearbeitet: 2022-04-06T19:06:40Z"
);
assertThat(testRenderer.getStdErr()).isEmpty();
}
}
@Nested
class ForUnsuccessfulModificationTest {
@Test
void shouldFailIfValidatorFails() {
doThrow(picocli.CommandLine.ParameterException.class).when(validator).validate();
assertThrows(
picocli.CommandLine.ParameterException.class,
() -> command.run()
);
assertThat(testRenderer.getStdOut()).isEmpty();
}
@Test
void shouldFailWithEnglishMsgIfUserNotFound() {
testRenderer.setLocale("en");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Could not find user");
}
@Test
void shouldFailWithGermanMsgIfUserNotFound() {
testRenderer.setLocale("de");
when(manager.get(any())).thenReturn(null);
assertThrows(CliExitException.class, () -> command.run());
verify(manager, never()).modify(any());
assertThat(testRenderer.getStdOut()).isEmpty();
assertThat(testRenderer.getStdErr()).contains("Benutzer konnte nicht gefunden werden");
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* 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 sonia.scm.user.cli;
import sonia.scm.cli.TemplateTestRenderer;
import java.util.ResourceBundle;
class UserTemplateTestRenderer {
private final TemplateTestRenderer testRenderer = new TemplateTestRenderer();
private final UserCommandBeanMapper beanMapper = new UserCommandBeanMapperImpl();
private final UserTemplateRenderer templateRenderer = new UserTemplateRenderer(testRenderer.getContextMock(), testRenderer.getTemplateEngineFactory(), beanMapper) {
@Override
protected ResourceBundle getBundle() {
return testRenderer.getResourceBundle();
}
};
UserTemplateRenderer getTemplateRenderer() {
return templateRenderer;
}
String getStdOut() {
return testRenderer.getStdOut();
}
String getStdErr() {
return testRenderer.getStdErr();
}
public void setLocale(String locale) {
testRenderer.setLocale(locale);
}
}