merged 2.0.0

This commit is contained in:
Eduard Heimbuch
2019-09-16 11:01:33 +02:00
13 changed files with 381 additions and 283 deletions

View File

@@ -6,4 +6,8 @@ public abstract class BadRequestException extends ExceptionWithContext {
public BadRequestException(List<ContextEntry> context, String message) { public BadRequestException(List<ContextEntry> context, String message) {
super(context, message); super(context, message);
} }
public BadRequestException(List<ContextEntry> context, String message, Exception cause) {
super(context, message, cause);
}
} }

View File

@@ -122,10 +122,12 @@ public class ModifyCommandRequest implements Resetable, Validateable {
} }
void cleanup() { void cleanup() {
try { if (content.exists()) {
IOUtil.delete(content); try {
} catch (IOException e) { IOUtil.delete(content);
LOG.warn("could not delete temporary file {}", content, e); } catch (IOException e) {
LOG.warn("could not delete temporary file {}", content, e);
}
} }
} }
} }

View File

@@ -1,10 +1,9 @@
//@flow //@flow
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import {Link} from "react-router-dom";
import type { Branch, Repository } from "@scm-manager/ui-types"; import type {Branch, Repository} from "@scm-manager/ui-types";
import injectSheet from "react-jss"; import injectSheet from "react-jss";
import { ExtensionPoint, binder } from "@scm-manager/ui-extensions"; import {binder, ExtensionPoint} from "@scm-manager/ui-extensions";
import {ButtonGroup} from "./buttons";
import classNames from "classnames"; import classNames from "classnames";
type Props = { type Props = {
@@ -64,33 +63,48 @@ class Breadcrumb extends React.Component<Props> {
} }
render() { render() {
const { classes, baseUrl, branch, defaultBranch, branches, revision, path, repository } = this.props; const {
classes,
baseUrl,
branch,
defaultBranch,
branches,
revision,
path,
repository
} = this.props;
return ( return (
<> <>
<div className={classes.flexRow}> <div className={classes.flexRow}>
<nav className={classNames(classes.flexStart, "breadcrumb sources-breadcrumb")} aria-label="breadcrumbs"> <nav
className={classNames(
classes.flexStart,
"breadcrumb sources-breadcrumb"
)}
aria-label="breadcrumbs"
>
<ul>{this.renderPath()}</ul> <ul>{this.renderPath()}</ul>
</nav> </nav>
{ {binder.hasExtension("repos.sources.actionbar") && (
binder.hasExtension("repos.sources.actionbar") &&
<div className={classes.buttonGroup}> <div className={classes.buttonGroup}>
<ButtonGroup> <ExtensionPoint
<ExtensionPoint name="repos.sources.actionbar"
name="repos.sources.actionbar" props={{
props={{ baseUrl,
baseUrl, branch: branch ? branch : defaultBranch,
branch: branch ? branch : defaultBranch, path,
path, isBranchUrl:
isBranchUrl: branches && branches &&
branches.filter(b => b.name.replace("/", "%2F") === revision).length > 0, branches.filter(
repository b => b.name.replace("/", "%2F") === revision
}} ).length > 0,
renderAll={true} repository
/> }}
</ButtonGroup> renderAll={true}
/>
</div> </div>
} )}
</div> </div>
<hr className={classes.noMargin} /> <hr className={classes.noMargin} />
</> </>

View File

@@ -8,13 +8,12 @@ type Props = {
body: any, body: any,
footer?: any, footer?: any,
active: boolean, active: boolean,
className?: string
}; };
class Modal extends React.Component<Props> { class Modal extends React.Component<Props> {
render() { render() {
const { title, closeFunction, body, footer, active } = this.props; const { title, closeFunction, body, footer, active, className } = this.props;
const isActive = active ? "is-active" : null; const isActive = active ? "is-active" : null;
@@ -24,7 +23,7 @@ class Modal extends React.Component<Props> {
} }
return ( return (
<div className={classNames("modal", isActive)}> <div className={classNames("modal", className, isActive)}>
<div className="modal-background" /> <div className="modal-background" />
<div className="modal-card"> <div className="modal-card">
<header className="modal-card-head"> <header className="modal-card-head">

View File

@@ -5,7 +5,7 @@ export const isNameValid = (name: string) => {
return nameRegex.test(name); return nameRegex.test(name);
}; };
const mailRegex = /^[ -~]+@[A-Za-z0-9][\w\-.]*\.[A-Za-z0-9][A-Za-z0-9-]+$/; const mailRegex = /^[ -~]+@[A-Za-z0-9][\w\-.]*\.[A-Za-z0-9][A-Za-z0-9-]+$/;
export const isMailValid = (mail: string) => { export const isMailValid = (mail: string) => {
return mailRegex.test(mail); return mailRegex.test(mail);
@@ -14,3 +14,9 @@ export const isMailValid = (mail: string) => {
export const isNumberValid = (number: string) => { export const isNumberValid = (number: string) => {
return !isNaN(number); return !isNaN(number);
}; };
const pathRegex = /^((?!\/{2,}).)*$/;
export const isPathValid = (path: string) => {
return pathRegex.test(path);
};

View File

@@ -2,102 +2,117 @@
import * as validator from "./validation"; import * as validator from "./validation";
describe("test name validation", () => { describe("test name validation", () => {
it("should return false", () => { // invalid names taken from ValidationUtilTest.java
// invalid names taken from ValidationUtilTest.java const invalidNames = [
const invalidNames = [ "@test",
"@test", " test 123",
" test 123", " test 123 ",
" test 123 ", "test 123 ",
"test 123 ", "test/123",
"test/123", "test%123",
"test%123", "test:123",
"test:123", "t ",
"t ", " t",
" t", " t ",
" t ", "",
"",
" invalid_name", " invalid_name",
"another%one", "another%one",
"!!!", "!!!",
"!_!" "!_!"
]; ];
for (let name of invalidNames) { for (let name of invalidNames) {
it(`should return false for '${name}'`, () => {
expect(validator.isNameValid(name)).toBe(false); expect(validator.isNameValid(name)).toBe(false);
} });
}); }
it("should return true", () => { // valid names taken from ValidationUtilTest.java
// valid names taken from ValidationUtilTest.java const validNames = [
const validNames = [ "test",
"test", "test.git",
"test.git", "Test123.git",
"Test123.git", "Test123-git",
"Test123-git", "Test_user-123.git",
"Test_user-123.git", "test@scm-manager.de",
"test@scm-manager.de", "test123",
"test123", "tt",
"tt", "t",
"t", "valid_name",
"valid_name", "another1",
"another1", "stillValid",
"stillValid", "this.one_as-well",
"this.one_as-well", "and@this"
"and@this" ];
]; for (let name of validNames) {
for (let name of validNames) { it(`should return true for '${name}'`, () => {
expect(validator.isNameValid(name)).toBe(true); expect(validator.isNameValid(name)).toBe(true);
} });
}); }
}); });
describe("test mail validation", () => { describe("test mail validation", () => {
it("should return false", () => { // invalid taken from ValidationUtilTest.java
// invalid taken from ValidationUtilTest.java const invalid = [
const invalid = [ "ostfalia.de",
"ostfalia.de", "@ostfalia.de",
"@ostfalia.de", "s.sdorra@",
"s.sdorra@", "s.sdorra@ostfalia",
"s.sdorra@ostfalia", "s.sdorra@ ostfalia.de",
"s.sdorra@ ostfalia.de", "s.sdorra@[ostfalia.de"
"s.sdorra@[ostfalia.de" ];
]; for (let mail of invalid) {
for (let mail of invalid) { it(`should return false for '${mail}'`, () => {
expect(validator.isMailValid(mail)).toBe(false); expect(validator.isMailValid(mail)).toBe(false);
} });
}); }
it("should return true", () => { // valid taken from ValidationUtilTest.java
// valid taken from ValidationUtilTest.java const valid = [
const valid = [ "s.sdorra@ostfalia.de",
"s.sdorra@ostfalia.de", "sdorra@ostfalia.de",
"sdorra@ostfalia.de", "s.sdorra@hbk-bs.de",
"s.sdorra@hbk-bs.de", "s.sdorra@gmail.com",
"s.sdorra@gmail.com", "s.sdorra@t.co",
"s.sdorra@t.co", "s.sdorra@ucla.college",
"s.sdorra@ucla.college", "s.sdorra@example.xn--p1ai",
"s.sdorra@example.xn--p1ai", "s.sdorra@scm.solutions",
"s.sdorra@scm.solutions", "s'sdorra@scm.solutions",
"s'sdorra@scm.solutions", "\"S Sdorra\"@scm.solutions"
"\"S Sdorra\"@scm.solutions" ];
]; for (let mail of valid) {
for (let mail of valid) { it(`should return true for '${mail}'`, () => {
expect(validator.isMailValid(mail)).toBe(true); expect(validator.isMailValid(mail)).toBe(true);
} });
}); }
}); });
describe("test number validation", () => { describe("test number validation", () => {
it("should return false", () => { const invalid = ["1a", "35gu", "dj6", "45,5", "test"];
const invalid = ["1a", "35gu", "dj6", "45,5", "test"]; for (let number of invalid) {
for (let number of invalid) { it(`should return false for '${number}'`, () => {
expect(validator.isNumberValid(number)).toBe(false); expect(validator.isNumberValid(number)).toBe(false);
} });
}); }
it("should return true", () => { const valid = ["1", "35", "2", "235", "34.4"];
const valid = ["1", "35", "2", "235", "34.4"]; for (let number of valid) {
for (let number of valid) { it(`should return true for '${number}'`, () => {
expect(validator.isNumberValid(number)).toBe(true); expect(validator.isNumberValid(number)).toBe(true);
} });
}); }
});
describe("test path validation", () => {
const invalid = ["//", "some//path", "end//"];
for (let path of invalid) {
it(`should return false for '${path}'`, () => {
expect(validator.isPathValid(path)).toBe(false);
});
}
const valid = ["", "/", "dir", "some/path", "end/"];
for (let path of valid) {
it(`should return true for '${path}'`, () => {
expect(validator.isPathValid(path)).toBe(true);
});
}
}); });

View File

@@ -106,17 +106,15 @@ class Content extends React.Component<Props, State> {
</div> </div>
<div className="buttons is-grouped"> <div className="buttons is-grouped">
<div className={classes.marginInHeader}>{selector}</div> <div className={classes.marginInHeader}>{selector}</div>
<ButtonGroup> <ExtensionPoint
<ExtensionPoint name="repos.sources.content.actionbar"
name="repos.sources.content.actionbar" props={{
props={{ file,
file, revision,
revision, handleExtensionError: this.handleExtensionError
handleExtensionError: this.handleExtensionError }}
}} renderAll={true}
renderAll={true} />
/>
</ButtonGroup>
</div> </div>
</article> </article>
</span> </span>

View File

@@ -2,9 +2,9 @@
import { validation } from "@scm-manager/ui-components"; import { validation } from "@scm-manager/ui-components";
const { isNameValid, isMailValid } = validation; const { isNameValid, isMailValid, isPathValid } = validation;
export { isNameValid, isMailValid }; export { isNameValid, isMailValid, isPathValid };
export const isDisplayNameValid = (displayName: string) => { export const isDisplayNameValid = (displayName: string) => {
if (displayName) { if (displayName) {

View File

@@ -2,18 +2,24 @@
@import "bulma/sass/utilities/functions"; @import "bulma/sass/utilities/functions";
$blue: #33b2e8; $blue: #33b2e8;
$cyan: $blue;
$green: #00c79b;
$mint: #11dfd0; $mint: #11dfd0;
$info: $blue;
// $footer-background-color
.is-ellipsis-overflow { .is-ellipsis-overflow {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.is-word-break {
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
word-break: break-all;
}
.has-rounded-border { .has-rounded-border {
border-radius: 0.25rem; border-radius: 0.25rem;
} }
@@ -29,14 +35,6 @@ $info: $blue;
padding: 0 0 0 3.8em !important; padding: 0 0 0 3.8em !important;
} }
.is-word-break {
-webkit-hyphens: auto;
-moz-hyphens: auto;
-ms-hyphens: auto;
hyphens: auto;
word-break: break-all;
}
.main { .main {
min-height: calc(100vh - 260px); min-height: calc(100vh - 260px);
} }
@@ -76,6 +74,128 @@ hr.header-with-actions {
@import "bulma/bulma"; @import "bulma/bulma";
@import "bulma-tooltip/dist/css/bulma-tooltip"; @import "bulma-tooltip/dist/css/bulma-tooltip";
$dark-75: scale-color($dark, $lightness: 25%);
$dark-50: scale-color($dark, $lightness: 50%);
$dark-25: scale-color($dark, $lightness: 75%);
$info-75: scale-color($info, $lightness: 25%);
$info-50: scale-color($info, $lightness: 50%);
$info-25: scale-color($info, $lightness: 75%);
$link-75: scale-color($link, $lightness: 25%);
$link-50: scale-color($link, $lightness: 50%);
$link-25: scale-color($link, $lightness: 75%);
$primary-75: scale-color($primary, $lightness: 25%);
$primary-50: scale-color($primary, $lightness: 50%);
$primary-25: scale-color($primary, $lightness: 75%);
$success-75: scale-color($success, $lightness: 25%);
$success-50: scale-color($success, $lightness: 50%);
$success-25: scale-color($success, $lightness: 75%);
$warning-75: scale-color($warning, $lightness: 25%);
$warning-50: scale-color($warning, $lightness: 50%);
$warning-25: scale-color($warning, $lightness: 75%);
$danger-75: scale-color($danger, $lightness: 25%);
$danger-50: scale-color($danger, $lightness: 50%);
$danger-25: scale-color($danger, $lightness: 75%);
:root {
// asc sorted derived-variables
--primary: #{$primary};
--primary-75: #{$primary-75};
--primary-50: #{$primary-50};
--primary-25: #{$primary-25};
--info: #{$info};
--info-75: #{$info-75};
--info-50: #{$info-50};
--info-25: #{$info-25};
--success: #{$success};
--success-75: #{$success-75};
--success-50: #{$success-50};
--success-25: #{$success-25};
--warning: #{$warning};
--warning-75: #{$warning-75};
--warning-50: #{$warning-50};
--warning-25: #{$warning-25};
--danger: #{$danger};
--danger-75: #{$danger-75};
--danger-50: #{$danger-50};
--danger-25: #{$danger-25};
--light: #{$light};
--dark: #{$dark};
--dark-75: #{$dark-75};
--dark-50: #{$dark-50};
--dark-25: #{$dark-25};
--background: #{$background};
--border: #{$border};
--text: #{$text};
--link: #{$link};
--link-75: #{$link-75};
--link-50: #{$link-50};
--link-25: #{$link-25};
}
.has-background-dark-75 {
background-color: $dark-75;
}
.has-background-dark-50 {
background-color: $dark-50;
}
.has-background-dark-25 {
background-color: $dark-25;
}
.has-background-info-75 {
background-color: $info-75;
}
.has-background-info-50 {
background-color: $info-50;
}
.has-background-info-25 {
background-color: $info-25;
}
.has-background-link-75 {
background-color: $link-75;
}
.has-background-link-50 {
background-color: $link-50;
}
.has-background-link-25 {
background-color: $link-25;
}
.has-background-primary-75 {
background-color: $primary-75;
}
.has-background-primary-50 {
background-color: $primary-50;
}
.has-background-primary-25 {
background-color: $primary-25;
}
.has-background-success-75 {
background-color: $success-75;
}
.has-background-success-50 {
background-color: $success-50;
}
.has-background-success-25 {
background-color: $success-25;
}
.has-background-warning-75 {
background-color: $warning-75;
}
.has-background-warning-50 {
background-color: $warning-50;
}
.has-background-warning-25 {
background-color: $warning-25;
}
.has-background-danger-75 {
background-color: $danger-75;
}
.has-background-danger-50 {
background-color: $danger-50;
}
.has-background-danger-25 {
background-color: $danger-25;
}
// import at the end, because we need a lot of stuff from bulma/bulma // import at the end, because we need a lot of stuff from bulma/bulma
.box-link-shadow { .box-link-shadow {
&:hover, &:hover,

View File

@@ -34,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static sonia.scm.plugin.PluginTestHelper.createInstalled;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class InstalledPluginResourceTest { class InstalledPluginResourceTest {
@@ -86,7 +87,7 @@ class InstalledPluginResourceTest {
@Test @Test
void getInstalledPlugins() throws URISyntaxException, UnsupportedEncodingException { void getInstalledPlugins() throws URISyntaxException, UnsupportedEncodingException {
InstalledPlugin installedPlugin = createPlugin(); InstalledPlugin installedPlugin = createInstalled("");
when(pluginManager.getInstalled()).thenReturn(Collections.singletonList(installedPlugin)); when(pluginManager.getInstalled()).thenReturn(Collections.singletonList(installedPlugin));
when(collectionMapper.mapInstalled(Collections.singletonList(installedPlugin), Collections.emptyList())).thenReturn(new MockedResultDto()); when(collectionMapper.mapInstalled(Collections.singletonList(installedPlugin), Collections.emptyList())).thenReturn(new MockedResultDto());
@@ -105,7 +106,7 @@ class InstalledPluginResourceTest {
PluginInformation pluginInformation = new PluginInformation(); PluginInformation pluginInformation = new PluginInformation();
pluginInformation.setVersion("2.0.0"); pluginInformation.setVersion("2.0.0");
pluginInformation.setName("pluginName"); pluginInformation.setName("pluginName");
InstalledPlugin installedPlugin = createPlugin(pluginInformation); InstalledPlugin installedPlugin = createInstalled(pluginInformation);
when(pluginManager.getInstalled("pluginName")).thenReturn(Optional.of(installedPlugin)); when(pluginManager.getInstalled("pluginName")).thenReturn(Optional.of(installedPlugin));
@@ -124,18 +125,6 @@ class InstalledPluginResourceTest {
} }
} }
private InstalledPlugin createPlugin() {
return createPlugin(new PluginInformation());
}
private InstalledPlugin createPlugin(PluginInformation information) {
InstalledPlugin plugin = mock(InstalledPlugin.class);
InstalledPluginDescriptor descriptor = mock(InstalledPluginDescriptor.class);
lenient().when(descriptor.getInformation()).thenReturn(information);
lenient().when(plugin.getDescriptor()).thenReturn(descriptor);
return plugin;
}
@Nested @Nested
class WithoutAuthorization { class WithoutAuthorization {

View File

@@ -23,6 +23,8 @@ import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static sonia.scm.plugin.PluginTestHelper.createAvailable;
import static sonia.scm.plugin.PluginTestHelper.createInstalled;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class PluginDtoMapperTest { class PluginDtoMapperTest {
@@ -74,22 +76,16 @@ class PluginDtoMapperTest {
@Test @Test
void shouldAppendInstalledSelfLink() { void shouldAppendInstalledSelfLink() {
InstalledPlugin plugin = createInstalled(); InstalledPlugin plugin = createInstalled(createPluginInformation());
PluginDto dto = mapper.mapInstalled(plugin, emptyList()); PluginDto dto = mapper.mapInstalled(plugin, emptyList());
assertThat(dto.getLinks().getLinkBy("self").get().getHref()) assertThat(dto.getLinks().getLinkBy("self").get().getHref())
.isEqualTo("https://hitchhiker.com/v2/plugins/installed/scm-cas-plugin"); .isEqualTo("https://hitchhiker.com/v2/plugins/installed/scm-cas-plugin");
} }
private InstalledPlugin createInstalled(PluginInformation information) {
InstalledPlugin plugin = mock(InstalledPlugin.class, Answers.RETURNS_DEEP_STUBS);
when(plugin.getDescriptor().getInformation()).thenReturn(information);
return plugin;
}
@Test @Test
void shouldAppendAvailableSelfLink() { void shouldAppendAvailableSelfLink() {
AvailablePlugin plugin = createAvailable(); AvailablePlugin plugin = createAvailable(createPluginInformation());
PluginDto dto = mapper.mapAvailable(plugin); PluginDto dto = mapper.mapAvailable(plugin);
assertThat(dto.getLinks().getLinkBy("self").get().getHref()) assertThat(dto.getLinks().getLinkBy("self").get().getHref())
@@ -98,7 +94,7 @@ class PluginDtoMapperTest {
@Test @Test
void shouldNotAppendInstallLinkWithoutPermissions() { void shouldNotAppendInstallLinkWithoutPermissions() {
AvailablePlugin plugin = createAvailable(); AvailablePlugin plugin = createAvailable(createPluginInformation());
PluginDto dto = mapper.mapAvailable(plugin); PluginDto dto = mapper.mapAvailable(plugin);
assertThat(dto.getLinks().getLinkBy("install")).isEmpty(); assertThat(dto.getLinks().getLinkBy("install")).isEmpty();
@@ -107,7 +103,7 @@ class PluginDtoMapperTest {
@Test @Test
void shouldAppendInstallLink() { void shouldAppendInstallLink() {
when(subject.isPermitted("plugin:manage")).thenReturn(true); when(subject.isPermitted("plugin:manage")).thenReturn(true);
AvailablePlugin plugin = createAvailable(); AvailablePlugin plugin = createAvailable(createPluginInformation());
PluginDto dto = mapper.mapAvailable(plugin); PluginDto dto = mapper.mapAvailable(plugin);
assertThat(dto.getLinks().getLinkBy("install").get().getHref()) assertThat(dto.getLinks().getLinkBy("install").get().getHref())
@@ -125,25 +121,10 @@ class PluginDtoMapperTest {
@Test @Test
void shouldAppendDependencies() { void shouldAppendDependencies() {
AvailablePlugin plugin = createAvailable(); AvailablePlugin plugin = createAvailable(createPluginInformation());
when(plugin.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("one", "two")); when(plugin.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("one", "two"));
PluginDto dto = mapper.mapAvailable(plugin); PluginDto dto = mapper.mapAvailable(plugin);
assertThat(dto.getDependencies()).containsOnly("one", "two"); assertThat(dto.getDependencies()).containsOnly("one", "two");
} }
private InstalledPlugin createInstalled() {
return createInstalled(createPluginInformation());
}
private AvailablePlugin createAvailable() {
return createAvailable(createPluginInformation());
}
private AvailablePlugin createAvailable(PluginInformation information) {
AvailablePluginDescriptor descriptor = mock(AvailablePluginDescriptor.class);
when(descriptor.getInformation()).thenReturn(information);
return new AvailablePlugin(descriptor);
}
} }

View File

@@ -16,7 +16,6 @@ import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import sonia.scm.NotFoundException; import sonia.scm.NotFoundException;
import sonia.scm.ScmConstraintViolationException;
import sonia.scm.event.ScmEventBus; import sonia.scm.event.ScmEventBus;
import sonia.scm.lifecycle.RestartEvent; import sonia.scm.lifecycle.RestartEvent;
@@ -24,8 +23,11 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.in;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import static sonia.scm.plugin.PluginTestHelper.createAvailable;
import static sonia.scm.plugin.PluginTestHelper.createInstalled;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class DefaultPluginManagerTest { class DefaultPluginManagerTest {
@@ -71,8 +73,8 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldReturnInstalledPlugins() { void shouldReturnInstalledPlugins() {
InstalledPlugin review = createInstalled("scm-review-plugin", "1"); InstalledPlugin review = createInstalled("scm-review-plugin");
InstalledPlugin git = createInstalled("scm-git-plugin", "1"); InstalledPlugin git = createInstalled("scm-git-plugin");
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git)); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git));
@@ -82,8 +84,8 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldReturnReviewPlugin() { void shouldReturnReviewPlugin() {
InstalledPlugin review = createInstalled("scm-review-plugin", "1"); InstalledPlugin review = createInstalled("scm-review-plugin");
InstalledPlugin git = createInstalled("scm-git-plugin", "1"); InstalledPlugin git = createInstalled("scm-git-plugin");
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git)); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(review, git));
@@ -101,8 +103,8 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldReturnAvailablePlugins() { void shouldReturnAvailablePlugins() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
AvailablePlugin git = createAvailable("scm-git-plugin", "1"); AvailablePlugin git = createAvailable("scm-git-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git));
@@ -111,35 +113,22 @@ class DefaultPluginManagerTest {
} }
@Test @Test
void shouldFilterOutAllInstalledWithSameVersion() { void shouldFilterOutAllInstalled() {
InstalledPlugin installedGit = createInstalled("scm-git-plugin", "1"); InstalledPlugin installedGit = createInstalled("scm-git-plugin");
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit)); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit));
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
AvailablePlugin git = createAvailable("scm-git-plugin", "1"); AvailablePlugin git = createAvailable("scm-git-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git));
List<AvailablePlugin> available = manager.getAvailable(); List<AvailablePlugin> available = manager.getAvailable();
assertThat(available).containsOnly(review); assertThat(available).containsOnly(review);
} }
@Test
void shouldKeepInstalledWithOlderVersion() {
InstalledPlugin installedGit = createInstalled("scm-git-plugin", "1");
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit));
AvailablePlugin review = createAvailable("scm-review-plugin", "1");
AvailablePlugin git = createAvailable("scm-git-plugin", "1.1");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git));
List<AvailablePlugin> available = manager.getAvailable();
assertThat(available).contains(git, review);
}
@Test @Test
void shouldReturnAvailable() { void shouldReturnAvailable() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
AvailablePlugin git = createAvailable("scm-git-plugin", "1"); AvailablePlugin git = createAvailable("scm-git-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, git));
Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin"); Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin");
@@ -148,7 +137,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldReturnEmptyForNonExistingAvailable() { void shouldReturnEmptyForNonExistingAvailable() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin"); Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin");
@@ -157,10 +146,10 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldReturnEmptyForInstalledPlugin() { void shouldReturnEmptyForInstalledPlugin() {
InstalledPlugin installedGit = createInstalled("scm-git-plugin", "1"); InstalledPlugin installedGit = createInstalled("scm-git-plugin");
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit)); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedGit));
AvailablePlugin git = createAvailable("scm-git-plugin", "1"); AvailablePlugin git = createAvailable("scm-git-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(git)); when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin"); Optional<AvailablePlugin> available = manager.getAvailable("scm-git-plugin");
@@ -169,7 +158,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldInstallThePlugin() { void shouldInstallThePlugin() {
AvailablePlugin git = createAvailable("scm-git-plugin", "1"); AvailablePlugin git = createAvailable("scm-git-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(git)); when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
manager.install("scm-git-plugin", false); manager.install("scm-git-plugin", false);
@@ -178,36 +167,11 @@ class DefaultPluginManagerTest {
verify(eventBus, never()).post(any()); verify(eventBus, never()).post(any());
} }
@Test
void shouldUpdateNormalPlugin() {
AvailablePlugin available = createAvailable("scm-git-plugin", "2");
InstalledPlugin installed = createInstalled("scm-git-plugin", "1");
when(installed.isCore()).thenReturn(false);
lenient().when(center.getAvailable()).thenReturn(ImmutableSet.of(available));
when(loader.getInstalledPlugins()).thenReturn(ImmutableSet.of(installed));
manager.install("scm-git-plugin", false);
verify(installer).install(available);
verify(eventBus, never()).post(any());
}
@Test
void shouldNotUpdateCorePlugin() {
AvailablePlugin available = createAvailable("scm-git-plugin", "2");
InstalledPlugin installed = createInstalled("scm-git-plugin", "1");
when(installed.isCore()).thenReturn(true);
lenient().when(center.getAvailable()).thenReturn(ImmutableSet.of(available));
when(loader.getInstalledPlugins()).thenReturn(ImmutableSet.of(installed));
assertThrows(ScmConstraintViolationException.class, () -> manager.install("scm-git-plugin", false));
}
@Test @Test
void shouldInstallDependingPlugins() { void shouldInstallDependingPlugins() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); AvailablePlugin mail = createAvailable("scm-mail-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail));
manager.install("scm-review-plugin", false); manager.install("scm-review-plugin", false);
@@ -218,12 +182,12 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldNotInstallAlreadyInstalledDependencies() { void shouldNotInstallAlreadyInstalledDependencies() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); AvailablePlugin mail = createAvailable("scm-mail-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail));
InstalledPlugin installedMail = createInstalled("scm-mail-plugin", "1"); InstalledPlugin installedMail = createInstalled("scm-mail-plugin");
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedMail)); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(installedMail));
manager.install("scm-review-plugin", false); manager.install("scm-review-plugin", false);
@@ -236,11 +200,11 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldRollbackOnFailedInstallation() { void shouldRollbackOnFailedInstallation() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); AvailablePlugin mail = createAvailable("scm-mail-plugin");
when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin")); when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin"));
AvailablePlugin notification = createAvailable("scm-notification-plugin", "1"); AvailablePlugin notification = createAvailable("scm-notification-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail, notification)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail, notification));
PendingPluginInstallation pendingNotification = mock(PendingPluginInstallation.class); PendingPluginInstallation pendingNotification = mock(PendingPluginInstallation.class);
@@ -259,9 +223,9 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldInstallNothingIfOneOfTheDependenciesIsNotAvailable() { void shouldInstallNothingIfOneOfTheDependenciesIsNotAvailable() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin")); when(review.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-mail-plugin"));
AvailablePlugin mail = createAvailable("scm-mail-plugin", "1"); AvailablePlugin mail = createAvailable("scm-mail-plugin");
when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin")); when(mail.getDescriptor().getDependencies()).thenReturn(ImmutableSet.of("scm-notification-plugin"));
when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review, mail));
@@ -272,7 +236,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldSendRestartEventAfterInstallation() { void shouldSendRestartEventAfterInstallation() {
AvailablePlugin git = createAvailable("scm-git-plugin", "1"); AvailablePlugin git = createAvailable("scm-git-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(git)); when(center.getAvailable()).thenReturn(ImmutableSet.of(git));
manager.install("scm-git-plugin", true); manager.install("scm-git-plugin", true);
@@ -283,7 +247,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldNotSendRestartEventIfNoPluginWasInstalled() { void shouldNotSendRestartEventIfNoPluginWasInstalled() {
InstalledPlugin gitInstalled = createInstalled("scm-git-plugin", "1"); InstalledPlugin gitInstalled = createInstalled("scm-git-plugin");
when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(gitInstalled)); when(loader.getInstalledPlugins()).thenReturn(ImmutableList.of(gitInstalled));
manager.install("scm-git-plugin", true); manager.install("scm-git-plugin", true);
@@ -292,7 +256,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldNotInstallAlreadyPendingPlugins() { void shouldNotInstallAlreadyPendingPlugins() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
manager.install("scm-review-plugin", false); manager.install("scm-review-plugin", false);
@@ -303,7 +267,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldSendRestartEvent() { void shouldSendRestartEvent() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
manager.install("scm-review-plugin", false); manager.install("scm-review-plugin", false);
@@ -321,7 +285,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldReturnSingleAvailableAsPending() { void shouldReturnSingleAvailableAsPending() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
manager.install("scm-review-plugin", false); manager.install("scm-review-plugin", false);
@@ -332,7 +296,7 @@ class DefaultPluginManagerTest {
@Test @Test
void shouldReturnAvailableAsPending() { void shouldReturnAvailableAsPending() {
AvailablePlugin review = createAvailable("scm-review-plugin", "1"); AvailablePlugin review = createAvailable("scm-review-plugin");
when(center.getAvailable()).thenReturn(ImmutableSet.of(review)); when(center.getAvailable()).thenReturn(ImmutableSet.of(review));
manager.install("scm-review-plugin", false); manager.install("scm-review-plugin", false);
@@ -392,35 +356,4 @@ class DefaultPluginManagerTest {
} }
} }
private AvailablePlugin createAvailable(String name, String version) {
PluginInformation information = new PluginInformation();
information.setName(name);
information.setVersion(version);
return createAvailable(information);
}
private InstalledPlugin createInstalled(String name, String version) {
PluginInformation information = new PluginInformation();
information.setName(name);
information.setVersion(version);
return createInstalled(information);
}
private InstalledPlugin createInstalled(PluginInformation information) {
InstalledPlugin plugin = mock(InstalledPlugin.class, Answers.RETURNS_DEEP_STUBS);
returnInformation(plugin, information);
return plugin;
}
private AvailablePlugin createAvailable(PluginInformation information) {
AvailablePluginDescriptor descriptor = mock(AvailablePluginDescriptor.class);
lenient().when(descriptor.getInformation()).thenReturn(information);
return new AvailablePlugin(descriptor);
}
private void returnInformation(Plugin mockedPlugin, PluginInformation information) {
when(mockedPlugin.getDescriptor().getInformation()).thenReturn(information);
}
} }

View File

@@ -0,0 +1,37 @@
package sonia.scm.plugin;
import org.mockito.Answers;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class PluginTestHelper {
public static AvailablePlugin createAvailable(String name) {
PluginInformation information = new PluginInformation();
information.setName(name);
return createAvailable(information);
}
public static InstalledPlugin createInstalled(String name) {
PluginInformation information = new PluginInformation();
information.setName(name);
return createInstalled(information);
}
public static InstalledPlugin createInstalled(PluginInformation information) {
InstalledPlugin plugin = mock(InstalledPlugin.class, Answers.RETURNS_DEEP_STUBS);
returnInformation(plugin, information);
return plugin;
}
public static AvailablePlugin createAvailable(PluginInformation information) {
AvailablePluginDescriptor descriptor = mock(AvailablePluginDescriptor.class);
lenient().when(descriptor.getInformation()).thenReturn(information);
return new AvailablePlugin(descriptor);
}
private static void returnInformation(Plugin mockedPlugin, PluginInformation information) {
when(mockedPlugin.getDescriptor().getInformation()).thenReturn(information);
}
}