From d32b91d9a9a099f6affabd84ff15456d78c8b0ee Mon Sep 17 00:00:00 2001 From: SamPanDonte Date: Sun, 26 Feb 2023 15:14:43 +0000 Subject: [PATCH 1/3] Bump version to 1.0.0 --- packages/client/package.json | 2 +- packages/core-ts/package.json | 2 +- packages/cypress/package.json | 2 +- packages/proto/package.json | 2 +- packages/proto/pom.xml | 2 +- packages/server/pom.xml | 2 +- packages/storybook/package.json | 2 +- packages/tools/package.json | 2 +- packages/ui/package.json | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/client/package.json b/packages/client/package.json index bf9aa462..b336e9ed 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "client", - "version": "1.0.2", + "version": "1.0.0", "scripts": { "@-------- MAIN SCRIPTS ----------": "", "start": "yarn serve", diff --git a/packages/core-ts/package.json b/packages/core-ts/package.json index bd515ba1..6560f871 100644 --- a/packages/core-ts/package.json +++ b/packages/core-ts/package.json @@ -1,4 +1,4 @@ { "name": "core-ts", - "version": "1.0.2" + "version": "1.0.0" } \ No newline at end of file diff --git a/packages/cypress/package.json b/packages/cypress/package.json index 455fb0c0..857b76f7 100644 --- a/packages/cypress/package.json +++ b/packages/cypress/package.json @@ -1,6 +1,6 @@ { "name": "cypress", - "version": "1.0.2", + "version": "1.0.0", "license": "BSD-2-Clause", "scripts": { "build": "echo build" diff --git a/packages/proto/package.json b/packages/proto/package.json index c3cc8ce2..82f539d2 100644 --- a/packages/proto/package.json +++ b/packages/proto/package.json @@ -1,6 +1,6 @@ { "name": "proto", - "version": "1.0.2", + "version": "1.0.0", "license": "BSD-2-Clause", "main": "dist/typescript/vernite.js", "scripts": { diff --git a/packages/proto/pom.xml b/packages/proto/pom.xml index 043fd787..1866ff64 100644 --- a/packages/proto/pom.xml +++ b/packages/proto/pom.xml @@ -6,7 +6,7 @@ dev.vernite protobuf - 1.0.2-SNAPSHOT + 1.0.0-SNAPSHOT protobuf Vernite Protobuf diff --git a/packages/server/pom.xml b/packages/server/pom.xml index 944145c9..b5f0eed2 100644 --- a/packages/server/pom.xml +++ b/packages/server/pom.xml @@ -13,7 +13,7 @@ dev.vernite vernite - 1.0.2-SNAPSHOT + 1.0.0-SNAPSHOT vernite Vernite server diff --git a/packages/storybook/package.json b/packages/storybook/package.json index 10e022df..4c69ff78 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "1.0.2", + "version": "1.0.0", "dependencies": { "client": "*" } diff --git a/packages/tools/package.json b/packages/tools/package.json index f52873c9..9e467b55 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -1,5 +1,5 @@ { "name": "tools", - "version": "1.0.2", + "version": "1.0.0", "type": "module" } \ No newline at end of file diff --git a/packages/ui/package.json b/packages/ui/package.json index 26d8522b..d4d13d86 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "ui", - "version": "1.0.2", + "version": "1.0.0", "main": "index.js", "dependencies": { "core-ts": "*" From f3e5914307e3ebc197b3c7d40f7419e126892f2c Mon Sep 17 00:00:00 2001 From: SamPanDonte Date: Sat, 11 Mar 2023 11:50:15 +0100 Subject: [PATCH 2/3] Use global configuration in workspace module; refactor workspace module tests --- .vscode/settings.json | 2 + packages/server/.gitignore | 3 - .../vernite/vernite/VerniteApplication.java | 22 +- .../vernite/common/constants/IDConstants.java | 53 +++ .../common/constants/NameConstants.java | 64 +++ .../common/constants/NullMessages.java | 44 ++ .../common/constraints/NullOrNotBlank.java | 23 +- .../projectworkspace/ProjectWorkspace.java | 4 +- .../vernite/workspace/CreateWorkspace.java | 23 +- .../vernite/workspace/UpdateWorkspace.java | 26 +- .../vernite/vernite/workspace/Workspace.java | 46 +- .../workspace/WorkspaceController.java | 37 +- .../vernite/workspace/WorkspaceId.java | 34 +- .../resources/application-test.properties | 3 +- .../vernite/utils/DataBaseRepository.java | 76 ++++ .../vernite/utils/IntegrationTestSetup.java | 128 ++++++ .../workspace/CreateWorkspaceTests.java | 59 ++- .../workspace/UpdateWorkspaceTests.java | 61 ++- .../workspace/WorkspaceControllerTests.java | 408 ++++++++++-------- .../vernite/workspace/WorkspaceIdTests.java | 54 ++- .../vernite/workspace/WorkspaceTests.java | 126 +++--- .../src/test/resources/application.properties | 30 ++ 22 files changed, 910 insertions(+), 416 deletions(-) create mode 100644 packages/server/src/main/java/dev/vernite/vernite/common/constants/IDConstants.java create mode 100644 packages/server/src/main/java/dev/vernite/vernite/common/constants/NameConstants.java create mode 100644 packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java create mode 100644 packages/server/src/test/java/dev/vernite/vernite/utils/DataBaseRepository.java create mode 100644 packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java create mode 100644 packages/server/src/test/resources/application.properties diff --git a/.vscode/settings.json b/.vscode/settings.json index f1d5e15a..fbf851d6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -88,6 +88,7 @@ /* ================== */ "cSpell.words": [ "auditlog", + "classpath", "compodoc", "devkit", "Donte", @@ -103,6 +104,7 @@ "protobuf", "protoc", "recaptcha", + "Servlet", "storysource", "tabuckner", "tailwindcss", diff --git a/packages/server/.gitignore b/packages/server/.gitignore index 12c55820..52e783ef 100644 --- a/packages/server/.gitignore +++ b/packages/server/.gitignore @@ -30,9 +30,6 @@ build/ !**/src/main/**/build/ !**/src/test/**/build/ -### VS Code ### -.vscode/ - ### Vernite ### vernite-2022.private-key.der application.properties diff --git a/packages/server/src/main/java/dev/vernite/vernite/VerniteApplication.java b/packages/server/src/main/java/dev/vernite/vernite/VerniteApplication.java index 0193ab3d..6180eb7b 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/VerniteApplication.java +++ b/packages/server/src/main/java/dev/vernite/vernite/VerniteApplication.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -32,15 +32,11 @@ import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.scheduling.annotation.EnableScheduling; -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.servers.Server; - @EnableScheduling @SpringBootApplication @ServletComponentScan -@OpenAPIDefinition(servers = @Server(url = "/api")) public class VerniteApplication { - public static void main(String[] args) { - SpringApplication.run(VerniteApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(VerniteApplication.class, args); + } } diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/constants/IDConstants.java b/packages/server/src/main/java/dev/vernite/vernite/common/constants/IDConstants.java new file mode 100644 index 00000000..7636a41b --- /dev/null +++ b/packages/server/src/main/java/dev/vernite/vernite/common/constants/IDConstants.java @@ -0,0 +1,53 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package dev.vernite.vernite.common.constants; + +import lombok.experimental.UtilityClass; + +/** + * Utility class for ID constants. Contains message keys for ID validation. + */ +@UtilityClass +public class IDConstants { + + /** + * Key for message when ID is null. + */ + public static final String NULL_MESSAGE = "notNullID"; + + /** + * Key for message when ID is negative. + */ + public static final String NEGATIVE_MESSAGE = "negativeID"; + + /** + * Key for message when ID is non-positive. + */ + public static final String NEGATIVE_OR_ZERO_MESSAGE = "nonPositiveID"; + +} diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/constants/NameConstants.java b/packages/server/src/main/java/dev/vernite/vernite/common/constants/NameConstants.java new file mode 100644 index 00000000..cabf508d --- /dev/null +++ b/packages/server/src/main/java/dev/vernite/vernite/common/constants/NameConstants.java @@ -0,0 +1,64 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package dev.vernite.vernite.common.constants; + +import lombok.experimental.UtilityClass; + +/** + * Utility class for name constants. Contains all constants used in the + * project REST API for name validation. + */ +@UtilityClass +public class NameConstants { + + /** + * Minimum length of name. + */ + public static final int MIN_LENGTH = 1; + + /** + * Maximum length of name. + */ + public static final int MAX_LENGTH = 50; + + /** + * Maximum length of long name. + */ + public static final int MAX_LONG_LENGTH = 100; + + /** + * Key for message when name size is not correct. + */ + public static final String SIZE_MESSAGE = "wrongNameSize"; + + /** + * Key for message when name is blank. + */ + public static final String BLANK_MESSAGE = "blankName"; + +} diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java b/packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java new file mode 100644 index 00000000..84586edf --- /dev/null +++ b/packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java @@ -0,0 +1,44 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package dev.vernite.vernite.common.constants; + +import lombok.experimental.UtilityClass; + +/** + * Utility class containing all message keys for not null validation on database + * relations. + */ +@UtilityClass +public class NullMessages { + + /** + * Key for message when project is null. + */ + public static final String PROJECT = "nullProject"; + +} diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java b/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java index 8df6cecb..f94770dc 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java +++ b/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,12 +27,7 @@ package dev.vernite.vernite.common.constraints; -import static java.lang.annotation.ElementType.ANNOTATION_TYPE; -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; @@ -70,9 +65,9 @@ * * @see NullOrNotBlank */ - @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) - @Retention(RUNTIME) @Documented + @Retention(RUNTIME) + @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) public @interface List { NullOrNotBlank[] value(); } diff --git a/packages/server/src/main/java/dev/vernite/vernite/projectworkspace/ProjectWorkspace.java b/packages/server/src/main/java/dev/vernite/vernite/projectworkspace/ProjectWorkspace.java index c665f14e..51ac569d 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/projectworkspace/ProjectWorkspace.java +++ b/packages/server/src/main/java/dev/vernite/vernite/projectworkspace/ProjectWorkspace.java @@ -1,7 +1,7 @@ /* * BSD 2-Clause License * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -36,6 +36,7 @@ import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.ToString; +import lombok.experimental.FieldNameConstants; import dev.vernite.vernite.project.Project; import dev.vernite.vernite.workspace.Workspace; @@ -48,6 +49,7 @@ */ @Data @NoArgsConstructor +@FieldNameConstants @Entity(name = "project_workspace") public class ProjectWorkspace { @EmbeddedId diff --git a/packages/server/src/main/java/dev/vernite/vernite/workspace/CreateWorkspace.java b/packages/server/src/main/java/dev/vernite/vernite/workspace/CreateWorkspace.java index aa8de363..aa6c142f 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/workspace/CreateWorkspace.java +++ b/packages/server/src/main/java/dev/vernite/vernite/workspace/CreateWorkspace.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,16 +27,15 @@ package dev.vernite.vernite.workspace; +import dev.vernite.vernite.common.constants.NameConstants; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; - import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** - * Class containing information needed to create new workspace entity. - * Has required constraints annotated using Java Bean Validation. + * Data transfer object containing information needed to create new workspace. */ @Data @NoArgsConstructor @@ -44,10 +43,10 @@ public class CreateWorkspace { /** - * Name for new workspace. Must contain at least one non-whitespace character. + * Name for new workspace. */ - @Size(min = 1, max = 50, message = "workspace name must be shorter than 50 characters") - @NotBlank(message = "workspace name must contain at least one non-whitespace character") + @NotBlank(message = NameConstants.BLANK_MESSAGE) + @Size(min = NameConstants.MIN_LENGTH, max = NameConstants.MAX_LENGTH, message = NameConstants.SIZE_MESSAGE) private String name; } diff --git a/packages/server/src/main/java/dev/vernite/vernite/workspace/UpdateWorkspace.java b/packages/server/src/main/java/dev/vernite/vernite/workspace/UpdateWorkspace.java index 9f8e202e..0927db00 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/workspace/UpdateWorkspace.java +++ b/packages/server/src/main/java/dev/vernite/vernite/workspace/UpdateWorkspace.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,17 +27,15 @@ package dev.vernite.vernite.workspace; -import jakarta.validation.constraints.Size; - +import dev.vernite.vernite.common.constants.NameConstants; import dev.vernite.vernite.common.constraints.NullOrNotBlank; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** - * Class containing information needed to update workspace entity. - * Has required constraints annotated using Java Bean Validation. - * It performs partial update using only present fields. + * Data transfer object containing information needed to update workspace. */ @Data @NoArgsConstructor @@ -45,10 +43,10 @@ public class UpdateWorkspace { /** - * New name for workspace. Must contain at least one non-whitespace character. + * New name for workspace. */ - @Size(min = 1, max = 50, message = "workspace name must be shorter than 50 characters") - @NullOrNotBlank(message = "workspace name must contain at least one non-whitespace character") + @NullOrNotBlank(message = NameConstants.BLANK_MESSAGE) + @Size(min = NameConstants.MIN_LENGTH, max = NameConstants.MAX_LENGTH, message = NameConstants.SIZE_MESSAGE) private String name; } diff --git a/packages/server/src/main/java/dev/vernite/vernite/workspace/Workspace.java b/packages/server/src/main/java/dev/vernite/vernite/workspace/Workspace.java index 0540be7a..5907e499 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/workspace/Workspace.java +++ b/packages/server/src/main/java/dev/vernite/vernite/workspace/Workspace.java @@ -28,6 +28,7 @@ package dev.vernite.vernite.workspace; import java.util.List; +import java.util.Optional; import java.util.Set; import jakarta.persistence.Column; @@ -48,6 +49,9 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonUnwrapped; +import dev.vernite.vernite.common.constants.IDConstants; +import dev.vernite.vernite.common.constants.NameConstants; +import dev.vernite.vernite.common.constants.NullMessages; import dev.vernite.vernite.project.Project; import dev.vernite.vernite.projectworkspace.ProjectWorkspace; import dev.vernite.vernite.user.User; @@ -67,34 +71,31 @@ @Data @Entity @NoArgsConstructor -public class Workspace { +public final class Workspace { @Valid @EmbeddedId @JsonUnwrapped - @NotNull(message = "workspace id cannot be null") + @NotNull(message = IDConstants.NULL_MESSAGE) private WorkspaceId id; - @Column(nullable = false, length = 50) - @Size(min = 1, max = 50, message = "workspace name must be shorter than 50 characters") - @NotBlank(message = "workspace name must contain at least one non-whitespace character") + @NotBlank(message = NameConstants.BLANK_MESSAGE) + @Column(nullable = false, length = NameConstants.MAX_LENGTH) + @Size(min = NameConstants.MIN_LENGTH, max = NameConstants.MAX_LENGTH, message = NameConstants.SIZE_MESSAGE) private String name; @JsonIgnore - @MapsId("userId") @ToString.Exclude @EqualsAndHashCode.Exclude @ManyToOne(optional = false) - @NotNull(message = "workspace must have user set") + @MapsId("userId") private User user; @JsonIgnore - @Deprecated @ToString.Exclude @EqualsAndHashCode.Exclude - @OneToMany(mappedBy = "workspace") @OnDelete(action = OnDeleteAction.CASCADE) - @NotNull(message = "project workspaces connection must be set") + @OneToMany(mappedBy = "workspace") private List projectWorkspaces = List.of(); @ManyToMany @@ -102,7 +103,7 @@ public class Workspace { @OrderBy("name, id") @EqualsAndHashCode.Exclude @Where(clause = "active is null") - @NotNull(message = "projects connection must be set") + @NotNull(message = NullMessages.PROJECT) @JoinTable(name = "project_workspace", joinColumns = { @JoinColumn(name = "workspace_user_id", referencedColumnName = "user_id"), @JoinColumn(name = "workspace_id", referencedColumnName = "id"), @@ -110,11 +111,11 @@ public class Workspace { private Set projects = Set.of(); /** - * Default constructor for workspace. + * Default constructor. * * @param id unique to user positive number for new workspace - * @param name must not be {@literal null} and have size between 1 and 50 - * @param user must not be {@literal null} and must be entity from database + * @param name name for new workspace + * @param user owner of new workspace */ public Workspace(long id, String name, User user) { this.setId(new WorkspaceId(id, user.getId())); @@ -123,32 +124,29 @@ public Workspace(long id, String name, User user) { } /** - * Constructor for workspace from create request. + * Constructor from create request. * * @param id unique to user positive number for new workspace - * @param user must not be {@literal null} and must be entity from database - * @param create must not be {@literal null} and must be valid + * @param user owner of new workspace + * @param create body of create request */ public Workspace(long id, User user, CreateWorkspace create) { this(id, create.getName(), user); } /** - * Updates workspace entity with data from update. + * Updates workspace with data from update. * - * @param update must not be {@literal null} and be valid + * @param update body of update request */ public void update(UpdateWorkspace update) { - if (update.getName() != null) { - setName(update.getName()); - } + Optional.ofNullable(update.getName()).ifPresent(this::setName); } /** * Setter for name value. It performs {@link String#trim()} on its argument. * - * @param name must not be {@literal null} and have at least one non-whitespace - * character and less than 50 characters + * @param name new name value */ public void setName(String name) { this.name = name.trim(); diff --git a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java index b949327e..1f9337dd 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java +++ b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -31,7 +31,6 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; - import dev.vernite.vernite.common.exception.ConflictStateException; import dev.vernite.vernite.common.utils.counter.CounterSequenceRepository; import dev.vernite.vernite.user.User; @@ -56,6 +55,8 @@ @RequestMapping("/workspace") public class WorkspaceController { + private static final String WORKSPACE_NOT_EMPTY = "workspaceNotEmpty"; + private CounterSequenceRepository counterRepository; private WorkspaceRepository workspaceRepository; @@ -63,8 +64,8 @@ public class WorkspaceController { /** * Retrieves all workspaces for authenticated user. There might be extra virtual * workspace with ID 0 for projects that aren't contained in any workspace. - * - * @param user logged in user + * + * @param user authenticated user * @return list with workspaces ordered by name and ID */ @GetMapping @@ -75,8 +76,8 @@ public List getAll(@NotNull @Parameter(hidden = true) User user) { /** * Create new workspace for authenticated user. New workspace will have next * unused ID unique for user. - * - * @param user logged in user + * + * @param user authenticated user * @param create data for new workspace * @return newly created workspace */ @@ -88,8 +89,8 @@ public Workspace create(@NotNull @Parameter(hidden = true) User user, @RequestBo /** * Retrieve workspace with given ID for authenticated user. - * - * @param user logged in user + * + * @param user authenticated user * @param id ID of workspace * @return workspace with given ID */ @@ -101,8 +102,8 @@ public Workspace get(@NotNull @Parameter(hidden = true) User user, @PathVariable /** * Update workspace with given ID. Performs partial update using only supplied * fields from request body. - * - * @param user logged in user + * + * @param user authenticated user * @param id ID of workspace * @param update data to update * @return workspace after update @@ -117,15 +118,15 @@ public Workspace update(@NotNull @Parameter(hidden = true) User user, @PathVaria /** * Delete workspace with given ID. Workspace to delete must be empty. - * - * @param user logged in user + * + * @param user authenticated user * @param id ID of workspace */ @DeleteMapping("/{id}") public void delete(@NotNull @Parameter(hidden = true) User user, @PathVariable long id) { Workspace workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(id, user.getId())); if (!workspace.getProjects().isEmpty()) { - throw new ConflictStateException("workspace must be empty to delete"); + throw new ConflictStateException(WORKSPACE_NOT_EMPTY); } workspaceRepository.delete(workspace); } diff --git a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java index db962a7b..94e5b63e 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java +++ b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * + * * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -34,37 +34,33 @@ import jakarta.validation.constraints.PositiveOrZero; import com.fasterxml.jackson.annotation.JsonIgnore; + +import dev.vernite.vernite.common.constants.IDConstants; import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; +import lombok.Data; import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; +import lombok.experimental.FieldNameConstants; /** * Composite ID for workspace. - * + * * It contains connected user id and id which is unique * among user workspaces and for each user starts on one. */ -@ToString +@Data @Embeddable @NoArgsConstructor -@EqualsAndHashCode @AllArgsConstructor +@FieldNameConstants public class WorkspaceId implements Serializable { - private static final long serialVersionUID = 1; + private static final long serialVersionUID = 1L; - @Setter - @Getter - @PositiveOrZero(message = "workspace unique number must be non negative number") + @PositiveOrZero(message = IDConstants.NEGATIVE_MESSAGE) private long id; - @Setter - @Getter @JsonIgnore - @Positive(message = "user ID must be positive number") + @Positive(message = IDConstants.NEGATIVE_OR_ZERO_MESSAGE) private long userId; } diff --git a/packages/server/src/main/resources/application-test.properties b/packages/server/src/main/resources/application-test.properties index 614aa9b4..978ed013 100644 --- a/packages/server/src/main/resources/application-test.properties +++ b/packages/server/src/main/resources/application-test.properties @@ -1,3 +1,4 @@ spring.datasource.url=jdbc:mysql://localhost:3306/vernite_test +spring.jpa.hibernate.ddl-auto=create-drop recaptcha.secret=6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe -vernite.rate-limit.enabled=false \ No newline at end of file +vernite.rate-limit.enabled=false diff --git a/packages/server/src/test/java/dev/vernite/vernite/utils/DataBaseRepository.java b/packages/server/src/test/java/dev/vernite/vernite/utils/DataBaseRepository.java new file mode 100644 index 00000000..6ccecffc --- /dev/null +++ b/packages/server/src/test/java/dev/vernite/vernite/utils/DataBaseRepository.java @@ -0,0 +1,76 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package dev.vernite.vernite.utils; + +import org.springframework.stereotype.Component; + +import dev.vernite.vernite.project.ProjectRepository; +import dev.vernite.vernite.projectworkspace.ProjectWorkspaceRepository; +import dev.vernite.vernite.release.ReleaseRepository; +import dev.vernite.vernite.sprint.SprintRepository; +import dev.vernite.vernite.status.StatusRepository; +import dev.vernite.vernite.task.TaskRepository; +import dev.vernite.vernite.task.comment.CommentRepository; +import dev.vernite.vernite.task.time.TimeTrackRepository; +import dev.vernite.vernite.user.UserRepository; +import dev.vernite.vernite.user.UserSessionRepository; +import dev.vernite.vernite.workspace.WorkspaceRepository; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Class containing database repositories. + */ +@Getter +@Component +@AllArgsConstructor +public class DataBaseRepository { + + private UserRepository user; + + private UserSessionRepository userSession; + + private WorkspaceRepository workspace; + + private ProjectWorkspaceRepository projectWorkspace; + + private ProjectRepository project; + + private StatusRepository status; + + private TaskRepository task; + + private ReleaseRepository release; + + private SprintRepository sprint; + + private TimeTrackRepository timeTrack; + + private CommentRepository comment; + +} diff --git a/packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java b/packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java new file mode 100644 index 00000000..fbd1673e --- /dev/null +++ b/packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java @@ -0,0 +1,128 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package dev.vernite.vernite.utils; + +import java.util.Date; + +import org.springframework.stereotype.Component; + +import dev.vernite.vernite.project.Project; +import dev.vernite.vernite.projectworkspace.ProjectWorkspace; +import dev.vernite.vernite.status.Status; +import dev.vernite.vernite.task.Task; +import dev.vernite.vernite.user.User; +import dev.vernite.vernite.user.UserSession; +import dev.vernite.vernite.workspace.Workspace; +import lombok.Getter; + +/** + * Class containing setup for integration tests. + */ +@Getter +@Component +public class IntegrationTestSetup { + + /** + * Class containing user and user session. + */ + public record UserInfo(User user, UserSession userSession) { + + /** + * @return user session token + */ + public String getSessionToken() { + return userSession.getSession(); + } + + } + + private DataBaseRepository dataBase; + + private UserInfo user; + + private UserInfo userNoAccess; + + private Workspace workspace; + + private Workspace workspaceEmpty; + + private Project project; + + private Project projectEmpty; + + private Task task; + + private Task taskEmpty; + + /** + * Constructor. Creates users, workspaces, projects, tasks and saves them in + * database. + */ + public IntegrationTestSetup(DataBaseRepository dataBase) { + this.dataBase = dataBase; + + var user = dataBase.getUser() + .save(new User("John", "Smith", "john_smith", "john_smith@examle.com", "password")); + var userSession = new UserSession(); + userSession.setIp("127.0.0.1"); + userSession.setSession("user_session_john"); + userSession.setLastUsed(new Date()); + userSession.setRemembered(true); + userSession.setUserAgent("userAgent"); + userSession.setUser(user); + + this.user = new UserInfo(user, dataBase.getUserSession().save(userSession)); + + user = dataBase.getUser() + .save(new User("Will", "Johnson", "will_johnson", "will_johnson@examle.com", "password")); + userSession = new UserSession(); + userSession.setIp("127.0.0.1"); + userSession.setSession("user_session_will"); + userSession.setLastUsed(new Date()); + userSession.setRemembered(true); + userSession.setUserAgent("userAgent"); + userSession.setUser(user); + + this.userNoAccess = new UserInfo(user, dataBase.getUserSession().save(userSession)); + + workspace = dataBase.getWorkspace().save(new Workspace(1, "Work", user)); + workspaceEmpty = dataBase.getWorkspace().save(new Workspace(2, "Hobby", user)); + + project = dataBase.getProject().save(new Project("Vernite", "Vernite application")); + var status = dataBase.getStatus().save(new Status("Begin", 0, 0, false, true, project)); + var statusEnd = dataBase.getStatus().save(new Status("Final", 0, 1, true, false, project)); + + projectEmpty = dataBase.getProject().save(new Project("Workflow", "Workflow application")); + + dataBase.getProjectWorkspace().save(new ProjectWorkspace(project, workspace, 1L)); + + task = dataBase.getTask().save(new Task(1, "First", "", status, user, 0, "low")); + taskEmpty = dataBase.getTask().save(new Task(2, "Second", "", statusEnd, user, 0, "low")); + } + +} diff --git a/packages/server/src/test/java/dev/vernite/vernite/workspace/CreateWorkspaceTests.java b/packages/server/src/test/java/dev/vernite/vernite/workspace/CreateWorkspaceTests.java index 72f68011..52a7ac30 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/workspace/CreateWorkspaceTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/workspace/CreateWorkspaceTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,16 +27,24 @@ package dev.vernite.vernite.workspace; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; + import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import dev.vernite.vernite.common.constants.NameConstants; +/** + * Tests for {@link CreateWorkspace} class. Tests validation constraints. + */ class CreateWorkspaceTests { private static Validator validator; @@ -47,20 +55,31 @@ static void init() { validator = factory.getValidator(); } - @Test - void validationValidTest() { - assertTrue(validator.validate(new CreateWorkspace("Name")).isEmpty()); - assertTrue(validator.validate(new CreateWorkspace(" Name ")).isEmpty()); - assertTrue(validator.validate(new CreateWorkspace("New name")).isEmpty()); + private static Stream testValidationValid() { + return Stream.of( + new CreateWorkspace("Name"), + new CreateWorkspace(" Name "), + new CreateWorkspace("New name")); + } + + private static Stream testValidationInvalid() { + return Stream.of( + new CreateWorkspace(null), + new CreateWorkspace(""), + new CreateWorkspace(" "), + new CreateWorkspace("a".repeat(NameConstants.MAX_LENGTH + 1))); + } + + @MethodSource + @ParameterizedTest + void testValidationValid(CreateWorkspace create) { + assertTrue(validator.validate(create).isEmpty(), "Validation failed for " + create); } - @Test - void validationInvalidTest() { - assertEquals(1, validator.validate(new CreateWorkspace(null)).size()); - assertEquals(2, validator.validate(new CreateWorkspace("")).size()); - assertEquals(1, validator.validate(new CreateWorkspace(" ")).size()); - assertEquals(1, validator.validate(new CreateWorkspace(" ")).size()); - assertEquals(1, validator.validate(new CreateWorkspace("a".repeat(51))).size()); + @MethodSource + @ParameterizedTest + void testValidationInvalid(CreateWorkspace create) { + assertFalse(validator.validate(create).isEmpty(), "Validation passed for " + create); } } diff --git a/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java b/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java index 80089817..0b198d99 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,17 +27,25 @@ package dev.vernite.vernite.workspace; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; + import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import dev.vernite.vernite.common.constants.NameConstants; -public class UpdateWorkspaceTests { +/** + * Tests for {@link CreateWorkspace} class. Tests validation constraints. + */ +class UpdateWorkspaceTests { private static Validator validator; @@ -47,20 +55,31 @@ static void init() { validator = factory.getValidator(); } - @Test - void validationValidTest() { - assertTrue(validator.validate(new UpdateWorkspace(null)).isEmpty()); - assertTrue(validator.validate(new UpdateWorkspace("Name")).isEmpty()); - assertTrue(validator.validate(new UpdateWorkspace(" Name ")).isEmpty()); - assertTrue(validator.validate(new UpdateWorkspace("New name")).isEmpty()); + private static Stream testValidationValid() { + return Stream.of( + new UpdateWorkspace(null), + new UpdateWorkspace("Name"), + new UpdateWorkspace(" Name "), + new UpdateWorkspace("New name")); + } + + private static Stream testValidationInvalid() { + return Stream.of( + new UpdateWorkspace(""), + new UpdateWorkspace(" "), + new UpdateWorkspace("a".repeat(NameConstants.MAX_LENGTH + 1))); + } + + @MethodSource + @ParameterizedTest + void testValidationValid(UpdateWorkspace create) { + assertTrue(validator.validate(create).isEmpty(), "Validation failed for " + create); } - @Test - void validationInvalidTest() { - assertEquals(2, validator.validate(new UpdateWorkspace("")).size()); - assertEquals(1, validator.validate(new UpdateWorkspace(" ")).size()); - assertEquals(1, validator.validate(new UpdateWorkspace(" ")).size()); - assertEquals(1, validator.validate(new UpdateWorkspace("a".repeat(51))).size()); + @MethodSource + @ParameterizedTest + void testValidationInvalid(UpdateWorkspace create) { + assertFalse(validator.validate(create).isEmpty(), "Validation passed for " + create); } } diff --git a/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceControllerTests.java b/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceControllerTests.java index 3a26bde7..622f98ba 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceControllerTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceControllerTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -28,270 +28,318 @@ package dev.vernite.vernite.workspace; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.ArrayList; +import java.util.Comparator; import java.util.Date; import java.util.List; -import java.util.Optional; +import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.reactive.server.WebTestClient; +import dev.vernite.vernite.common.constants.NameConstants; import dev.vernite.vernite.project.Project; -import dev.vernite.vernite.project.ProjectRepository; import dev.vernite.vernite.projectworkspace.ProjectWorkspace; -import dev.vernite.vernite.projectworkspace.ProjectWorkspaceRepository; -import dev.vernite.vernite.user.User; -import dev.vernite.vernite.user.UserRepository; -import dev.vernite.vernite.user.UserSession; -import dev.vernite.vernite.user.UserSessionRepository; import dev.vernite.vernite.user.auth.AuthController; +import dev.vernite.vernite.utils.IntegrationTestSetup; /** - * TODO: refactor this class + * Integration tests for {@link WorkspaceController} */ @SpringBootTest @AutoConfigureMockMvc @TestInstance(Lifecycle.PER_CLASS) -@TestPropertySource({ "classpath:application.properties", "classpath:application-test.properties" }) class WorkspaceControllerTests { + + private static void assertWorkspaceEquals(Workspace w1, Workspace w2) { + assertEquals(w1.getId().getId(), w2.getId().getId(), "Workspace id should be equal"); + assertEquals(w1.getName(), w2.getName(), "Workspace name should be equal"); + } + @Autowired private WebTestClient client; - @Autowired - private UserRepository userRepository; - @Autowired - private UserSessionRepository sessionRepository; - @Autowired - private WorkspaceRepository workspaceRepository; - - private User user; - private UserSession session; - @BeforeAll - void init() { - this.user = userRepository.findByUsername("Username"); - if (this.user == null) { - this.user = userRepository.save(new User("Name", "Surname", "Username", "Email@test.pl", "1")); - } - session = new UserSession(); - session.setIp("127.0.0.1"); - session.setSession("session_token_workspace_tests"); - session.setLastUsed(new Date()); - session.setRemembered(true); - session.setUserAgent("userAgent"); - session.setUser(user); - try { - session = sessionRepository.save(session); - } catch (DataIntegrityViolationException e) { - session = sessionRepository.findBySession("session_token_workspace_tests").orElseThrow(); - } - } + @Autowired + private IntegrationTestSetup setup; @BeforeEach void clean() { - workspaceRepository.deleteAll(); + setup.getDataBase().getWorkspace().deleteAll(); } - void workspaceEquals(Workspace w1, Workspace w2) { - assertEquals(w1.getId().getId(), w2.getId().getId()); - assertEquals(w1.getName(), w2.getName()); + private Stream> testGetAllSuccess() { + return Stream.of(new ArrayList<>(), + new ArrayList<>(List.of(new Workspace(1, "Test 1", setup.getUser().user()), + new Workspace(2, "Test 3", setup.getUser().user()), + new Workspace(3, "Test 2", setup.getUser().user())))); } - @Test - void getAllSuccess() { - // Test empty return list - client.get().uri("/workspace").cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() - .expectStatus().isOk().expectBodyList(Workspace.class).hasSize(0); - // Prepare some workspaces for next test - List workspaces = List.of(new Workspace(1, "Test 1", user), new Workspace(2, "Test 3", user), - new Workspace(3, "Test 2", user)); - workspaceRepository.saveAll(workspaces); - // Test non empty return list - List result = client.get().uri("/workspace").cookie(AuthController.COOKIE_NAME, session.getSession()) - .exchange().expectStatus().isOk().expectBodyList(Workspace.class).hasSize(3).returnResult() - .getResponseBody(); - assertNotNull(result); - workspaceEquals(workspaces.get(0), result.get(0)); - workspaceEquals(workspaces.get(1), result.get(2)); - workspaceEquals(workspaces.get(2), result.get(1)); - // Test soft delete - workspaceRepository.delete(workspaces.get(0)); - client.get().uri("/workspace").cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() - .expectStatus().isOk().expectBodyList(Workspace.class).hasSize(2); + @MethodSource + @ParameterizedTest + void testGetAllSuccess(List workspaces) { + setup.getDataBase().getWorkspace().saveAll(workspaces); + workspaces.sort(Comparator.comparing(Workspace::getName)); + var result = client.get().uri("/workspace") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() + .expectBodyList(Workspace.class).hasSize(workspaces.size()).returnResult().getResponseBody(); + + assertNotNull(result, "Response should not be null"); + + for (var i = 0; i < workspaces.size(); i++) { + assertWorkspaceEquals(workspaces.get(i), result.get(i)); + } } - @Test - void getAllUnauthorized() { - client.get().uri("/workspace").cookie(AuthController.COOKIE_NAME, "invalid_token").exchange().expectStatus() + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testGetAllUnauthorized(String token) { + client.get().uri("/workspace").cookie(AuthController.COOKIE_NAME, token).exchange().expectStatus() .isUnauthorized(); - client.get().uri("/workspace").exchange().expectStatus().isUnauthorized(); } @Test - void createSuccess() { - Workspace workspace = client.post().uri("/workspace").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateWorkspace("POST")).exchange().expectStatus().isOk().expectBody(Workspace.class) + void testCreateSuccess() { + var workspace = client.post().uri("/workspace") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(new CreateWorkspace("Test")).exchange().expectStatus().isOk().expectBody(Workspace.class) .returnResult().getResponseBody(); - assertNotNull(workspace); - Optional optional = workspaceRepository.findById(new WorkspaceId(workspace.getId().getId(), user.getId())); - assertEquals(true, optional.isPresent()); - Workspace result = optional.get(); - workspaceEquals(result, workspace); + + assertNotNull(workspace, "Response should not be null"); + + var optional = setup.getDataBase().getWorkspace() + .findById(new WorkspaceId(workspace.getId().getId(), setup.getUser().user().getId())); + + assertTrue(optional.isPresent(), "Workspace should be present in database"); + + var result = optional.get(); + + assertWorkspaceEquals(workspace, result); } - @Test - void createBadRequest() { - // Test null name - client.post().uri("/workspace").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateWorkspace(null)).exchange().expectStatus().isBadRequest(); - // Test empty name - client.post().uri("/workspace").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateWorkspace("")).exchange().expectStatus().isBadRequest(); - // Test too long name - client.post().uri("/workspace").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateWorkspace("a".repeat(51))).exchange().expectStatus().isBadRequest(); + private Stream testCreateBadRequest() { + return Stream.of(new CreateWorkspace(""), new CreateWorkspace(" "), new CreateWorkspace()); } - @Test - void createUnauthorized() { - client.post().uri("/workspace").cookie(AuthController.COOKIE_NAME, "invalid_token").exchange().expectStatus() + @MethodSource + @ParameterizedTest + void testCreateBadRequest(CreateWorkspace create) { + client.post().uri("/workspace").cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(create).exchange().expectStatus().isBadRequest(); + } + + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testCreateUnauthorized(String token) { + client.post().uri("/workspace").cookie(AuthController.COOKIE_NAME, token).exchange().expectStatus() .isUnauthorized(); - client.post().uri("/workspace").exchange().expectStatus().isUnauthorized(); } @Test - void getSuccess() { - Workspace workspace = workspaceRepository.save(new Workspace(1, "GET", user)); + void testGetSuccess() { + var workspace = new Workspace(1, "Test", setup.getUser().user()); + setup.getDataBase().getWorkspace().save(workspace); - Workspace result = client.get().uri("/workspace/{id}", workspace.getId().getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + var result = client.get().uri("/workspace/{id}", workspace.getId().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBody(Workspace.class).returnResult().getResponseBody(); - workspaceEquals(workspace, result); - } + assertNotNull(result, "Response should not be null"); - @Test - void getUnauthorized() { - client.get().uri("/workspace/1").exchange().expectStatus().isUnauthorized(); + assertWorkspaceEquals(workspace, result); + } - long id = workspaceRepository.save(new Workspace(1, "GET", user)).getId().getId(); - client.get().uri("/workspace/{id}", id).exchange().expectStatus().isUnauthorized(); - client.get().uri("/workspace/{id}", id).cookie(AuthController.COOKIE_NAME, "invalid_token").exchange() + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testGetUnauthorized(String token) { + client.get().uri("/workspace/{id}", Long.MAX_VALUE).cookie(AuthController.COOKIE_NAME, token).exchange() .expectStatus().isUnauthorized(); + + var id = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())).getId() + .getId(); + + client.get().uri("/workspace/{id}", id).cookie(AuthController.COOKIE_NAME, token).exchange().expectStatus() + .isUnauthorized(); } @Test - void getNotFound() { - client.get().uri("/workspace/1").cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() - .expectStatus().isNotFound(); - - Workspace workspace = new Workspace(1, "GET", user); - workspaceRepository.delete(workspace); - client.get().uri("/workspace/{id}", workspace.getId().getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isNotFound(); + void testGetNotFound() { + client.get().uri("/workspace/{id}", Long.MAX_VALUE) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); + + var id = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())).getId(); + + client.get().uri("/workspace/{id}", id.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUserNoAccess().getSessionToken()) + .exchange().expectStatus().isNotFound(); + + setup.getDataBase().getWorkspace().deleteById(id); + + client.get().uri("/workspace/{id}", id.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); } - @Test - void updateSuccess() { - Workspace workspace = workspaceRepository.save(new Workspace(1, "PUT", user)); + private Stream testUpdateSuccess() { + return Stream.of(new UpdateWorkspace("Test 1"), new UpdateWorkspace("Test 2")); + } - client.put().uri("/workspace/{id}", workspace.getId().getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).bodyValue(new UpdateWorkspace()).exchange() - .expectStatus().isOk(); - - Workspace result = client.put().uri("/workspace/{id}", workspace.getId().getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).bodyValue(new UpdateWorkspace("NEW PUT")) - .exchange().expectStatus().isOk().expectBody(Workspace.class).returnResult().getResponseBody(); - workspace.setName("NEW PUT"); - workspaceEquals(workspace, result); - workspaceEquals(workspace, workspaceRepository.findByIdOrThrow(workspace.getId())); + @MethodSource + @ParameterizedTest + void testUpdateSuccess(UpdateWorkspace update) { + var workspace = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())); + + var result = client.put().uri("/workspace/{id}", workspace.getId().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).bodyValue(update).exchange() + .expectStatus().isOk().expectBody(Workspace.class).returnResult().getResponseBody(); + + workspace.update(update); + + assertNotNull(result, "Response should not be null"); + + assertWorkspaceEquals(workspace, result); + + var optional = setup.getDataBase().getWorkspace() + .findById(new WorkspaceId(workspace.getId().getId(), setup.getUser().user().getId())); + + assertTrue(optional.isPresent(), "Workspace should be present in database"); + + result = optional.get(); + + assertWorkspaceEquals(workspace, result); } - @Test - void updateBadRequest() { - long id = workspaceRepository.save(new Workspace(1, "PUT", user)).getId().getId(); + private Stream testUpdateBadRequest() { + return Stream.of(new UpdateWorkspace(""), new UpdateWorkspace(" "), + new UpdateWorkspace("a".repeat(NameConstants.MAX_LENGTH + 1))); + } - client.put().uri("/workspace/{id}", id) - .cookie(AuthController.COOKIE_NAME, session.getSession()).bodyValue(new UpdateWorkspace("")).exchange() - .expectStatus().isBadRequest(); + @MethodSource + @ParameterizedTest + void testUpdateBadRequest(UpdateWorkspace update) { + var workspace = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())); - client.put().uri("/workspace/{id}", id) - .cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateWorkspace("a".repeat(51))).exchange() + client.put().uri("/workspace/{id}", workspace.getId().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).bodyValue(update).exchange() .expectStatus().isBadRequest(); } - @Test - void updateUnauthorized() { - client.put().uri("/workspace/1").bodyValue(new UpdateWorkspace("NEW PUT")).exchange().expectStatus() - .isUnauthorized(); + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testUpdateUnauthorized(String token) { + client.put().uri("/workspace/{id}", Long.MAX_VALUE).cookie(AuthController.COOKIE_NAME, token).exchange() + .expectStatus().isUnauthorized(); + + var id = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())).getId() + .getId(); - long id = workspaceRepository.save(new Workspace(1, "PUT", user)).getId().getId(); - client.put().uri("/workspace/{id}", id).bodyValue(new UpdateWorkspace("NEW PUT")).exchange().expectStatus() + client.put().uri("/workspace/{id}", id).cookie(AuthController.COOKIE_NAME, token).exchange().expectStatus() .isUnauthorized(); - client.put().uri("/workspace/{id}", id).cookie(AuthController.COOKIE_NAME, "invalid_token") - .bodyValue(new UpdateWorkspace("NEW PUT")).exchange().expectStatus().isUnauthorized(); } @Test - void updateNotFound() { - client.put().uri("/workspace/1").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateWorkspace("NEW PUT")).exchange().expectStatus().isNotFound(); + void testUpdateNotFound() { + client.put().uri("/workspace/{id}", Long.MAX_VALUE) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).bodyValue(new UpdateWorkspace()) + .exchange().expectStatus().isNotFound(); + + var id = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())).getId(); + + client.put().uri("/workspace/{id}", id.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUserNoAccess().getSessionToken()) + .bodyValue(new UpdateWorkspace()).exchange().expectStatus().isNotFound(); + + setup.getDataBase().getWorkspace().deleteById(id); + + client.put().uri("/workspace/{id}", id.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).bodyValue(new UpdateWorkspace()) + .exchange().expectStatus().isNotFound(); } @Test - void deleteSuccess(@Autowired ProjectRepository pRepo, @Autowired ProjectWorkspaceRepository pwRepo) { - Workspace workspace = workspaceRepository.save(new Workspace(1, "DELETE", user)); + void testDeleteSuccess() { + var workspace = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())); + client.delete().uri("/workspace/{id}", workspace.getId().getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk(); - assertNotEquals(false, workspaceRepository.findById(workspace.getId()).isEmpty()); + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isOk(); + + var optional = setup.getDataBase().getWorkspace() + .findById(new WorkspaceId(workspace.getId().getId(), setup.getUser().user().getId())); + + assertTrue(optional.isEmpty(), "Workspace should not be present in database"); - Project project = new Project("DELETE", ""); + var project = new Project("Vernite tests", ""); project.setActive(new Date()); - project = pRepo.save(project); - Workspace workspace2 = workspaceRepository.save(new Workspace(1, "DELETE", user)); - pwRepo.save(new ProjectWorkspace(project, workspace2, 1L)); + project = setup.getDataBase().getProject().save(project); + + workspace = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, workspace, 1L)); + + client.delete().uri("/workspace/{id}", workspace.getId().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isOk(); + + optional = setup.getDataBase().getWorkspace() + .findById(new WorkspaceId(workspace.getId().getId(), setup.getUser().user().getId())); - client.delete().uri("/workspace/{id}", workspace2.getId().getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk(); - assertNotEquals(false, workspaceRepository.findById(workspace2.getId()).isEmpty()); + assertTrue(optional.isEmpty(), "Workspace should not be present in database"); } - @Test - void deleteConflict(@Autowired ProjectRepository pRepo, @Autowired ProjectWorkspaceRepository pwRepo) { - Project project = pRepo.save(new Project("DELETE", "")); - Workspace workspace = workspaceRepository.save(new Workspace(1, "DELETE", user)); - pwRepo.save(new ProjectWorkspace(project, workspace, 1L)); + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testDeleteUnauthorized(String token) { + client.delete().uri("/workspace/{id}", Long.MAX_VALUE).cookie(AuthController.COOKIE_NAME, token).exchange() + .expectStatus().isUnauthorized(); - client.delete().uri("/workspace/{id}", workspace.getId().getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().is4xxClientError(); + var id = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())).getId() + .getId(); + + client.delete().uri("/workspace/{id}", id).cookie(AuthController.COOKIE_NAME, token).exchange().expectStatus() + .isUnauthorized(); } @Test - void deleteUnauthorized() { - client.delete().uri("/workspace/1").exchange().expectStatus().isUnauthorized(); + void testDeleteNotFound() { + client.delete().uri("/workspace/{id}", Long.MAX_VALUE) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); - Workspace workspace = workspaceRepository.save(new Workspace(1, "DELETE", user)); - client.delete().uri("/workspace/{id}", workspace.getId().getId()).exchange().expectStatus().isUnauthorized(); - client.delete().uri("/workspace/{id}", workspace.getId().getId()) - .cookie(AuthController.COOKIE_NAME, "invalid_token").exchange().expectStatus().isUnauthorized(); + var id = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())).getId(); + + client.delete().uri("/workspace/{id}", id.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUserNoAccess().getSessionToken()).exchange().expectStatus() + .isNotFound(); + + setup.getDataBase().getWorkspace().deleteById(id); - workspaceRepository.findByIdOrThrow(workspace.getId()); + client.delete().uri("/workspace/{id}", id.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); } @Test - void deleteNotFound() { - client.delete().uri("/workspace/1").cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() - .expectStatus().isNotFound(); + void testDeleteConflict() { + var workspace = setup.getDataBase().getWorkspace().save(new Workspace(1, "Test", setup.getUser().user())); + var project = setup.getDataBase().getProject().save(new Project("Vernite tests", "")); + + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, workspace, 1L)); + + client.delete().uri("/workspace/{id}", workspace.getId().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isEqualTo(409); } + } diff --git a/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceIdTests.java b/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceIdTests.java index c4dd2bdf..5ac6e718 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceIdTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceIdTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,16 +27,22 @@ package dev.vernite.vernite.workspace; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; + import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +/** + * Tests for {@link WorkspaceId} class. Tests validation constraints. + */ class WorkspaceIdTests { private static Validator validator; @@ -47,18 +53,30 @@ static void init() { validator = factory.getValidator(); } - @Test - void validationValidTest() { - assertTrue(validator.validate(new WorkspaceId(1, 1)).isEmpty()); - assertTrue(validator.validate(new WorkspaceId(3, 7)).isEmpty()); - assertTrue(validator.validate(new WorkspaceId(0, 4)).isEmpty()); + private static Stream testValidationValid() { + return Stream.of( + new WorkspaceId(1, 1), + new WorkspaceId(3, 7), + new WorkspaceId(0, 4)); + } + + private static Stream testValidationInvalid() { + return Stream.of( + new WorkspaceId(-1, 4), + new WorkspaceId(0, 0), + new WorkspaceId(-3, 0)); + } + + @MethodSource + @ParameterizedTest + void testValidationValid(WorkspaceId workspaceId) { + assertTrue(validator.validate(workspaceId).isEmpty(), "WorkspaceId " + workspaceId + " should be valid"); } - @Test - void validationInvalidTest() { - assertEquals(1, validator.validate(new WorkspaceId(-1, 4)).size()); - assertEquals(1, validator.validate(new WorkspaceId(0, 0)).size()); - assertEquals(2, validator.validate(new WorkspaceId(-3, 0)).size()); + @MethodSource + @ParameterizedTest + void testValidationInvalid(WorkspaceId workspaceId) { + assertFalse(validator.validate(workspaceId).isEmpty(), "WorkspaceId " + workspaceId + " should be invalid"); } } diff --git a/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceTests.java b/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceTests.java index cf60b79c..a86de215 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/workspace/WorkspaceTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -28,17 +28,29 @@ package dev.vernite.vernite.workspace; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; + import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import dev.vernite.vernite.common.constants.NameConstants; import dev.vernite.vernite.user.User; +/** + * Tests for {@link Workspace} class. Tests validation constraints, constructor + * and custom getters/setters. + */ class WorkspaceTests { private static final User user = new User("name", "surname", "username", "email", "password"); @@ -52,78 +64,76 @@ static void init() { validator = factory.getValidator(); } - @Test - void constructorBaseTest() { - Workspace workspace = new Workspace(1, "Name", user); - - assertEquals(1, workspace.getId().getId()); - assertEquals("Name", workspace.getName()); - assertEquals(user, workspace.getUser()); + private static Stream testConstructor() { + return Stream.of( + Arguments.of(1, "Name", user), + Arguments.of(1, " Name ", user)); + } - workspace = new Workspace(1, " Name ", user); + private static Stream testUpdate() { + return Stream.of( + new UpdateWorkspace("New name"), + new UpdateWorkspace(" New name "), + new UpdateWorkspace(null)); + } - assertEquals(1, workspace.getId().getId()); - assertEquals("Name", workspace.getName()); - assertEquals(user, workspace.getUser()); + private static Stream testValidationInvalid() { + return Stream.of( + new Workspace(1, "", user), + new Workspace(1, " ", user), + new Workspace(-1, "Name", user), + new Workspace(1, "a".repeat(NameConstants.MAX_LENGTH + 1), user)); } - @Test - void constructorCreateTest() { - Workspace workspace = new Workspace(1, user, new CreateWorkspace("Name")); + @ParameterizedTest + @MethodSource("testConstructor") + void testBaseConstructor(int id, String name, User user) { + Workspace workspace = new Workspace(id, name, user); - assertEquals(1, workspace.getId().getId()); - assertEquals("Name", workspace.getName()); - assertEquals(user, workspace.getUser()); + assertEquals(id, workspace.getId().getId(), "Id should be equal"); + assertEquals(name.trim(), workspace.getName(), "Trimmed name should be equal"); + assertEquals(user, workspace.getUser(), "User should be equal"); + } - workspace = new Workspace(1, user, new CreateWorkspace(" Name ")); + @ParameterizedTest + @MethodSource("testConstructor") + void testCreateConstructor(int id, String name, User user) { + Workspace workspace = new Workspace(1, user, new CreateWorkspace("Name")); - assertEquals(1, workspace.getId().getId()); - assertEquals("Name", workspace.getName()); - assertEquals(user, workspace.getUser()); + assertEquals(id, workspace.getId().getId(), "Id should be equal"); + assertEquals(name.trim(), workspace.getName(), "Trimmed name should be equal"); + assertEquals(user, workspace.getUser(), "User should be equal"); } - @Test - void updateTest() { + @MethodSource + @ParameterizedTest + void testUpdate(UpdateWorkspace update) { Workspace workspace = new Workspace(1, "Name", user); - workspace.update(new UpdateWorkspace("New name")); + workspace.update(update); - assertEquals(1, workspace.getId().getId()); - assertEquals("New name", workspace.getName()); - assertEquals(user, workspace.getUser()); + String newName = update.getName() == null ? "Name" : update.getName().trim(); - workspace.update(new UpdateWorkspace(null)); - - assertEquals(1, workspace.getId().getId()); - assertEquals("New name", workspace.getName()); - assertEquals(user, workspace.getUser()); + assertEquals(newName, workspace.getName(), "Trimmed name should be equal"); } - @Test - void setNameTest() { + @ParameterizedTest + @ValueSource(strings = { "New name", " New name ", "" }) + void testSetName(String name) { Workspace workspace = new Workspace(1, "Name", user); - workspace.setName("New name"); + workspace.setName(name); - assertEquals(1, workspace.getId().getId()); - assertEquals("New name", workspace.getName()); - assertEquals(user, workspace.getUser()); - - workspace.setName(" New name "); - - assertEquals(1, workspace.getId().getId()); - assertEquals("New name", workspace.getName()); - assertEquals(user, workspace.getUser()); + assertEquals(name.trim(), workspace.getName(), "Trimmed name should be equal"); } @Test - void validationValidTest() { - assertTrue(validator.validate(new Workspace(1, "Name", user)).isEmpty()); + void testValidationValid() { + assertTrue(validator.validate(new Workspace(1, "Name", user)).isEmpty(), "Workspace should be valid"); } - @Test - void validationInvalidTest() { - assertEquals(2, validator.validate(new Workspace(1, "", user)).size()); - assertEquals(2, validator.validate(new Workspace(1, " ", user)).size()); - assertEquals(3, validator.validate(new Workspace(-1, " ", user)).size()); - assertEquals(1, validator.validate(new Workspace(1, "a".repeat(51), user)).size()); + @MethodSource + @ParameterizedTest + void testValidationInvalid(Workspace workspace) { + assertFalse(validator.validate(workspace).isEmpty(), "Workspace should be invalid"); } + } diff --git a/packages/server/src/test/resources/application.properties b/packages/server/src/test/resources/application.properties new file mode 100644 index 00000000..381479a2 --- /dev/null +++ b/packages/server/src/test/resources/application.properties @@ -0,0 +1,30 @@ +server.servlet.context-path=/api +springdoc.api-docs.path=/api/api-docs +springdoc.swagger-ui.path=/swagger-ui +spring.jpa.hibernate.ddl-auto=create-drop +spring.datasource.url=jdbc:mysql://localhost:3306/vernite_test +spring.jpa.defer-datasource-initialization=true +spring.datasource.username=vernite +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.sql.init.mode=always +spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect +spring.jpa.show-sql=false +server.error.include-message=always +spring.sql.init.separator=^; +spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true +spring.jackson.mapper.accept-case-insensitive-enums=true +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username=contact.vernite@gmail.com +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.connectiontimeout=5000 +spring.mail.properties.mail.smtp.timeout=5000 +spring.mail.properties.mail.smtp.writetimeout=5000 +spring.mail.properties.mail.smtp.starttls.enable=true +slack.userScope=channels:history,channels:read,chat:write,files:read,files:write,groups:history,groups:read,groups:write,im:history,im:read,im:write,mpim:history,mpim:read,mpim:write,users:read +github.client.id=Iv1.3cc076e3d9f4867a +github.app.id=195507 +github.jwt.secret.path=vernite-2022.private-key.der +github.api.url=https://api.github.com +recaptcha.secret=6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe +vernite.rate-limit.enabled=false From 2ab4742d3fcce0c859fd618a69acef27898f6777 Mon Sep 17 00:00:00 2001 From: SamPanDonte Date: Sat, 18 Mar 2023 20:41:09 +0100 Subject: [PATCH 3/3] Use global configuration in project module; refactor project module tests --- .../constants/DescriptionConstants.java | 59 ++ .../common/constants/NullMessages.java | 40 ++ .../common/constraints/NullOrNotBlank.java | 2 +- .../common/utils/SecureRandomUtils.java | 25 +- .../vernite/common/utils/StateManager.java | 28 +- .../vernite/project/CreateProject.java | 33 +- .../dev/vernite/vernite/project/Project.java | 101 ++-- .../vernite/project/ProjectController.java | 68 +-- .../vernite/project/UpdateProject.java | 33 +- .../workspace/WorkspaceController.java | 6 +- .../vernite/workspace/WorkspaceId.java | 3 +- .../vernite/project/CreateProjectTests.java | 63 +- .../project/ProjectControllerTests.java | 559 ++++++++++-------- .../vernite/vernite/project/ProjectTests.java | 168 +++--- .../vernite/project/UpdateProjectTests.java | 67 ++- .../vernite/utils/IntegrationTestSetup.java | 4 +- .../workspace/UpdateWorkspaceTests.java | 2 +- 17 files changed, 722 insertions(+), 539 deletions(-) create mode 100644 packages/server/src/main/java/dev/vernite/vernite/common/constants/DescriptionConstants.java diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/constants/DescriptionConstants.java b/packages/server/src/main/java/dev/vernite/vernite/common/constants/DescriptionConstants.java new file mode 100644 index 00000000..89df2528 --- /dev/null +++ b/packages/server/src/main/java/dev/vernite/vernite/common/constants/DescriptionConstants.java @@ -0,0 +1,59 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package dev.vernite.vernite.common.constants; + +import lombok.experimental.UtilityClass; + +/** + * Utility class for description constants. Contains all constraints used in + * the project REST API for description validation. + */ +@UtilityClass +public class DescriptionConstants { + + /** + * Minimum length of description. + */ + public static final int MIN_LENGTH = 0; + + /** + * Maximum length of description. + */ + public static final int MAX_LENGTH = 1000; + + /** + * Key for message when description size is not correct. + */ + public static final String SIZE_MESSAGE = "wrongDescriptionSize"; + + /** + * Key for message when description is null. + */ + public static final String NULL_MESSAGE = "nullDescription"; + +} diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java b/packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java index 84586edf..bdaf36e3 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java +++ b/packages/server/src/main/java/dev/vernite/vernite/common/constants/NullMessages.java @@ -41,4 +41,44 @@ public class NullMessages { */ public static final String PROJECT = "nullProject"; + /** + * Key for message when workspace id is null. + */ + public static final String WORKSPACE_ID = "nullWorkspaceId"; + + /** + * Key for message when member is null. + */ + public static final String MEMBER = "nullMember"; + + /** + * Key for message when user is null. + */ + public static final String USER = "nullUser"; + + /** + * Key for message when status is null. + */ + public static final String STATUS = "nullStatus"; + + /** + * Key for message when counter is null. + */ + public static final String COUNTER = "nullCounter"; + + /** + * Key for message when sprint is null. + */ + public static final String SPRINT = "nullSprint"; + + /** + * Key for message when release is null. + */ + public static final String RELEASE = "nullRelease"; + + /** + * Key for message when meeting is null. + */ + public static final String MEETING = "nullMeeting"; + } diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java b/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java index f94770dc..5b541298 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java +++ b/packages/server/src/main/java/dev/vernite/vernite/common/constraints/NullOrNotBlank.java @@ -68,7 +68,7 @@ @Documented @Retention(RUNTIME) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) - public @interface List { + @interface List { NullOrNotBlank[] value(); } } diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/utils/SecureRandomUtils.java b/packages/server/src/main/java/dev/vernite/vernite/common/utils/SecureRandomUtils.java index 002eb1b9..0d508a31 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/common/utils/SecureRandomUtils.java +++ b/packages/server/src/main/java/dev/vernite/vernite/common/utils/SecureRandomUtils.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -29,22 +29,23 @@ import java.security.SecureRandom; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; +import lombok.experimental.UtilityClass; /** * Utils for common secure random operations. */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@UtilityClass public class SecureRandomUtils { + private static final int DEFAULT_LENGTH = 128; + private static final SecureRandom RANDOM = new SecureRandom(); private static final char[] CHARS = "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM".toCharArray(); /** * Generates a secure random string of the given length. - * + * * @param length must be greater than 0 * @return the generated string */ @@ -60,11 +61,11 @@ public static String generateSecureRandomString(int length) { /** * Generates a secure random string of length 128. - * + * * @return the generated string */ public static String generateSecureRandomString() { - return generateSecureRandomString(128); + return generateSecureRandomString(DEFAULT_LENGTH); } } diff --git a/packages/server/src/main/java/dev/vernite/vernite/common/utils/StateManager.java b/packages/server/src/main/java/dev/vernite/vernite/common/utils/StateManager.java index 22270ca0..d86754ca 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/common/utils/StateManager.java +++ b/packages/server/src/main/java/dev/vernite/vernite/common/utils/StateManager.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -39,11 +39,15 @@ @RequiredArgsConstructor public class StateManager { - private static record Item(long id, long expire) { + private static final long DEFAULT_TTL = 1000L * 60L * 5L; + + private static final int DEFAULT_STATE_SIZE = 128; + + private record Item(long id, long expire) { /** * Checks if the item is invalid. - * + * * @param now the current time * @return true if the item is invalid */ @@ -63,7 +67,7 @@ public boolean isInvalid(long now) { * Creates a new state manager with ttl of 5 minutes and state size of 128. */ public StateManager() { - this(1000 * 60 * 5, 128); + this(DEFAULT_TTL, DEFAULT_STATE_SIZE); } private void update() { @@ -73,7 +77,7 @@ private void update() { /** * Creates a new state. - * + * * @param id id connected to the state * @return the state */ @@ -86,7 +90,7 @@ public String createState(long id) { /** * Checks if the state is valid. - * + * * @param state the state * @return true if the state is valid */ @@ -98,7 +102,7 @@ public boolean containsState(String state) { /** * Gets the id connected to the state. Removes the state from the manager in * case of success. - * + * * @param state the state * @return the id or null if the state is invalid */ diff --git a/packages/server/src/main/java/dev/vernite/vernite/project/CreateProject.java b/packages/server/src/main/java/dev/vernite/vernite/project/CreateProject.java index 23b0627e..7ea668e4 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/project/CreateProject.java +++ b/packages/server/src/main/java/dev/vernite/vernite/project/CreateProject.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,6 +27,10 @@ package dev.vernite.vernite.project; +import dev.vernite.vernite.common.constants.DescriptionConstants; +import dev.vernite.vernite.common.constants.IDConstants; +import dev.vernite.vernite.common.constants.NameConstants; +import dev.vernite.vernite.common.constants.NullMessages; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; @@ -37,8 +41,7 @@ import lombok.NoArgsConstructor; /** - * Class containing information needed to create new project entity. - * Has required constraints annotated using Java Bean Validation. + * Data transfer object containing information needed to create new project. */ @Data @NoArgsConstructor @@ -46,24 +49,24 @@ public class CreateProject { /** - * Name for new project. Must contain at least one non-whitespace character. + * Name for new project. */ - @Size(min = 1, max = 50, message = "project name must be shorter than 50 characters") - @NotBlank(message = "project name must contain at least one non-whitespace character") + @NotBlank(message = NameConstants.BLANK_MESSAGE) + @Size(min = NameConstants.MIN_LENGTH, max = NameConstants.MAX_LENGTH, message = NameConstants.SIZE_MESSAGE) private String name; /** * Description for new project. */ - @NotNull(message = "description cannot be null") - @Size(max = 1000, message = "project description must be shorter than 1000 characters") + @NotNull(message = DescriptionConstants.NULL_MESSAGE) + @Size(max = DescriptionConstants.MAX_LENGTH, message = DescriptionConstants.SIZE_MESSAGE) private String description; /** * Workspace ID for new project. */ - @NotNull(message = "workspace ID cannot be null") - @Positive(message = "workspace ID must be positive") + @NotNull(message = NullMessages.WORKSPACE_ID) + @Positive(message = IDConstants.NEGATIVE_OR_ZERO_MESSAGE) private Long workspaceId; } diff --git a/packages/server/src/main/java/dev/vernite/vernite/project/Project.java b/packages/server/src/main/java/dev/vernite/vernite/project/Project.java index 4acd627b..fbcf4435 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/project/Project.java +++ b/packages/server/src/main/java/dev/vernite/vernite/project/Project.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.List; import java.util.ListIterator; +import java.util.Optional; import java.util.Set; import jakarta.persistence.CascadeType; @@ -57,6 +58,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import dev.vernite.vernite.cdn.File; +import dev.vernite.vernite.common.constants.DescriptionConstants; +import dev.vernite.vernite.common.constants.IDConstants; +import dev.vernite.vernite.common.constants.NameConstants; +import dev.vernite.vernite.common.constants.NullMessages; import dev.vernite.vernite.common.utils.counter.CounterSequence; import dev.vernite.vernite.integration.git.github.model.ProjectIntegration; import dev.vernite.vernite.meeting.Meeting; @@ -78,51 +83,51 @@ @Entity @NoArgsConstructor @EqualsAndHashCode(callSuper = true) -public class Project extends SoftDeleteEntity implements Comparable { +public final class Project extends SoftDeleteEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @PositiveOrZero(message = "project ID must be non negative number") + @PositiveOrZero(message = IDConstants.NEGATIVE_MESSAGE) private long id; - @Column(nullable = false, length = 50) - @Size(min = 1, max = 50, message = "project name must be shorter than 50 characters") - @NotBlank(message = "project name must contain at least one non-whitespace character") + @NotBlank(message = NameConstants.BLANK_MESSAGE) + @Column(nullable = false, length = NameConstants.MAX_LENGTH) + @Size(min = NameConstants.MIN_LENGTH, max = NameConstants.MAX_LENGTH, message = NameConstants.SIZE_MESSAGE) private String name; - @Column(nullable = false, length = 1000) - @NotNull(message = "project description cannot be null") - @Size(max = 1000, message = "project description must be shorter than 1000 characters") + @NotNull(message = DescriptionConstants.NULL_MESSAGE) + @Column(nullable = false, length = DescriptionConstants.MAX_LENGTH) + @Size(max = DescriptionConstants.MAX_LENGTH, message = DescriptionConstants.SIZE_MESSAGE) private String description; @JsonIgnore @ToString.Exclude @EqualsAndHashCode.Exclude @OneToMany(mappedBy = "project") + @NotNull(message = NullMessages.MEMBER) @OnDelete(action = OnDeleteAction.CASCADE) - @NotNull(message = "project workspaces connection must be set") private List projectWorkspaces = new ArrayList<>(); @ManyToMany @JsonIgnore @ToString.Exclude @EqualsAndHashCode.Exclude - @NotNull(message = "users connection must be set") + @NotNull(message = NullMessages.USER) @JoinTable(name = "project_workspace", joinColumns = @JoinColumn(name = "project_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "workspace_user_id", referencedColumnName = "id")) private Set users = new HashSet<>(); @ToString.Exclude @OrderBy("ordinal") @EqualsAndHashCode.Exclude + @NotNull(message = NullMessages.STATUS) @OnDelete(action = OnDeleteAction.CASCADE) - @NotNull(message = "project must have statuses") @OneToMany(cascade = CascadeType.PERSIST, mappedBy = "project") private List statuses = new ArrayList<>(); @JsonIgnore @ToString.Exclude @EqualsAndHashCode.Exclude - @NotNull(message = "counter must be set") + @NotNull(message = NullMessages.COUNTER) @OnDelete(action = OnDeleteAction.CASCADE) @OneToOne(cascade = CascadeType.PERSIST, optional = false) private CounterSequence taskCounter; @@ -139,7 +144,7 @@ public class Project extends SoftDeleteEntity implements Comparable { @OrderBy("startDate") @EqualsAndHashCode.Exclude @OneToMany(mappedBy = "project") - @NotNull(message = "counter must be set") + @NotNull(message = NullMessages.SPRINT) @OnDelete(action = OnDeleteAction.CASCADE) private List sprints = new ArrayList<>(); @@ -148,7 +153,7 @@ public class Project extends SoftDeleteEntity implements Comparable { @OrderBy("deadline DESC") @EqualsAndHashCode.Exclude @OneToMany(mappedBy = "project") - @NotNull(message = "releases must be set") + @NotNull(message = NullMessages.RELEASE) @OnDelete(action = OnDeleteAction.CASCADE) private List releases = new ArrayList<>(); @@ -157,7 +162,7 @@ public class Project extends SoftDeleteEntity implements Comparable { @EqualsAndHashCode.Exclude @OrderBy("startDate, endDate") @OneToMany(mappedBy = "project") - @NotNull(message = "meetings must be set") + @NotNull(message = NullMessages.MEETING) @OnDelete(action = OnDeleteAction.CASCADE) private List meetings = new ArrayList<>(); @@ -167,11 +172,10 @@ public class Project extends SoftDeleteEntity implements Comparable { private File logo; /** - * Default constructor for project. - * - * @param name must not be {@literal null} and have size between 1 and 50 - * @param description must not be {@literal null} and must be shorter than 1000 - * characters. + * Default constructor. + * + * @param name name of new project + * @param description description of new project */ public Project(String name, String description) { setName(name); @@ -180,33 +184,29 @@ public Project(String name, String description) { } /** - * Constructor for project from create request. - * - * @param create must not be {@literal null} and must be valid + * Constructor from create request. + * + * @param create body of create request */ public Project(CreateProject create) { this(create.getName(), create.getDescription()); } /** - * Updates project entity with data from update. - * - * @param update must not be {@literal null} and be valid + * Updates project with data from update. + * + * @param update body of update request */ public void update(UpdateProject update) { - if (update.getName() != null) { - setName(update.getName()); - } - if (update.getDescription() != null) { - setDescription(update.getDescription()); - } + Optional.ofNullable(update.getName()).ifPresent(this::setName); + Optional.ofNullable(update.getDescription()).ifPresent(this::setDescription); } /** * Checks whether user is member of project. - * + * * @param user potential project member - * @return {@literal true} if given user is member of project; {@literal false} + * @return {@literal true} if given user is member of project, {@literal false} * otherwise */ public boolean isMember(User user) { @@ -215,7 +215,7 @@ public boolean isMember(User user) { /** * Remove user from project members. - * + * * @param user must not be {@literal null} * @return removed connection; can be null if user wasn't member */ @@ -228,7 +228,7 @@ public ProjectWorkspace removeMember(User user) { /** * Find index of user in project workspace list. - * + * * @param user must not be {@literal null}. Must be value returned by * repository. * @return index in project workspaces with given user or -1 when not found. @@ -246,9 +246,8 @@ public int member(User user) { /** * Setter for name value. It performs {@link String#trim()} on its argument. - * - * @param name must not be {@literal null} and have at least one non-whitespace - * character and less than 50 characters + * + * @param name new name value */ public void setName(String name) { this.name = name.trim(); @@ -257,21 +256,13 @@ public void setName(String name) { /** * Setter for description value. It performs {@link String#trim()} on its * argument. - * - * @param description must not be {@literal null} and have at least one - * non-whitespace character and less than 50 characters + * + * @param description new description value */ public void setDescription(String description) { this.description = description.trim(); } - @Override - @Deprecated - public int compareTo(Project other) { - return getName().equals(other.getName()) ? Long.compare(getId(), other.getId()) - : getName().compareTo(other.getName()); - } - @Deprecated public Project(String name) { this(name, ""); diff --git a/packages/server/src/main/java/dev/vernite/vernite/project/ProjectController.java b/packages/server/src/main/java/dev/vernite/vernite/project/ProjectController.java index bdc36717..51dfc79d 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/project/ProjectController.java +++ b/packages/server/src/main/java/dev/vernite/vernite/project/ProjectController.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * + * * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -53,6 +53,7 @@ import dev.vernite.vernite.auditlog.AuditLogRepository; import dev.vernite.vernite.cdn.File; import dev.vernite.vernite.cdn.FileManager; +import dev.vernite.vernite.common.utils.SecureRandomUtils; import dev.vernite.vernite.event.Event; import dev.vernite.vernite.event.EventFilter; import dev.vernite.vernite.event.EventService; @@ -72,7 +73,6 @@ import dev.vernite.vernite.utils.ErrorType; import dev.vernite.vernite.utils.ImageConverter; import dev.vernite.vernite.utils.ObjectNotFoundException; -import dev.vernite.vernite.utils.SecureStringUtils; import dev.vernite.vernite.workspace.Workspace; import dev.vernite.vernite.workspace.WorkspaceId; import dev.vernite.vernite.workspace.WorkspaceRepository; @@ -116,16 +116,16 @@ public class ProjectController { /** * Create new project. Creating user will be automatically added to that * project. - * + * * @param user logged in user * @param create data for new project * @return newly created project */ @PostMapping public Project create(@NotNull @Parameter(hidden = true) User user, @RequestBody @Valid CreateProject create) { - long id = create.getWorkspaceId(); - Workspace workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(id, user.getId())); - Project project = projectRepository.save(new Project(create)); + var id = create.getWorkspaceId(); + var workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(id, user.getId())); + var project = projectRepository.save(new Project(create)); projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); return project; } @@ -133,8 +133,8 @@ public Project create(@NotNull @Parameter(hidden = true) User user, @RequestBody /** * Retrieve project. If user is not member of project with given ID this method * returns not found error. - * - * @param user logged in user + * + * @param user authenticated user * @param id ID of project * @return project with given ID */ @@ -146,8 +146,8 @@ public Project get(@NotNull @Parameter(hidden = true) User user, @PathVariable l /** * Update project with given ID. Performs partial update using only supplied * fields from request body. Authenticated user must be member of project. - * - * @param user logged in user + * + * @param user authenticated user * @param id ID of project * @param update data to update * @return project after update @@ -155,7 +155,7 @@ public Project get(@NotNull @Parameter(hidden = true) User user, @PathVariable l @PutMapping("/{id}") public Project update(@NotNull @Parameter(hidden = true) User user, @PathVariable long id, @RequestBody @Valid UpdateProject update) { - Project project = projectRepository.findByIdAndMemberOrThrow(id, user); + var project = projectRepository.findByIdAndMemberOrThrow(id, user); if (update.getWorkspaceId() != null) { changeWorkspace(update.getWorkspaceId(), project, user); } @@ -164,8 +164,8 @@ public Project update(@NotNull @Parameter(hidden = true) User user, @PathVariabl } private void changeWorkspace(long workspaceId, Project project, User user) { - Workspace workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(workspaceId, user.getId())); - ProjectWorkspace pw = project.removeMember(user); + var workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(workspaceId, user.getId())); + var pw = project.removeMember(user); projectWorkspaceRepository.delete(pw); projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, pw.getPrivileges())); if (pw.getWorkspace().getId().getId() == 0 && pw.getWorkspace().getProjectWorkspaces().isEmpty()) { @@ -176,7 +176,7 @@ private void changeWorkspace(long workspaceId, Project project, User user) { /** * Delete project with given ID. Project will be soft deleted and full delete * wil happen after a week. Authenticated user must be member of project. - * + * * @param user logged in user * @param id ID of project */ @@ -189,7 +189,7 @@ public void delete(@NotNull @Parameter(hidden = true) User user, @PathVariable l /** * Retrieve project members. Authenticated user must be member of project. - * + * * @param user logged in user * @param id ID of project * @return list of project members @@ -203,7 +203,7 @@ public List getProjectMembers(@NotNull @Parameter(hidden = true) /** * Retrieve project member. Authenticated user must be member of project. - * + * * @param user logged in user * @param id ID of project * @param memberId ID of searched user @@ -224,7 +224,7 @@ public ProjectMember getProjectMember(@NotNull @Parameter(hidden = true) User us * project. If authenticated user is not member of project no one will be added * to this project. If user with given email / username does not exists no error * will be thrown. - * + * * @param user logged in user * @param invite list of project and user to add. * @return list with project and users which were added to projects @@ -258,7 +258,7 @@ public ProjectInvite addProjectMembers(@NotNull @Parameter(hidden = true) User u /** * Remove members from project. Authenticated user must be member of project and * have sufficient privileges. - * + * * @param user logged in user * @param id ID of project * @param ids IDs of users to remove @@ -286,7 +286,7 @@ public List deleteMember(@NotNull @Parameter(hidden = true) User user, @Pa /** * Leave project. Authenticated user leaves project with given ID. - * + * * @param user logged in user * @param id ID of project */ @@ -303,7 +303,7 @@ public void leaveProject(@NotNull @Parameter(hidden = true) User user, @PathVari /** * Retrieve project time tracks. Authenticated user must be member of project. - * + * * @param user logged in user * @param id ID of project * @return list with all time tracks from given project @@ -317,7 +317,7 @@ public List getTimeTracks(@NotNull @Parameter(hidden = true) User use /** * Retrieve git issues for project. Retrieve all issues from integrated git * providers. - * + * * @param user logged in user * @param id ID of project * @return list with issues @@ -331,7 +331,7 @@ public Flux getIssues(@NotNull @Parameter(hidden = true) User user, @Path /** * Retrieve git pull requests for project. Retrieve all pull requests from * integrated git providers. - * + * * @param user logged in user * @param id ID of project * @return list with pull requests @@ -345,7 +345,7 @@ public Flux getPullRequests(@NotNull @Parameter(hidden = true) User /** * Retrieve git branches for project. Retrieve all branches from integrated git * providers. - * + * * @param user logged in user * @param id ID of project * @return list with branches @@ -358,7 +358,7 @@ public Flux getBranches(@NotNull @Parameter(hidden = true) User user, @P /** * Retrieve events for project. - * + * * @param user logged in user * @param id ID of project * @param from timestamp after events happen @@ -376,7 +376,7 @@ public Set getEvents(@NotNull @Parameter(hidden = true) User user, @PathV /** * Update project logo. Given file will be converted to image/webp format with * resolution 400x400. Alpha channel is supported. - * + * * @param user logged in user * @param id ID of project * @param file new logo image @@ -402,7 +402,7 @@ public File uploadLogo(@NotNull @Parameter(hidden = true) User user, @PathVariab /** * Delete project logo. After that logo will be empty. - * + * * @param user logged in user * @param id ID of project */ @@ -416,7 +416,7 @@ public void uploadImage(@NotNull @Parameter(hidden = true) User user, @PathVaria /** * Create calendar synchronization link. Creates link for iCalendar format * synchronization of project calendar. - * + * * @param user logged in user * @param id ID of project * @return link to project calendar in iCalendar format @@ -424,9 +424,9 @@ public void uploadImage(@NotNull @Parameter(hidden = true) User user, @PathVaria @PostMapping("/{id}/events/sync") public String createCalendarSync(@NotNull @Parameter(hidden = true) User user, @PathVariable long id) { Project project = projectRepository.findByIdAndMemberOrThrow(id, user); - String key = SecureStringUtils.generateRandomSecureString(); + String key = SecureRandomUtils.generateSecureRandomString(); while (calendarRepository.findByKey(key).isPresent()) { - key = SecureStringUtils.generateRandomSecureString(); + key = SecureRandomUtils.generateSecureRandomString(); } Optional integration = calendarRepository.findByUserAndProject(user, project); if (integration.isPresent()) { @@ -443,4 +443,4 @@ public List getAuditLog(@NotNull @Parameter(hidden = true) User user, return auditLogRepository.findByProject(project); } -} \ No newline at end of file +} diff --git a/packages/server/src/main/java/dev/vernite/vernite/project/UpdateProject.java b/packages/server/src/main/java/dev/vernite/vernite/project/UpdateProject.java index 44e131a1..e3a49f96 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/project/UpdateProject.java +++ b/packages/server/src/main/java/dev/vernite/vernite/project/UpdateProject.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -30,15 +30,16 @@ import jakarta.validation.constraints.PositiveOrZero; import jakarta.validation.constraints.Size; +import dev.vernite.vernite.common.constants.DescriptionConstants; +import dev.vernite.vernite.common.constants.IDConstants; +import dev.vernite.vernite.common.constants.NameConstants; import dev.vernite.vernite.common.constraints.NullOrNotBlank; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** - * Class containing information needed to update project entity. - * Has required constraints annotated using Java Bean Validation. - * It performs partial update using only present fields. + * Data transfer object containing information needed to update project. */ @Data @NoArgsConstructor @@ -46,22 +47,22 @@ public class UpdateProject { /** - * New name for project. Must contain at least one non-whitespace character. + * New name for project. */ - @Size(min = 1, max = 50, message = "project name must be shorter than 50 characters") - @NullOrNotBlank(message = "project name must contain at least one non-whitespace character") + @NullOrNotBlank(message = NameConstants.BLANK_MESSAGE) + @Size(min = NameConstants.MIN_LENGTH, max = NameConstants.MAX_LENGTH, message = NameConstants.SIZE_MESSAGE) private String name; /** - * New description for new project. + * New description for project. */ - @Size(max = 1000, message = "project description must be shorter than 1000 characters") + @Size(max = DescriptionConstants.MAX_LENGTH, message = DescriptionConstants.SIZE_MESSAGE) private String description; /** - * New workspace id for project. + * New workspace ID for project. */ - @PositiveOrZero(message = "workspace id must be positive or zero") + @PositiveOrZero(message = IDConstants.NEGATIVE_OR_ZERO_MESSAGE) private Long workspaceId; } diff --git a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java index 1f9337dd..6dd84694 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java +++ b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceController.java @@ -83,7 +83,7 @@ public List getAll(@NotNull @Parameter(hidden = true) User user) { */ @PostMapping public Workspace create(@NotNull @Parameter(hidden = true) User user, @RequestBody @Valid CreateWorkspace create) { - long id = counterRepository.getIncrementCounter(user.getCounterSequence().getId()); + var id = counterRepository.getIncrementCounter(user.getCounterSequence().getId()); return workspaceRepository.save(new Workspace(id, user, create)); } @@ -111,7 +111,7 @@ public Workspace get(@NotNull @Parameter(hidden = true) User user, @PathVariable @PutMapping("/{id}") public Workspace update(@NotNull @Parameter(hidden = true) User user, @PathVariable long id, @RequestBody @Valid UpdateWorkspace update) { - Workspace workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(id, user.getId())); + var workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(id, user.getId())); workspace.update(update); return workspaceRepository.save(workspace); } @@ -124,7 +124,7 @@ public Workspace update(@NotNull @Parameter(hidden = true) User user, @PathVaria */ @DeleteMapping("/{id}") public void delete(@NotNull @Parameter(hidden = true) User user, @PathVariable long id) { - Workspace workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(id, user.getId())); + var workspace = workspaceRepository.findByIdOrThrow(new WorkspaceId(id, user.getId())); if (!workspace.getProjects().isEmpty()) { throw new ConflictStateException(WORKSPACE_NOT_EMPTY); } diff --git a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java index 94e5b63e..42d20a86 100644 --- a/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java +++ b/packages/server/src/main/java/dev/vernite/vernite/workspace/WorkspaceId.java @@ -27,6 +27,7 @@ package dev.vernite.vernite.workspace; +import java.io.Serial; import java.io.Serializable; import jakarta.persistence.Embeddable; @@ -43,7 +44,6 @@ /** * Composite ID for workspace. - * * It contains connected user id and id which is unique * among user workspaces and for each user starts on one. */ @@ -54,6 +54,7 @@ @FieldNameConstants public class WorkspaceId implements Serializable { + @Serial private static final long serialVersionUID = 1L; @PositiveOrZero(message = IDConstants.NEGATIVE_MESSAGE) diff --git a/packages/server/src/test/java/dev/vernite/vernite/project/CreateProjectTests.java b/packages/server/src/test/java/dev/vernite/vernite/project/CreateProjectTests.java index 843df627..0ddc43bc 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/project/CreateProjectTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/project/CreateProjectTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,16 +27,25 @@ package dev.vernite.vernite.project; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; + import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import dev.vernite.vernite.common.constants.DescriptionConstants; +import dev.vernite.vernite.common.constants.NameConstants; +/** + * Tests for {@link CreateProject} class. Tests validation constraints. + */ class CreateProjectTests { private static Validator validator; @@ -47,21 +56,33 @@ static void init() { validator = factory.getValidator(); } - @Test - void validationValidTest() { - assertTrue(validator.validate(new CreateProject("Name", "Description", 1L)).isEmpty()); - assertTrue(validator.validate(new CreateProject(" Name ", " ", 4L)).isEmpty()); - assertTrue(validator.validate(new CreateProject(" Name ", " Description", 73L)).isEmpty()); + private static Stream testValidationValid() { + return Stream.of( + new CreateProject("Name", "Description", 1L), + new CreateProject(" Name ", " ", 4L), + new CreateProject(" Name ", " Description", 73L)); + } + + private static Stream testValidationInvalid() { + return Stream.of( + new CreateProject(), + new CreateProject("Name", null, 1L), + new CreateProject("Name", "", -1L), + new CreateProject("", null, 1L), + new CreateProject("a".repeat(NameConstants.MAX_LENGTH + 1), "", 1L), + new CreateProject("Name", "a".repeat(DescriptionConstants.MAX_LENGTH + 1), 1L)); + } + + @MethodSource + @ParameterizedTest + void testValidationValid(CreateProject create) { + assertTrue(validator.validate(create).isEmpty(), "Validation failed for " + create); } - @Test - void validationInvalidTest() { - assertEquals(3, validator.validate(new CreateProject()).size()); - assertEquals(1, validator.validate(new CreateProject("Name", null, 1L)).size()); - assertEquals(1, validator.validate(new CreateProject("Name", "", -1L)).size()); - assertEquals(3, validator.validate(new CreateProject("", null, 1L)).size()); - assertEquals(1, validator.validate(new CreateProject("a".repeat(51), "", 1L)).size()); - assertEquals(1, validator.validate(new CreateProject("Name", "a".repeat(1001), 1L)).size()); + @MethodSource + @ParameterizedTest + void testValidationInvalid(CreateProject create) { + assertFalse(validator.validate(create).isEmpty(), "Validation passed for " + create); } } diff --git a/packages/server/src/test/java/dev/vernite/vernite/project/ProjectControllerTests.java b/packages/server/src/test/java/dev/vernite/vernite/project/ProjectControllerTests.java index 1915fa4e..429cf2e2 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/project/ProjectControllerTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/project/ProjectControllerTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -28,19 +28,21 @@ package dev.vernite.vernite.project; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Date; import java.util.List; +import java.util.stream.Stream; +import dev.vernite.vernite.common.constants.DescriptionConstants; +import dev.vernite.vernite.common.constants.NameConstants; import dev.vernite.vernite.event.Event; import dev.vernite.vernite.meeting.Meeting; import dev.vernite.vernite.meeting.MeetingRepository; import dev.vernite.vernite.projectworkspace.ProjectMember; import dev.vernite.vernite.projectworkspace.ProjectWorkspace; import dev.vernite.vernite.projectworkspace.ProjectWorkspaceKey; -import dev.vernite.vernite.projectworkspace.ProjectWorkspaceRepository; import dev.vernite.vernite.release.Release; import dev.vernite.vernite.release.ReleaseRepository; import dev.vernite.vernite.sprint.Sprint; @@ -48,247 +50,242 @@ import dev.vernite.vernite.task.Task; import dev.vernite.vernite.task.TaskRepository; import dev.vernite.vernite.task.time.TimeTrack; -import dev.vernite.vernite.task.time.TimeTrackRepository; import dev.vernite.vernite.user.User; -import dev.vernite.vernite.user.UserRepository; -import dev.vernite.vernite.user.UserSession; -import dev.vernite.vernite.user.UserSessionRepository; import dev.vernite.vernite.user.auth.AuthController; +import dev.vernite.vernite.utils.IntegrationTestSetup; import dev.vernite.vernite.workspace.Workspace; -import dev.vernite.vernite.workspace.WorkspaceRepository; +import dev.vernite.vernite.workspace.WorkspaceId; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.dao.DataIntegrityViolationException; import org.springframework.http.MediaType; -import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.reactive.server.WebTestClient; +/** + * Integration tests for {@link ProjectController} + */ @SpringBootTest @AutoConfigureMockMvc @TestInstance(Lifecycle.PER_CLASS) -@TestPropertySource({ "classpath:application.properties", "classpath:application-test.properties" }) class ProjectControllerTests { + @Autowired private WebTestClient client; - @Autowired - private UserRepository userRepository; - @Autowired - private UserSessionRepository userSessionRepository; - @Autowired - private ProjectRepository projectRepository; - @Autowired - private WorkspaceRepository workspaceRepository; - @Autowired - private ProjectWorkspaceRepository projectWorkspaceRepository; - @Autowired - private TimeTrackRepository timeTrackRepository; - - private User user; - private UserSession session; - private Workspace workspace; - @BeforeAll - void init() { - this.user = userRepository.findByUsername("Username"); - if (this.user == null) { - this.user = userRepository.save(new User("Name", "Surname", "Username", "Email@test.pl", "1")); - } - session = new UserSession(); - session.setIp("127.0.0.1"); - session.setSession("session_token_projects_tests"); - session.setLastUsed(new Date()); - session.setRemembered(true); - session.setUserAgent("userAgent"); - session.setUser(user); - try { - session = userSessionRepository.save(session); - } catch (DataIntegrityViolationException e) { - session = userSessionRepository.findBySession("session_token_projects_tests").orElseThrow(); - } - workspace = workspaceRepository.save(new Workspace(1, "Project Tests", user)); - } + @Autowired + private IntegrationTestSetup setup; @BeforeEach void reset() { - projectRepository.deleteAll(); + setup.getDataBase().getProject().deleteAll(); } @Test - void createSuccess() { - CreateProject request = new CreateProject("POST", "", workspace.getId().getId()); - Project result = client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(request).exchange().expectStatus().isOk().expectBody(Project.class).returnResult() - .getResponseBody(); - - assertNotNull(result); - Project project = projectRepository.findByIdOrThrow(result.getId()); - - assertEquals(result, project); - assertEquals(0, project.getStatuses().size()); - assertEquals(1, project.getProjectWorkspaces().size()); - } + void testCreateSuccess() { + var project = client.post().uri("/project") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(new CreateProject("Test", "", setup.getWorkspace().getId().getId())).exchange() + .expectStatus().isOk().expectBody(Project.class).returnResult().getResponseBody(); - @Test - void createBadRequest() { - client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateProject()).exchange().expectStatus().isBadRequest(); + assertNotNull(project, "Response should not be null"); - client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateProject("NAME", "", null)).exchange().expectStatus().isBadRequest(); + var result = setup.getDataBase().getProject().findByIdOrThrow(project.getId()); - client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateProject(null, "", workspace.getId().getId())).exchange().expectStatus() - .isBadRequest(); + assertEquals(project, result, "Project should be the same"); + assertEquals(0, result.getStatuses().size(), "Project should have no statuses"); + assertEquals(1, result.getProjectWorkspaces().size(), "Project should have one workspace"); + assertEquals(1, result.getUsers().size(), "Project should have one user"); + } - client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateProject("", "", null)).exchange().expectStatus().isBadRequest(); + private Stream testCreateBadRequest() { + var id = setup.getWorkspace().getId().getId(); + return Stream.of(new CreateProject(), new CreateProject("Test", "", null), + new CreateProject(null, "", id), new CreateProject("", "", id), + new CreateProject("a".repeat(NameConstants.MAX_LENGTH + 1), "", id), + new CreateProject("a", "a".repeat(DescriptionConstants.MAX_LENGTH + 1), id), + new CreateProject("Test", "", null)); + } - client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateProject("a".repeat(51), "", null)).exchange().expectStatus().isBadRequest(); + @MethodSource + @ParameterizedTest + void testCreateBadRequest(CreateProject create) { + client.post().uri("/project").cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(create).exchange().expectStatus().isBadRequest(); - client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateProject("a", "a".repeat(1001), null)).exchange().expectStatus().isBadRequest(); + assertEquals(0, setup.getDataBase().getProject().count(), "Project should not be created"); } - @Test - void createUnauthorized() { - client.post().uri("/project").exchange().expectStatus().isUnauthorized(); + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testCreateUnauthorized(String token) { + client.post().uri("/project").cookie(AuthController.COOKIE_NAME, token).exchange().expectStatus() + .isUnauthorized(); } @Test - void createNotFound() { - client.post().uri("/project").cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new CreateProject("POST", "", 1000L)).exchange().expectStatus().isNotFound(); + void testCreateNotFound() { + client.post().uri("/project").cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(new CreateProject("Test", "", 1000L)).exchange().expectStatus().isNotFound(); } @Test - void getSuccess() { - Project project = projectRepository.save(new Project("GET", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + void testGetSuccess() { + var project = setup.getDataBase().getProject().save(new Project("Test", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - client.get().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) + client.get().uri("/project/{id}", project.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .exchange().expectStatus().isOk().expectBody(Project.class).isEqualTo(project); } - @Test - void getUnauthorized() { - client.get().uri("/project/{id}", 1).exchange().expectStatus().isUnauthorized(); + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testGetUnauthorized(String token) { + client.get().uri("/project/{id}", Long.MAX_VALUE).cookie(AuthController.COOKIE_NAME, token).exchange() + .expectStatus().isUnauthorized(); - Project project = projectRepository.save(new Project("GET", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + var project = setup.getDataBase().getProject().save(new Project("Test", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - client.get().uri("/project/{id}", project.getId()).exchange().expectStatus().isUnauthorized(); + client.get().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, token).exchange() + .expectStatus().isUnauthorized(); } @Test - void getNotFound() { - client.get().uri("/project/{id}", -1).cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() - .expectStatus().isNotFound(); + void testGetNotFound() { + client.get().uri("/project/{id}", Long.MAX_VALUE) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); + + var project = setup.getDataBase().getProject().save(new Project("Test", "")); - Project project = projectRepository.save(new Project("GET", "")); - client.get().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) + client.get().uri("/project/{id}", project.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUserNoAccess().getSessionToken()) .exchange().expectStatus().isNotFound(); } - @Test - void updateSuccess() { - Project project = projectRepository.save(new Project("PUT", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + private Stream testUpdateSuccess() { + return Stream.of(new UpdateProject(), new UpdateProject("New test", "", null), + new UpdateProject(null, "", setup.getWorkspaceEmpty().getId().getId())); + } + + @MethodSource + @ParameterizedTest + void testUpdateSuccess(UpdateProject update) { + var project = setup.getDataBase().getProject().save(new Project("Test", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); + + project.update(update); - client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject()).exchange().expectStatus().isOk().expectBody(Project.class) + client.put().uri("/project/{id}", project.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(update).exchange().expectStatus().isOk().expectBody(Project.class) .isEqualTo(project); - assertEquals(project, projectRepository.findByIdOrThrow(project.getId())); - project.setName("NEW PUT"); - client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject("NEW PUT", "", null)).exchange().expectStatus().isOk() - .expectBody(Project.class).isEqualTo(project); - assertEquals(project, projectRepository.findByIdOrThrow(project.getId())); + assertEquals(project, setup.getDataBase().getProject().findByIdOrThrow(project.getId()), + "Project should be updated"); - Workspace newWorkspace = workspaceRepository.save(new Workspace(2, "New Workspace", user)); - client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject(null, "", 2L)).exchange().expectStatus().isOk() - .expectBody(Project.class).isEqualTo(project); - assertEquals(project, projectRepository.findByIdOrThrow(project.getId())); - assertEquals(1, workspaceRepository.findByIdOrThrow(newWorkspace.getId()).getProjectWorkspaces().size()); - assertEquals(0, workspaceRepository.findByIdOrThrow(workspace.getId()).getProjectWorkspaces().size()); + if (update.getWorkspaceId() != null) { + assertEquals(1, + setup.getDataBase().getWorkspace() + .findById(new WorkspaceId(update.getWorkspaceId(), setup.getUser().user().getId())) + .orElseThrow().getProjects().size(), + "Workspace should have one project"); + } } - @Test - void updateBadRequest() { - Project project = projectRepository.save(new Project("PUT", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + private Stream testUpdateBadRequest() { + return Stream.of(new UpdateProject(" ", "", null), + new UpdateProject(null, "a".repeat(DescriptionConstants.MAX_LENGTH + 1), null), + new UpdateProject("a".repeat(NameConstants.MAX_LENGTH + 1), "", null)); + } + + @MethodSource + @ParameterizedTest + void testUpdateBadRequest(UpdateProject update) { + var project = setup.getDataBase().getProject().save(new Project("Test", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject(" ", "", null)).exchange().expectStatus().isBadRequest(); + client.put().uri("/project/{id}", project.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(update).exchange().expectStatus().isBadRequest(); - client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject("a".repeat(51), "", null)).exchange().expectStatus().isBadRequest(); + assertEquals(project, setup.getDataBase().getProject().findByIdOrThrow(project.getId()), + "Project should not be updated"); } - @Test - void updateUnauthorized() { - UpdateProject request = new UpdateProject("PUT", "", 1L); - client.put().uri("/project/1").bodyValue(request).exchange().expectStatus().isUnauthorized(); + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testUpdateUnauthorized(String token) { + client.put().uri("/project/{id}", Long.MAX_VALUE).cookie(AuthController.COOKIE_NAME, token).exchange() + .expectStatus().isUnauthorized(); - Project project = projectRepository.save(new Project("PUT", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + var project = setup.getDataBase().getProject().save(new Project("Test", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - client.put().uri("/project/{id}", project.getId()).contentType(MediaType.APPLICATION_JSON).bodyValue(request) - .exchange().expectStatus().isUnauthorized(); + client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, token).exchange() + .expectStatus().isUnauthorized(); } @Test - void updateNotFound() { - Project project = projectRepository.save(new Project("PUT", "")); - - client.put().uri("/project/{pId}", Long.MAX_VALUE).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject("PUT", "", 1L)).exchange().expectStatus().isNotFound(); + void testUpdateNotFound() { + var project = setup.getDataBase().getProject().save(new Project("Test", "")); - client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject("PUT", "", Long.MAX_VALUE)).exchange().expectStatus().isNotFound(); + client.put().uri("/project/{pId}", Long.MAX_VALUE) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(new UpdateProject(null, "", 1L)).exchange().expectStatus().isNotFound(); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - client.put().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(new UpdateProject("PUT", "", 2L)).exchange().expectStatus().isNotFound(); + client.put().uri("/project/{id}", project.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(new UpdateProject(null, "", Long.MAX_VALUE)).exchange().expectStatus().isNotFound(); } @Test - void deleteSuccess() { - Project project = projectRepository.save(new Project("PUT", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + void testDeleteSuccess() { + var project = setup.getDataBase().getProject().save(new Project("PUT", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); + + client.delete().uri("/project/{id}", project.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk(); - client.delete().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) - .exchange().expectStatus().isOk(); - assertNotEquals(null, projectRepository.findById(project.getId()).get().getActive()); + assertNotNull(setup.getDataBase().getProject().findById(project.getId()).get().getActive(), + "Project should be deleted"); } - @Test - void deleteUnauthorized() { - client.delete().uri("/project/1").exchange().expectStatus().isUnauthorized(); + @ParameterizedTest + @ValueSource(strings = { "invalid_token", "", " " }) + void testDeleteUnauthorized(String token) { + client.delete().uri("/project/{id}", Long.MAX_VALUE).cookie(AuthController.COOKIE_NAME, token).exchange() + .expectStatus().isUnauthorized(); - Project project = projectRepository.save(new Project("PUT", "")); + var id = setup.getDataBase().getProject().save(new Project("Test", "")).getId(); - client.delete().uri("/project/{id}", project.getId()).exchange().expectStatus().isUnauthorized(); - assertEquals(project.getActive(), projectRepository.findByIdOrThrow(project.getId()).getActive()); + client.delete().uri("/project/{id}", id).cookie(AuthController.COOKIE_NAME, token).exchange().expectStatus() + .isUnauthorized(); + + assertNull(setup.getDataBase().getProject().findById(id).get().getActive(), "Project should not be deleted"); } @Test - void deleteNotFound() { - client.delete().uri("/project/1").cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() - .expectStatus().isNotFound(); + void testDeleteNotFound() { + client.delete().uri("/project/{id}", Long.MAX_VALUE) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .exchange().expectStatus().isNotFound(); + + var project = setup.getDataBase().getProject().save(new Project("Test", "")); - Project project = projectRepository.save(new Project("DELETE", "")); - client.delete().uri("/project/{id}", project.getId()).cookie(AuthController.COOKIE_NAME, session.getSession()) + client.delete().uri("/project/{id}", project.getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .exchange().expectStatus().isNotFound(); } @@ -296,102 +293,118 @@ void deleteNotFound() { @Deprecated void moveProjectWorkspaceNotFound() { client.put().uri("/project/{id}/workspace/1", 1024) - .cookie(AuthController.COOKIE_NAME, session.getSession()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .exchange() .expectStatus().isNotFound(); - Project project = projectRepository.save(new Project("PUT", "")); + Project project = setup.getDataBase().getProject().save(new Project("PUT", "")); client.put().uri("/project/{id}/workspace/{wId}", project.getId(), 1024) - .cookie(AuthController.COOKIE_NAME, session.getSession()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .exchange() .expectStatus().isNotFound(); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); client.put().uri("/project/{id}/workspace/{wId}", project.getId(), 1024) - .cookie(AuthController.COOKIE_NAME, session.getSession()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .exchange() .expectStatus().isNotFound(); } @Test + @Deprecated void getProjectMembersSuccess() { - Project project = projectRepository.save(new Project("PROJECT", "")); - ProjectWorkspace ps = projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("PROJECT", "")); + var ps = setup.getDataBase().getProjectWorkspace() + .save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); client.get().uri("/project/{id}/member", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(ProjectMember.class).hasSize(1).contains(ps.getProjectMember()); } @Test + @Deprecated void getProjectMembersUnauthorized() { client.get().uri("/project/1/member").exchange().expectStatus().isUnauthorized(); - Project project = projectRepository.save(new Project("PROJECT", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("PROJECT", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); client.get().uri("/project/{id}/member", project.getId()).exchange().expectStatus().isUnauthorized(); } @Test + @Deprecated void getProjectMembersNotFound() { - client.get().uri("/project/1/member").cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() + client.get().uri("/project/1/member").cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .exchange() .expectStatus().isNotFound(); - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); client.get().uri("/project/{id}/member", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isNotFound(); + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); } @Test + @Deprecated void getProjectMemberSuccess() { - Project project = projectRepository.save(new Project("PROJECT", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("PROJECT", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - ProjectMember pm = client.get().uri("/project/{id}/member/{memberId}", project.getId(), user.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + ProjectMember pm = client.get() + .uri("/project/{id}/member/{memberId}", project.getId(), setup.getUser().user().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBody(ProjectMember.class).returnResult().getResponseBody(); assertNotNull(pm); - assertEquals(pm.user().getId(), user.getId()); - assertEquals(pm.user().getUsername(), user.getUsername()); + assertEquals(pm.user().getId(), setup.getUser().user().getId()); + assertEquals(pm.user().getUsername(), setup.getUser().user().getUsername()); } @Test + @Deprecated void getProjectMemberUnauthorized() { - client.get().uri("/project/1/member/{memberId}", user.getId()).exchange().expectStatus().isUnauthorized(); + client.get().uri("/project/1/member/{memberId}", setup.getUser().user().getId()).exchange().expectStatus() + .isUnauthorized(); - Project project = projectRepository.save(new Project("PROJECT", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("PROJECT", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - client.get().uri("/project/{id}/member/{memberId}", project.getId(), user.getId()).exchange().expectStatus() + client.get().uri("/project/{id}/member/{memberId}", project.getId(), setup.getUser().user().getId()).exchange() + .expectStatus() .isUnauthorized(); } @Test + @Deprecated void getProjectMemberNotFound() { - client.get().uri("/project/1/member/{memberId}", user.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() + client.get().uri("/project/1/member/{memberId}", setup.getUser().user().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange() .expectStatus().isNotFound(); - Project project = projectRepository.save(new Project("MEMBER", "")); - client.get().uri("/project/{id}/member/{memberId}", project.getId(), user.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isNotFound(); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); + client.get().uri("/project/{id}/member/{memberId}", project.getId(), setup.getUser().user().getId()) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); client.get().uri("/project/{id}/member/{memberId}", project.getId(), 0) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isNotFound(); + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); } @Test + @Deprecated void addProjectMemberSuccess() { - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); - User user2 = userRepository.findByUsername("member_add_test_name"); + User user2 = setup.getDataBase().getUser().findByUsername("member_add_test_name"); if (user2 == null) { - user2 = userRepository.save(new User("1", "2", "member_add_test_name", "member_add_test@Dname", "1")); + user2 = setup.getDataBase().getUser() + .save(new User("1", "2", "member_add_test_name", "member_add_test@Dname", "1")); } ProjectInvite invite = new ProjectInvite(); @@ -399,40 +412,44 @@ void addProjectMemberSuccess() { invite.setProjects(List.of(project.getId())); ProjectInvite result = client.post().uri("/project/member") - .cookie(AuthController.COOKIE_NAME, session.getSession()).bodyValue(invite).exchange().expectStatus() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).bodyValue(invite).exchange() + .expectStatus() .isOk().expectBody(ProjectInvite.class).returnResult().getResponseBody(); assertNotNull(result); assertEquals(0, result.getEmails().size()); assertEquals(0, result.getProjectList().size()); - assertEquals(true, projectWorkspaceRepository + assertEquals(true, setup.getDataBase().getProjectWorkspace() .findById(new ProjectWorkspaceKey(new Workspace(0, "inbox", user2), project)).isEmpty()); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); - result = client.post().uri("/project/member").cookie(AuthController.COOKIE_NAME, session.getSession()) + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); + result = client.post().uri("/project/member") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .bodyValue(invite).exchange().expectStatus().isOk().expectBody(ProjectInvite.class).returnResult() .getResponseBody(); assertNotNull(result); - assertEquals(true, projectWorkspaceRepository + assertEquals(true, setup.getDataBase().getProjectWorkspace() .findById(new ProjectWorkspaceKey(new Workspace(0, "inbox", user2), project)).isPresent()); assertEquals(1, result.getEmails().size()); assertEquals(1, result.getProjectList().size()); assertEquals("member_add_test_name", result.getEmails().get(0)); assertEquals(project.getId(), result.getProjectList().get(0).getId()); - result = client.post().uri("/project/member").cookie(AuthController.COOKIE_NAME, session.getSession()) + result = client.post().uri("/project/member") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .bodyValue(invite).exchange().expectStatus().isOk().expectBody(ProjectInvite.class).returnResult() .getResponseBody(); assertNotNull(result); - assertEquals(true, projectWorkspaceRepository + assertEquals(true, setup.getDataBase().getProjectWorkspace() .findById(new ProjectWorkspaceKey(new Workspace(0, "inbox", user2), project)).isPresent()); assertEquals(1, result.getEmails().size()); assertEquals(1, result.getProjectList().size()); invite.setEmails(null); - result = client.post().uri("/project/member").cookie(AuthController.COOKIE_NAME, session.getSession()) + result = client.post().uri("/project/member") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .bodyValue(invite).exchange().expectStatus().isOk().expectBody(ProjectInvite.class).returnResult() .getResponseBody(); assertNotNull(result); @@ -441,7 +458,8 @@ void addProjectMemberSuccess() { invite.setProjects(null); - result = client.post().uri("/project/member").cookie(AuthController.COOKIE_NAME, session.getSession()) + result = client.post().uri("/project/member") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .bodyValue(invite).exchange().expectStatus().isOk().expectBody(ProjectInvite.class).returnResult() .getResponseBody(); assertNotNull(result); @@ -450,201 +468,230 @@ void addProjectMemberSuccess() { } @Test + @Deprecated void addProjectMemberUnauthorized() { client.post().uri("/project/member").exchange().expectStatus().isUnauthorized(); } @Test + @Deprecated void deleteMemberSuccess() { - Project project = projectRepository.save(new Project("MEMBER", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); - User user2 = userRepository.findByUsername("member_add_test_name"); + User user2 = setup.getDataBase().getUser().findByUsername("member_add_test_name"); if (user2 == null) { - user2 = userRepository.save(new User("1", "2", "member_add_test_name", "member_add_test@Dname", "1")); + user2 = setup.getDataBase().getUser() + .save(new User("1", "2", "member_add_test_name", "member_add_test@Dname", "1")); } - Workspace workspace2 = workspaceRepository.save(new Workspace(1, "test", user2)); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace2, 2L)); + Workspace workspace2 = setup.getDataBase().getWorkspace().save(new Workspace(1, "test", user2)); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, workspace2, 2L)); List result = client.put().uri("/project/{id}/member", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()) - .bodyValue(List.of(user2.getId(), 666, 54, user.getId())).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .bodyValue(List.of(user2.getId(), 666, 54, setup.getUser().user().getId())).exchange().expectStatus() + .isOk() .expectBodyList(User.class).returnResult().getResponseBody(); assertNotNull(result); assertEquals(1, result.size()); assertEquals(user2.getName(), result.get(0).getName()); assertEquals(user2.getId(), result.get(0).getId()); assertEquals(false, - projectWorkspaceRepository.findById(new ProjectWorkspaceKey(workspace2, project)).isPresent()); + setup.getDataBase().getProjectWorkspace().findById(new ProjectWorkspaceKey(workspace2, project)) + .isPresent()); assertEquals(true, - projectWorkspaceRepository.findById(new ProjectWorkspaceKey(workspace, project)).isPresent()); + setup.getDataBase().getProjectWorkspace() + .findById(new ProjectWorkspaceKey(setup.getWorkspace(), project)) + .isPresent()); } @Test + @Deprecated void deleteMemberUnauthorized() { - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); client.put().uri("/project/{id}/member", project.getId()).bodyValue(List.of()).exchange().expectStatus() .isUnauthorized(); } @Test + @Deprecated void deleteProjectMemberForbidden() { - Project project = projectRepository.save(new Project("MEMBER", "")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 2L)); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 2L)); client.put().uri("/project/{id}/member", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).bodyValue(List.of()).exchange().expectStatus() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).bodyValue(List.of()).exchange() + .expectStatus() .isForbidden(); } @Test + @Deprecated void deleteProjectMemberNotFound() { - client.put().uri("/project/666/member").cookie(AuthController.COOKIE_NAME, session.getSession()) + client.put().uri("/project/666/member").cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .bodyValue(List.of()).exchange().expectStatus().isNotFound(); - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); client.put().uri("/project/{id}/member", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).contentType(MediaType.APPLICATION_JSON) + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .contentType(MediaType.APPLICATION_JSON) .bodyValue(List.of()).exchange().expectStatus().isNotFound(); } @Test + @Deprecated void leaveProjectSuccess() { - Project project = projectRepository.save(new Project("MEMBER", "")); - ProjectWorkspace pw = projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); + ProjectWorkspace pw = setup.getDataBase().getProjectWorkspace() + .save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); client.delete().uri("/project/{id}/member", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk(); - assertEquals(false, projectWorkspaceRepository.findById(pw.getId()).isPresent()); + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk(); + assertEquals(false, setup.getDataBase().getProjectWorkspace().findById(pw.getId()).isPresent()); } @Test + @Deprecated void leaveProjectUnauthorized() { client.delete().uri("/project/1/member").exchange().expectStatus().isUnauthorized(); - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); client.delete().uri("/project/{id}/member", project.getId()).exchange().expectStatus().isUnauthorized(); } @Test + @Deprecated void leaveProjectNotFound() { - client.delete().uri("/project/666/member").cookie(AuthController.COOKIE_NAME, session.getSession()).exchange() + client.delete().uri("/project/666/member").cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) + .exchange() .expectStatus().isNotFound(); - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); client.delete().uri("/project/{id}/member", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isNotFound(); + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); } @Test + @Deprecated void getTimeTracksSuccess(@Autowired TaskRepository taskRepository) { - Project project = projectRepository.save(new Project("MEMBER")); - Task task = taskRepository.save(new Task(1, "n", "d", project.getStatuses().get(0), user, 1, "low")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER")); + Task task = taskRepository + .save(new Task(1, "n", "d", project.getStatuses().get(0), setup.getUser().user(), 1, "low")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); client.get().uri("/project/{id}/track", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(TimeTrack.class).hasSize(0); - timeTrackRepository.save(new TimeTrack(user, task)); + setup.getDataBase().getTimeTrack().save(new TimeTrack(setup.getUser().user(), task)); client.get().uri("/project/{id}/track", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(TimeTrack.class).hasSize(1); } @Test + @Deprecated void getTimeTracksUnauthorized() { client.get().uri("/project/1/track").exchange().expectStatus().isUnauthorized(); } @Test + @Deprecated void getTimeTracksNotFound() { - client.get().uri("/project/666/track").cookie(AuthController.COOKIE_NAME, session.getSession()) + client.get().uri("/project/666/track").cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .exchange().expectStatus().isNotFound(); - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); client.get().uri("/project/{id}/track", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isNotFound(); + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); } @Test + @Deprecated void getEventsSuccess(@Autowired TaskRepository taskRepository, @Autowired MeetingRepository meetingRepository, @Autowired SprintRepository sprintRepository, @Autowired ReleaseRepository releaseRepository) { - Project project = projectRepository.save(new Project("MEMBER")); - Task task = taskRepository.save(new Task(1, "n", "d", project.getStatuses().get(0), user, 1, "low")); - projectWorkspaceRepository.save(new ProjectWorkspace(project, workspace, 1L)); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER")); + Task task = taskRepository + .save(new Task(1, "n", "d", project.getStatuses().get(0), setup.getUser().user(), 1, "low")); + setup.getDataBase().getProjectWorkspace().save(new ProjectWorkspace(project, setup.getWorkspace(), 1L)); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(0); task.setDeadline(new Date(2)); taskRepository.save(task); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(1); meetingRepository.save(new Meeting(project, "1", "1", new Date(3), new Date(1001))); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(2); meetingRepository.save(new Meeting(project, "1", "1", new Date(2001), new Date(3032))); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(2); task.setDeadline(new Date(3000)); taskRepository.save(task); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(1); sprintRepository.save(new Sprint("n", new Date(1), new Date(1000), Sprint.Status.CREATED, "d", project)); sprintRepository.save(new Sprint("n", new Date(2000), new Date(3000), Sprint.Status.CREATED, "d", project)); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(2); Release release = new Release("Name", "description", new Date(500), project); releaseRepository.save(release); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(3); client.get().uri("/project/{id}/events?from=1&to=1000&type=0", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(1); task.setEstimatedDate(new Date(100)); taskRepository.save(task); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isOk() + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus().isOk() .expectBodyList(Event.class).hasSize(4); } @Test + @Deprecated void getEventsUnauthorized() { client.get().uri("/project/1/events?from=1&to=1000").exchange().expectStatus().isUnauthorized(); } @Test + @Deprecated void getTEventsNotFound() { - client.get().uri("/project/666/events?from=1&to=1000").cookie(AuthController.COOKIE_NAME, session.getSession()) + client.get().uri("/project/666/events?from=1&to=1000") + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()) .exchange().expectStatus().isNotFound(); - Project project = projectRepository.save(new Project("MEMBER", "")); + Project project = setup.getDataBase().getProject().save(new Project("MEMBER", "")); client.get().uri("/project/{id}/events?from=1&to=1000", project.getId()) - .cookie(AuthController.COOKIE_NAME, session.getSession()).exchange().expectStatus().isNotFound(); + .cookie(AuthController.COOKIE_NAME, setup.getUser().getSessionToken()).exchange().expectStatus() + .isNotFound(); } } diff --git a/packages/server/src/test/java/dev/vernite/vernite/project/ProjectTests.java b/packages/server/src/test/java/dev/vernite/vernite/project/ProjectTests.java index c3fb7c73..2fe1c98a 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/project/ProjectTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/project/ProjectTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,19 +27,27 @@ package dev.vernite.vernite.project; -import static org.junit.Assert.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import java.util.stream.Stream; + import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import dev.vernite.vernite.common.constants.DescriptionConstants; +import dev.vernite.vernite.common.constants.NameConstants; import dev.vernite.vernite.projectworkspace.ProjectWorkspace; import dev.vernite.vernite.user.User; import dev.vernite.vernite.workspace.Workspace; @@ -57,129 +65,113 @@ static void init() { validator = factory.getValidator(); } - @Test - void constructorBaseTest() { - Project project = new Project("Name", "Description"); - - assertEquals("Name", project.getName()); - assertEquals("Description", project.getDescription()); - assertNotNull(project.getTaskCounter()); + private static Stream testConstructor() { + return Stream.of( + Arguments.of("Name", "Description"), + Arguments.of(" Name ", " Description ")); + } - project = new Project(" Name ", " Description "); + private static Stream testUpdate() { + return Stream.of( + new UpdateProject("NewName", "NewDescription", null), + new UpdateProject(" Name ", " Description ", null), + new UpdateProject()); + } - assertEquals("Name", project.getName()); - assertEquals("Description", project.getDescription()); - assertNotNull(project.getTaskCounter()); + private static Stream testValidationInvalid() { + return Stream.of( + new Project("", "Description"), + new Project(" ", "Description"), + new Project("a".repeat(NameConstants.MAX_LENGTH + 1), "Description"), + new Project("Name", "a".repeat(DescriptionConstants.MAX_LENGTH + 1))); } - @Test - void constructorCreateTest() { - Project project = new Project(new CreateProject("Name", "Description", 1L)); + @ParameterizedTest + @MethodSource("testConstructor") + void testBaseConstructor(String name, String description) { + Project project = new Project(name, description); - assertEquals("Name", project.getName()); - assertEquals("Description", project.getDescription()); - assertNotNull(project.getTaskCounter()); + assertEquals(name.trim(), project.getName(), "Trimmed name should be equal"); + assertEquals(description.trim(), project.getDescription(), "Trimmed description should be equal"); + assertNotNull(project.getTaskCounter(), "Task counter should not be null"); + } - project = new Project(new CreateProject(" Name ", " Description ", 1L)); + @ParameterizedTest + @MethodSource("testConstructor") + void testCreateConstructor(String name, String description) { + Project project = new Project(new CreateProject(name, description, 1L)); - assertEquals("Name", project.getName()); - assertEquals("Description", project.getDescription()); - assertNotNull(project.getTaskCounter()); + assertEquals(name.trim(), project.getName(), "Trimmed name should be equal"); + assertEquals(description.trim(), project.getDescription(), "Trimmed description should be equal"); + assertNotNull(project.getTaskCounter(), "Task counter should not be null"); } - @Test - void updateTest() { + @MethodSource + @ParameterizedTest + void testUpdate(UpdateProject update) { Project project = new Project("Name", "Description"); - project.update(new UpdateProject("NewName", "NewDescription", null)); - - assertEquals("NewName", project.getName()); - assertEquals("NewDescription", project.getDescription()); - - project.update(new UpdateProject(" Name ", " Description ", null)); + project.update(update); - assertEquals("Name", project.getName()); - assertEquals("Description", project.getDescription()); + String newName = update.getName() == null ? "Name" : update.getName().trim(); + String newDescription = update.getDescription() == null ? "Description" : update.getDescription().trim(); - project.update(new UpdateProject()); - - assertEquals("Name", project.getName()); - assertEquals("Description", project.getDescription()); + assertEquals(newName, project.getName(), "Trimmed name should be equal"); + assertEquals(newDescription, project.getDescription(), "Trimmed description should be equal"); } @Test - void isMemberTest() { + void testIsMember() { Project project = new Project("Name", "Description"); - assertFalse(project.isMember(user)); + assertFalse(project.isMember(user), "User should not be a member of the project"); project.getUsers().add(user); project.getProjectWorkspaces().add(new ProjectWorkspace(project, new Workspace(1, "Name", user), 1L)); - assertTrue(project.isMember(user)); + assertTrue(project.isMember(user), "User should be a member of the project"); } @Test - void removeMemberTest() { + void testRemoveMember() { Project project = new Project("Name", "Description"); + + assertNull(project.removeMember(user), "User should not be a member of the project"); + project.getUsers().add(user); project.getProjectWorkspaces().add(new ProjectWorkspace(project, new Workspace(1, "Name", user), 1L)); - assertNotNull(project.removeMember(user)); + assertNotNull(project.removeMember(user), "User should be a member of the project"); - assertNull(project.removeMember(user)); + assertNull(project.removeMember(user), "User should not be a member of the project"); } - @Test - void setNameTest() { + @ParameterizedTest + @ValueSource(strings = { "New name", " New name ", "" }) + void testSetName(String name) { Project project = new Project("Name", "Description"); - project.setName("New name"); - - assertEquals("New name", project.getName()); + project.setName(name); - project.setName(" New name "); - - assertEquals("New name", project.getName()); + assertEquals(name.trim(), project.getName(), "Trimmed name should be equal"); } - @Test - void setDescriptionTest() { + @ParameterizedTest + @ValueSource(strings = { "New description", " New description ", "" }) + void testSetDescription(String description) { Project project = new Project("Name", "Description"); - project.setDescription("New description"); + project.setDescription(description); - assertEquals("New description", project.getDescription()); - - project.setDescription(" New description "); - - assertEquals("New description", project.getDescription()); + assertEquals(description.trim(), project.getDescription(), "Trimmed description should be equal"); } @Test - void validationValidTest() { - assertTrue(validator.validate(new Project("Name", "Description")).isEmpty()); + void testValidationValid() { + assertTrue(validator.validate(new Project("Name", "Description")).isEmpty(), "Project should be valid"); } - @Test - void validationInvalidTest() { - assertEquals(2, validator.validate(new Project("", "Description")).size()); - assertEquals(2, validator.validate(new Project(" ", "Description")).size()); - assertEquals(1, validator.validate(new Project("a".repeat(51), "Description")).size()); - assertEquals(1, validator.validate(new Project("Name", "a".repeat(1001))).size()); + @MethodSource + @ParameterizedTest + void testValidationInvalid(Project project) { + assertFalse(validator.validate(project).isEmpty(), "Project should be invalid"); } - @Test - void compareToTest() { - Project project = new Project("name", "desc"); - Project other = new Project("other", "desc"); - - assertEquals(true, project.compareTo(other) < 0); - - other.setName("name"); - other.setId(1); - - assertEquals(true, project.compareTo(other) < 0); - - other.setId(project.getId()); - - assertEquals(0, project.compareTo(other)); - } } diff --git a/packages/server/src/test/java/dev/vernite/vernite/project/UpdateProjectTests.java b/packages/server/src/test/java/dev/vernite/vernite/project/UpdateProjectTests.java index 79de6235..7a0bb3ad 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/project/UpdateProjectTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/project/UpdateProjectTests.java @@ -1,18 +1,18 @@ /* * BSD 2-Clause License - * - * Copyright (c) 2022, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] - * + * + * Copyright (c) 2023, [Aleksandra Serba, Marcin Czerniak, Bartosz Wawrzyniak, Adrian Antkowiak] + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -27,16 +27,25 @@ package dev.vernite.vernite.project; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; + import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import dev.vernite.vernite.common.constants.DescriptionConstants; +import dev.vernite.vernite.common.constants.NameConstants; +/** + * Tests for {@link UpdateProject} class. Tests validation constraints. + */ class UpdateProjectTests { private static Validator validator; @@ -47,23 +56,35 @@ static void init() { validator = factory.getValidator(); } - @Test - void validationValidTest() { - assertTrue(validator.validate(new UpdateProject()).isEmpty()); - assertTrue(validator.validate(new UpdateProject("Name", "Description", 1L)).isEmpty()); - assertTrue(validator.validate(new UpdateProject(" Name ", " ", 4L)).isEmpty()); - assertTrue(validator.validate(new UpdateProject(" Name ", " Description", 73L)).isEmpty()); - assertTrue(validator.validate(new UpdateProject(" Name ", " Description", null)).isEmpty()); - assertTrue(validator.validate(new UpdateProject(" Name ", null, 2L)).isEmpty()); - assertTrue(validator.validate(new UpdateProject(null, "Description", 3L)).isEmpty()); + private static Stream testValidationValid() { + return Stream.of( + new UpdateProject(), + new UpdateProject("Name", "Description", 1L), + new UpdateProject(" Name ", " ", 4L), + new UpdateProject(" Name ", " Description", 73L), + new UpdateProject(" Name ", " Description", null), + new UpdateProject(" Name ", null, 2L), + new UpdateProject(null, "Description", 3L)); + } + + private static Stream testValidationInvalid() { + return Stream.of( + new UpdateProject("Name", "", -1L), + new UpdateProject("", null, 1L), + new UpdateProject("a".repeat(NameConstants.MAX_LENGTH + 1), "", null), + new UpdateProject(null, "a".repeat(DescriptionConstants.MAX_LENGTH + 1), 1L)); + } + + @MethodSource + @ParameterizedTest + void testValidationValid(UpdateProject create) { + assertTrue(validator.validate(create).isEmpty(), "Validation failed for " + create); } - @Test - void validationInvalidTest() { - assertEquals(1, validator.validate(new UpdateProject("Name", "", -1L)).size()); - assertEquals(2, validator.validate(new UpdateProject("", null, 1L)).size()); - assertEquals(1, validator.validate(new UpdateProject("a".repeat(51), "", null)).size()); - assertEquals(1, validator.validate(new UpdateProject(null, "a".repeat(1001), 1L)).size()); + @MethodSource + @ParameterizedTest + void testValidationInvalid(UpdateProject create) { + assertFalse(validator.validate(create).isEmpty(), "Validation passed for " + create); } } diff --git a/packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java b/packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java index fbd1673e..47537eb7 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java +++ b/packages/server/src/test/java/dev/vernite/vernite/utils/IntegrationTestSetup.java @@ -108,7 +108,9 @@ public IntegrationTestSetup(DataBaseRepository dataBase) { userSession.setUserAgent("userAgent"); userSession.setUser(user); - this.userNoAccess = new UserInfo(user, dataBase.getUserSession().save(userSession)); + userNoAccess = new UserInfo(user, dataBase.getUserSession().save(userSession)); + + user = this.user.user(); workspace = dataBase.getWorkspace().save(new Workspace(1, "Work", user)); workspaceEmpty = dataBase.getWorkspace().save(new Workspace(2, "Hobby", user)); diff --git a/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java b/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java index 0b198d99..809a673e 100644 --- a/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java +++ b/packages/server/src/test/java/dev/vernite/vernite/workspace/UpdateWorkspaceTests.java @@ -43,7 +43,7 @@ import dev.vernite.vernite.common.constants.NameConstants; /** - * Tests for {@link CreateWorkspace} class. Tests validation constraints. + * Tests for {@link UpdateWorkspace} class. Tests validation constraints. */ class UpdateWorkspaceTests {