diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java index 6ff219f..9132f36 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/BooleanTriggerable.java @@ -1,5 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -public interface BooleanTriggerable { +public interface BooleanTriggerable extends Triggerable { boolean readTriggerState(); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Condition.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Condition.java index a063ca6..476fefc 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Condition.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Condition.java @@ -11,6 +11,7 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Transient; import lombok.Data; +import lombok.EqualsAndHashCode; @Data @Entity @@ -47,6 +48,7 @@ public abstract class Condition { @ManyToOne @JoinColumn(name = "automation_id", updatable = false, insertable = false) @GsonExclude + @EqualsAndHashCode.Exclude private Automation automation; @Column(name = "automation_id", nullable = false) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java index 489a763..c850541 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/RangeTriggerable.java @@ -1,5 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -public interface RangeTriggerable { +public interface RangeTriggerable extends Triggerable { double readTriggerState(); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java index 3633a35..f70a8b0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Trigger.java @@ -3,10 +3,11 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import io.swagger.annotations.ApiModelProperty; import javax.persistence.*; +import lombok.EqualsAndHashCode; @Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) -public abstract class Trigger { +public abstract class Trigger { @Transient private String kind; @@ -41,6 +42,7 @@ public abstract class Trigger { @ManyToOne @JoinColumn(name = "automation_id", updatable = false, insertable = false) @GsonExclude + @EqualsAndHashCode.Exclude private Automation automation; @Column(name = "automation_id", nullable = false) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Triggerable.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Triggerable.java new file mode 100644 index 0000000..1215212 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Triggerable.java @@ -0,0 +1,3 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +public interface Triggerable {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/AutomationService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/AutomationService.java index 9eaf401..8668e1a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/AutomationService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/AutomationService.java @@ -8,17 +8,17 @@ import org.springframework.stereotype.Component; @Component public class AutomationService { private final AutomationRepository automationRepository; - private final TriggerRepository> triggerRepository; + private final TriggerRepository> triggerRepository; @Autowired public AutomationService( AutomationRepository automationRepository, - TriggerRepository> triggerRepository) { + TriggerRepository> triggerRepository) { this.automationRepository = automationRepository; this.triggerRepository = triggerRepository; } - public List> findTriggersByDeviceId(Long deviceId) { + public List> findTriggersByDeviceId(Long deviceId) { return triggerRepository.findAllByDeviceId(deviceId); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index ea21d5d..c28ad1f 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -52,10 +52,10 @@ public class DeviceService { if (!r.getId().equals(roomId)) throw new IllegalStateException(); } - private void triggerTriggers(Device device, final String username) { + public void triggerTriggers(Device device, final String username) { final long deviceId = device.getId(); - final List> triggers = automationService.findTriggersByDeviceId(deviceId); + final List> triggers = automationService.findTriggersByDeviceId(deviceId); triggers.stream() .filter(Trigger::triggered) diff --git a/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceServiceTests.java b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceServiceTests.java new file mode 100644 index 0000000..683ec65 --- /dev/null +++ b/src/test/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceServiceTests.java @@ -0,0 +1,139 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + +import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class DeviceServiceTests { + + @Mock private DeviceRepository deviceRepository; + + @Mock private SceneService sceneService; + + @Mock private RoomRepository roomRepository; + + @Mock private AutomationService automationService; + + @Mock private EagerUserRepository userRepository; + + @Mock private DevicePopulationService devicePopulationService; + + @Mock private DevicePropagationService devicePropagationService; + + @Mock private ConditionRepository> conditionRepository; + + @InjectMocks private DeviceService deviceService; + + @Test + public void testThrowIfRoomNotOwned() { + final Room r = new Room(); + r.setId(1L); + + when(roomRepository.findByIdAndUsername(1L, "user")).thenReturn(Optional.of(r)); + when(roomRepository.findByIdAndUsername(2L, "user")).thenReturn(Optional.empty()); + + try { + deviceService.throwIfRoomNotOwned(1L, "user"); + } catch (NotFoundException e) { + fail(e.getMessage()); + } + + assertThatThrownBy(() -> deviceService.throwIfRoomNotOwned(2L, "user")) + .isInstanceOf(NotFoundException.class); + + r.setId(2L); + + assertThatThrownBy(() -> deviceService.throwIfRoomNotOwned(1L, "user")) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void triggerTriggers() { + final RegularLight r = new RegularLight(); + r.setId(1L); + r.setOn(true); + + final BooleanTrigger b = new BooleanTrigger(); + b.setId(2L); + b.setDevice(r); + b.setOn(true); + b.setDeviceId(r.getId()); + + final BooleanCondition c = new BooleanCondition(); + c.setId(3L); + c.setDevice(r); + c.setOn(true); + c.setDeviceId(r.getId()); + + final Scene s = new Scene(); + s.setId(4L); + + final Automation a = new Automation(); + a.setId(5L); + + final ScenePriority sp = new ScenePriority(); + sp.setSceneId(s.getId()); + sp.setScene(s); + sp.setAutomationId(a.getId()); + sp.setAutomation(a); + + a.getTriggers().add(b); + b.setAutomation(a); + b.setAutomationId(a.getId()); + + a.getConditions().add(c); + c.setAutomation(a); + c.setAutomationId(a.getId()); + + a.getScenes().add(sp); + + when(automationService.findTriggersByDeviceId(1L)).thenReturn(List.of(b)); + when(conditionRepository.findAllByAutomationId(5L)).thenReturn(List.of(c)); + when(automationService.findByVerifiedId(5L)).thenReturn(a); + when(sceneService.findByValidatedId(4L)).thenReturn(s); + + final boolean[] passed = new boolean[1]; + when(sceneService.apply(s, "user", true)) + .thenAnswer( + invocation -> { + passed[0] = true; + return null; + }); + + deviceService.triggerTriggers(r, "user"); + + assertThat(passed[0]).isTrue(); + } + + @Test + public void testSaveAsGuest() throws NotFoundException { + Thermostat t = new Thermostat(); + + User u = new User(); + u.setUsername("user"); + + User host = new User(); + host.setId(1L); + host.setUsername("host"); + host.getGuests().add(u); + u.getHosts().add(host); + + when(userRepository.findByUsername("user")).thenReturn(u); + when(userRepository.findById(1L)).thenReturn(Optional.of(host)); + doNothing().when(devicePropagationService).renameIfDuplicate(t, "host"); + when(deviceRepository.save(t)).thenAnswer(ta -> ta.getArguments()[0]); + + assertThat(deviceService.saveAsGuest(t, "user", 1L)).isEqualTo(t); + } +}