Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DOJOT-75] [DOJOT-76] Feature - Unique Labels #201

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions DeviceManager/DatabaseModels.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ class DeviceTemplate(db.Model):
__tablename__ = 'templates'

id = db.Column(db.Integer, db.Sequence('template_id'), primary_key=True)
label = db.Column(db.String(128), nullable=False)
label = db.Column(db.String(128), nullable=False, unique=True)
created = db.Column(db.DateTime, default=datetime.now)
updated = db.Column(db.DateTime, onupdate=datetime.now)

Expand Down Expand Up @@ -99,7 +99,7 @@ class Device(db.Model):
__tablename__ = 'devices'

id = db.Column(db.String(8), unique=True, nullable=False, primary_key=True)
label = db.Column(db.String(128), nullable=False)
label = db.Column(db.String(128), nullable=False, unique=True)
created = db.Column(db.DateTime, default=datetime.now)
updated = db.Column(db.DateTime, onupdate=datetime.now)

Expand Down
6 changes: 3 additions & 3 deletions DeviceManager/TemplateHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ def create_template(params, token):
try:
db.session.commit()
LOGGER.debug(f" Created template in database")
except IntegrityError as e:
LOGGER.error(f' {e}')
raise HTTPRequestError(400, 'Template attribute constraints are violated by the request')
except IntegrityError as error:
LOGGER.error(f' {error}')
handle_consistency_exception(error)

results = {
'template': template_schema.dump(loaded_template),
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ The information model used for both “real” and virtual devices is as followi
| **attrs** | Map of attributes | read-only | No | Map of device's attributes (check the attributes in the next table)
| **created** | DateTime (with timezone and µs precision) in ISO format | read-only | No | Device creation time.
| **id** | String (length of 8 bytes) | read-only | No | Unique identifier for the device.
| **label** | String (length of 128 bytes) | read-write | Yes | An user-defined label to facilitate the device's identification.
| **label** | String (length of 128 bytes) | read-write | Yes | An user-defined label to facilitate the device's identification. The label is unique for this device.
| **templates** | Strings list | read-only | No | List of template IDs used by the device.
| **updated** | DateTime (with timezone and µs precision) in ISO format | read-only | No | Device last update time.

Expand Down Expand Up @@ -214,7 +214,7 @@ An example of such structure would be:
### **Template**

All devices are based on a **template**, which can be thought as a blueprint: all devices built
using the same template will have the same characteristics. Templates in dojot have one label (any
using the same template will have the same characteristics. Templates in dojot have one unique label (any
alphanumeric sequence), a list of attributes which will hold all the device emitted information, and
optionally a few special attributes which will indicate how the device communicates, including
transmission methods (protocol, ports, etc.) and message formats.
Expand All @@ -239,7 +239,7 @@ The information model used for templates is:
| **created** | DateTime (with timezone and µs precision) in ISO format | read-only | No | Device creation time.
| **data_attrs** | Map of attributes | read-write | No | Stores attributes with the types `dynamic`, `static` and `actuator`.
| **id** | String (length of 8 bytes) | read-write | No | Unique identifier for the template.
| **label** | String (length of 128 bytes) | read-write | Yes | An user-defined label to facilitate the template's identification.
| **label** | String (length of 128 bytes) | read-write | Yes | An user-defined label to facilitate the template's identification. The label is unique for this template.
| **updated** | DateTime (with timezone and µs precision) in ISO format | read-only | No | Device last update time.

An example template structure:
Expand Down
48 changes: 47 additions & 1 deletion docs/apiary.apib
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ Register a new template
}
}


+ Response 400 (application/json)

{
Expand All @@ -112,6 +111,19 @@ Register a new template
"message": "failed to parse input"
}

+ Response 400 (application/json)

{
"message": "duplicate key value violates unique constraint \"templates_label_key\"",
"status": 400
}

+ Response 400 (application/json)

{
"message": "duplicate key value violates unique constraint \"attrs_template_id_type_label_key\"",
"status": 400
}

### Get the current list of templates [GET /template{?page_size,page_num,attr_format,attr,attr_type,label,sortBy}]

Expand Down Expand Up @@ -498,6 +510,20 @@ updated.
"message": "No such template: 123",
"status": 404
}

+ Response 400 (application/json)

{
"message": "duplicate key value violates unique constraint \"templates_label_key\"",
"status": 400
}

+ Response 400 (application/json)

{
"message": "duplicate key value violates unique constraint \"attrs_template_id_type_label_key\"",
"status": 400
}

### Delete template [DELETE /template/{id}]

Expand Down Expand Up @@ -648,6 +674,13 @@ attributes to be applied to this device.
"status": 400
}

+ Response 400 (application/json)

{
"message": "duplicate key value violates unique constraint \"devices_label_key\"",
"status": 400
}

+ Response 404 (application/json)

{
Expand Down Expand Up @@ -750,6 +783,13 @@ attributes to be applied to this device.
"status": 400
}

+ Response 400 (application/json)

{
"message": "duplicate key value violates unique constraint \"devices_label_key\"",
"status": 400
}

+ Response 404 (application/json)

{
Expand Down Expand Up @@ -1160,6 +1200,12 @@ Updates a device's configuration
"status": 400
}

+ Response 400 (application/json)

{
"message": "duplicate key value violates unique constraint \"devices_label_key\"",
"status": 400
}

### Configure device [PUT /device/{id}/actuate]

Expand Down
30 changes: 30 additions & 0 deletions migrations/versions/944f3122f51e_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""empty message

Revision ID: 944f3122f51e
Revises: fabf2ca39860
Create Date: 2022-08-12 13:44:41.398334

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '944f3122f51e'
down_revision = 'fabf2ca39860'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_unique_constraint(None, 'devices', ['label'])
op.create_unique_constraint(None, 'templates', ['label'])
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'templates', type_='unique')
op.drop_constraint(None, 'devices', type_='unique')
# ### end Alembic commands ###
11 changes: 7 additions & 4 deletions tests/dredd-hooks/operation_hook.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import absolute_import
import dredd_hooks as hooks
from uuid import uuid4
import json
import re

Expand All @@ -17,13 +18,15 @@ def __init__(self, data):
self.args = data['args']
self.data = data['body']

def generate_unique_label(prefix):
return f"{prefix}_{uuid4()}"

def sort_attributes(device, attribute):
device[attribute] = sorted(device[attribute], key=lambda k: k['label'])

def create_sample_template():
template = {
"label": "SensorModel",
"label": generate_unique_label("SensorModel"),
"attrs": [
{
"label": "temperature",
Expand Down Expand Up @@ -68,7 +71,7 @@ def create_sample_template():

def create_actuator_template():
template = {
"label": "SensorModel",
"label": generate_unique_label("SensorModel"),
"attrs": [
{
"label": "temperature",
Expand Down Expand Up @@ -168,7 +171,7 @@ def create_single_device(transaction):
transaction['proprietary'] = {}
transaction['proprietary']['template_id'] = template_id
device = {
"label": "test_device",
"label": generate_unique_label("test_device"),
"templates": [template_id]
}
req = {
Expand Down Expand Up @@ -202,7 +205,7 @@ def create_actuator_device(transaction):
transaction['proprietary'] = {}
transaction['proprietary']['template_id'] = template_id
device = {
"label": "test_device",
"label": generate_unique_label("test_device"),
"templates": [template_id]
}
req = {
Expand Down