diff --git a/backend/openshift.deploy.yml b/backend/openshift.deploy.yml index da13d72ce..7b3ba7213 100644 --- a/backend/openshift.deploy.yml +++ b/backend/openshift.deploy.yml @@ -103,12 +103,12 @@ objects: - name: ALLOWED_ORIGINS valueFrom: secretKeyRef: - name: ${NAME} + name: ${NAME}-backend key: allowed_origins - name: KEYCLOAK_REALM_URL valueFrom: secretKeyRef: - name: ${NAME} + name: ${NAME}-backend key: keycloak-realm-url - name: POSTGRESQL_HOST value: ${NAME}-${ZONE}-database @@ -130,12 +130,12 @@ objects: - name: FORESTCLIENTAPI_ADDRESS valueFrom: secretKeyRef: - name: ${NAME} + name: ${NAME}-backend key: forest-client-api.address - name: FORESTCLIENTAPI_KEY valueFrom: secretKeyRef: - name: ${NAME} + name: ${NAME}-backend key: forest-client-api.key ports: - containerPort: 8090 diff --git a/backend/pom.xml b/backend/pom.xml index b3d64a63c..5600e8a0c 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -10,7 +10,7 @@ ca.bc.gov nr-spar-backend - 0.18.5 + 0.19.1 nr-spar-backend Starting backend API project diff --git a/backend/src/main/java/ca/bc/gov/backendstartapi/endpoint/ActiveOrchardSeedPlanningUnitEndpoint.java b/backend/src/main/java/ca/bc/gov/backendstartapi/endpoint/ActiveOrchardSeedPlanningUnitEndpoint.java new file mode 100644 index 000000000..c81c523d1 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/backendstartapi/endpoint/ActiveOrchardSeedPlanningUnitEndpoint.java @@ -0,0 +1,48 @@ +package ca.bc.gov.backendstartapi.endpoint; + +import ca.bc.gov.backendstartapi.entity.ActiveOrchardSeedPlanningUnit; +import ca.bc.gov.backendstartapi.repository.ActiveOrchardSeedPlanningUnitRepository; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.util.MimeTypeUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** Rest controller to fetch relations between orchards and Seed Plan Units (SPU). */ +@RestController +@RequestMapping(path = "/api/orchards", produces = MimeTypeUtils.APPLICATION_JSON_VALUE) +@Tag(name = "Orchard") +@RequiredArgsConstructor +public class ActiveOrchardSeedPlanningUnitEndpoint { + + private final ActiveOrchardSeedPlanningUnitRepository repository; + + @Operation( + operationId = "findSpuByOrchard", + summary = "Find associations between seed plan units and an orchard", + description = + "Find the associations of seed plan units and the orchard identified by `orchardId`.", + responses = { + @ApiResponse( + responseCode = "200", + description = "A list of the associations between the orchard and seed plan units.") + }) + @GetMapping(path = "/{orchardId}/seed-plan-units") + @PreAuthorize("hasRole('user_read')") + public List findByOrchard( + @Parameter(description = "The identifier of an orchard") @PathVariable(name = "orchardId") + String orchardId, + @Parameter(description = "If the association must be active or not") + @RequestParam(name = "active", defaultValue = "true") + boolean active) { + return repository.findByOrchardIdAndActive(orchardId, active); + } +} diff --git a/backend/src/main/java/ca/bc/gov/backendstartapi/entity/ActiveOrchardSeedPlanningUnit.java b/backend/src/main/java/ca/bc/gov/backendstartapi/entity/ActiveOrchardSeedPlanningUnit.java new file mode 100644 index 000000000..0a1effea0 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/backendstartapi/entity/ActiveOrchardSeedPlanningUnit.java @@ -0,0 +1,62 @@ +package ca.bc.gov.backendstartapi.entity; + +import ca.bc.gov.backendstartapi.entity.idclass.ActiveOrchardSeedPlanningUnitId; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +/** Auxiliary entity connecting an Orchard and a Seed Plan Unit (SPU). */ +@Entity +@Table(name = "active_orchard_spu") +@IdClass(ActiveOrchardSeedPlanningUnitId.class) +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@RequiredArgsConstructor +@Getter +@Setter +@Schema(description = "An association between an orchard and a Seed Plan Unit (SPU).") +public class ActiveOrchardSeedPlanningUnit { + + @Id + @Column(name = "orchard_id", length = 3, nullable = false) + @NonNull + private String orchardId; + + @Id + @Column(name = "seed_plan_unit_id", nullable = false) + @NonNull + private int seedPlanningUnitId; + + @Column(name = "active_ind", nullable = false) + @NonNull + @Schema( + description = + "If this association is active; if `false`, it should not be used for new registries.") + private boolean active; + + @Column(name = "retired_ind", nullable = false) + @NonNull + @Schema( + description = + """ + If the orchard has been retired (e.g. is out of business); could be the reason for the + inactivity of this association.""") + private boolean retired; + + /** + * If the orchard hasn't had a SPU assigned to it. If {@code true}, {@link #seedPlanningUnitId}'s + * value will most likely be {@code -1}. + */ + @Column(name = "no_spu_ind", nullable = false) + @NonNull + @Schema(description = "If this orchard has never had a SPU assigned to it.") + private boolean spuNotAssigned; +} diff --git a/backend/src/main/java/ca/bc/gov/backendstartapi/entity/idclass/ActiveOrchardSeedPlanningUnitId.java b/backend/src/main/java/ca/bc/gov/backendstartapi/entity/idclass/ActiveOrchardSeedPlanningUnitId.java new file mode 100644 index 000000000..fc2d7cb26 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/backendstartapi/entity/idclass/ActiveOrchardSeedPlanningUnitId.java @@ -0,0 +1,19 @@ +package ca.bc.gov.backendstartapi.entity.idclass; + +import ca.bc.gov.backendstartapi.entity.ActiveOrchardSeedPlanningUnit; +import lombok.AccessLevel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +/** Composite key for {@link ActiveOrchardSeedPlanningUnit}. */ +@Data +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@RequiredArgsConstructor +public class ActiveOrchardSeedPlanningUnitId { + + @NonNull private String orchardId; + + @NonNull private int seedPlanningUnitId; +} diff --git a/backend/src/main/java/ca/bc/gov/backendstartapi/repository/ActiveOrchardSeedPlanningUnitRepository.java b/backend/src/main/java/ca/bc/gov/backendstartapi/repository/ActiveOrchardSeedPlanningUnitRepository.java new file mode 100644 index 000000000..bc56bb4c5 --- /dev/null +++ b/backend/src/main/java/ca/bc/gov/backendstartapi/repository/ActiveOrchardSeedPlanningUnitRepository.java @@ -0,0 +1,13 @@ +package ca.bc.gov.backendstartapi.repository; + +import ca.bc.gov.backendstartapi.entity.ActiveOrchardSeedPlanningUnit; +import ca.bc.gov.backendstartapi.entity.idclass.ActiveOrchardSeedPlanningUnitId; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +/** The repository for {@link ActiveOrchardSeedPlanningUnit ActiveOrchardSeedPlanningUnits}. */ +public interface ActiveOrchardSeedPlanningUnitRepository + extends JpaRepository { + + List findByOrchardIdAndActive(String orchardId, boolean active); +} diff --git a/backend/src/main/resources/db/migration/V14__create_active_orchard_spu.sql b/backend/src/main/resources/db/migration/V14__create_active_orchard_spu.sql new file mode 100644 index 000000000..871c153af --- /dev/null +++ b/backend/src/main/resources/db/migration/V14__create_active_orchard_spu.sql @@ -0,0 +1,8 @@ +create table spar.active_orchard_spu ( + orchard_id varchar(3) not null, + seed_plan_unit_id int not null, + active_ind boolean not null, + retired_ind boolean not null, + no_spu_ind boolean not null, + constraint active_orchard_spu_pk + primary key(orchard_id, seed_plan_unit_id)); diff --git a/backend/src/main/resources/db/migration/V15__populate_active_orchard_spu.sql b/backend/src/main/resources/db/migration/V15__populate_active_orchard_spu.sql new file mode 100644 index 000000000..dc03f95bb --- /dev/null +++ b/backend/src/main/resources/db/migration/V15__populate_active_orchard_spu.sql @@ -0,0 +1,262 @@ +insert into spar.active_orchard_spu + (orchard_id, seed_plan_unit_id, active_ind, retired_ind, no_spu_ind) + values ('101', 7, 'False', 'True', 'False'), + ('102', 5, 'True', 'False', 'False'), + ('103', 78, 'True', 'False', 'False'), + ('105', 140, 'True', 'False', 'False'), + ('109', 7, 'False', 'True', 'False'), + ('111', 7, 'False', 'True', 'False'), + ('114', 6, 'False', 'True', 'False'), + ('115', 7, 'False', 'True', 'False'), + ('116', 6, 'False', 'True', 'False'), + ('118', 55, 'False', 'True', 'False'), + ('120', 8, 'False', 'True', 'False'), + ('121', 6, 'False', 'True', 'False'), + ('122', 7, 'False', 'True', 'False'), + ('123', 7, 'False', 'True', 'False'), + ('124', 7, 'False', 'True', 'False'), + ('126', 22, 'False', 'True', 'False'), + ('127', 21, 'False', 'True', 'False'), + ('128', 4, 'False', 'True', 'False'), + ('129', 1, 'False', 'True', 'False'), + ('130', 21, 'False', 'True', 'False'), + ('131', 77, 'False', 'True', 'False'), + ('132', 22, 'False', 'True', 'False'), + ('133', 22, 'False', 'True', 'False'), + ('134', 7, 'True', 'False', 'False'), + ('135', 1, 'False', 'True', 'False'), + ('136', 22, 'False', 'True', 'False'), + ('137', 78, 'False', 'True', 'False'), + ('138', 78, 'False', 'True', 'False'), + ('139', 4, 'False', 'True', 'False'), + ('140', 4, 'True', 'False', 'False'), + ('141', 1, 'False', 'True', 'False'), + ('142', 55, 'False', 'True', 'False'), + ('143', 21, 'False', 'True', 'False'), + ('145', 54, 'True', 'False', 'False'), + ('146', 8, 'False', 'True', 'False'), + ('147', 8, 'False', 'True', 'False'), + ('148', 4, 'True', 'False', 'False'), + ('149', 7, 'False', 'True', 'False'), + ('150', 22, 'False', 'True', 'False'), + ('151', 68, 'False', 'True', 'False'), + ('152', 4, 'True', 'False', 'False'), + ('153', 4, 'False', 'True', 'False'), + ('154', 7, 'True', 'False', 'False'), + ('155', 4, 'False', 'True', 'False'), + ('156', 22, 'False', 'True', 'False'), + ('157', 55, 'False', 'True', 'False'), + ('158', 4, 'False', 'True', 'False'), + ('159', -1, 'False', 'True', 'True'), + ('160', 1, 'False', 'True', 'False'), + ('161', -1, 'False', 'True', 'True'), + ('162', 7, 'False', 'True', 'False'), + ('164', 78, 'False', 'True', 'False'), + ('165', 22, 'False', 'True', 'False'), + ('166', 7, 'True', 'False', 'False'), + ('168', 7, 'False', 'True', 'False'), + ('169', 7, 'False', 'True', 'False'), + ('170', 22, 'True', 'False', 'False'), + ('171', 4, 'False', 'True', 'False'), + ('172', 55, 'True', 'False', 'False'), + ('173', 54, 'False', 'True', 'False'), + ('174', 54, 'False', 'True', 'False'), + ('175', 54, 'True', 'False', 'False'), + ('176', 22, 'False', 'True', 'False'), + ('177', 7, 'False', 'True', 'False'), + ('178', 77, 'False', 'True', 'False'), + ('179', 22, 'False', 'True', 'False'), + ('180', 1, 'False', 'True', 'False'), + ('181', 8, 'True', 'False', 'False'), + ('182', 22, 'False', 'True', 'False'), + ('183', 7, 'True', 'False', 'False'), + ('184', 4, 'True', 'False', 'False'), + ('185', 7, 'False', 'True', 'False'), + ('186', 4, 'False', 'True', 'False'), + ('187', 21, 'True', 'False', 'False'), + ('188', 22, 'False', 'True', 'False'), + ('189', 4, 'False', 'True', 'False'), + ('190', 4, 'True', 'False', 'False'), + ('191', 78, 'False', 'True', 'False'), + ('192', 55, 'True', 'False', 'False'), + ('193', 4, 'False', 'True', 'False'), + ('194', 78, 'False', 'True', 'False'), + ('195', 55, 'True', 'False', 'False'), + ('196', 21, 'True', 'False', 'False'), + ('197', 7, 'True', 'False', 'False'), + ('198', 4, 'True', 'False', 'False'), + ('199', 7, 'True', 'False', 'False'), + ('201', 35, 'False', 'True', 'False'), + ('202', 35, 'False', 'True', 'False'), + ('203', 45, 'False', 'True', 'False'), + ('204', 29, 'False', 'True', 'False'), + ('205', 68, 'False', 'True', 'False'), + ('207', 57, 'True', 'False', 'False'), + ('208', 57, 'True', 'False', 'False'), + ('209', 68, 'False', 'True', 'False'), + ('210', 68, 'False', 'True', 'False'), + ('211', 68, 'True', 'False', 'False'), + ('212', 90, 'True', 'False', 'False'), + ('213', 72, 'True', 'False', 'False'), + ('215', 68, 'False', 'True', 'False'), + ('216', 68, 'False', 'True', 'False'), + ('218', 35, 'True', 'False', 'False'), + ('219', 29, 'True', 'False', 'False'), + ('220', 45, 'True', 'False', 'False'), + ('221', 45, 'True', 'False', 'False'), + ('222', 45, 'True', 'False', 'False'), + ('223', 35, 'True', 'False', 'False'), + ('224', 35, 'False', 'True', 'False'), + ('225', 14, 'True', 'False', 'False'), + ('226', 16, 'True', 'False', 'False'), + ('228', 29, 'True', 'False', 'False'), + ('229', 57, 'True', 'False', 'False'), + ('231', 10, 'True', 'False', 'False'), + ('232', 16, 'True', 'False', 'False'), + ('233', 14, 'True', 'False', 'False'), + ('234', 29, 'True', 'False', 'False'), + ('236', 45, 'True', 'False', 'False'), + ('237', 45, 'True', 'False', 'False'), + ('238', 35, 'True', 'False', 'False'), + ('239', 67, 'True', 'False', 'False'), + ('240', 29, 'True', 'False', 'False'), + ('241', 35, 'True', 'False', 'False'), + ('242', 57, 'True', 'False', 'False'), + ('243', 57, 'True', 'False', 'False'), + ('244', 45, 'True', 'False', 'False'), + ('245', 29, 'True', 'False', 'False'), + ('246', 35, 'True', 'False', 'False'), + ('247', 68, 'True', 'False', 'False'), + ('249', 57, 'True', 'False', 'False'), + ('250', 57, 'True', 'False', 'False'), + ('301', 89, 'False', 'True', 'False'), + ('302', 63, 'False', 'True', 'False'), + ('304', 60, 'False', 'True', 'False'), + ('305', 89, 'True', 'False', 'False'), + ('306', 63, 'True', 'False', 'False'), + ('307', 41, 'False', 'True', 'False'), + ('308', 51, 'False', 'True', 'False'), + ('310', 50, 'True', 'False', 'False'), + ('311', 51, 'True', 'False', 'False'), + ('313', 41, 'True', 'False', 'False'), + ('321', 13, 'True', 'False', 'False'), + ('324', 12, 'True', 'False', 'False'), + ('332', 24, 'True', 'False', 'False'), + ('333', 23, 'True', 'False', 'False'), + ('334', 23, 'False', 'True', 'False'), + ('335', 85, 'True', 'False', 'False'), + ('336', 11, 'True', 'False', 'False'), + ('337', 41, 'True', 'False', 'False'), + ('338', 51, 'True', 'False', 'False'), + ('339', 50, 'True', 'False', 'False'), + ('341', 62, 'True', 'False', 'False'), + ('342', 74, 'True', 'False', 'False'), + ('343', 73, 'True', 'False', 'False'), + ('345', -1, 'True', 'False', 'True'), + ('346', 135, 'True', 'False', 'False'), + ('347', 41, 'True', 'False', 'False'), + ('349', 40, 'True', 'False', 'False'), + ('350', 51, 'True', 'False', 'False'), + ('351', 85, 'True', 'False', 'False'), + ('352', 35, 'True', 'False', 'False'), + ('353', 80, 'True', 'False', 'False'), + ('354', 142, 'True', 'False', 'False'), + ('355', 141, 'True', 'False', 'False'), + ('356', 60, 'True', 'False', 'False'), + ('357', 140, 'True', 'False', 'False'), + ('358', 50, 'True', 'False', 'False'), + ('401', 7, 'False', 'True', 'False'), + ('403', 54, 'True', 'False', 'False'), + ('405', 7, 'True', 'False', 'False'), + ('406', 6, 'True', 'False', 'False'), + ('407', -1, 'True', 'False', 'True'), + ('408', 4, 'True', 'False', 'False'), + ('409', 130, 'True', 'False', 'False'), + ('410', 130, 'True', 'False', 'False'), + ('411', 29, 'True', 'False', 'False'), + ('412', 29, 'True', 'False', 'False'), + ('413', 29, 'True', 'False', 'False'), + ('414', 85, 'True', 'False', 'False'), + ('415', 85, 'True', 'False', 'False'), + ('416', 54, 'True', 'False', 'False'), + ('417', 29, 'True', 'False', 'False'), + ('418', 29, 'True', 'False', 'False'), + ('607', 85, 'False', 'True', 'False'), + ('609', 85, 'True', 'False', 'False'), + ('610', 56, 'False', 'True', 'False'), + ('611', 67, 'False', 'True', 'False'), + ('612', 60, 'False', 'True', 'False'), + ('620', 57, 'False', 'True', 'False'), + ('800', 78, 'True', 'False', 'False'), + ('801', 4, 'True', 'False', 'False'), + ('802', 78, 'False', 'True', 'False'), + ('803', 78, 'True', 'False', 'False'), + ('804', 78, 'False', 'True', 'False'), + ('805', 78, 'True', 'False', 'False'), + ('806', 78, 'False', 'True', 'False'), + ('807', 78, 'False', 'True', 'False'), + ('808', 78, 'True', 'False', 'False'), + ('810', -1, 'False', 'True', 'True'), + ('811', 4, 'True', 'False', 'False'), + ('813', -1, 'True', 'False', 'True'), + ('814', 103, 'False', 'True', 'False'), + ('815', -1, 'True', 'False', 'True'), + ('816', 103, 'False', 'True', 'False'), + ('818', 103, 'False', 'True', 'False'), + ('819', 103, 'False', 'True', 'False'), + ('820', -1, 'True', 'False', 'True'), + ('821', 103, 'False', 'True', 'False'), + ('822', 68, 'False', 'True', 'False'), + ('823', 68, 'False', 'True', 'False'), + ('824', 103, 'True', 'False', 'False'), + ('825', 103, 'False', 'True', 'False'), + ('826', 103, 'False', 'True', 'False'), + ('829', 78, 'False', 'True', 'False'), + ('830', 104, 'True', 'False', 'False'), + ('831', 108, 'False', 'True', 'False'), + ('833', 78, 'False', 'True', 'False'), + ('834', -1, 'False', 'True', 'True'), + ('835', 7, 'False', 'True', 'False'), + ('836', 78, 'True', 'False', 'False'), + ('837', -1, 'False', 'True', 'True'), + ('838', 7, 'False', 'True', 'False'), + ('839', 68, 'False', 'True', 'False'), + ('840', 55, 'False', 'True', 'False'), + ('841', 103, 'False', 'True', 'False'), + ('842', 78, 'True', 'False', 'False'), + ('989', -1, 'False', 'True', 'True'), + ('990', -1, 'True', 'False', 'True'), + ('991', 7, 'False', 'True', 'False'), + ('992', 22, 'True', 'False', 'False'), + ('993', 4, 'True', 'False', 'False'), + ('994', -1, 'True', 'False', 'True'), + ('995', -1, 'True', 'False', 'True'), + ('996', 7, 'True', 'False', 'False'), + ('997', -1, 'True', 'False', 'True'), + ('998', 54, 'True', 'False', 'False'), + ('999', 85, 'True', 'False', 'False'), + ('110', 6, 'False', 'True', 'False'), + ('110', 7, 'False', 'True', 'False'), + ('144', 55, 'False', 'False', 'False'), + ('144', 108, 'True', 'False', 'False'), + ('163', 21, 'False', 'True', 'False'), + ('163', 22, 'False', 'True', 'False'), + ('206', 67, 'True', 'False', 'False'), + ('206', 68, 'False', 'False', 'False'), + ('214', 67, 'False', 'False', 'False'), + ('214', 68, 'True', 'False', 'False'), + ('217', 56, 'False', 'True', 'False'), + ('217', 57, 'False', 'True', 'False'), + ('230', 29, 'True', 'False', 'False'), + ('230', 43, 'False', 'False', 'False'), + ('235', 29, 'False', 'False', 'False'), + ('235', 35, 'True', 'False', 'False'), + ('235', 45, 'False', 'False', 'False'), + ('303', 73, 'False', 'True', 'False'), + ('303', 74, 'False', 'True', 'False'), + ('340', 38, 'True', 'False', 'False'), + ('340', 39, 'False', 'False', 'False'), + ('614', 67, 'False', 'True', 'True'), + ('614', 68, 'False', 'True', 'True'), + ('809', 103, 'False', 'True', 'False'), + ('809', 104, 'False', 'True', 'False'); diff --git a/backend/src/test/java/ca/bc/gov/backendstartapi/endpoint/ActiveOrchardSeedPlanningUnitEndpointTest.java b/backend/src/test/java/ca/bc/gov/backendstartapi/endpoint/ActiveOrchardSeedPlanningUnitEndpointTest.java new file mode 100644 index 000000000..79b566819 --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/backendstartapi/endpoint/ActiveOrchardSeedPlanningUnitEndpointTest.java @@ -0,0 +1,80 @@ +package ca.bc.gov.backendstartapi.endpoint; + +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import ca.bc.gov.backendstartapi.entity.ActiveOrchardSeedPlanningUnit; +import ca.bc.gov.backendstartapi.repository.ActiveOrchardSeedPlanningUnitRepository; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@WithMockUser(roles = "user_read") +class ActiveOrchardSeedPlanningUnitEndpointTest { + + @MockBean private ActiveOrchardSeedPlanningUnitRepository repository; + + private MockMvc mockMvc; + + private final WebApplicationContext webApplicationContext; + + ActiveOrchardSeedPlanningUnitEndpointTest(WebApplicationContext webApplicationContext) { + this.webApplicationContext = webApplicationContext; + } + + @BeforeEach + void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + } + + @Test + void testSearchActiveDefault() throws Exception { + List actives = + List.of(new ActiveOrchardSeedPlanningUnit("000", 1, true, false, false)); + List inactives = + List.of(new ActiveOrchardSeedPlanningUnit("000", 2, false, false, false)); + given(repository.findByOrchardIdAndActive("000", true)).willReturn(actives); + given(repository.findByOrchardIdAndActive("000", false)).willReturn(inactives); + + mockMvc + .perform(get("/api/orchards/000/seed-plan-units").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + jsonPath("$[0].active").value("true"), jsonPath("$[0].seedPlanningUnitId").value("1")); + } + + @Test + void testSearchInactiveDefault() throws Exception { + List actives = + List.of(new ActiveOrchardSeedPlanningUnit("000", 1, true, false, false)); + List inactives = + List.of(new ActiveOrchardSeedPlanningUnit("000", 2, false, false, false)); + given(repository.findByOrchardIdAndActive("000", true)).willReturn(actives); + given(repository.findByOrchardIdAndActive("000", false)).willReturn(inactives); + + mockMvc + .perform( + get("/api/orchards/000/seed-plan-units?active=false") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpectAll( + jsonPath("$[0].active").value("false"), jsonPath("$[0].seedPlanningUnitId").value("2")); + } +} diff --git a/backend/src/test/java/ca/bc/gov/backendstartapi/repository/ActiveOrchardSeedPlanningUnitRepositoryTest.java b/backend/src/test/java/ca/bc/gov/backendstartapi/repository/ActiveOrchardSeedPlanningUnitRepositoryTest.java new file mode 100644 index 000000000..f56e1eb67 --- /dev/null +++ b/backend/src/test/java/ca/bc/gov/backendstartapi/repository/ActiveOrchardSeedPlanningUnitRepositoryTest.java @@ -0,0 +1,44 @@ +package ca.bc.gov.backendstartapi.repository; + +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 org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ActiveOrchardSeedPlanningUnitRepositoryTest { + + private final ActiveOrchardSeedPlanningUnitRepository repository; + + @Autowired + ActiveOrchardSeedPlanningUnitRepositoryTest( + ActiveOrchardSeedPlanningUnitRepository activeOrchardSeedPlanningUnitRepository) { + repository = activeOrchardSeedPlanningUnitRepository; + } + + @Test + void testFindByOrchardIdAndActive() { + var actives = repository.findByOrchardIdAndActive("144", true); + assertEquals(1, actives.size()); + + var active = actives.get(0); + assertEquals("144", active.getOrchardId()); + assertEquals(108, active.getSeedPlanningUnitId()); + assertTrue(active.isActive()); + assertFalse(active.isRetired()); + assertFalse(active.isSpuNotAssigned()); + + var inactives = repository.findByOrchardIdAndActive("144", false); + assertEquals(1, inactives.size()); + + var inactive = inactives.get(0); + assertEquals("144", inactive.getOrchardId()); + assertEquals(55, inactive.getSeedPlanningUnitId()); + assertFalse(inactive.isActive()); + assertFalse(inactive.isRetired()); + assertFalse(inactive.isSpuNotAssigned()); + } +}