mirror of
https://github.com/OpenMTC/OpenMTC.git
synced 2025-02-09 03:51:11 +00:00
Merge pull request #17 from OpenMTC/master
Update development branche to master
This commit is contained in:
commit
36d4e84059
114
README.md
114
README.md
@ -4,43 +4,95 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
The OpenMTC SDK aims to provide developers with a convenient yet flexible tool to write oneM2M compliant applications. This includes network applications (NAs), gateway application (GAs), device applications (DAs), as well as interworking proxy entities (IPEs).
|
[![FIWARE IoT Agents](https://nexus.lab.fiware.org/static/badges/chapters/iot-agents.svg)](https://www.fiware.org/developers/catalogue/)
|
||||||
|
[![License: Eclipse](https://img.shields.io/github/license/OpenMTC/OpenMTC.svg)](https://www.eclipse.org/legal/epl-v10.html)
|
||||||
|
[![Support badge](https://nexus.lab.fiware.org/repository/raw/public/badges/stackoverflow/iot-agents.svg)](https://stackoverflow.com/questions/tagged/fiware+iot)
|
||||||
|
<br/>
|
||||||
|
[![Documentation badge](https://img.shields.io/readthedocs/fiware-openmtc.svg)](http://fiware-openmtc.readthedocs.org/en/latest/?badge=latest)
|
||||||
|
![Status](https://nexus.lab.fiware.org/static/badges/statuses/iot-openmtc.svg)
|
||||||
|
[![](https://img.shields.io/docker/pulls/openmtc/gateway-amd64.svg)](https://hub.docker.com/u/openmtc)
|
||||||
|
[![Build Status](https://travis-ci.org/OpenMTC/OpenMTC.svg?branch=master)](https://travis-ci.org/OpenMTC/OpenMTC)
|
||||||
|
|
||||||
# Table of Content
|
The OpenMTC SDK aims to provide developers with a convenient yet flexible tool
|
||||||
|
to write oneM2M compliant applications. This includes network applications
|
||||||
|
(NAs), gateway application (GAs), device applications (DAs), as well as
|
||||||
|
interworking proxy entities (IPEs).
|
||||||
|
|
||||||
- [Quick Start](doc/openmtc-get-started.md)
|
This project is part of [FIWARE](https://www.fiware.org/). For more information
|
||||||
- [Introduction](doc/introduction.md)
|
check the FIWARE Catalogue entry for the
|
||||||
- [Deployment](doc/deployment-guide.md)
|
[IoT Agents](https://github.com/Fiware/catalogue/tree/master/iot-agents).
|
||||||
- [The MQTT Client](doc/onem2m-client-mqtt.md)
|
|
||||||
- [Authentication Guide](doc/authentication.md)
|
# Content
|
||||||
- [Installation of the OpenMTC SDK](doc/install-sdk.md)
|
|
||||||
- [Overview REST API](doc/overview-rest-api.md)
|
- [Install](#install)
|
||||||
- [Write your first OpenMTC applications](doc/training/training-index.md)
|
- [Usage](#usage)
|
||||||
- [SDK - Using the Application Framework](doc/sdk-framework.md)
|
- [API](#api)
|
||||||
- [SDK - The low-level CSE Client](doc/sdk-client.md)
|
- [Quality Assurance](#quality-assurance)
|
||||||
- [SDK - The Data Model](doc/sdk-datamodel.md)
|
- [License](#license)
|
||||||
- Examples
|
|
||||||
- [IoT Data Visualization](doc/example-apps/IoT-data-visualization.py)
|
|
||||||
- [Data Aggregation](doc/example-apps/data-aggregation.py)
|
|
||||||
- [Simple Decision](doc/example-apps/simple-decision.py)
|
|
||||||
- [Simple Decision 2](doc/example-apps/simple-decision-2.py)
|
|
||||||
- Scripts
|
|
||||||
- [Create App Structure Script](doc/create-app-structure.md)
|
|
||||||
- [Create binary docker images Script](doc/create-binary-docker.md)
|
|
||||||
- [Code Repository Structure](doc/repository-structure.md)
|
|
||||||
- [Developer FAQ](doc/developer-faq.md)
|
|
||||||
|
|
||||||
|
|
||||||
# Python
|
## Install
|
||||||
|
|
||||||
The OpenMTC SDK is written in and for the Python programming language. Users should therefore have at least a certain knowledge of Python and its paradigms. For this matter, the following material is recommended:
|
Information about how to install the JSON IoTAgent can be found at the
|
||||||
|
corresponding section of the
|
||||||
|
[Installation & Administration Guide](https://fiware-openmtc.readthedocs.io/en/latest/deployment-guide).
|
||||||
|
|
||||||
- [The Python Homepage](http://www.python.org)
|
## Usage
|
||||||
- [Expert Python Programming by Tarek Ziadé](http://www.e-reading.by/bookreader.php/138816/Ziade_-_Expert_Python_programming.pdf)
|
|
||||||
- [Code Like a Pythonista: Idiomatic Python](http://www.omahapython.org/IdiomaticPython.html)
|
|
||||||
|
|
||||||
# Feedback
|
Information about how to use the IoT Agent can be found in the
|
||||||
|
[User & Programmers Manual](https://fiware-openmtc.readthedocs.io/en/latest/introduction).
|
||||||
|
|
||||||
Please create issues for any problems and direct any comments or feedback you are having to <a href="mailto:support@openmtc.org">support@openmtc.org</a>
|
## API
|
||||||
|
|
||||||
|
Information about the REST API can be found in the
|
||||||
|
[API Section](https://fiware-openmtc.readthedocs.io/en/latest/overview-rest-api)
|
||||||
|
|
||||||
|
|
||||||
|
## Python
|
||||||
|
|
||||||
|
The OpenMTC SDK is written in and for the Python programming language. Users
|
||||||
|
should therefore have at least a certain knowledge of Python and its paradigms.
|
||||||
|
For this matter, the following material is recommended:
|
||||||
|
|
||||||
|
- [The Python Homepage](http://www.python.org)
|
||||||
|
- [Expert Python Programming by Tarek Ziadé](http://www.e-reading.by/bookreader.php/138816/Ziade_-_Expert_Python_programming.pdf)
|
||||||
|
- [Code Like a Pythonista: Idiomatic Python](http://www.omahapython.org/IdiomaticPython.html)
|
||||||
|
|
||||||
|
## Feedback
|
||||||
|
|
||||||
|
Please create issues for any problems and direct any comments or feedback you
|
||||||
|
are having to <a href="mailto:support@openmtc.org">support@openmtc.org</a>
|
||||||
|
|
||||||
|
Please let us know what you think. We are also very interested in any use case
|
||||||
|
you are _not_ able to implement with the SDK or if you find it difficult to do
|
||||||
|
so.
|
||||||
|
|
||||||
|
|
||||||
|
## Quality Assurance
|
||||||
|
|
||||||
|
This project is part of [FIWARE](https://fiware.org/) and has been rated as
|
||||||
|
follows:
|
||||||
|
|
||||||
|
- **Version Tested:**
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Version&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.version&colorB=blue)
|
||||||
|
- **Documentation:**
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Completeness&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.docCompleteness&colorB=blue)
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Usability&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.docSoundness&colorB=blue)
|
||||||
|
- **Responsiveness:**
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Time%20to%20Respond&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.timeToCharge&colorB=blue)
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Time%20to%20Fix&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.timeToFix&colorB=blue)
|
||||||
|
- **FIWARE Testing:**
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Tests%20Passed&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.failureRate&colorB=blue)
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Scalability&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.scalability&colorB=blue)
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Performance&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.performance&colorB=blue)
|
||||||
|
![ ](https://img.shields.io/badge/dynamic/json.svg?label=Stability&url=https://fiware.github.io/catalogue/json/open_mtc.json&query=$.stability&colorB=blue)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
The OpenMTC SDK is licensed under the Eclipse Public License (EPL)
|
||||||
|
version 1.
|
||||||
|
|
||||||
|
© 2018 OpenMTC
|
||||||
|
|
||||||
Please let us know what you think. We are also very interested in any use case you are *not* able to implement with the SDK or if you find it difficult to do so.
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
Transfer OpenMTC Data to an InfluxDB
|
Transfer OpenMTC Data to an InfluxDB
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.2.0"
|
||||||
__description__ = "InfluxdbApp"
|
__description__ = "InfluxdbApp"
|
||||||
__author_name__ = "Christian Klopp"
|
__author_name__ = "Christian Klopp"
|
||||||
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"
|
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"
|
||||||
|
@ -3,7 +3,7 @@ This App will forward all incoming sensor traffic to the Fiware Orion Context
|
|||||||
Broker
|
Broker
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.2.0"
|
||||||
__description__ = "OrionContextBroker"
|
__description__ = "OrionContextBroker"
|
||||||
__author_name__ = "Christian Klopp"
|
__author_name__ = "Christian Klopp"
|
||||||
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"
|
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"
|
||||||
|
@ -43,6 +43,13 @@ class OrionAPI(LoggerMixin):
|
|||||||
self.logger.error('Type of "{}" unknown'.format(element))
|
self.logger.error('Type of "{}" unknown'.format(element))
|
||||||
return u"Unknown"
|
return u"Unknown"
|
||||||
|
|
||||||
|
def is_host_alive(self):
|
||||||
|
req = self._request(
|
||||||
|
"{}/v2/entities".format(self.host),
|
||||||
|
method="get"
|
||||||
|
)
|
||||||
|
return req['status'] >= 0
|
||||||
|
|
||||||
def create_entity(self,
|
def create_entity(self,
|
||||||
entity_name,
|
entity_name,
|
||||||
entity_type="openmtc",
|
entity_type="openmtc",
|
||||||
|
@ -37,10 +37,13 @@ class OrionContextBroker(ResourceManagementXAE):
|
|||||||
accumulate_address = "http://" + self._get_auto_host(orion_host) + ":8080"
|
accumulate_address = "http://" + self._get_auto_host(orion_host) + ":8080"
|
||||||
|
|
||||||
# Orion API
|
# Orion API
|
||||||
|
self._dry_run = not orion_host
|
||||||
self.orion_api = OrionAPI(
|
self.orion_api = OrionAPI(
|
||||||
orion_host=orion_host,
|
orion_host=orion_host,
|
||||||
api_version=orion_api,
|
api_version=orion_api,
|
||||||
accumulate_endpoint="{}/accumulate".format(accumulate_address))
|
accumulate_endpoint="{}/accumulate".format(accumulate_address))
|
||||||
|
if not self._dry_run:
|
||||||
|
self._dry_run = not self.orion_api.is_host_alive()
|
||||||
|
|
||||||
# Subscription Sink for OCB
|
# Subscription Sink for OCB
|
||||||
self.app = Flask(__name__)
|
self.app = Flask(__name__)
|
||||||
@ -116,6 +119,9 @@ class OrionContextBroker(ResourceManagementXAE):
|
|||||||
return re.sub('[\W]', '_', f_s), '%s-%s' % (e_pre, dev_id)
|
return re.sub('[\W]', '_', f_s), '%s-%s' % (e_pre, dev_id)
|
||||||
|
|
||||||
def _sensor_data_cb(self, sensor_info, sensor_data):
|
def _sensor_data_cb(self, sensor_info, sensor_data):
|
||||||
|
if self._dry_run:
|
||||||
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fiware_service, entity_name = self._entity_names[sensor_info['ID']]
|
fiware_service, entity_name = self._entity_names[sensor_info['ID']]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -138,6 +144,10 @@ class OrionContextBroker(ResourceManagementXAE):
|
|||||||
'ID']]
|
'ID']]
|
||||||
self.logger.info("Create new Entity {} on Fiware Service {}".format(
|
self.logger.info("Create new Entity {} on Fiware Service {}".format(
|
||||||
entity_name, fiware_service))
|
entity_name, fiware_service))
|
||||||
|
|
||||||
|
if self._dry_run:
|
||||||
|
return
|
||||||
|
|
||||||
self.orion_api.create_entity(
|
self.orion_api.create_entity(
|
||||||
entity_name, fiware_service=fiware_service)
|
entity_name, fiware_service=fiware_service)
|
||||||
data_dummy = {
|
data_dummy = {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
App to inject data from a csv file to OpenMTC
|
App to inject data from a csv file to OpenMTC
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.2.0"
|
||||||
__description__ = "csvInjector"
|
__description__ = "csvInjector"
|
||||||
__author_name__ = "Christian Klopp"
|
__author_name__ = "Christian Klopp"
|
||||||
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"
|
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
TODO: Add description here
|
TODO: Add description here
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.2.0"
|
||||||
__description__ = "mqttConnector"
|
__description__ = "mqttConnector"
|
||||||
__author_name__ = "Ronald Steinke"
|
__author_name__ = "Ronald Steinke"
|
||||||
__author_mail__ = "ronald.steinke@fokus.fraunhofer.de"
|
__author_mail__ = "ronald.steinke@fokus.fraunhofer.de"
|
||||||
|
@ -48,7 +48,7 @@ _method_map_to_http = {
|
|||||||
|
|
||||||
_clients = LRUCache(threadsafe=False)
|
_clients = LRUCache(threadsafe=False)
|
||||||
|
|
||||||
_query_params = frozenset(['rt', 'rp', 'rcn', 'da', 'drt'])
|
_query_params = frozenset(['rt', 'rp', 'rcn', 'da', 'drt', 'rids', 'tids', 'ltids', 'tqi'])
|
||||||
|
|
||||||
_header_to_field_map = {
|
_header_to_field_map = {
|
||||||
'X-M2M-ORIGIN': 'originator',
|
'X-M2M-ORIGIN': 'originator',
|
||||||
@ -59,6 +59,8 @@ _header_to_field_map = {
|
|||||||
'X-M2M-RET': 'rqet',
|
'X-M2M-RET': 'rqet',
|
||||||
'X-M2M-OET': 'oet',
|
'X-M2M-OET': 'oet',
|
||||||
'X-M2M-EC': 'ec',
|
'X-M2M-EC': 'ec',
|
||||||
|
'X-M2M-RVI': 'rvi',
|
||||||
|
'X-M2M-VSI': 'vsi',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -162,11 +164,14 @@ class OneM2MHTTPClient(OneM2MClient):
|
|||||||
content_type += '; ty=' + str(ResourceTypeE[onem2m_request.resource_type.typename])
|
content_type += '; ty=' + str(ResourceTypeE[onem2m_request.resource_type.typename])
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
header: getattr(onem2m_request, field) for header, field in _header_to_field_map.iteritems()
|
header: getattr(onem2m_request, field)
|
||||||
|
for header, field in _header_to_field_map.iteritems()
|
||||||
if getattr(onem2m_request, field) is not None
|
if getattr(onem2m_request, field) is not None
|
||||||
}
|
}
|
||||||
headers['content-type'] = content_type
|
headers['content-type'] = content_type
|
||||||
|
|
||||||
|
headers['accept'] = self.content_type
|
||||||
|
|
||||||
self.logger.debug("Added request params: %s", params)
|
self.logger.debug("Added request params: %s", params)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -83,11 +83,12 @@ class OneM2MMQTTClient(OneM2MClient):
|
|||||||
|
|
||||||
__request_fields = frozenset([
|
__request_fields = frozenset([
|
||||||
'op',
|
'op',
|
||||||
|
'to',
|
||||||
'fr',
|
'fr',
|
||||||
'rqi',
|
'rqi',
|
||||||
'ty',
|
'ty',
|
||||||
'pc',
|
'pc',
|
||||||
'rol',
|
'rids',
|
||||||
'ot',
|
'ot',
|
||||||
'rqet',
|
'rqet',
|
||||||
'rset',
|
'rset',
|
||||||
@ -98,17 +99,28 @@ class OneM2MMQTTClient(OneM2MClient):
|
|||||||
'ec',
|
'ec',
|
||||||
'da',
|
'da',
|
||||||
'gid',
|
'gid',
|
||||||
'drt',
|
|
||||||
'to',
|
|
||||||
'fc',
|
'fc',
|
||||||
|
'drt',
|
||||||
|
'tids',
|
||||||
|
'ltids',
|
||||||
|
'tqi',
|
||||||
|
'rvi',
|
||||||
|
'vsi',
|
||||||
])
|
])
|
||||||
|
|
||||||
__response_fields = frozenset([
|
__response_fields = frozenset([
|
||||||
'rsc',
|
'rsc',
|
||||||
'rqi',
|
'rqi',
|
||||||
'pc',
|
'pc',
|
||||||
'fr',
|
|
||||||
'to',
|
'to',
|
||||||
|
'fr',
|
||||||
|
'ot',
|
||||||
|
'rset',
|
||||||
|
'ec',
|
||||||
|
'cts',
|
||||||
|
'cto',
|
||||||
|
'rvi',
|
||||||
|
'vsi',
|
||||||
])
|
])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -370,7 +382,8 @@ class OneM2MMQTTClient(OneM2MClient):
|
|||||||
sp_id, cse_id, _ = split_onem2m_address(response.to)
|
sp_id, cse_id, _ = split_onem2m_address(response.to)
|
||||||
response.content = self._decode(
|
response.content = self._decode(
|
||||||
encode_onem2m_content(response.content, 'application/json',
|
encode_onem2m_content(response.content, 'application/json',
|
||||||
path=sp_id + cse_id)[1]
|
path=sp_id + cse_id,
|
||||||
|
fields=response.fields)[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
self._publish_message(
|
self._publish_message(
|
||||||
|
@ -13,6 +13,10 @@ STATUS_ACCEPTED = STATUS(
|
|||||||
1000, "ACCEPTED", 202)
|
1000, "ACCEPTED", 202)
|
||||||
STATUS_OK = STATUS(
|
STATUS_OK = STATUS(
|
||||||
2000, "OK", 200)
|
2000, "OK", 200)
|
||||||
|
STATUS_UPDATED = STATUS(
|
||||||
|
2004, "UPDATED", 200)
|
||||||
|
STATUS_DELETED = STATUS(
|
||||||
|
2002, "DELETED", 200)
|
||||||
STATUS_CREATED = STATUS(
|
STATUS_CREATED = STATUS(
|
||||||
2001, "CREATED", 201)
|
2001, "CREATED", 201)
|
||||||
STATUS_BAD_REQUEST = STATUS(
|
STATUS_BAD_REQUEST = STATUS(
|
||||||
|
@ -49,7 +49,8 @@ class OneM2MMapper(BasicMapper):
|
|||||||
path,
|
path,
|
||||||
self.originator,
|
self.originator,
|
||||||
ty=type(instance),
|
ty=type(instance),
|
||||||
pc=instance
|
pc=instance,
|
||||||
|
rvi='2a'
|
||||||
)).get()
|
)).get()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -83,7 +84,8 @@ class OneM2MMapper(BasicMapper):
|
|||||||
OneM2MOperation.update,
|
OneM2MOperation.update,
|
||||||
instance.path,
|
instance.path,
|
||||||
self.originator,
|
self.originator,
|
||||||
pc=instance
|
pc=instance,
|
||||||
|
rvi='2a'
|
||||||
)).get()
|
)).get()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -105,6 +107,8 @@ class OneM2MMapper(BasicMapper):
|
|||||||
path,
|
path,
|
||||||
self.originator,
|
self.originator,
|
||||||
filter_criteria=fc,
|
filter_criteria=fc,
|
||||||
|
rvi='2a',
|
||||||
|
rcn=5,
|
||||||
**request_options
|
**request_options
|
||||||
)).get()
|
)).get()
|
||||||
|
|
||||||
@ -112,7 +116,8 @@ class OneM2MMapper(BasicMapper):
|
|||||||
self._send_request(OneM2MRequest(
|
self._send_request(OneM2MRequest(
|
||||||
OneM2MOperation.delete,
|
OneM2MOperation.delete,
|
||||||
getattr(instance, "path", instance),
|
getattr(instance, "path", instance),
|
||||||
self.originator
|
self.originator,
|
||||||
|
rvi='2a'
|
||||||
))
|
))
|
||||||
|
|
||||||
# TODO(rst): check if this can be removed in parent class
|
# TODO(rst): check if this can be removed in parent class
|
||||||
|
@ -6,7 +6,7 @@ from openmtc.model import (Resource as Res, UnicodeAttribute, DatetimeAttribute,
|
|||||||
from openmtc.model.exc import ModelTypeError
|
from openmtc.model.exc import ModelTypeError
|
||||||
from futile import issubclass
|
from futile import issubclass
|
||||||
|
|
||||||
LATEST_VERSION = "1.6"
|
LATEST_VERSION = "2a"
|
||||||
|
|
||||||
|
|
||||||
class OneM2MIntEnum(IntEnum):
|
class OneM2MIntEnum(IntEnum):
|
||||||
@ -24,7 +24,7 @@ class OneM2MContentResource(ContentResource, OneM2MEntity):
|
|||||||
|
|
||||||
class OneM2MResource(Res, OneM2MEntity):
|
class OneM2MResource(Res, OneM2MEntity):
|
||||||
__model_name__ = "onem2m"
|
__model_name__ = "onem2m"
|
||||||
__model_version__ = "1.6"
|
__model_version__ = "2a"
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
@ -41,8 +41,8 @@ class ResourceTypeE(OneM2MIntEnum):
|
|||||||
eventConfig = 7
|
eventConfig = 7
|
||||||
execInstance = 8
|
execInstance = 8
|
||||||
group = 9
|
group = 9
|
||||||
localPolicy = 10
|
locationPolicy = 10
|
||||||
m2mServiceSubscriptionProfile = 11
|
m2mServiceSubscription = 11
|
||||||
mgmtCmd = 12
|
mgmtCmd = 12
|
||||||
mgmtObj = 13
|
mgmtObj = 13
|
||||||
node = 14
|
node = 14
|
||||||
@ -56,6 +56,16 @@ class ResourceTypeE(OneM2MIntEnum):
|
|||||||
statsConfig = 22
|
statsConfig = 22
|
||||||
subscription = 23
|
subscription = 23
|
||||||
semanticDescriptor = 24
|
semanticDescriptor = 24
|
||||||
|
notificationTargetMgmtPolicyRef = 25
|
||||||
|
notificationTargetPolicy = 26
|
||||||
|
policyDeletionRules = 27
|
||||||
|
flexContainer = 28
|
||||||
|
timeSeries = 29
|
||||||
|
timeSeriesInstance = 30
|
||||||
|
role = 31
|
||||||
|
token = 32
|
||||||
|
trafficPattern = 33
|
||||||
|
dynamicAuthorizationConsultation = 34
|
||||||
accessControlPolicyAnnc = 10001
|
accessControlPolicyAnnc = 10001
|
||||||
AEAnnc = 10002
|
AEAnnc = 10002
|
||||||
containerAnnc = 10003
|
containerAnnc = 10003
|
||||||
@ -66,6 +76,12 @@ class ResourceTypeE(OneM2MIntEnum):
|
|||||||
nodeAnnc = 10014
|
nodeAnnc = 10014
|
||||||
remoteCSEAnnc = 10016
|
remoteCSEAnnc = 10016
|
||||||
scheduleAnnc = 10018
|
scheduleAnnc = 10018
|
||||||
|
semanticDescriptorAnnc = 10024
|
||||||
|
flexContainerAnnc = 10028
|
||||||
|
timeSeriesAnnc = 10029
|
||||||
|
timeSeriesInstanceAnnc = 10030
|
||||||
|
trafficPatternAnnc = 10033
|
||||||
|
dynamicAuthorizationConsultationAnnc = 10034
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
@ -106,15 +122,17 @@ class ResponseType(OneM2MIntEnum):
|
|||||||
|
|
||||||
|
|
||||||
# @unique
|
# @unique
|
||||||
# class ResultConentE(OneM2MIntEnum):
|
class ResultContentE(OneM2MIntEnum):
|
||||||
# nothing = 0
|
nothing = 0
|
||||||
# attributes = 1
|
attributes = 1
|
||||||
# hierarchical_address = 2
|
hierarchical_address = 2
|
||||||
# hierarchical_address_and_attributes = 3
|
hierarchical_address_and_attributes = 3
|
||||||
# attributes_and_child_resources = 4
|
attributes_and_child_resources = 4
|
||||||
# attributes_and_child_resource_references = 6
|
attributes_and_child_resource_references = 5
|
||||||
# child_resource_references = 6
|
child_resource_references = 6
|
||||||
# original_resource = 7
|
original_resource = 7
|
||||||
|
child_resources = 8
|
||||||
|
modified_attributes = 9
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
@ -136,6 +154,7 @@ class RequestStatusE(OneM2MIntEnum):
|
|||||||
|
|
||||||
@unique
|
@unique
|
||||||
class MemberTypeE(OneM2MIntEnum):
|
class MemberTypeE(OneM2MIntEnum):
|
||||||
|
mixed = 0
|
||||||
accessControlPolicy = 1
|
accessControlPolicy = 1
|
||||||
AE = 2
|
AE = 2
|
||||||
container = 3
|
container = 3
|
||||||
@ -159,7 +178,16 @@ class MemberTypeE(OneM2MIntEnum):
|
|||||||
statsCollect = 21
|
statsCollect = 21
|
||||||
statsConfig = 22
|
statsConfig = 22
|
||||||
subscription = 23
|
subscription = 23
|
||||||
|
semanticDescriptor = 24
|
||||||
|
notificationTargetMgmtPolicyRef = 25
|
||||||
|
notificationTargetPolicy = 26
|
||||||
|
policyDeletionRules = 27
|
||||||
|
flexContainer = 28
|
||||||
|
timeSeries = 29
|
||||||
|
timeSeriesInstance = 30
|
||||||
|
role = 31
|
||||||
token = 32
|
token = 32
|
||||||
|
trafficPattern = 33
|
||||||
dynamicAuthorizationConsultation = 34
|
dynamicAuthorizationConsultation = 34
|
||||||
accessControlPolicyAnnc = 10001
|
accessControlPolicyAnnc = 10001
|
||||||
AEAnnc = 10002
|
AEAnnc = 10002
|
||||||
@ -170,11 +198,15 @@ class MemberTypeE(OneM2MIntEnum):
|
|||||||
mgmtObjAnnc = 10013
|
mgmtObjAnnc = 10013
|
||||||
nodeAnnc = 10014
|
nodeAnnc = 10014
|
||||||
remoteCSEAnnc = 10016
|
remoteCSEAnnc = 10016
|
||||||
scheduleAnnc = 10019
|
scheduleAnnc = 10018
|
||||||
|
semanticDescriptorAnnc = 10024
|
||||||
|
flexContainerAnnc = 10028
|
||||||
|
timeSeriesAnnc = 10029
|
||||||
|
timeSeriesInstanceAnnc = 10030
|
||||||
|
trafficPatternAnnc = 10033
|
||||||
dynamicAuthorizationConsultationAnnc = 10034
|
dynamicAuthorizationConsultationAnnc = 10034
|
||||||
mixed = 24
|
oldest = 20001
|
||||||
# Mixed is a mixture of the resource types from 1 to 23, 10001 to 10004, 10009 to 10010,
|
latest = 20002
|
||||||
# 10013 to 10014 and 10016 to 10018 as listed above.
|
|
||||||
|
|
||||||
|
|
||||||
@unique
|
@unique
|
||||||
@ -952,7 +984,7 @@ class ContentInstance(AnnounceableSubordinateResourceC,
|
|||||||
SubscribableResource):
|
SubscribableResource):
|
||||||
"""See TS-0001 section 9.6.7"""
|
"""See TS-0001 section 9.6.7"""
|
||||||
|
|
||||||
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
|
stateTag = Attribute(int, accesstype=Attribute.RO)
|
||||||
creator = UnicodeAttribute() # m2m:ID
|
creator = UnicodeAttribute() # m2m:ID
|
||||||
# contentInfo = typeOfContent(:EncodingType)
|
# contentInfo = typeOfContent(:EncodingType)
|
||||||
# typeOfContent => Media Types
|
# typeOfContent => Media Types
|
||||||
@ -969,7 +1001,7 @@ class ContentInstance(AnnounceableSubordinateResourceC,
|
|||||||
|
|
||||||
|
|
||||||
class ContentInstanceAnnc(AnnouncedSubordinateResourceC):
|
class ContentInstanceAnnc(AnnouncedSubordinateResourceC):
|
||||||
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
|
stateTag = Attribute(int, accesstype=Attribute.RO)
|
||||||
contentInfo = UnicodeAttribute(EncodingTypeE) # m2m:contentInfo
|
contentInfo = UnicodeAttribute(EncodingTypeE) # m2m:contentInfo
|
||||||
contentSize = Attribute(int, accesstype=Attribute.WO)
|
contentSize = Attribute(int, accesstype=Attribute.WO)
|
||||||
ontologyRef = UnicodeAttribute(accesstype=Attribute.WO)
|
ontologyRef = UnicodeAttribute(accesstype=Attribute.WO)
|
||||||
@ -983,7 +1015,7 @@ class ContentInstanceAnnc(AnnouncedSubordinateResourceC):
|
|||||||
class Container(AnnounceableResourceC, SubscribableResource):
|
class Container(AnnounceableResourceC, SubscribableResource):
|
||||||
"""See TS-0001 section 9.6.6"""
|
"""See TS-0001 section 9.6.6"""
|
||||||
|
|
||||||
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
|
stateTag = Attribute(int, accesstype=Attribute.RO)
|
||||||
creator = UnicodeAttribute()
|
creator = UnicodeAttribute()
|
||||||
maxNrOfInstances = Attribute(int)
|
maxNrOfInstances = Attribute(int)
|
||||||
maxByteSize = Attribute(int)
|
maxByteSize = Attribute(int)
|
||||||
@ -1012,7 +1044,7 @@ Container.__child_types__ = (
|
|||||||
|
|
||||||
class ContainerAnnc(AnnouncedResourceC, SubscribableResource):
|
class ContainerAnnc(AnnouncedResourceC, SubscribableResource):
|
||||||
|
|
||||||
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
|
stateTag = Attribute(int, accesstype=Attribute.RO)
|
||||||
maxNrOfInstances = Attribute(int)
|
maxNrOfInstances = Attribute(int)
|
||||||
maxByteSize = Attribute(int)
|
maxByteSize = Attribute(int)
|
||||||
maxInstanceAge = UnicodeAttribute(mandatory=False) # todo
|
maxInstanceAge = UnicodeAttribute(mandatory=False) # todo
|
||||||
|
@ -49,7 +49,7 @@ class OneM2MSerializer(LoggerMixin):
|
|||||||
except (TypeError, AttributeError, KeyError, ValueError):
|
except (TypeError, AttributeError, KeyError, ValueError):
|
||||||
raise CSEValueError("Invalid entry in child resources: %s",
|
raise CSEValueError("Invalid entry in child resources: %s",
|
||||||
child_resource)
|
child_resource)
|
||||||
if resource_type is Notification and "notificationEvent" in data:
|
if resource_type is Notification and data.get("notificationEvent"):
|
||||||
representation = data["notificationEvent"]["representation"]
|
representation = data["notificationEvent"]["representation"]
|
||||||
representation = self.decode(self.dumps(representation))
|
representation = self.decode(self.dumps(representation))
|
||||||
data["notificationEvent"]["representation"] = representation
|
data["notificationEvent"]["representation"] = representation
|
||||||
@ -62,7 +62,10 @@ class OneM2MSerializer(LoggerMixin):
|
|||||||
class OneM2MDictSerializer(OneM2MSerializer):
|
class OneM2MDictSerializer(OneM2MSerializer):
|
||||||
def encode_resource(self, resource, pretty=False, path=None, encoding="utf-8", fields=None,
|
def encode_resource(self, resource, pretty=False, path=None, encoding="utf-8", fields=None,
|
||||||
encapsulated=False):
|
encapsulated=False):
|
||||||
representation = resource.values
|
if fields and isinstance(resource, OneM2MResource):
|
||||||
|
representation = {k: v for k, v in resource.values.items() if fields and k in fields}
|
||||||
|
else:
|
||||||
|
representation = resource.values
|
||||||
|
|
||||||
self.logger.debug("Encoding representation: %s", representation)
|
self.logger.debug("Encoding representation: %s", representation)
|
||||||
|
|
||||||
@ -93,7 +96,7 @@ class OneM2MDictSerializer(OneM2MSerializer):
|
|||||||
return resource_id
|
return resource_id
|
||||||
return val_path + resource_id
|
return val_path + resource_id
|
||||||
|
|
||||||
if isinstance(resource, OneM2MResource):
|
if isinstance(resource, OneM2MResource) and "childResource" in representation:
|
||||||
|
|
||||||
def get_child_rep(c):
|
def get_child_rep(c):
|
||||||
return {
|
return {
|
||||||
@ -112,53 +115,12 @@ class OneM2MDictSerializer(OneM2MSerializer):
|
|||||||
if isinstance(resource.oldest, ContentInstance):
|
if isinstance(resource.oldest, ContentInstance):
|
||||||
representation['oldest'] = resource.oldest.resourceID
|
representation['oldest'] = resource.oldest.resourceID
|
||||||
|
|
||||||
# cleans representation
|
|
||||||
def clean_representation(o):
|
|
||||||
try:
|
|
||||||
# removes empty attributes
|
|
||||||
empty_keys = []
|
|
||||||
for k, v in o.items():
|
|
||||||
if v is None:
|
|
||||||
empty_keys.append(k)
|
|
||||||
elif isinstance(v, OneM2MEntity):
|
|
||||||
o[k] = self.encode_resource(v, pretty, path, encoding, fields)
|
|
||||||
elif isinstance(v, list):
|
|
||||||
|
|
||||||
def encode_list_item(item):
|
|
||||||
if isinstance(item, OneM2MEntity):
|
|
||||||
return self.encode_resource(item, pretty, path, encoding, fields)
|
|
||||||
return item
|
|
||||||
if len(v):
|
|
||||||
o[k] = map(encode_list_item, v)
|
|
||||||
else:
|
|
||||||
empty_keys.append(k)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
if len(v) == 0:
|
|
||||||
empty_keys.append(k)
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for k in empty_keys:
|
|
||||||
del o[k]
|
|
||||||
|
|
||||||
for k, v in o.items():
|
|
||||||
if not isinstance(v, (unicode, str, bool, datetime,
|
|
||||||
OneM2MIntEnum)):
|
|
||||||
clean_representation(v)
|
|
||||||
except AttributeError:
|
|
||||||
if isinstance(o, list):
|
|
||||||
for p in o:
|
|
||||||
clean_representation(p)
|
|
||||||
|
|
||||||
if not isinstance(resource, OneM2MContentResource):
|
if not isinstance(resource, OneM2MContentResource):
|
||||||
representation = {
|
representation = {
|
||||||
get_short_resource_name(k) or get_short_attribute_name(k) or
|
get_short_resource_name(k) or get_short_attribute_name(k) or
|
||||||
get_short_member_name(k): v for
|
get_short_member_name(k): v for
|
||||||
k, v in representation.items()}
|
k, v in representation.items()}
|
||||||
|
|
||||||
clean_representation(representation)
|
|
||||||
|
|
||||||
if not isinstance(resource, (OneM2MResource, Notification,
|
if not isinstance(resource, (OneM2MResource, Notification,
|
||||||
SecurityInfo, OneM2MContentResource)):
|
SecurityInfo, OneM2MContentResource)):
|
||||||
return representation
|
return representation
|
||||||
|
@ -30,12 +30,7 @@ del logger
|
|||||||
|
|
||||||
def _default(x):
|
def _default(x):
|
||||||
if isinstance(x, datetime):
|
if isinstance(x, datetime):
|
||||||
try:
|
return x.strftime("%Y%m%dT%H%M%S")
|
||||||
isoformat = x.isoformat
|
|
||||||
except AttributeError:
|
|
||||||
raise TypeError("%s (%s)" % (x, type(x)))
|
|
||||||
|
|
||||||
return isoformat()
|
|
||||||
elif isinstance(x, ContentInstance):
|
elif isinstance(x, ContentInstance):
|
||||||
return x.resourceID
|
return x.resourceID
|
||||||
else:
|
else:
|
||||||
|
@ -27,9 +27,6 @@ def encode_onem2m_content(content, content_type, pretty=False, path=None,
|
|||||||
if content is None:
|
if content is None:
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
fields = fields # TODO(rst): maybe necessary
|
|
||||||
# fields = ["resourceID"]
|
|
||||||
|
|
||||||
serializer = get_onem2m_encoder(content_type)
|
serializer = get_onem2m_encoder(content_type)
|
||||||
|
|
||||||
data = serializer.encode_resource(content, pretty=pretty, path=path,
|
data = serializer.encode_resource(content, pretty=pretty, path=path,
|
||||||
|
@ -201,10 +201,11 @@ class OneM2MRequest(object):
|
|||||||
|
|
||||||
"""Class representing a OneM2M request"""
|
"""Class representing a OneM2M request"""
|
||||||
|
|
||||||
def __init__(self, op, to, fr=None, rqi=None, ty=None, pc=None, rol=None,
|
def __init__(self, op, to, fr=None, rqi=None, ty=None, pc=None, rids=None,
|
||||||
ot=None, rqet=None, rset=None, oet=None, rt=None, rp=None,
|
ot=None, rqet=None, rset=None, oet=None, rt=None, rp=None,
|
||||||
rcn=None, ec=None, da=None, gid=None, filter_criteria=None,
|
rcn=None, ec=None, da=None, gid=None, filter_criteria=None,
|
||||||
fc=None, drt=None):
|
fc=None, drt=None, tids=None, ltids=None, tqi=None, rvi=None,
|
||||||
|
vsi=None):
|
||||||
# Operation
|
# Operation
|
||||||
self.operation = op
|
self.operation = op
|
||||||
# Target uri
|
# Target uri
|
||||||
@ -216,7 +217,7 @@ class OneM2MRequest(object):
|
|||||||
self.resource_type = ty
|
self.resource_type = ty
|
||||||
# Resource content to be transferred.
|
# Resource content to be transferred.
|
||||||
self.content = pc
|
self.content = pc
|
||||||
self.role = rol
|
self.role_ids = rids
|
||||||
self.originating_timestamp = ot
|
self.originating_timestamp = ot
|
||||||
self.request_expiration_timestamp = rqet
|
self.request_expiration_timestamp = rqet
|
||||||
self.result_expiration_timestamp = rset
|
self.result_expiration_timestamp = rset
|
||||||
@ -230,6 +231,11 @@ class OneM2MRequest(object):
|
|||||||
self.filter_criteria = filter_criteria or fc
|
self.filter_criteria = filter_criteria or fc
|
||||||
# Optional Discovery result type
|
# Optional Discovery result type
|
||||||
self.discovery_result_type = drt
|
self.discovery_result_type = drt
|
||||||
|
self.token_ids = tids
|
||||||
|
self.local_token_ids = ltids
|
||||||
|
self.token_request_identifier = tqi
|
||||||
|
self.release_version_indicator = rvi
|
||||||
|
self.vendor_information = vsi
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def op(self):
|
def op(self):
|
||||||
@ -272,12 +278,12 @@ class OneM2MRequest(object):
|
|||||||
self.content = pc
|
self.content = pc
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rol(self):
|
def rids(self):
|
||||||
return self.role
|
return self.role_ids
|
||||||
|
|
||||||
@rol.setter
|
@rids.setter
|
||||||
def rol(self, rol):
|
def rids(self, rids):
|
||||||
self.role = rol
|
self.role_ids = rids
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ot(self):
|
def ot(self):
|
||||||
@ -375,6 +381,46 @@ class OneM2MRequest(object):
|
|||||||
def drt(self, drt):
|
def drt(self, drt):
|
||||||
self.discovery_result_type = drt
|
self.discovery_result_type = drt
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tids(self):
|
||||||
|
return self.token_ids
|
||||||
|
|
||||||
|
@tids.setter
|
||||||
|
def tids(self, tids):
|
||||||
|
self.token_ids = tids
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ltids(self):
|
||||||
|
return self.local_token_ids
|
||||||
|
|
||||||
|
@ltids.setter
|
||||||
|
def ltids(self, rvi):
|
||||||
|
self.local_token_ids = ltids
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tqi(self):
|
||||||
|
return self.token_request_identifier
|
||||||
|
|
||||||
|
@tqi.setter
|
||||||
|
def tqi(self, tqi):
|
||||||
|
self.token_request_identifier = tqi
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rvi(self):
|
||||||
|
return self.release_version_indicator
|
||||||
|
|
||||||
|
@rvi.setter
|
||||||
|
def rvi(self, rvi):
|
||||||
|
self.release_version_indicator = rvi
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vsi(self):
|
||||||
|
return self.vendor_information
|
||||||
|
|
||||||
|
@vsi.setter
|
||||||
|
def vsi(self, vsi):
|
||||||
|
self.vendor_information = vsi
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s: %s' % (self.__class__.__name__, ' | '.join([
|
return '%s: %s' % (self.__class__.__name__, ' | '.join([
|
||||||
'%s: %s' % (str(k), str(v)) for k, v in self.__dict__.iteritems()
|
'%s: %s' % (str(k), str(v)) for k, v in self.__dict__.iteritems()
|
||||||
@ -385,7 +431,8 @@ class OneM2MResponse(object):
|
|||||||
"""Class representing a OneM2M response"""
|
"""Class representing a OneM2M response"""
|
||||||
|
|
||||||
def __init__(self, status_code, request=None, rqi=None, pc=None, to=None,
|
def __init__(self, status_code, request=None, rqi=None, pc=None, to=None,
|
||||||
fr=None, rsc=None):
|
fr=None, rsc=None, ot=None, rset=None, ec=None, cts=None,
|
||||||
|
cto=None, rvi=None, vsi=None, fields=None):
|
||||||
# Operation result
|
# Operation result
|
||||||
if isinstance(status_code, STATUS):
|
if isinstance(status_code, STATUS):
|
||||||
self.response_status_code = status_code
|
self.response_status_code = status_code
|
||||||
@ -397,14 +444,27 @@ class OneM2MResponse(object):
|
|||||||
self.to = request.to
|
self.to = request.to
|
||||||
# Originator ID
|
# Originator ID
|
||||||
self.originator = request.fr
|
self.originator = request.fr
|
||||||
|
self.originating_timestamp = request.ot
|
||||||
|
self.result_expiration_timestamp = request.rset
|
||||||
|
self.event_category = request.ec
|
||||||
|
self.release_version_indicator = request.rvi
|
||||||
|
self.vendor_information = request.vsi
|
||||||
else:
|
else:
|
||||||
self.request_identifier = rqi
|
self.request_identifier = rqi
|
||||||
# Target uri
|
# Target uri
|
||||||
self.to = to
|
self.to = to
|
||||||
# Originator ID
|
# Originator ID
|
||||||
self.originator = fr
|
self.originator = fr
|
||||||
|
self.originating_timestamp = ot
|
||||||
|
self.release_version_indicator = rvi
|
||||||
|
self.vendor_information = vsi
|
||||||
|
self.result_expiration_timestamp = rset
|
||||||
|
self.event_category = ec
|
||||||
# Resource content to be transferred.
|
# Resource content to be transferred.
|
||||||
self.content = pc
|
self.content = pc
|
||||||
|
self.content_status = cts
|
||||||
|
self.content_offset = cto
|
||||||
|
self.fields = fields
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status_code(self):
|
def status_code(self):
|
||||||
@ -438,6 +498,62 @@ class OneM2MResponse(object):
|
|||||||
def fr(self, fr):
|
def fr(self, fr):
|
||||||
self.originator = fr
|
self.originator = fr
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ot(self):
|
||||||
|
return self.originating_timestamp
|
||||||
|
|
||||||
|
@ot.setter
|
||||||
|
def ot(self, ot):
|
||||||
|
self.originating_timestamp = ot
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rset(self):
|
||||||
|
return self.result_expiration_timestamp
|
||||||
|
|
||||||
|
@rset.setter
|
||||||
|
def rset(self, rset):
|
||||||
|
self.result_expiration_timestamp = rset
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ec(self):
|
||||||
|
return self.event_category
|
||||||
|
|
||||||
|
@ec.setter
|
||||||
|
def ec(self, ec):
|
||||||
|
self.event_category = ec
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cts(self):
|
||||||
|
return self.content_status
|
||||||
|
|
||||||
|
@cts.setter
|
||||||
|
def cts(self, cts):
|
||||||
|
self.content_status = cts
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cto(self):
|
||||||
|
return self.content_offset
|
||||||
|
|
||||||
|
@cto.setter
|
||||||
|
def cto(self, cto):
|
||||||
|
self.content_offset = cto
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rvi(self):
|
||||||
|
return self.release_version_indicator
|
||||||
|
|
||||||
|
@rvi.setter
|
||||||
|
def rvi(self, rvi):
|
||||||
|
self.release_version_indicator = rvi
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vsi(self):
|
||||||
|
return self.vendor_information
|
||||||
|
|
||||||
|
@vsi.setter
|
||||||
|
def vsi(self, vsi):
|
||||||
|
self.vendor_information = vsi
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s: %s' % (self.__class__.__name__, ' | '.join([
|
return '%s: %s' % (self.__class__.__name__, ' | '.join([
|
||||||
'%s: %s' % (str(k), str(v)) for k, v in self.__dict__.iteritems()
|
'%s: %s' % (str(k), str(v)) for k, v in self.__dict__.iteritems()
|
||||||
|
9
doc/index.md
Normal file
9
doc/index.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Open MTC IoT Agent
|
||||||
|
|
||||||
|
[![FIWARE IoT Agents](https://nexus.lab.fiware.org/repository/raw/public/badges/chapters/iot-agents.svg)](https://www.fiware.org/developers/catalogue/)
|
||||||
|
[![](https://nexus.lab.fiware.org/repository/raw/public/badges/stackoverflow/iot-agents.svg)](https://stackoverflow.com/questions/tagged/fiware+iot)
|
||||||
|
|
||||||
|
The OpenMTC SDK aims to provide developers with a convenient yet flexible tool
|
||||||
|
to write oneM2M compliant applications. This includes network applications
|
||||||
|
(NAs), gateway application (GAs), device applications (DAs), as well as
|
||||||
|
interworking proxy entities (IPEs).
|
@ -2,7 +2,7 @@
|
|||||||
Interworking Proxy for Cul868 devices.
|
Interworking Proxy for Cul868 devices.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = "1.1.0"
|
__version__ = "1.2.0"
|
||||||
__description__ = "The OpenMTC Cul868IPE"
|
__description__ = "The OpenMTC Cul868IPE"
|
||||||
__author_name__ = "Ronny Kreuch"
|
__author_name__ = "Ronny Kreuch"
|
||||||
__author_mail__ = "ronny.kreuch@fokus.fraunhofer.de"
|
__author_mail__ = "ronny.kreuch@fokus.fraunhofer.de"
|
||||||
|
52
mkdocs.yml
Normal file
52
mkdocs.yml
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
site_name: Open MTC
|
||||||
|
site_url: https://github.com/OpenMTC/OpenMTC
|
||||||
|
repo_url: https://github.com/OpenMTC/OpenMTC.git
|
||||||
|
site_description: FIWARE Open MTC IoT Agent document site
|
||||||
|
docs_dir: doc/
|
||||||
|
site_dir: html
|
||||||
|
markdown_extensions: [toc,tables, fenced_code]
|
||||||
|
use_directory_urls: false
|
||||||
|
theme: readthedocs
|
||||||
|
extra_css: ["https://fiware.org/style/fiware_readthedocs.css", "https://fiware.org/style/fiware_readthedocs_iot.css"]
|
||||||
|
pages:
|
||||||
|
- Home: index.md
|
||||||
|
- 'User & Programmers Manual':
|
||||||
|
- Introduction: introduction.md
|
||||||
|
- Quick Start: openmtc-get-started.md
|
||||||
|
- The MQTT Client: onem2m-client-mqtt.md
|
||||||
|
- Authentication Guide: authentication.md
|
||||||
|
- Overview REST API: overview-rest-api.md
|
||||||
|
- Write your first OpenMTC applications: training/training-index.md
|
||||||
|
- Console Outputs:
|
||||||
|
- Sensor Backend: training/console-outputs/training-sensor-backend.md
|
||||||
|
- Sensor Gateway: training/console-outputs/training-sensor-gateway.md
|
||||||
|
- Sensor IPE: training/console-outputs/training-sensor-ipe.md
|
||||||
|
- Sensor GUI: training/console-outputs/training-sensor-gui.md
|
||||||
|
- Sensor Actuator Backend: training/console-outputs/training-sensor-actuator-backend.md
|
||||||
|
- Sensor Actuator Gateway: training/console-outputs/training-sensor-actuator-gateway.md
|
||||||
|
- Sensor Actuator IPE: training/console-outputs/training-sensor-actuator-ipe.md
|
||||||
|
- Sensor Actuator GUI: training/console-outputs/training-sensor-actuator-gui.md
|
||||||
|
- Training:
|
||||||
|
- IPE Sensors: training/training-ipe-sensors.md
|
||||||
|
- IPE Sensors Actuators: training/training-ipe-sensors-actuators.md
|
||||||
|
- GUI Sensors: training/training-gui-sensors.md
|
||||||
|
- GUI Sensors Actuators: training/training-gui-sensors-actuators.md
|
||||||
|
- SDK - Using the Application Framework: sdk-framework.md
|
||||||
|
- SDK - The low-level CSE Client: sdk-client.md
|
||||||
|
- SDK - The Data Model: sdk-datamodel.md
|
||||||
|
- Examples:
|
||||||
|
- IoT Data Visualization: example-apps/IoT-data-visualization.py
|
||||||
|
- Data Aggregation: example-apps/data-aggregation.py
|
||||||
|
- Simple Decision: example-apps/simple-decision.py
|
||||||
|
- Simple Decision 2: example-apps/simple-decision-2.py
|
||||||
|
- Scripts:
|
||||||
|
- Create App Structure Script: create-app-structure.md
|
||||||
|
- Create binary docker images Script: create-binary-docker.md
|
||||||
|
- Code Repository Structure: repository-structure.md
|
||||||
|
- Developer FAQ: developer-faq.md
|
||||||
|
- 'Installation & Administration Manual':
|
||||||
|
- Deployment: deployment-guide.md
|
||||||
|
- Installation of the OpenMTC SDK: install-sdk.md
|
||||||
|
- Appendix : various.md
|
||||||
|
- Resource Names & Types : reference-doc/resource-names-and-types.md
|
||||||
|
- Gateway & Backend Configuration : reference-doc/gateway-and-backend-configuration.md
|
@ -205,8 +205,9 @@ class MqttNotificationHandler(BaseNotificationHandler):
|
|||||||
from openmtc_onem2m.exc import get_response_status
|
from openmtc_onem2m.exc import get_response_status
|
||||||
|
|
||||||
def wrapper(request):
|
def wrapper(request):
|
||||||
notification = self._unpack_notification(request.content)
|
if not request.content.verificationRequest:
|
||||||
self._callback(request.originator, **notification)
|
notification = self._unpack_notification(request.content)
|
||||||
|
self._callback(request.originator, **notification)
|
||||||
return OneM2MResponse(status_code=get_response_status(2000), request=request)
|
return OneM2MResponse(status_code=get_response_status(2000), request=request)
|
||||||
|
|
||||||
self._client = get_client(self._endpoint.geturl(), handle_request_func=wrapper)
|
self._client = get_client(self._endpoint.geturl(), handle_request_func=wrapper)
|
||||||
@ -255,9 +256,17 @@ class HttpNotificationHandler(BaseNotificationHandler):
|
|||||||
assert 'x-m2m-ri' in request.headers, 'Missing request id'
|
assert 'x-m2m-ri' in request.headers, 'Missing request id'
|
||||||
assert 'content-type' in request.headers, 'Unspecified content type'
|
assert 'content-type' in request.headers, 'Unspecified content type'
|
||||||
|
|
||||||
|
if not request.data:
|
||||||
|
if request.environ.get('HTTP_TRANSFER_ENCODING') == 'chunked':
|
||||||
|
request.data = request.environ['wsgi.input'].read()
|
||||||
|
else:
|
||||||
|
cl = int(request.environ.get('CONTENT_LENGTH'), 0)
|
||||||
|
request.data = request.environ['wsgi.input'].read(cl)
|
||||||
|
|
||||||
notification = get_onem2m_decoder(request.content_type).decode(request.data)
|
notification = get_onem2m_decoder(request.content_type).decode(request.data)
|
||||||
notification = self._unpack_notification(notification)
|
if not notification.verificationRequest:
|
||||||
self._callback(request.headers['x-m2m-origin'], **notification)
|
notification = self._unpack_notification(notification)
|
||||||
|
self._callback(request.headers['x-m2m-origin'], **notification)
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
headers={
|
headers={
|
||||||
|
@ -547,7 +547,7 @@ class XAE(LoggerMixin):
|
|||||||
"""
|
"""
|
||||||
return self._get_content_from_cin(
|
return self._get_content_from_cin(
|
||||||
self.mapper.get(
|
self.mapper.get(
|
||||||
getattr(container, 'path', container) + '/latest'
|
getattr(container, 'path', container) + '/la'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -851,7 +851,7 @@ class ResourceManagementXAE(XAE):
|
|||||||
self._discovered_sensors[sensor_path]['blacklisted'] = True
|
self._discovered_sensors[sensor_path]['blacklisted'] = True
|
||||||
|
|
||||||
def _handle_new_sensor(self, sensor_path):
|
def _handle_new_sensor(self, sensor_path):
|
||||||
latest = self.get_resource(sensor_path + '/latest')
|
latest = self.get_resource(sensor_path + '/la')
|
||||||
if latest:
|
if latest:
|
||||||
spawn(self._handle_sensor_data, sensor_path, self._get_content_from_cin(latest))
|
spawn(self._handle_sensor_data, sensor_path, self._get_content_from_cin(latest))
|
||||||
|
|
||||||
|
@ -13,6 +13,12 @@ from openmtc_server.exc import ConfigurationError
|
|||||||
from openmtc_server.util import log_error
|
from openmtc_server.util import log_error
|
||||||
|
|
||||||
|
|
||||||
|
container_virtual_mapping = {
|
||||||
|
'la': 'latest',
|
||||||
|
'ol': 'oldest'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class OneM2MMethodDomain(Component):
|
class OneM2MMethodDomain(Component):
|
||||||
def __init__(self, config, *args, **kw):
|
def __init__(self, config, *args, **kw):
|
||||||
super(OneM2MMethodDomain, self).__init__(*args, **kw)
|
super(OneM2MMethodDomain, self).__init__(*args, **kw)
|
||||||
@ -209,11 +215,11 @@ class OneM2MMethodDomain(Component):
|
|||||||
# oldest, latest -> Container
|
# oldest, latest -> Container
|
||||||
# TODO(rst): fanOutPoint -> group
|
# TODO(rst): fanOutPoint -> group
|
||||||
# TODO(rst): pollingChannelURI -> pollingChannel
|
# TODO(rst): pollingChannelURI -> pollingChannel
|
||||||
if path.endswith(('latest', 'oldest')):
|
if path.endswith(tuple(container_virtual_mapping.keys())):
|
||||||
parent_path, virtual = path.rsplit('/', 1)
|
parent_path, virtual = path.rsplit('/', 1)
|
||||||
parent = get_resource(parent_path)
|
parent = get_resource(parent_path)
|
||||||
if isinstance(parent, model.Container):
|
if isinstance(parent, model.Container):
|
||||||
resource = getattr(parent, virtual)
|
resource = getattr(parent, container_virtual_mapping[virtual])
|
||||||
if resource is None:
|
if resource is None:
|
||||||
raise CSENotFound()
|
raise CSENotFound()
|
||||||
return resource
|
return resource
|
||||||
|
@ -22,14 +22,16 @@ from openmtc_onem2m.exc import (CSEOperationNotAllowed, STATUS_OK, CSETypeError,
|
|||||||
CSEMissingValue, CSEValueError, STATUS_CREATED,
|
CSEMissingValue, CSEValueError, STATUS_CREATED,
|
||||||
CSEError, CSESyntaxError, CSEBadRequest,
|
CSEError, CSESyntaxError, CSEBadRequest,
|
||||||
CSEPermissionDenied, STATUS_NOT_FOUND, CSEConflict,
|
CSEPermissionDenied, STATUS_NOT_FOUND, CSEConflict,
|
||||||
CSEContentsUnacceptable, CSETargetNotReachable)
|
CSEContentsUnacceptable, CSETargetNotReachable,
|
||||||
|
STATUS_UPDATED, STATUS_DELETED)
|
||||||
from openmtc_onem2m.model import (ExpiringResource, Notification,
|
from openmtc_onem2m.model import (ExpiringResource, Notification,
|
||||||
AccessControlOperationE, ResourceTypeE,
|
AccessControlOperationE, ResourceTypeE,
|
||||||
NotificationContentTypeE, FilterUsageE,
|
NotificationContentTypeE, FilterUsageE,
|
||||||
get_short_resource_name, URIList,
|
get_short_resource_name, URIList,
|
||||||
DiscResTypeE, Container, AccessControlPolicy,
|
DiscResTypeE, Container, AccessControlPolicy,
|
||||||
AccessControlPolicyIDHolder, AccessControlRuleC,
|
AccessControlPolicyIDHolder, AccessControlRuleC,
|
||||||
DynAuthDasRequestC, SecurityInfo, SecurityInfoTypeE, AE)
|
DynAuthDasRequestC, SecurityInfo, SecurityInfoTypeE,
|
||||||
|
AE, ResultContentE, ContentInstance)
|
||||||
from openmtc_onem2m.transport import (OneM2MResponse, OneM2MRequest,
|
from openmtc_onem2m.transport import (OneM2MResponse, OneM2MRequest,
|
||||||
OneM2MOperation, OneM2MErrorResponse)
|
OneM2MOperation, OneM2MErrorResponse)
|
||||||
from openmtc_onem2m.util import split_onem2m_address
|
from openmtc_onem2m.util import split_onem2m_address
|
||||||
@ -51,9 +53,22 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
def __init__(self, db_session, resource_type, handle_onem2m_request):
|
def __init__(self, db_session, resource_type, handle_onem2m_request):
|
||||||
super(OneM2MDefaultController, self).__init__()
|
super(OneM2MDefaultController, self).__init__()
|
||||||
self.resource_type = resource_type
|
self.resource_type = resource_type
|
||||||
self.db_session = db_session
|
|
||||||
self.handle_onem2m_request = handle_onem2m_request
|
self.handle_onem2m_request = handle_onem2m_request
|
||||||
|
|
||||||
|
# DB wrapper
|
||||||
|
|
||||||
|
def _update(resource, fields=None):
|
||||||
|
if isinstance(resource, (Container, ContentInstance)):
|
||||||
|
resource.stateTag += 1
|
||||||
|
return db_session.update(resource, fields)
|
||||||
|
self._create = db_session.store
|
||||||
|
self._get = db_session.get
|
||||||
|
self._update = _update
|
||||||
|
self._delete = db_session.delete
|
||||||
|
self._get_collection = db_session.get_collection
|
||||||
|
self._get_latest_content_instance = db_session.get_latest_content_instance
|
||||||
|
self._get_oldest_content_instance = db_session.get_oldest_content_instance
|
||||||
|
|
||||||
def __call__(self, request, target_resource):
|
def __call__(self, request, target_resource):
|
||||||
self.logger.debug("%s servicing request", type(self).__name__)
|
self.logger.debug("%s servicing request", type(self).__name__)
|
||||||
|
|
||||||
@ -91,6 +106,10 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
self._dynamic_authorization_supported = dynamic_authorization.get('enabled', False)
|
self._dynamic_authorization_supported = dynamic_authorization.get('enabled', False)
|
||||||
self._dynamic_authorization_poa = dynamic_authorization.get('poa', [])
|
self._dynamic_authorization_poa = dynamic_authorization.get('poa', [])
|
||||||
|
|
||||||
|
# release version indicator
|
||||||
|
if not self.request.rvi:
|
||||||
|
self.request.rvi = '2a'
|
||||||
|
|
||||||
return self._handle_request()
|
return self._handle_request()
|
||||||
|
|
||||||
def _handle_request(self):
|
def _handle_request(self):
|
||||||
@ -200,7 +219,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
self._check_privileges(parent)
|
self._check_privileges(parent)
|
||||||
|
|
||||||
def _get_parent_of_resource(self, resource):
|
def _get_parent_of_resource(self, resource):
|
||||||
return self.db_session.get(resource.parentID)
|
return self._get(resource.parentID)
|
||||||
|
|
||||||
def _check_privileges(self, resource):
|
def _check_privileges(self, resource):
|
||||||
# get all ACPs
|
# get all ACPs
|
||||||
@ -374,7 +393,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
try:
|
try:
|
||||||
for dac_id in resource.dynamicAuthorizationConsultationIDs:
|
for dac_id in resource.dynamicAuthorizationConsultationIDs:
|
||||||
try:
|
try:
|
||||||
dac = self.db_session.get(dac_id)
|
dac = self._get(dac_id)
|
||||||
if dac.dynamicAuthorizationEnabled:
|
if dac.dynamicAuthorizationEnabled:
|
||||||
return dac
|
return dac
|
||||||
except DBNotFound:
|
except DBNotFound:
|
||||||
@ -384,7 +403,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return self._get_dynamic_authorization_consultation(self.db_session.get(pid))
|
return self._get_dynamic_authorization_consultation(self._get(pid))
|
||||||
|
|
||||||
def _create_dynamic_policy(self, resource, acp_info):
|
def _create_dynamic_policy(self, resource, acp_info):
|
||||||
acp = AccessControlPolicy(
|
acp = AccessControlPolicy(
|
||||||
@ -407,7 +426,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
resp = self.api.handle_onem2m_request(req).get()
|
resp = self.api.handle_onem2m_request(req).get()
|
||||||
dyn_acp_id = resp.content.resourceID
|
dyn_acp_id = resp.content.resourceID
|
||||||
resource.accessControlPolicyIDs.append(dyn_acp_id)
|
resource.accessControlPolicyIDs.append(dyn_acp_id)
|
||||||
self.db_session.update(resource, ['accessControlPolicyIDs'])
|
self._update(resource, ['accessControlPolicyIDs'])
|
||||||
|
|
||||||
def _perform_evaluation(self, policies, privilege_type):
|
def _perform_evaluation(self, policies, privilege_type):
|
||||||
|
|
||||||
@ -725,7 +744,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
|
|
||||||
self.resource = resource
|
self.resource = resource
|
||||||
|
|
||||||
return self.db_session.store(resource)
|
return self._create(resource)
|
||||||
|
|
||||||
def _set_resource_id(self, values):
|
def _set_resource_id(self, values):
|
||||||
short_name = get_short_resource_name(self.resource_type.typename)
|
short_name = get_short_resource_name(self.resource_type.typename)
|
||||||
@ -789,6 +808,12 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
self.fields = self.request.content and self.request.content.values
|
self.fields = self.request.content and self.request.content.values
|
||||||
|
|
||||||
def _handle_retrieve(self):
|
def _handle_retrieve(self):
|
||||||
|
try:
|
||||||
|
self.request.rcn = ResultContentE(int(self.request.rcn))
|
||||||
|
except ValueError:
|
||||||
|
raise CSEBadRequest()
|
||||||
|
except TypeError:
|
||||||
|
self.request.rcn = ResultContentE.attributes
|
||||||
try:
|
try:
|
||||||
fu = self.request.filter_criteria.filterUsage
|
fu = self.request.filter_criteria.filterUsage
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
@ -857,7 +882,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
self.logger.debug("is resource '%s' virtual? -> %s", s.name,
|
self.logger.debug("is resource '%s' virtual? -> %s", s.name,
|
||||||
s.virtual)
|
s.virtual)
|
||||||
if not s.virtual:
|
if not s.virtual:
|
||||||
sub_node = self.db_session.get(s.path)
|
sub_node = self._get(s.path)
|
||||||
self._do_discovery(sub_node)
|
self._do_discovery(sub_node)
|
||||||
|
|
||||||
def _prepare_resource(self):
|
def _prepare_resource(self):
|
||||||
@ -872,17 +897,22 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
if self.fields and isinstance(self.fields, list):
|
if self.fields and isinstance(self.fields, list):
|
||||||
res.set_values({k: v if k in self.fields else None for
|
res.set_values({k: v if k in self.fields else None for
|
||||||
k, v in res.get_values().items()})
|
k, v in res.get_values().items()})
|
||||||
return self._retrieve_children()
|
|
||||||
|
if self.request.rcn == ResultContentE.attributes_and_child_resource_references:
|
||||||
|
self._retrieve_children()
|
||||||
|
|
||||||
def _send_retrieve_response(self):
|
def _send_retrieve_response(self):
|
||||||
return OneM2MResponse(STATUS_OK, pc=self.result, request=self.request)
|
fields = self.resource.values.keys()
|
||||||
|
if self.request.rcn != ResultContentE.attributes_and_child_resource_references:
|
||||||
|
fields = [k for k in fields if k != 'childResource']
|
||||||
|
return OneM2MResponse(STATUS_OK, pc=self.result, request=self.request, fields=fields)
|
||||||
|
|
||||||
def _retrieve_children(self):
|
def _retrieve_children(self):
|
||||||
return self._retrieve_children_for_resource(self.resource)
|
return self._retrieve_children_for_resource(self.resource)
|
||||||
|
|
||||||
def _retrieve_children_for_resource(self, resource):
|
def _retrieve_children_for_resource(self, resource):
|
||||||
self.logger.debug("getting children of: %s", resource)
|
self.logger.debug("getting children of: %s", resource)
|
||||||
children = self.db_session.get_collection(None, resource)
|
children = self._get_collection(None, resource)
|
||||||
resource.childResource = children
|
resource.childResource = children
|
||||||
|
|
||||||
# UPDATE
|
# UPDATE
|
||||||
@ -988,8 +1018,8 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
|
|
||||||
# self.resource = resource
|
# self.resource = resource
|
||||||
|
|
||||||
return self.db_session.update(self.resource)
|
return self._update(self.resource)
|
||||||
# return self.db_session.update(resource, values.keys())
|
# return self._update(resource, values.keys())
|
||||||
|
|
||||||
def _set_mandatory_update_attributes(self, values):
|
def _set_mandatory_update_attributes(self, values):
|
||||||
values["lastModifiedTime"] = self.now
|
values["lastModifiedTime"] = self.now
|
||||||
@ -1000,7 +1030,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
self.request)
|
self.request)
|
||||||
|
|
||||||
def _send_update_response(self):
|
def _send_update_response(self):
|
||||||
return OneM2MResponse(STATUS_OK, pc=self.resource,
|
return OneM2MResponse(STATUS_UPDATED, pc=self.resource,
|
||||||
request=self.request)
|
request=self.request)
|
||||||
|
|
||||||
# DELETE
|
# DELETE
|
||||||
@ -1014,14 +1044,14 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
return self._send_delete_response()
|
return self._send_delete_response()
|
||||||
|
|
||||||
def _get_parent(self):
|
def _get_parent(self):
|
||||||
self.parent = self.db_session.get(self.resource.parent_path)
|
self.parent = self._get(self.resource.parent_path)
|
||||||
|
|
||||||
def _delete_resource(self):
|
def _delete_resource(self):
|
||||||
self._delete_children()
|
self._delete_children()
|
||||||
self._do_delete_resource()
|
self._do_delete_resource()
|
||||||
|
|
||||||
def _do_delete_resource(self):
|
def _do_delete_resource(self):
|
||||||
return self.db_session.delete(self.resource)
|
return self._delete(self.resource)
|
||||||
|
|
||||||
def _delete_children(self):
|
def _delete_children(self):
|
||||||
self._retrieve_children()
|
self._retrieve_children()
|
||||||
@ -1045,7 +1075,7 @@ class OneM2MDefaultController(LoggerMixin):
|
|||||||
self.events.resource_deleted.fire(self.resource, self.request)
|
self.events.resource_deleted.fire(self.resource, self.request)
|
||||||
|
|
||||||
def _send_delete_response(self):
|
def _send_delete_response(self):
|
||||||
return OneM2MResponse(STATUS_OK, request=self.request)
|
return OneM2MResponse(STATUS_DELETED, request=self.request)
|
||||||
|
|
||||||
|
|
||||||
# see TS-0004 7.4.4
|
# see TS-0004 7.4.4
|
||||||
@ -1115,7 +1145,7 @@ class AEController(OneM2MDefaultController):
|
|||||||
ae_id = get_generic_ae_id()
|
ae_id = get_generic_ae_id()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.db_session.get(ae_id)
|
self._get(ae_id)
|
||||||
except DBNotFound:
|
except DBNotFound:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
@ -1283,17 +1313,14 @@ class ContentInstanceController(OneM2MDefaultController):
|
|||||||
def _create_resource(self):
|
def _create_resource(self):
|
||||||
super(ContentInstanceController, self)._create_resource()
|
super(ContentInstanceController, self)._create_resource()
|
||||||
|
|
||||||
# handle_old_instances
|
def remove_oldest_child():
|
||||||
max_nr_of_instances = self.parent.maxNrOfInstances
|
|
||||||
current_nr_of_instances = self.parent.currentNrOfInstances
|
|
||||||
if 0 < max_nr_of_instances <= current_nr_of_instances:
|
|
||||||
self.parent.currentNrOfInstances -= 1
|
self.parent.currentNrOfInstances -= 1
|
||||||
self.parent.currentByteSize -= self.parent.oldest.contentSize
|
self.parent.currentByteSize -= self.parent.oldest.contentSize
|
||||||
|
|
||||||
self.db_session.delete(self.parent.oldest)
|
self._delete(self.parent.oldest)
|
||||||
|
|
||||||
if self.parent.currentNrOfInstances >= 1:
|
if self.parent.currentNrOfInstances >= 1:
|
||||||
oldest = self.db_session.get_oldest_content_instance(
|
oldest = self._get_oldest_content_instance(
|
||||||
self.parent)
|
self.parent)
|
||||||
self.logger.debug("Setting new oldest: %s", oldest)
|
self.logger.debug("Setting new oldest: %s", oldest)
|
||||||
self.parent.oldest = oldest
|
self.parent.oldest = oldest
|
||||||
@ -1301,6 +1328,14 @@ class ContentInstanceController(OneM2MDefaultController):
|
|||||||
self.logger.debug("Setting oldest to None")
|
self.logger.debug("Setting oldest to None")
|
||||||
self.parent.oldest = None
|
self.parent.oldest = None
|
||||||
|
|
||||||
|
# handle_old_instances
|
||||||
|
if 0 < self.parent.maxNrOfInstances <= self.parent.currentNrOfInstances:
|
||||||
|
remove_oldest_child()
|
||||||
|
|
||||||
|
while (0 < self.parent.maxByteSize <
|
||||||
|
self.parent.currentByteSize + self.resource.contentSize):
|
||||||
|
remove_oldest_child()
|
||||||
|
|
||||||
# handle_new_instance
|
# handle_new_instance
|
||||||
self.parent.currentNrOfInstances += 1
|
self.parent.currentNrOfInstances += 1
|
||||||
self.parent.currentByteSize += self.resource.contentSize
|
self.parent.currentByteSize += self.resource.contentSize
|
||||||
@ -1309,7 +1344,13 @@ class ContentInstanceController(OneM2MDefaultController):
|
|||||||
self.resource)
|
self.resource)
|
||||||
self.parent.oldest = self.resource
|
self.parent.oldest = self.resource
|
||||||
self.parent.latest = self.resource
|
self.parent.latest = self.resource
|
||||||
self.db_session.update(self.parent)
|
self._update(self.parent)
|
||||||
|
|
||||||
|
def _check_create_representation(self):
|
||||||
|
super(ContentInstanceController, self)._check_create_representation()
|
||||||
|
|
||||||
|
if self.request.content.resourceName in ('la', 'ol'):
|
||||||
|
raise CSEConflict()
|
||||||
|
|
||||||
def _set_mandatory_create_attributes(self, vals):
|
def _set_mandatory_create_attributes(self, vals):
|
||||||
self.request.name = None
|
self.request.name = None
|
||||||
@ -1323,21 +1364,23 @@ class ContentInstanceController(OneM2MDefaultController):
|
|||||||
def _delete_resource(self):
|
def _delete_resource(self):
|
||||||
super(ContentInstanceController, self)._delete_resource()
|
super(ContentInstanceController, self)._delete_resource()
|
||||||
|
|
||||||
cnt = self.db_session.get(self.resource.parentID)
|
cnt = self._get(self.resource.parentID)
|
||||||
# TODO(rst): handle byte size
|
# TODO(rst): handle byte size
|
||||||
try:
|
try:
|
||||||
ci_l = self.db_session.get_latest_content_instance(cnt)
|
ci_l = self._get_latest_content_instance(cnt)
|
||||||
ci_o = self.db_session.get_oldest_content_instance(cnt)
|
ci_o = self._get_oldest_content_instance(cnt)
|
||||||
except (DBError, KeyError):
|
except (DBError, KeyError):
|
||||||
cnt.latest = None
|
cnt.latest = None
|
||||||
cnt.oldest = None
|
cnt.oldest = None
|
||||||
cnt.currentNrOfInstances = 0
|
cnt.currentNrOfInstances = 0
|
||||||
|
cnt.currentByteSize = 0
|
||||||
else:
|
else:
|
||||||
cnt.latest = ci_l
|
cnt.latest = ci_l
|
||||||
cnt.oldest = ci_o
|
cnt.oldest = ci_o
|
||||||
cnt.currentNrOfInstances -= 1
|
cnt.currentNrOfInstances -= 1
|
||||||
|
cnt.currentByteSize -= self.resource.contentSize
|
||||||
|
|
||||||
return self.db_session.update(cnt)
|
return self._update(cnt)
|
||||||
|
|
||||||
|
|
||||||
class AccessControlPolicyController(OneM2MDefaultController):
|
class AccessControlPolicyController(OneM2MDefaultController):
|
||||||
|
@ -249,11 +249,21 @@ class OpenMTCWSGIApplication(LoggerMixin):
|
|||||||
# request and response primitives, and vice versa, if applicable.
|
# request and response primitives, and vice versa, if applicable.
|
||||||
ec = get_header("x-m2m-ec")
|
ec = get_header("x-m2m-ec")
|
||||||
|
|
||||||
|
# The X-M2M-CTS header shall be mapped to the Content Status parameter
|
||||||
|
# of response primitives and vice versa, if applicable.
|
||||||
|
rvi = get_header("x-m2m-rvi")
|
||||||
|
|
||||||
|
# The X-M2M-CTS header shall be mapped to the Content Status parameter
|
||||||
|
# of response primitives and vice versa, if applicable.
|
||||||
|
vsi = get_header("x-m2m-vsi")
|
||||||
|
|
||||||
onem2m_request = OneM2MRequest(op=op, to=to, fr=fr, rqi=rqi, ty=ty,
|
onem2m_request = OneM2MRequest(op=op, to=to, fr=fr, rqi=rqi, ty=ty,
|
||||||
pc=pc, ot=ot, rqet=rqet, rset=rset,
|
pc=pc, ot=ot, rqet=rqet, rset=rset,
|
||||||
oet=oet, rt=rt, ec=ec, gid=gid)
|
oet=oet, rt=rt, ec=ec, gid=gid, rvi=rvi,
|
||||||
|
vsi=vsi)
|
||||||
|
|
||||||
not_filter_params = ('rt', 'rp', 'rcn', 'da', 'drt')
|
not_filter_params = ('rt', 'rp', 'rcn', 'da', 'drt', 'rids', 'tids',
|
||||||
|
'ltids', 'tqi')
|
||||||
multiple_params = ('lbl', 'ty', 'cty', 'atr')
|
multiple_params = ('lbl', 'ty', 'cty', 'atr')
|
||||||
|
|
||||||
if http_request.query_string:
|
if http_request.query_string:
|
||||||
@ -315,9 +325,18 @@ class OpenMTCWSGIApplication(LoggerMixin):
|
|||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"x-m2m-ri": str(response.rqi),
|
"x-m2m-ri": str(response.rqi),
|
||||||
"x-m2m-rsc": str(response.rsc)
|
"x-m2m-rsc": str(response.rsc),
|
||||||
|
'x-m2m-rvi': str(response.rvi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if response.fr:
|
||||||
|
headers['x-m2m-origin'] = str(response.fr)
|
||||||
|
|
||||||
|
response_fields = ['ot', 'rset', 'ec', 'cts', 'cto', 'vsi']
|
||||||
|
for f in response_fields:
|
||||||
|
if getattr(response, f):
|
||||||
|
headers['x-m2m-%s' % f] = str(getattr(response, f))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
headers['Content-Location'] = (resource_id_pre + response.content.resourceID)
|
headers['Content-Location'] = (resource_id_pre + response.content.resourceID)
|
||||||
except (AttributeError, TypeError):
|
except (AttributeError, TypeError):
|
||||||
@ -339,7 +358,8 @@ class OpenMTCWSGIApplication(LoggerMixin):
|
|||||||
try:
|
try:
|
||||||
content_type, payload = encode_onem2m_content(response.content,
|
content_type, payload = encode_onem2m_content(response.content,
|
||||||
accept, pretty,
|
accept, pretty,
|
||||||
path=resource_id_pre)
|
path=resource_id_pre,
|
||||||
|
fields=response.fields)
|
||||||
except CSEContentsUnacceptable as e:
|
except CSEContentsUnacceptable as e:
|
||||||
status_code = e.status_code
|
status_code = e.status_code
|
||||||
content_type = "text/plain"
|
content_type = "text/plain"
|
||||||
@ -369,7 +389,8 @@ class OpenMTCWSGIApplication(LoggerMixin):
|
|||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
"x-m2m-ri": str(response.rqi),
|
"x-m2m-ri": str(response.rqi),
|
||||||
"x-m2m-rsc": str(response.rsc)
|
"x-m2m-rsc": str(response.rsc),
|
||||||
|
'x-m2m-rvi': str(response.rvi)
|
||||||
}
|
}
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
status_code = STATUS_INTERNAL_SERVER_ERROR.http_status_code
|
status_code = STATUS_INTERNAL_SERVER_ERROR.http_status_code
|
||||||
|
@ -13,7 +13,7 @@ from utils import (get_packages, OpenMTCSdist, OpenMTCBuildPy,
|
|||||||
|
|
||||||
# name and version
|
# name and version
|
||||||
SETUP_NAME = "openmtc-all"
|
SETUP_NAME = "openmtc-all"
|
||||||
SETUP_VERSION = "1.1.0"
|
SETUP_VERSION = "1.2.0"
|
||||||
SETUP_DESCRIPTION = "The OpenMTC Backend and Gateway (GEvent version)"
|
SETUP_DESCRIPTION = "The OpenMTC Backend and Gateway (GEvent version)"
|
||||||
|
|
||||||
# meta
|
# meta
|
||||||
|
@ -7,7 +7,7 @@ from utils import get_packages, OpenMTCSdist
|
|||||||
# name and version
|
# name and version
|
||||||
NAME = "sdk"
|
NAME = "sdk"
|
||||||
SETUP_NAME = "openmtc-" + NAME
|
SETUP_NAME = "openmtc-" + NAME
|
||||||
SETUP_VERSION = "1.1.0"
|
SETUP_VERSION = "1.2.0"
|
||||||
SETUP_DESCRIPTION = "The OpenMTC Python SDK"
|
SETUP_DESCRIPTION = "The OpenMTC Python SDK"
|
||||||
|
|
||||||
# meta
|
# meta
|
||||||
|
27
tests/interoperability/README.md
Normal file
27
tests/interoperability/README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Conformance testing
|
||||||
|
|
||||||
|
Based on [pyresttest](https://github.com/svanoort/pyresttest). It implements the tests from [TS-0013](http://www.onem2m.org/component/rsfiles/download-file/files?path=Release_2_Draft_TS%255CTS-0013-Interoperability_Testing-V2_6_0.DOC&Itemid=238).
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
The python module pyresttest has to be installed.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pip install pyresttest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the Tests
|
||||||
|
|
||||||
|
The tests can be run from the command line. Make sure that a instance is running.
|
||||||
|
|
||||||
|
Assuming that a gateway is running at localhost, port 8000.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pyresttest http://localhost:8000 tests/interoperability/basic.yaml
|
||||||
|
Test Group Openmtc Test 8.1.1 SUCCEEDED: : 1/1 Tests Passed!
|
||||||
|
Test Group Openmtc Test 8.1.2 SUCCEEDED: : 4/4 Tests Passed!
|
||||||
|
Test Group Openmtc Test 8.1.3 SUCCEEDED: : 4/4 Tests Passed!
|
||||||
|
Test Group Openmtc Test 8.1.4 SUCCEEDED: : 8/8 Tests Passed!
|
||||||
|
Test Group Openmtc Test 8.1.5 SUCCEEDED: : 13/13 Tests Passed!
|
||||||
|
Test Group Openmtc Test 8.1.6 SUCCEEDED: : 4/4 Tests Passed!
|
||||||
|
```
|
423
tests/interoperability/basic.yaml
Normal file
423
tests/interoperability/basic.yaml
Normal file
@ -0,0 +1,423 @@
|
|||||||
|
---
|
||||||
|
- config:
|
||||||
|
- testset: "Openmtc pyresttests"
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# ResourceType: CSEBASE
|
||||||
|
###############################################################################
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.1"
|
||||||
|
- name: "CSEBase Retrieve on Mca"
|
||||||
|
- url: "/onem2m"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', 'x-m2m-rvi': '2a'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {header: x-m2m-rvi, comparator: 'eq', expected: '2a'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cb.ty', comparator: 'eq', expected: 5}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# ResourceType: RemoteCSE
|
||||||
|
###############################################################################
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.2"
|
||||||
|
- name: "RemoteCSE Create"
|
||||||
|
- url: "/onem2m/"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:csr": {"csi":"/mn-cse-1", "cb":"onem2m", "rr":true, "cst":2, "rn":"mn-cse-1"}}' #pc
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:csr.ty', comparator: 'eq', expected: 16}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.2"
|
||||||
|
- name: "remoteCSE Retrieve"
|
||||||
|
- url: "/onem2m/mn-cse-1"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:csr.ty', comparator: 'eq', expected: 16}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.2"
|
||||||
|
- name: "RemoteCSE Update"
|
||||||
|
- url: "/onem2m/mn-cse-1"
|
||||||
|
- method: "PUT" #Update
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:csr": {"rr":false}}' #pc
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2004'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:csr.ty', comparator: 'eq', expected: 16}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.2"
|
||||||
|
- name: "remoteCSE Delete"
|
||||||
|
- url: "/onem2m/mn-cse-1"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# ResourceType: AE
|
||||||
|
###############################################################################
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.3"
|
||||||
|
- name: "AE Create"
|
||||||
|
- url: "/onem2m/"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:ae": {"api":"/myAE","rr":true,"rn":"myAE"}}' #pc
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.3"
|
||||||
|
- name: "AE Retrieve"
|
||||||
|
- url: "/onem2m/myAE"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.3"
|
||||||
|
- name: "AE Update"
|
||||||
|
- url: "/onem2m/myAE"
|
||||||
|
- method: "PUT" #Update
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:csr": {"rr":false}}' #pc
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2004'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.3"
|
||||||
|
- name: "AE Delete"
|
||||||
|
- url: "/onem2m/myAE"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# ResourceType: Container
|
||||||
|
###############################################################################
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "AE Create"
|
||||||
|
- url: "/onem2m/"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:ae": {"api":"/myAE","rr":true,"rn":"myAE"}}' #pc
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "Container Create"
|
||||||
|
- url: "/onem2m/myAE"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:cnt": {"rn":"myContainer"}}' #pc, , "li" = "Container1"
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "Container Retrieve"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "Container Update"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "PUT" #Update
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:cnt": {"mni": 4}}' #pc
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2004'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "Container Delete"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "AE Delete"
|
||||||
|
- url: "/onem2m/myAE"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# ResourceType: ContentInstance
|
||||||
|
###############################################################################
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "AE Create"
|
||||||
|
- url: "/onem2m/"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:ae": {"api":"/myAE","rr":true,"rn":"myAE"}}' #pc
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:ae.ty', comparator: 'eq', expected: 2}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.4"
|
||||||
|
- name: "Container Create"
|
||||||
|
- url: "/onem2m/myAE"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:cnt": {"rn":"myContainer"}}' #pc, , "li" = "Container1"
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cnt.ty', comparator: 'eq', expected: 3}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "ContentInstance Create"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1"
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "Container Retrieve"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- validators:
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cnt.cni', comparator: 'eq', expected: 1}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "ContentInstance Retrieve"
|
||||||
|
- url: "/onem2m/myAE/myContainer/Testcontent"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "ContentInstance Delete"
|
||||||
|
- url: "/onem2m/myAE/myContainer/Testcontent"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "ContentInstance Create"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1"
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "latest ContentInstance Delete"
|
||||||
|
- url: "/onem2m/myAE/myContainer/la"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "ContentInstance Create"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1"
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "oldest ContentInstance Delete"
|
||||||
|
- url: "/onem2m/myAE/myContainer/ol"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "ContentInstance Create"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "POST" #Create
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- body: '{"m2m:cin": {"con":"Type" , "rn":"Testcontent", "cnf": "text/plain:0" }}' #pc, , "li" = "Container1"
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2001'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "latest ContentInstance Retrieve"
|
||||||
|
- url: "/onem2m/myAE/myContainer/la"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "oldest ContentInstance Retrieve"
|
||||||
|
- url: "/onem2m/myAE/myContainer/ol"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: {jsonpath_mini: 'm2m:cin.ty', comparator: 'eq', expected: 4}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "Container Delete"
|
||||||
|
- url: "/onem2m/myAE/myContainer"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.5"
|
||||||
|
- name: "AE Delete"
|
||||||
|
- url: "/onem2m/myAE"
|
||||||
|
- method: "DELETE" #Delete
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar'}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2002'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
- compare: [raw_body: "", expected: ""]
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Discovery
|
||||||
|
###############################################################################
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.6"
|
||||||
|
- name: "Discovery all resources"
|
||||||
|
- url: "/onem2m?fu=1"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.6"
|
||||||
|
- name: "Discovery with filter criteria"
|
||||||
|
- url: "/onem2m?fu=1&lbl=key1"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.6"
|
||||||
|
- name: "Discovery with limit filter criteria"
|
||||||
|
- url: "/onem2m?fu=1&lim=2"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
|
||||||
|
- test:
|
||||||
|
- group: "Openmtc Test 8.1.6"
|
||||||
|
- name: "Discovery with mulriple filter criteria"
|
||||||
|
- url: "/onem2m?fu=1&lbl=key1&lbl=key2&lim=1"
|
||||||
|
- method: "GET" #Retrieve
|
||||||
|
- headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f}
|
||||||
|
- validators:
|
||||||
|
- compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
- compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
|
||||||
|
#- test:
|
||||||
|
# - group: "Openmtc Test 8.1.6"
|
||||||
|
# - name: "Discovery with level filter criteria"
|
||||||
|
# - url: "/onem2m?fu=1&lvl=2"
|
||||||
|
# - method: "GET" #Retrieve
|
||||||
|
# - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f}
|
||||||
|
# - validators:
|
||||||
|
# - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
# - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
||||||
|
|
||||||
|
#- test:
|
||||||
|
# - group: "Openmtc Test 8.1.6"
|
||||||
|
# - name: "Discovery with offset filter criteria"
|
||||||
|
# - url: "/onem2m?fu=1&ofst=1"
|
||||||
|
# - method: "GET" #Retrieve
|
||||||
|
# - headers: {'x-m2m-origin':'CAE0', 'x-m2m-ri': 'foobar', Content-Type: application/vnd.onem2m-res+json, Content-Location: CAE0, f}
|
||||||
|
# - validators:
|
||||||
|
# - compare: {header: x-m2m-rsc, comparator: 'eq', expected: '2000'}
|
||||||
|
# - compare: {header: x-m2m-ri, comparator: 'eq', expected: 'foobar'}
|
Loading…
x
Reference in New Issue
Block a user