Corrado Stortini, Francesco Carlucci, Marco Raggini
The GUI is a website made in Vue + Html + Css.
We have prepared a full demo to allow you to test it. In this demo there are already users, devices and tasks/automations ready to use. To run it, this is the command:
docker compose up -d
Once the docker containers are all up, you can go to http://localhost to view the website.
In almost all of the pages there is an “info” button that explains exactly what you can do in that page (like what instructions do and why).
The development of the server has been done following the TDD metodology.
Unfortunatly, for the Scripts part it was really hard to test everything because there are a lot of different outcomes when it comes to programming (there are Ifs, If-Elses, that can be also nested and with checking of constant declarations etc.), so it was preferred to test them from the GUI interface.
The test of the GUI has been done entirely from the GUI itself. The devices were tested only by the GUI and with means of PostMan. (There were not really requirements about them, so it was preferrable to just test their comunication with the server)
All of the tests are passing correctly and are checked automatically every time a Pull Request is done.
There are 34 test suites, with 439 total tests.
| File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
|---|---|---|---|---|---|
| All files | 91.18 | 92.98 | 88.81 | 91.18 | |
| adapters | 97.56 | 93.33 | 100 | 97.56 | |
| BaseRepositoryMongoAdapter.ts | 97.56 | 93.33 | 100 | 97.56 | 39-40,55 |
| adapters/devices-management | 98.32 | 86.36 | 100 | 98.32 | |
| DeviceGroupRepositoryMongoAdapter.ts | 100 | 100 | 100 | 100 | |
| DeviceRepositoryMongoAdapter.ts | 97.99 | 84.21 | 100 | 97.99 | 194,196,200,206,212 |
| adapters/notifications-management | 100 | 100 | 100 | 100 | |
| DeviceOfflineNotificationSubscription.ts | 100 | 100 | 100 | 100 | |
| adapters/permissions-management | 83.52 | 87.09 | 83.72 | 83.52 | |
| EditListRepositoryMongoAdapter.ts | 67.12 | 85.71 | 75 | 67.12 | 49-50,64-65,86-87,93-106,109-122,125-138 |
| TaskListsRepositoryMongoAdapter.ts | 94.49 | 86.36 | 92.3 | 94.49 | 59-60,74-75,96-97 |
| UserDevicePermissionRepositoryMongoAdapter.ts | 95.87 | 89.47 | 85.71 | 95.87 | 50-51,67-68 |
| adapters/scripts-management | 98.1 | 97.56 | 100 | 98.1 | |
| ScriptRepositoryMongoAdapter.ts | 98.1 | 97.56 | 100 | 98.1 | 325-329,449-453 |
| adapters/users-management | 100 | 100 | 100 | 100 | |
| RegistrationRequestRepositoryAdapter.ts | 100 | 100 | 100 | 100 | |
| UserRepositoryAdapter.ts | 100 | 100 | 100 | 100 | |
| domain/devices-management | 97.72 | 94.05 | 97.45 | 97.72 | |
| Device.ts | 99.57 | 94.59 | 100 | 99.57 | 143 |
| DeviceActionsServiceImpl.ts | 100 | 100 | 100 | 100 | |
| DeviceEventsServiceImpl.ts | 100 | 100 | 100 | 100 | |
| DeviceGroup.ts | 100 | 100 | 100 | 100 | |
| DeviceGroupsServiceImpl.ts | 99.5 | 96.49 | 90.47 | 99.5 | 100 |
| DeviceStatusesServiceImpl.ts | 98.26 | 95.83 | 100 | 98.26 | 81-82 |
| DevicesServiceImpl.ts | 99.27 | 97.61 | 100 | 99.27 | 56,108 |
| Types.ts | 89.85 | 80.39 | 96.87 | 89.85 | 16-17,19-20,22-23,28-29,126-127,172-174,176-178,180-182,184,186 |
| domain/notifications-management | 94.76 | 96.66 | 77.77 | 94.76 | |
| DeviceOfflineNotificationSubscription.ts | 100 | 100 | 100 | 100 | |
| NotificationsServiceImpl.ts | 94.19 | 96.55 | 76.47 | 94.19 | 115-117,131-136 |
| domain/permissions-management | 75.32 | 96.45 | 72.91 | 75.32 | |
| EditList.ts | 100 | 100 | 100 | 100 | |
| PermissionsServiceImpl.ts | 71.46 | 95.86 | 67.9 | 71.46 | …9,333-340,383-386,454-461,504-538,566-586,634-668,696-716,719-729 |
| TaskLists.ts | 100 | 100 | 100 | 100 | |
| UserDevicePermission.ts | 100 | 100 | 100 | 100 | |
| domain/scripts-management | 90.15 | 89.23 | 88.33 | 90.15 | |
| Instruction.ts | 100 | 100 | 100 | 100 | |
| InstructionImpl.ts | 99.64 | 93.75 | 100 | 99.64 | 159 |
| Operators.ts | 100 | 100 | 100 | 100 | |
| Refs.ts | 100 | 100 | 100 | 100 | |
| Script.ts | 100 | 100 | 100 | 100 | |
| ScriptBuilder.ts | 91.33 | 70.66 | 100 | 91.33 | …0-231,237-240,255-256,265,280-281,283-286,351-352,392-393,396-399 |
| ScriptsServiceImpl.ts | 75.55 | 88.88 | 57.14 | 75.55 | …2,396-397,402-414,418-420,423-431,434-459,479-482,514-520,546-549 |
| Trigger.ts | 100 | 100 | 100 | 100 | |
| domain/users-management | 91.84 | 92.5 | 90 | 91.84 | |
| RegistrationRequest.ts | 100 | 100 | 100 | 100 | |
| Token.ts | 100 | 100 | 100 | 100 | |
| User.ts | 100 | 100 | 100 | 100 | |
| UsersServiceImpl.ts | 89.19 | 90.9 | 85.18 | 89.19 | 122-127,205-215,237-248,267-268 |
| ports | 100 | 100 | 100 | 100 | |
| Repository.ts | 100 | 100 | 100 | 100 | |
| ports/devices-management | 100 | 100 | 100 | 100 | |
| Errors.ts | 100 | 100 | 100 | 100 | |
| Types.ts | 100 | 100 | 100 | 100 | |
| ports/permissions-management | 53.65 | 100 | 40 | 53.65 | |
| Errors.ts | 53.65 | 100 | 40 | 53.65 | 21-23,25-33,35-41 |
| ports/scripts-management | 100 | 100 | 100 | 100 | |
| Errors.ts | 100 | 100 | 100 | 100 | |
| ports/users-management | 88.13 | 100 | 85.71 | 88.13 | |
| Errors.ts | 88.13 | 100 | 85.71 | 88.13 | 45-51 |
| utils | 100 | 100 | 100 | 100 | |
| MongoDBErrorCodes.ts | 100 | 100 | 100 | 100 |
For the deployment of our application we decided to use Kubernetes.
To run the system, go to the server repository, then here there are some instructions to be executed.
kubectl apply -f ./k8s/persistence
kubectl apply -f ./k8s/deployment
kubectl apply -f ./k8s/devices
To stop the server and/or the devices use one or both of the following commands:
kubectl delete -f ./k8s/deployment
kubectl delete -f ./k8s/devices
To reset the DB use the following command:
kubectl delete -f ./k8s/persistence
Our system heavily relies on the server part, which usually would not be a really good choice, but in our scope the server runs locally on a computer, without being hosted on internet (and, even if so, a local server needs always to exists, making a remote server a sort of a “proxy” of the real one), removing then all the implications of the net (like being unable to contact the server without internet).
The only things that can occur to the server in order to make it unavailable are really rare and (nowadays) also not very likely to happen, like:
This made us focus more on the aspects of Availability and Consistency, making network Partitioning less “important”.
The Availability is really well achieved in our system because every time something fails (like a device not reachable by the server of a device going online) the user interested is notified, either by a notification or a popup.
The server find offline devices sending a request of “check-status” every 5 seconds, if they answer it with status code 202 they are healthy, otherwise either they answer with an error (specifying the cause) or don’t answer at all (they are offline).
Our system is also really well Consistent because we use MongoDB API for the DB with one replica, and at the application level, each instruction (add, get, getAll, remove, update) ensures that it does only if in the right circumstances.
In all these cases, the user is notified that something went wrong with a pop-up.
Unfortunatly, the server (also due to the low partitioning and the same reasons above) is not easy to be scaled, but usually being it a server used locally just for the devices inside an house and the users inside an house (about 4/5 for family or 20/30 for agencies), the scalability we think is an aspect of a less importance respect to the availability and consistency (an user doesn’t want to think that a device is doing something when it does not, or viceversa).
With kubernetes we tried to make server replicas, but there were problems were the devices where comunicating updates to random replicas and not just one of them (the one comunicating also with the GUI), we tried with the “sessionAffinity: ClientIP” configuration but it was not working, so at last we decided to stuck with only one replica of the server.
We think that something that could have been really good to do for fault tolerance is deciding which replica is the “main” one and which are the ones to be used only in case of a failure, maybe in the application level.
We think in the future some works that can be done are:
Being a really big project, we learned really lot of things, like: