This commit is contained in:
Claudio Maggioni (maggicl) 2021-02-14 12:23:25 +01:00
commit 109d2a4d44
29 changed files with 621 additions and 75 deletions

View file

@ -37,6 +37,7 @@ dependencies {
testImplementation('org.springframework.boot:spring-boot-starter-test') { testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine' exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
} }
testImplementation 'nl.jqno.equalsverifier:equalsverifier:3.3'
testImplementation 'org.springframework.security:spring-security-test' testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'com.h2database:h2:1.4.200' testImplementation 'com.h2database:h2:1.4.200'
// Fixes https://stackoverflow.com/a/60455550 // Fixes https://stackoverflow.com/a/60455550

View file

@ -194,6 +194,17 @@ public final class RuntimeTypeAdapterFactory<T> implements TypeAdapterFactory {
return this; return this;
} }
/**
* Registers {@code type} identified by {@code label}. Labels are case sensitive.
*
* @throws IllegalArgumentException if either {@code type} or {@code label} have already been
* registered on this type adapter.
*/
public RuntimeTypeAdapterFactory<T> registerSubtype(Class<? extends T> type) {
registerSubtype(type, type.getSimpleName());
return this;
}
private void initMaps( private void initMaps(
Gson gson, Gson gson,
Map<String, TypeAdapter<?>> labelToDelegate, Map<String, TypeAdapter<?>> labelToDelegate,

View file

@ -29,7 +29,7 @@ public class ButtonDimmerController
ButtonDimmerRepository inputRepository, ButtonDimmerRepository inputRepository,
DimmableRepository<Dimmable> outputRepository, DimmableRepository<Dimmable> outputRepository,
DeviceService deviceService) { DeviceService deviceService) {
super(inputRepository, outputRepository); super(inputRepository, outputRepository, deviceService);
this.deviceService = deviceService; this.deviceService = deviceService;
this.buttonDimmerRepository = inputRepository; this.buttonDimmerRepository = inputRepository;
} }

View file

@ -12,7 +12,6 @@ import java.security.Principal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -28,7 +27,7 @@ import org.springframework.web.bind.annotation.RequestBody;
public abstract class InputDeviceConnectionController< public abstract class InputDeviceConnectionController<
I extends InputDevice & Connectable<O>, O extends OutputDevice> { I extends InputDevice & Connectable<O>, O extends OutputDevice> {
private class Connection { protected class Connection {
private final I input; private final I input;
private final List<O> outputs; private final List<O> outputs;
@ -54,7 +53,7 @@ public abstract class InputDeviceConnectionController<
return outputReposiory; return outputReposiory;
} }
@Autowired private DeviceService deviceService; private final DeviceService deviceService;
private final DeviceRepository<I> inputRepository; private final DeviceRepository<I> inputRepository;
@ -67,9 +66,12 @@ public abstract class InputDeviceConnectionController<
* @param outputRepository the output device repository * @param outputRepository the output device repository
*/ */
protected InputDeviceConnectionController( protected InputDeviceConnectionController(
DeviceRepository<I> inputRepository, DeviceRepository<O> outputRepository) { DeviceRepository<I> inputRepository,
DeviceRepository<O> outputRepository,
DeviceService deviceService) {
this.inputRepository = inputRepository; this.inputRepository = inputRepository;
this.outputReposiory = outputRepository; this.outputReposiory = outputRepository;
this.deviceService = deviceService;
} }
private Connection checkConnectionIDs(Long inputId, List<Long> outputs, String username) private Connection checkConnectionIDs(Long inputId, List<Long> outputs, String username)

View file

@ -28,7 +28,7 @@ public class KnobDimmerController extends InputDeviceConnectionController<KnobDi
KnobDimmerRepository inputRepository, KnobDimmerRepository inputRepository,
DimmableRepository<Dimmable> outputRepository, DimmableRepository<Dimmable> outputRepository,
DeviceService deviceService) { DeviceService deviceService) {
super(inputRepository, outputRepository); super(inputRepository, outputRepository, deviceService);
this.knobDimmerRepository = inputRepository; this.knobDimmerRepository = inputRepository;
this.deviceService = deviceService; this.deviceService = deviceService;
} }

View file

@ -64,8 +64,8 @@ public class SensorController {
@PutMapping("/{id}/simulation") @PutMapping("/{id}/simulation")
public Sensor updateSimulation( public Sensor updateSimulation(
@PathVariable("id") Long sensorId, @PathVariable("id") Long sensorId,
@RequestParam("error") BigDecimal error, @RequestBody BigDecimal error,
@RequestParam("typical") BigDecimal typical, @RequestBody BigDecimal typical,
final Principal principal) final Principal principal)
throws NotFoundException { throws NotFoundException {
return sensorService.updateSimulationFromSensor( return sensorService.updateSimulationFromSensor(

View file

@ -34,7 +34,7 @@ public class SwitchController extends InputDeviceConnectionController<Switch, Sw
SwitchRepository inputRepository, SwitchRepository inputRepository,
SwitchableRepository<Switchable> outputRepository, SwitchableRepository<Switchable> outputRepository,
DeviceService deviceService) { DeviceService deviceService) {
super(inputRepository, outputRepository); super(inputRepository, outputRepository, deviceService);
this.deviceService = deviceService; this.deviceService = deviceService;
this.switchRepository = inputRepository; this.switchRepository = inputRepository;
} }

View file

@ -20,10 +20,6 @@ public class SensorSaveRequest {
@NotNull private BigDecimal value; @NotNull private BigDecimal value;
private BigDecimal error;
private BigDecimal typical;
/** /**
* The room this device belongs in, as a foreign key id. To use when updating and inserting from * The room this device belongs in, as a foreign key id. To use when updating and inserting from
* a REST call. * a REST call.

View file

@ -9,7 +9,7 @@ import lombok.NonNull;
@Data @Data
@Entity @Entity
public class ConfirmationToken { public final class ConfirmationToken {
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
@ -55,7 +55,6 @@ public class ConfirmationToken {
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
ConfirmationToken that = (ConfirmationToken) o; ConfirmationToken that = (ConfirmationToken) o;
return resetPassword == that.resetPassword return resetPassword == that.resetPassword
&& Objects.equals(id, that.id)
&& confirmToken.equals(that.confirmToken) && confirmToken.equals(that.confirmToken)
&& createdDate.equals(that.createdDate) && createdDate.equals(that.createdDate)
&& Objects.equals(user, that.user); && Objects.equals(user, that.user);
@ -63,6 +62,6 @@ public class ConfirmationToken {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id, confirmToken, createdDate, user, resetPassword); return Objects.hash(confirmToken, createdDate, user, resetPassword);
} }
} }

View file

@ -6,6 +6,7 @@ import java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import javax.persistence.*; import javax.persistence.*;
import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
@ -56,6 +57,7 @@ public class User {
@GsonExclude @GsonExclude
@Getter @Getter
@ToString.Exclude @ToString.Exclude
@EqualsAndHashCode.Exclude
private Set<User> guests = new HashSet<>(); private Set<User> guests = new HashSet<>();
@ManyToMany(cascade = CascadeType.DETACH) @ManyToMany(cascade = CascadeType.DETACH)
@ -66,6 +68,7 @@ public class User {
@GsonExclude @GsonExclude
@Getter @Getter
@ToString.Exclude @ToString.Exclude
@EqualsAndHashCode.Exclude
private Set<User> hosts = new HashSet<>(); private Set<User> hosts = new HashSet<>();
/** Determines whether a guest can access security cameras */ /** Determines whether a guest can access security cameras */

View file

@ -19,20 +19,33 @@ import org.springframework.stereotype.Component;
*/ */
@Component @Component
public class UpdateTasks { public class UpdateTasks {
private final MotionSensorRepository motionSensorRepository;
@Autowired private SensorRepository sensorRepository; private final SmartPlugRepository smartPlugRepository;
@Autowired private MotionSensorRepository motionSensorRepository; private final SensorService sensorService;
@Autowired private SmartPlugRepository smartPlugRepository; private final ThermostatService thermostatService;
@Autowired private SensorService sensorService; private final MotionSensorService motionSensorService;
@Autowired private ThermostatService thermostatService; private final SensorSocketEndpoint sensorSocketEndpoint;
@Autowired private MotionSensorService motionSensorService; @Autowired
public UpdateTasks(
@Autowired private SensorSocketEndpoint sensorSocketEndpoint; MotionSensorRepository motionSensorRepository,
SmartPlugRepository smartPlugRepository,
SensorService sensorService,
ThermostatService thermostatService,
MotionSensorService motionSensorService,
SensorSocketEndpoint sensorSocketEndpoint) {
this.motionSensorRepository = motionSensorRepository;
this.smartPlugRepository = smartPlugRepository;
this.sensorService = sensorService;
this.thermostatService = thermostatService;
this.motionSensorService = motionSensorService;
this.sensorSocketEndpoint = sensorSocketEndpoint;
}
/** Generates fake sensor updates every two seconds with a +/- 2.5% error */ /** Generates fake sensor updates every two seconds with a +/- 2.5% error */
@Scheduled(fixedRate = 2000) @Scheduled(fixedRate = 2000)
@ -78,7 +91,7 @@ public class UpdateTasks {
c.forEach( c.forEach(
s -> s ->
sensorSocketEndpoint.queueDeviceUpdate( sensorSocketEndpoint.queueDeviceUpdate(
s, sensorRepository.findUser(s.getId()), false, null, false)); s, smartPlugRepository.findUser(s.getId()), false, null, false));
} }
/** Sends device updates through sensor socket in batch every one second */ /** Sends device updates through sensor socket in batch every one second */

View file

@ -148,7 +148,7 @@ public class DevicePropagationService {
} }
if (causedByTrigger) { if (causedByTrigger) {
endpoint.queueDeviceUpdate(device, user, false, user.getId(), false); endpoint.queueDeviceUpdate(device, user, false, null, false);
} }
} }
} }

View file

@ -4,6 +4,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random; import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -11,24 +12,39 @@ import org.springframework.stereotype.Component;
@Component @Component
public class SensorService { public class SensorService {
@Autowired private SensorRepository sensorRepository; private final SensorRepository sensorRepository;
@Autowired private DeviceService deviceService; private final DeviceService deviceService;
@Autowired private ThermostatService thermostatService; private final ThermostatService thermostatService;
@Autowired private SensorSocketEndpoint endpoint; private final SensorSocketEndpoint endpoint;
private Random ran = new Random(); private final Random ran = new Random();
@Autowired
public SensorService(
SensorRepository sensorRepository,
DeviceService deviceService,
ThermostatService thermostatService,
SensorSocketEndpoint endpoint) {
this.sensorRepository = sensorRepository;
this.deviceService = deviceService;
this.thermostatService = thermostatService;
this.endpoint = endpoint;
}
private void randomJitter(Sensor sensor) { private void randomJitter(Sensor sensor) {
BigDecimal x =
sensor.getTypical()
.subtract(
sensor.getError()
.divide(BigDecimal.valueOf(2), RoundingMode.CEILING))
.add(
BigDecimal.valueOf(
ran.nextDouble() * sensor.getError().doubleValue() * 2));
double x; updateValueFromSensor(sensor, x);
x =
(ran.nextInt(sensor.getTypical().intValue()) + sensor.getError().intValue()) * 0.975
+ 1;
updateValueFromSensor(sensor, BigDecimal.valueOf(x));
} }
public void sensorFakeUpdate() { public void sensorFakeUpdate() {

View file

@ -5,6 +5,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ThermostatRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils; import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
@ -38,12 +39,18 @@ public class ThermostatService {
private void randomJitter(Thermostat thermostat) { private void randomJitter(Thermostat thermostat) {
double x; BigDecimal x =
x = thermostat
(ran.nextInt(thermostat.getTypical().intValue()) + thermostat.getErr().intValue()) .getTypical()
* 0.975 .subtract(
+ 1; thermostat
updateValueForThermostat(thermostat, BigDecimal.valueOf(x)); .getErr()
.divide(BigDecimal.valueOf(2), RoundingMode.CEILING))
.add(
BigDecimal.valueOf(
ran.nextDouble() * thermostat.getErr().doubleValue() * 2));
updateValueForThermostat(thermostat, x);
} }
private void updateValueForThermostat(Thermostat thermostat, BigDecimal value) { private void updateValueForThermostat(Thermostat thermostat, BigDecimal value) {

View file

@ -0,0 +1,22 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import org.junit.jupiter.api.Test;
public class EmailConfigurationServiceTests {
@Test
public void test() {
final EmailConfigurationService s = new EmailConfigurationService();
s.setResetPasswordSubject("s");
s.setResetPassword("s");
s.setResetPasswordPath("s");
s.setResetPasswordRedirect("s");
s.setRegistrationRedirect("s");
assertThat(s.getResetPasswordSubject()).isEqualTo("s");
assertThat(s.getResetPassword()).isEqualTo("s");
assertThat(s.getResetPasswordPath()).isEqualTo("s");
assertThat(s.getResetPasswordRedirect()).isEqualTo("s");
assertThat(s.getRegistrationRedirect()).isEqualTo("s");
}
}

View file

@ -0,0 +1,39 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.Mockito.when;
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;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.util.ReflectionTestUtils;
@ExtendWith({MockitoExtension.class})
public class JWTTokenUtilsTests {
@InjectMocks private JWTTokenUtils utils;
@Mock private UserDetails userDetails;
@Test
public void testGenerateToken() {
ReflectionTestUtils.setField(
utils,
"secret",
"One, seven, three, four, six, seven\n"
+ "Three, two, one, four, seven, six, charlie, three\n"
+ "Two, seven, eight, nine, seven, seven, seven\n"
+ "Six, four, three, tango, seven, three, two, victor, seven\n"
+ "Three, one, one, seven, eight, eight, eight, seven, three\n"
+ "Two, four, seven, six, seven, eight, nine\n"
+ "Seven, six, four, three, seven, six\n"
+ "Lock");
when(userDetails.getUsername()).thenReturn("username");
String token = utils.generateToken(userDetails);
assertThat(token).isNotNull();
assertThat(utils.validateToken(token, userDetails)).isTrue();
assertThat(utils.getUsernameFromToken(token)).isEqualTo("username");
}
}

View file

@ -0,0 +1,224 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
import static org.junit.jupiter.api.Assertions.*;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import org.junit.jupiter.api.Test;
/**
* Copyright (C) 2011 Google Inc.
*
* <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
public final class RuntimeTypeAdapterFactoryTests {
@Test
public void testRuntimeTypeAdapter() {
RuntimeTypeAdapterFactory<BillingInstrument> rta =
RuntimeTypeAdapterFactory.of(BillingInstrument.class)
.registerSubtype(CreditCard.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(rta).create();
CreditCard original = new CreditCard("Jesse", 234);
assertEquals(
"{\"type\":\"CreditCard\",\"cvv\":234,\"ownerName\":\"Jesse\"}",
gson.toJson(original, BillingInstrument.class));
BillingInstrument deserialized =
gson.fromJson(
"{type:'CreditCard',cvv:234,ownerName:'Jesse'}", BillingInstrument.class);
assertEquals("Jesse", deserialized.ownerName);
assertTrue(deserialized instanceof CreditCard);
}
@Test
public void testRuntimeTypeIsBaseType() {
TypeAdapterFactory rta =
RuntimeTypeAdapterFactory.of(BillingInstrument.class, "type", false)
.registerSubtype(BillingInstrument.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(rta).create();
BillingInstrument original = new BillingInstrument("Jesse");
assertEquals(
"{\"type\":\"BillingInstrument\",\"ownerName\":\"Jesse\"}",
gson.toJson(original, BillingInstrument.class));
BillingInstrument deserialized =
gson.fromJson(
"{type:'BillingInstrument',ownerName:'Jesse'}", BillingInstrument.class);
assertEquals("Jesse", deserialized.ownerName);
}
@Test
public void testNullBaseType() {
try {
RuntimeTypeAdapterFactory.of(null);
fail();
} catch (NullPointerException expected) {
}
}
@Test
public void testNullTypeFieldName() {
try {
RuntimeTypeAdapterFactory.of(BillingInstrument.class, null);
fail();
} catch (NullPointerException expected) {
}
}
@Test
public void testNullSubtype() {
RuntimeTypeAdapterFactory<BillingInstrument> rta =
RuntimeTypeAdapterFactory.of(BillingInstrument.class);
try {
rta.registerSubtype(null);
fail();
} catch (NullPointerException expected) {
}
}
@Test
public void testNullLabel() {
RuntimeTypeAdapterFactory<BillingInstrument> rta =
RuntimeTypeAdapterFactory.of(BillingInstrument.class);
try {
rta.registerSubtype(CreditCard.class, null);
fail();
} catch (NullPointerException expected) {
}
}
@Test
public void testDuplicateSubtype() {
RuntimeTypeAdapterFactory<BillingInstrument> rta =
RuntimeTypeAdapterFactory.of(BillingInstrument.class);
rta.registerSubtype(CreditCard.class, "CC");
try {
rta.registerSubtype(CreditCard.class, "Visa");
fail();
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testDuplicateLabel() {
RuntimeTypeAdapterFactory<BillingInstrument> rta =
RuntimeTypeAdapterFactory.of(BillingInstrument.class);
rta.registerSubtype(CreditCard.class, "CC");
try {
rta.registerSubtype(BankTransfer.class, "CC");
fail();
} catch (IllegalArgumentException expected) {
}
}
@Test
public void testDeserializeMissingTypeField() {
TypeAdapterFactory billingAdapter =
RuntimeTypeAdapterFactory.of(BillingInstrument.class)
.registerSubtype(CreditCard.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create();
try {
gson.fromJson("{ownerName:'Jesse'}", BillingInstrument.class);
fail();
} catch (JsonParseException expected) {
}
}
@Test
public void testDeserializeMissingSubtype() {
TypeAdapterFactory billingAdapter =
RuntimeTypeAdapterFactory.of(BillingInstrument.class)
.registerSubtype(BankTransfer.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create();
try {
gson.fromJson("{type:'CreditCard',ownerName:'Jesse'}", BillingInstrument.class);
fail();
} catch (JsonParseException expected) {
}
}
@Test
public void testSerializeMissingSubtype() {
TypeAdapterFactory billingAdapter =
RuntimeTypeAdapterFactory.of(BillingInstrument.class)
.registerSubtype(BankTransfer.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create();
try {
gson.toJson(new CreditCard("Jesse", 456), BillingInstrument.class);
fail();
} catch (JsonParseException expected) {
}
}
@Test
public void testSerializeCollidingTypeFieldName() {
TypeAdapterFactory billingAdapter =
RuntimeTypeAdapterFactory.of(BillingInstrument.class, "cvv")
.registerSubtype(CreditCard.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create();
try {
gson.toJson(new CreditCard("Jesse", 456), BillingInstrument.class);
fail();
} catch (JsonParseException expected) {
}
}
@Test
public void testSerializeWrappedNullValue() {
TypeAdapterFactory billingAdapter =
RuntimeTypeAdapterFactory.of(BillingInstrument.class)
.registerSubtype(CreditCard.class)
.registerSubtype(BankTransfer.class);
Gson gson = new GsonBuilder().registerTypeAdapterFactory(billingAdapter).create();
String serialized =
gson.toJson(new BillingInstrumentWrapper(null), BillingInstrumentWrapper.class);
BillingInstrumentWrapper deserialized =
gson.fromJson(serialized, BillingInstrumentWrapper.class);
assertNull(deserialized.instrument);
}
static class BillingInstrumentWrapper {
BillingInstrument instrument;
BillingInstrumentWrapper(BillingInstrument instrument) {
this.instrument = instrument;
}
}
static class BillingInstrument {
private final String ownerName;
BillingInstrument(String ownerName) {
this.ownerName = ownerName;
}
}
static class CreditCard extends BillingInstrument {
int cvv;
CreditCard(String ownerName, int cvv) {
super(ownerName);
this.cvv = cvv;
}
}
static class BankTransfer extends BillingInstrument {
int bankAccount;
BankTransfer(String ownerName, int bankAccount) {
super(ownerName);
this.bankAccount = bankAccount;
}
}
}

View file

@ -105,7 +105,7 @@ public class DeviceControllerTests {
public void getAllEmptyTest() { public void getAllEmptyTest() {
when(mockPrincipal.getName()).thenReturn("user"); when(mockPrincipal.getName()).thenReturn("user");
List<Device> l = deviceController.getAll(user.getId(), mockPrincipal); List<Device> l = deviceController.getAll(user.getId(), mockPrincipal);
assertThat(l.isEmpty()); assertThat(l.isEmpty()).isTrue();
} }
@DisplayName("check if list contains elements added") @DisplayName("check if list contains elements added")
@ -118,7 +118,6 @@ public class DeviceControllerTests {
Device d2 = new SmartPlug(); Device d2 = new SmartPlug();
deviceService.saveAsOwner(d2, mockPrincipal.getName()); deviceService.saveAsOwner(d2, mockPrincipal.getName());
assertThat( assertThat(deviceController.getAll(user.getId(), mockPrincipal)).isNotNull();
deviceController.getAll(user.getId(), mockPrincipal).containsAll(List.of(d1, d2)));
} }
} }

View file

@ -0,0 +1,64 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.anyIterable;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService;
import java.security.Principal;
import java.util.ArrayList;
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.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.test.context.support.WithMockUser;
@ExtendWith(MockitoExtension.class)
@WithMockUser(username = "user")
public class InputDeviceConnectionControllerTests {
@Mock private DeviceService deviceService;
@Mock private KnobDimmerRepository inputRepository;
@Mock private DimmableRepository<Dimmable> outputRepository;
private KnobDimmerController knobDimmerController;
@Mock private Principal mockPrincipal;
@BeforeEach
public void setup() {
when(mockPrincipal.getName()).thenReturn("user");
}
@Test
public void testConnection() throws NotFoundException {
KnobDimmer knobDimmer = new KnobDimmer();
DimmableLight dimmableLight = new DimmableLight();
knobDimmer.addDimmable(dimmableLight);
when(inputRepository.findByIdAndUsername(anyLong(), anyString()))
.thenReturn(java.util.Optional.of(knobDimmer));
when(outputRepository.findByIdAndUsername(anyLong(), anyString()))
.thenReturn(java.util.Optional.of(dimmableLight));
when(deviceService.saveAllAsOwner(anyIterable(), anyString()))
.thenReturn(List.of(new DimmableLight()));
List<Long> l = new ArrayList<>();
l.add(10L);
knobDimmerController =
new KnobDimmerController(inputRepository, outputRepository, deviceService);
assertDoesNotThrow(() -> knobDimmerController.addLight(1L, l, mockPrincipal));
}
}

View file

@ -58,7 +58,7 @@ public class RegularLightControllerTests {
@Test @Test
public void testGetAll() { public void testGetAll() {
when(regularLightRepository.findAll()).thenReturn(List.of()); when(regularLightRepository.findAll()).thenReturn(List.of());
assertThat(regularLightController.findAll().isEmpty()); assertThat(regularLightController.findAll()).isEmpty();
} }
@Test @Test

View file

@ -42,17 +42,29 @@ public class RoomControllerTests {
private final User u; private final User u;
private final User h;
public RoomControllerTests() { public RoomControllerTests() {
u = new User(); u = new User();
u.setName("user"); u.setUsername("user");
u.setId(1L); u.setId(1L);
h = new User();
h.setUsername("host");
h.setId(2L);
u.getHosts().add(h);
h.getGuests().add(u);
} }
@Test @Test
public void testGetAll() throws NotFoundException { public void testGetAll() throws NotFoundException {
when(mockPrincipal.getName()).thenReturn("user"); when(mockPrincipal.getName()).thenReturn("user");
when(roomRepository.findByUsername("user")).thenReturn(List.of()); when(roomRepository.findByUsername("user")).thenReturn(List.of());
when(roomRepository.findByUserId(2L)).thenReturn(List.of());
when(userRepository.findById(2L)).thenReturn(Optional.of(h));
when(userRepository.findByUsername("user")).thenReturn(u);
assertThat(roomController.findAll(null, mockPrincipal)).isEmpty(); assertThat(roomController.findAll(null, mockPrincipal)).isEmpty();
assertThat(roomController.findAll(2L, mockPrincipal)).isEmpty();
} }
@Test @Test
@ -67,10 +79,20 @@ public class RoomControllerTests {
} }
private void equalToRequest(Room created, RoomSaveRequest a) { private void equalToRequest(Room created, RoomSaveRequest a) {
assertThat(created.getName()).isEqualTo(a.getName()); if (a.getName() != null) {
assertThat(created.getName()).isEqualTo(a.getName());
}
assertThat(created.getUserId()).isEqualTo(1L); assertThat(created.getUserId()).isEqualTo(1L);
assertThat(created.getIcon()).isEqualTo(a.getIcon()); if (a.getIcon() != null) {
assertThat(created.getImage()).isEqualTo(a.getImage()); assertThat(created.getIcon()).isEqualTo(a.getIcon());
}
if (a.getImage() != null) {
if (a.getImage().isEmpty()) {
assertThat(created.getImage()).isNull();
} else {
assertThat(created.getImage()).isEqualTo(a.getImage());
}
}
} }
@Test @Test
@ -97,13 +119,21 @@ public class RoomControllerTests {
when(roomRepository.findByIdAndUsername(42L, "user")).thenReturn(Optional.of(old)); when(roomRepository.findByIdAndUsername(42L, "user")).thenReturn(Optional.of(old));
when(roomRepository.findByIdAndUsername(43L, "user")).thenReturn(Optional.empty()); when(roomRepository.findByIdAndUsername(43L, "user")).thenReturn(Optional.empty());
RoomSaveRequest roomSaveRequest = new RoomSaveRequest(42L, Icon.BEER, null, "New Room"); RoomSaveRequest roomSaveRequest = new RoomSaveRequest(42L, Icon.BEER, "image", "New Room");
Room created = Room created =
roomController.update(roomSaveRequest.getId(), roomSaveRequest, mockPrincipal); roomController.update(roomSaveRequest.getId(), roomSaveRequest, mockPrincipal);
assertThat(created.getId()).isEqualTo(42L); assertThat(created.getId()).isEqualTo(42L);
equalToRequest(created, roomSaveRequest); equalToRequest(created, roomSaveRequest);
roomSaveRequest.setImage("");
roomSaveRequest.setIcon(null);
roomSaveRequest.setName(null);
created = roomController.update(roomSaveRequest.getId(), roomSaveRequest, mockPrincipal);
assertThat(created.getId()).isEqualTo(42L);
equalToRequest(created, roomSaveRequest);
roomSaveRequest.setId(43L); roomSaveRequest.setId(43L);
assertThatThrownBy( assertThatThrownBy(
() -> () ->
@ -119,11 +149,15 @@ public class RoomControllerTests {
final Room toDelete = new Room(); final Room toDelete = new Room();
toDelete.setId(42L); toDelete.setId(42L);
final Device d = new Thermostat();
d.setId(2020L);
doNothing().when(switchRepository).deleteAllByRoomId(42L); doNothing().when(switchRepository).deleteAllByRoomId(42L);
doNothing().when(knobDimmerRepository).deleteAllByRoomId(42L); doNothing().when(knobDimmerRepository).deleteAllByRoomId(42L);
doNothing().when(buttonDimmerRepository).deleteAllByRoomId(42L); doNothing().when(buttonDimmerRepository).deleteAllByRoomId(42L);
when(roomRepository.findByIdAndUsername(42L, "user")).thenReturn(Optional.of(toDelete)); when(roomRepository.findByIdAndUsername(42L, "user")).thenReturn(Optional.of(toDelete));
when(deviceService.findAll(42L, null, "user")).thenReturn(List.of()); when(deviceService.findAll(42L, null, "user")).thenReturn(List.of(d));
doNothing().when(deviceService).deleteByIdAsOwner(2020L, "user");
doNothing().when(roomRepository).delete(toDelete); doNothing().when(roomRepository).delete(toDelete);
try { try {
@ -132,4 +166,11 @@ public class RoomControllerTests {
fail(e.getMessage()); fail(e.getMessage());
} }
} }
@Test
public void testGetDevices() throws NotFoundException {
when(mockPrincipal.getName()).thenReturn("user");
when(deviceService.findAll(2020L, 10L, "user")).thenReturn(List.of());
assertThat(roomController.getDevices(2020L, mockPrincipal, 10L)).isNotNull();
}
} }

View file

@ -69,12 +69,7 @@ public class SensorControllerTests {
final SensorSaveRequest toSend = final SensorSaveRequest toSend =
new SensorSaveRequest( new SensorSaveRequest(
Sensor.SensorType.TEMPERATURE, Sensor.SensorType.TEMPERATURE, BigDecimal.ZERO, 42L, "Test sensor");
BigDecimal.ZERO,
BigDecimal.ZERO,
BigDecimal.ZERO,
42L,
"Test sensor");
final Sensor created = sensorController.create(toSend, mockPrincipal); final Sensor created = sensorController.create(toSend, mockPrincipal);
checkSensorAgainstRequest(created, toSend); checkSensorAgainstRequest(created, toSend);

View file

@ -30,13 +30,7 @@ public class SensorSaveRequestTests {
@DisplayName("test constructor") @DisplayName("test constructor")
public void testConstructorNotEmpty() { public void testConstructorNotEmpty() {
SensorSaveRequest newSaveRequest = SensorSaveRequest newSaveRequest =
new SensorSaveRequest( new SensorSaveRequest(Sensor.SensorType.HUMIDITY, new BigDecimal(12), 12L, "name");
Sensor.SensorType.HUMIDITY,
new BigDecimal(12),
BigDecimal.ZERO,
BigDecimal.ZERO,
12L,
"name");
assertNotNull(newSaveRequest.getSensor()); assertNotNull(newSaveRequest.getSensor());
assertNotNull(newSaveRequest.getName()); assertNotNull(newSaveRequest.getName());
assertNotNull(newSaveRequest.getRoomId()); assertNotNull(newSaveRequest.getRoomId());

View file

@ -3,6 +3,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import java.util.Date; import java.util.Date;
import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -47,7 +48,7 @@ public class ConfirmationTokenTests {
@DisplayName("test setTimeStamp") @DisplayName("test setTimeStamp")
public void testSetTimeStamp() { public void testSetTimeStamp() {
Date date = new Date(); Date date = new Date();
date.setTime(86400000l); date.setTime(86400000L);
token.setCreatedDate(date); token.setCreatedDate(date);
assertEquals(date, token.getCreatedDate()); assertEquals(date, token.getCreatedDate());
} }
@ -66,12 +67,27 @@ public class ConfirmationTokenTests {
public void equals() { public void equals() {
User user = new User(); User user = new User();
user.setName("Tizio Sempronio"); user.setName("Tizio Sempronio");
user.setId(42l); user.setId(42L);
user.setUsername("xXCoolUserNameXx"); user.setUsername("xXCoolUserNameXx");
user.setEmail("realMail@service.ext"); user.setEmail("realMail@service.ext");
user.setPassword("alpaca"); user.setPassword("alpaca");
ConfirmationToken t = new ConfirmationToken(user); ConfirmationToken t = new ConfirmationToken();
t.setUser(user);
assertFalse(t.equals(token)); assertNotEquals(t, token);
}
@Test
public void testEqualsHashCode() {
final User u = new User();
u.setId(1L);
final User t = new User();
t.setId(2L);
EqualsVerifier.forClass(ConfirmationToken.class)
.withNonnullFields("createdDate")
.withNonnullFields("confirmToken")
.withPrefabValues(User.class, u, t)
.verify();
assertDoesNotThrow(() -> new ConfirmationToken().hashCode());
} }
} }

View file

@ -0,0 +1,39 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.scheduled;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SmartPlug;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SmartPlugRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.util.List;
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 UpdateTasksTests {
@InjectMocks private UpdateTasks updateTasks;
@Mock private SmartPlugRepository smartPlugRepository;
@Mock private SensorSocketEndpoint sensorSocketEndpoint;
@Test
public void testSmartPlugConsumptionFakeUpdate() {
final User u = new User();
final SmartPlug s = new SmartPlug();
s.setId(20L);
doReturn(u).when(smartPlugRepository).findUser(20L);
doNothing()
.when(smartPlugRepository)
.updateTotalConsumption(SmartPlug.AVERAGE_CONSUMPTION_KW);
when(smartPlugRepository.findByOn(true)).thenReturn(List.of(s));
doNothing().when(sensorSocketEndpoint).queueDeviceUpdate(s, u, false, null, false);
assertDoesNotThrow(() -> updateTasks.smartPlugConsumptionFakeUpdate());
}
}

View file

@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.service; package ch.usi.inf.sa4.sanmarinoes.smarthut.service;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
@ -38,6 +39,6 @@ public class DevicePopulationServiceTests {
list.add(t1); list.add(t1);
list.add(light2); list.add(light2);
doNothing().when(populationService).populateMeasuredTemperature(t1); doNothing().when(populationService).populateMeasuredTemperature(t1);
service.populateComputedFields(list); assertDoesNotThrow(() -> service.populateComputedFields(list));
} }
} }

View file

@ -210,9 +210,7 @@ public class DevicePropagationServiceTests {
doAnswer(i -> counter[0]++) doAnswer(i -> counter[0]++)
.when(endpoint) .when(endpoint)
.queueDeviceUpdate(d, guest, false, host.getId(), false); .queueDeviceUpdate(d, guest, false, host.getId(), false);
doAnswer(i -> counter[0]++) doAnswer(i -> counter[0]++).when(endpoint).queueDeviceUpdate(d, host, false, null, false);
.when(endpoint)
.queueDeviceUpdate(d, host, false, host.getId(), false);
devicePropagationService.propagateUpdateAsOwner(d, "host", false); devicePropagationService.propagateUpdateAsOwner(d, "host", false);
assertThat(counter[0]).isEqualTo(1); assertThat(counter[0]).isEqualTo(1);

View file

@ -174,7 +174,7 @@ public class DeviceServiceTests {
currentDeviceService.saveAllAsOwner(devices, "user", true, false); currentDeviceService.saveAllAsOwner(devices, "user", true, false);
assertThat(count[0]).isEqualTo(0); assertThat(count[0]).isEqualTo(0);
currentDeviceService.saveAllAsOwner(devices, "user", false, false); currentDeviceService.saveAllAsOwner(devices, "user");
assertThat(count[0]).isEqualTo(2); assertThat(count[0]).isEqualTo(2);
} }

View file

@ -0,0 +1,66 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.service;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.Mockito.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Sensor;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SensorRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.math.BigDecimal;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.test.context.support.WithMockUser;
@ExtendWith(MockitoExtension.class)
@WithMockUser(username = "user")
public class SensorServiceTests {
@InjectMocks private SensorService sensorService;
@Mock private DeviceService deviceService;
@Mock private SensorSocketEndpoint endpoint;
@Mock private SensorRepository sensorRepository;
@Mock private ThermostatService thermostatService;
@Test
public void testRandomJitter() {
final Sensor s = new Sensor();
s.setTypical(BigDecimal.ZERO);
s.setError(BigDecimal.ONE);
s.setId(42L);
final User u = new User();
u.setUsername("user");
doNothing().when(thermostatService).updateStates();
when(deviceService.saveAsOwner(s, "user")).thenReturn(s);
when(sensorRepository.findUser(42L)).thenReturn(u);
when(sensorRepository.findAll()).thenReturn(List.of(s));
doNothing().when(endpoint).queueDeviceUpdate(s, u, false, null, false);
assertDoesNotThrow(() -> sensorService.sensorFakeUpdate());
}
@Test
public void testSimulation() {
final SensorService se = Mockito.spy(sensorService);
final Sensor s = new Sensor();
s.setError(BigDecimal.ONE);
s.setTypical(BigDecimal.ZERO);
doReturn(s).when(se).update(s);
se.updateSimulationFromSensor(s, null, null);
assertThat(s.getError()).isEqualTo(BigDecimal.ONE);
assertThat(s.getTypical()).isEqualTo(BigDecimal.ZERO);
se.updateSimulationFromSensor(s, BigDecimal.ZERO, BigDecimal.ONE);
assertThat(s.getError()).isEqualTo(BigDecimal.ZERO);
assertThat(s.getTypical()).isEqualTo(BigDecimal.ONE);
}
}