Merge pull request #17 from OpenMTC/master

Update development branche to master
This commit is contained in:
aor-fokus 2019-01-18 13:47:25 +01:00 committed by GitHub
commit 36d4e84059
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 962 additions and 174 deletions

114
README.md
View File

@ -4,43 +4,95 @@
</a>
</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)
- [Introduction](doc/introduction.md)
- [Deployment](doc/deployment-guide.md)
- [The MQTT Client](doc/onem2m-client-mqtt.md)
- [Authentication Guide](doc/authentication.md)
- [Installation of the OpenMTC SDK](doc/install-sdk.md)
- [Overview REST API](doc/overview-rest-api.md)
- [Write your first OpenMTC applications](doc/training/training-index.md)
- [SDK - Using the Application Framework](doc/sdk-framework.md)
- [SDK - The low-level CSE Client](doc/sdk-client.md)
- [SDK - The Data Model](doc/sdk-datamodel.md)
- 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)
This project is part of [FIWARE](https://www.fiware.org/). For more information
check the FIWARE Catalogue entry for the
[IoT Agents](https://github.com/Fiware/catalogue/tree/master/iot-agents).
# Content
- [Install](#install)
- [Usage](#usage)
- [API](#api)
- [Quality Assurance](#quality-assurance)
- [License](#license)
# 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)
- [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)
## Usage
# 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.

View File

@ -2,7 +2,7 @@
Transfer OpenMTC Data to an InfluxDB
"""
__version__ = "1.1.0"
__version__ = "1.2.0"
__description__ = "InfluxdbApp"
__author_name__ = "Christian Klopp"
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"

View File

@ -3,7 +3,7 @@ This App will forward all incoming sensor traffic to the Fiware Orion Context
Broker
"""
__version__ = "1.1.0"
__version__ = "1.2.0"
__description__ = "OrionContextBroker"
__author_name__ = "Christian Klopp"
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"

View File

@ -43,6 +43,13 @@ class OrionAPI(LoggerMixin):
self.logger.error('Type of "{}" unknown'.format(element))
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,
entity_name,
entity_type="openmtc",

View File

@ -37,10 +37,13 @@ class OrionContextBroker(ResourceManagementXAE):
accumulate_address = "http://" + self._get_auto_host(orion_host) + ":8080"
# Orion API
self._dry_run = not orion_host
self.orion_api = OrionAPI(
orion_host=orion_host,
api_version=orion_api,
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
self.app = Flask(__name__)
@ -116,6 +119,9 @@ class OrionContextBroker(ResourceManagementXAE):
return re.sub('[\W]', '_', f_s), '%s-%s' % (e_pre, dev_id)
def _sensor_data_cb(self, sensor_info, sensor_data):
if self._dry_run:
return
try:
fiware_service, entity_name = self._entity_names[sensor_info['ID']]
except KeyError:
@ -138,6 +144,10 @@ class OrionContextBroker(ResourceManagementXAE):
'ID']]
self.logger.info("Create new Entity {} on Fiware Service {}".format(
entity_name, fiware_service))
if self._dry_run:
return
self.orion_api.create_entity(
entity_name, fiware_service=fiware_service)
data_dummy = {

View File

@ -2,7 +2,7 @@
App to inject data from a csv file to OpenMTC
"""
__version__ = "1.1.0"
__version__ = "1.2.0"
__description__ = "csvInjector"
__author_name__ = "Christian Klopp"
__author_mail__ = "christian.klopp@fokus.fraunhofer.de"

View File

@ -2,7 +2,7 @@
TODO: Add description here
"""
__version__ = "1.1.0"
__version__ = "1.2.0"
__description__ = "mqttConnector"
__author_name__ = "Ronald Steinke"
__author_mail__ = "ronald.steinke@fokus.fraunhofer.de"

View File

@ -48,7 +48,7 @@ _method_map_to_http = {
_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 = {
'X-M2M-ORIGIN': 'originator',
@ -59,6 +59,8 @@ _header_to_field_map = {
'X-M2M-RET': 'rqet',
'X-M2M-OET': 'oet',
'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])
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
}
headers['content-type'] = content_type
headers['accept'] = self.content_type
self.logger.debug("Added request params: %s", params)
return {

View File

@ -83,11 +83,12 @@ class OneM2MMQTTClient(OneM2MClient):
__request_fields = frozenset([
'op',
'to',
'fr',
'rqi',
'ty',
'pc',
'rol',
'rids',
'ot',
'rqet',
'rset',
@ -98,17 +99,28 @@ class OneM2MMQTTClient(OneM2MClient):
'ec',
'da',
'gid',
'drt',
'to',
'fc',
'drt',
'tids',
'ltids',
'tqi',
'rvi',
'vsi',
])
__response_fields = frozenset([
'rsc',
'rqi',
'pc',
'fr',
'to',
'fr',
'ot',
'rset',
'ec',
'cts',
'cto',
'rvi',
'vsi',
])
@staticmethod
@ -370,7 +382,8 @@ class OneM2MMQTTClient(OneM2MClient):
sp_id, cse_id, _ = split_onem2m_address(response.to)
response.content = self._decode(
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(

View File

@ -13,6 +13,10 @@ STATUS_ACCEPTED = STATUS(
1000, "ACCEPTED", 202)
STATUS_OK = STATUS(
2000, "OK", 200)
STATUS_UPDATED = STATUS(
2004, "UPDATED", 200)
STATUS_DELETED = STATUS(
2002, "DELETED", 200)
STATUS_CREATED = STATUS(
2001, "CREATED", 201)
STATUS_BAD_REQUEST = STATUS(

View File

@ -49,7 +49,8 @@ class OneM2MMapper(BasicMapper):
path,
self.originator,
ty=type(instance),
pc=instance
pc=instance,
rvi='2a'
)).get()
try:
@ -83,7 +84,8 @@ class OneM2MMapper(BasicMapper):
OneM2MOperation.update,
instance.path,
self.originator,
pc=instance
pc=instance,
rvi='2a'
)).get()
try:
@ -105,6 +107,8 @@ class OneM2MMapper(BasicMapper):
path,
self.originator,
filter_criteria=fc,
rvi='2a',
rcn=5,
**request_options
)).get()
@ -112,7 +116,8 @@ class OneM2MMapper(BasicMapper):
self._send_request(OneM2MRequest(
OneM2MOperation.delete,
getattr(instance, "path", instance),
self.originator
self.originator,
rvi='2a'
))
# TODO(rst): check if this can be removed in parent class

View File

@ -6,7 +6,7 @@ from openmtc.model import (Resource as Res, UnicodeAttribute, DatetimeAttribute,
from openmtc.model.exc import ModelTypeError
from futile import issubclass
LATEST_VERSION = "1.6"
LATEST_VERSION = "2a"
class OneM2MIntEnum(IntEnum):
@ -24,7 +24,7 @@ class OneM2MContentResource(ContentResource, OneM2MEntity):
class OneM2MResource(Res, OneM2MEntity):
__model_name__ = "onem2m"
__model_version__ = "1.6"
__model_version__ = "2a"
################################################################################
@ -41,8 +41,8 @@ class ResourceTypeE(OneM2MIntEnum):
eventConfig = 7
execInstance = 8
group = 9
localPolicy = 10
m2mServiceSubscriptionProfile = 11
locationPolicy = 10
m2mServiceSubscription = 11
mgmtCmd = 12
mgmtObj = 13
node = 14
@ -56,6 +56,16 @@ class ResourceTypeE(OneM2MIntEnum):
statsConfig = 22
subscription = 23
semanticDescriptor = 24
notificationTargetMgmtPolicyRef = 25
notificationTargetPolicy = 26
policyDeletionRules = 27
flexContainer = 28
timeSeries = 29
timeSeriesInstance = 30
role = 31
token = 32
trafficPattern = 33
dynamicAuthorizationConsultation = 34
accessControlPolicyAnnc = 10001
AEAnnc = 10002
containerAnnc = 10003
@ -66,6 +76,12 @@ class ResourceTypeE(OneM2MIntEnum):
nodeAnnc = 10014
remoteCSEAnnc = 10016
scheduleAnnc = 10018
semanticDescriptorAnnc = 10024
flexContainerAnnc = 10028
timeSeriesAnnc = 10029
timeSeriesInstanceAnnc = 10030
trafficPatternAnnc = 10033
dynamicAuthorizationConsultationAnnc = 10034
@unique
@ -106,15 +122,17 @@ class ResponseType(OneM2MIntEnum):
# @unique
# class ResultConentE(OneM2MIntEnum):
# nothing = 0
# attributes = 1
# hierarchical_address = 2
# hierarchical_address_and_attributes = 3
# attributes_and_child_resources = 4
# attributes_and_child_resource_references = 6
# child_resource_references = 6
# original_resource = 7
class ResultContentE(OneM2MIntEnum):
nothing = 0
attributes = 1
hierarchical_address = 2
hierarchical_address_and_attributes = 3
attributes_and_child_resources = 4
attributes_and_child_resource_references = 5
child_resource_references = 6
original_resource = 7
child_resources = 8
modified_attributes = 9
@unique
@ -136,6 +154,7 @@ class RequestStatusE(OneM2MIntEnum):
@unique
class MemberTypeE(OneM2MIntEnum):
mixed = 0
accessControlPolicy = 1
AE = 2
container = 3
@ -159,7 +178,16 @@ class MemberTypeE(OneM2MIntEnum):
statsCollect = 21
statsConfig = 22
subscription = 23
semanticDescriptor = 24
notificationTargetMgmtPolicyRef = 25
notificationTargetPolicy = 26
policyDeletionRules = 27
flexContainer = 28
timeSeries = 29
timeSeriesInstance = 30
role = 31
token = 32
trafficPattern = 33
dynamicAuthorizationConsultation = 34
accessControlPolicyAnnc = 10001
AEAnnc = 10002
@ -170,11 +198,15 @@ class MemberTypeE(OneM2MIntEnum):
mgmtObjAnnc = 10013
nodeAnnc = 10014
remoteCSEAnnc = 10016
scheduleAnnc = 10019
scheduleAnnc = 10018
semanticDescriptorAnnc = 10024
flexContainerAnnc = 10028
timeSeriesAnnc = 10029
timeSeriesInstanceAnnc = 10030
trafficPatternAnnc = 10033
dynamicAuthorizationConsultationAnnc = 10034
mixed = 24
# Mixed is a mixture of the resource types from 1 to 23, 10001 to 10004, 10009 to 10010,
# 10013 to 10014 and 10016 to 10018 as listed above.
oldest = 20001
latest = 20002
@unique
@ -952,7 +984,7 @@ class ContentInstance(AnnounceableSubordinateResourceC,
SubscribableResource):
"""See TS-0001 section 9.6.7"""
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
stateTag = Attribute(int, accesstype=Attribute.RO)
creator = UnicodeAttribute() # m2m:ID
# contentInfo = typeOfContent(:EncodingType)
# typeOfContent => Media Types
@ -969,7 +1001,7 @@ class ContentInstance(AnnounceableSubordinateResourceC,
class ContentInstanceAnnc(AnnouncedSubordinateResourceC):
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
stateTag = Attribute(int, accesstype=Attribute.RO)
contentInfo = UnicodeAttribute(EncodingTypeE) # m2m:contentInfo
contentSize = Attribute(int, accesstype=Attribute.WO)
ontologyRef = UnicodeAttribute(accesstype=Attribute.WO)
@ -983,7 +1015,7 @@ class ContentInstanceAnnc(AnnouncedSubordinateResourceC):
class Container(AnnounceableResourceC, SubscribableResource):
"""See TS-0001 section 9.6.6"""
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
stateTag = Attribute(int, accesstype=Attribute.RO)
creator = UnicodeAttribute()
maxNrOfInstances = Attribute(int)
maxByteSize = Attribute(int)
@ -1012,7 +1044,7 @@ Container.__child_types__ = (
class ContainerAnnc(AnnouncedResourceC, SubscribableResource):
stateTag = UnicodeAttribute(accesstype=Attribute.RO)
stateTag = Attribute(int, accesstype=Attribute.RO)
maxNrOfInstances = Attribute(int)
maxByteSize = Attribute(int)
maxInstanceAge = UnicodeAttribute(mandatory=False) # todo

View File

@ -49,7 +49,7 @@ class OneM2MSerializer(LoggerMixin):
except (TypeError, AttributeError, KeyError, ValueError):
raise CSEValueError("Invalid entry in child resources: %s",
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 = self.decode(self.dumps(representation))
data["notificationEvent"]["representation"] = representation
@ -62,7 +62,10 @@ class OneM2MSerializer(LoggerMixin):
class OneM2MDictSerializer(OneM2MSerializer):
def encode_resource(self, resource, pretty=False, path=None, encoding="utf-8", fields=None,
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)
@ -93,7 +96,7 @@ class OneM2MDictSerializer(OneM2MSerializer):
return resource_id
return val_path + resource_id
if isinstance(resource, OneM2MResource):
if isinstance(resource, OneM2MResource) and "childResource" in representation:
def get_child_rep(c):
return {
@ -112,53 +115,12 @@ class OneM2MDictSerializer(OneM2MSerializer):
if isinstance(resource.oldest, ContentInstance):
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):
representation = {
get_short_resource_name(k) or get_short_attribute_name(k) or
get_short_member_name(k): v for
k, v in representation.items()}
clean_representation(representation)
if not isinstance(resource, (OneM2MResource, Notification,
SecurityInfo, OneM2MContentResource)):
return representation

View File

@ -30,12 +30,7 @@ del logger
def _default(x):
if isinstance(x, datetime):
try:
isoformat = x.isoformat
except AttributeError:
raise TypeError("%s (%s)" % (x, type(x)))
return isoformat()
return x.strftime("%Y%m%dT%H%M%S")
elif isinstance(x, ContentInstance):
return x.resourceID
else:

View File

@ -27,9 +27,6 @@ def encode_onem2m_content(content, content_type, pretty=False, path=None,
if content is None:
return None, None
fields = fields # TODO(rst): maybe necessary
# fields = ["resourceID"]
serializer = get_onem2m_encoder(content_type)
data = serializer.encode_resource(content, pretty=pretty, path=path,

View File

@ -201,10 +201,11 @@ class OneM2MRequest(object):
"""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,
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
self.operation = op
# Target uri
@ -216,7 +217,7 @@ class OneM2MRequest(object):
self.resource_type = ty
# Resource content to be transferred.
self.content = pc
self.role = rol
self.role_ids = rids
self.originating_timestamp = ot
self.request_expiration_timestamp = rqet
self.result_expiration_timestamp = rset
@ -230,6 +231,11 @@ class OneM2MRequest(object):
self.filter_criteria = filter_criteria or fc
# Optional Discovery result type
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
def op(self):
@ -272,12 +278,12 @@ class OneM2MRequest(object):
self.content = pc
@property
def rol(self):
return self.role
def rids(self):
return self.role_ids
@rol.setter
def rol(self, rol):
self.role = rol
@rids.setter
def rids(self, rids):
self.role_ids = rids
@property
def ot(self):
@ -375,6 +381,46 @@ class OneM2MRequest(object):
def drt(self, 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):
return '%s: %s' % (self.__class__.__name__, ' | '.join([
'%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"""
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
if isinstance(status_code, STATUS):
self.response_status_code = status_code
@ -397,14 +444,27 @@ class OneM2MResponse(object):
self.to = request.to
# Originator ID
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:
self.request_identifier = rqi
# Target uri
self.to = to
# Originator ID
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.
self.content = pc
self.content_status = cts
self.content_offset = cto
self.fields = fields
@property
def status_code(self):
@ -438,6 +498,62 @@ class OneM2MResponse(object):
def fr(self, 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):
return '%s: %s' % (self.__class__.__name__, ' | '.join([
'%s: %s' % (str(k), str(v)) for k, v in self.__dict__.iteritems()

9
doc/index.md Normal file
View 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).

View File

@ -2,7 +2,7 @@
Interworking Proxy for Cul868 devices.
"""
__version__ = "1.1.0"
__version__ = "1.2.0"
__description__ = "The OpenMTC Cul868IPE"
__author_name__ = "Ronny Kreuch"
__author_mail__ = "ronny.kreuch@fokus.fraunhofer.de"

52
mkdocs.yml Normal file
View 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

View File

@ -205,8 +205,9 @@ class MqttNotificationHandler(BaseNotificationHandler):
from openmtc_onem2m.exc import get_response_status
def wrapper(request):
notification = self._unpack_notification(request.content)
self._callback(request.originator, **notification)
if not request.content.verificationRequest:
notification = self._unpack_notification(request.content)
self._callback(request.originator, **notification)
return OneM2MResponse(status_code=get_response_status(2000), request=request)
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 '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 = self._unpack_notification(notification)
self._callback(request.headers['x-m2m-origin'], **notification)
if not notification.verificationRequest:
notification = self._unpack_notification(notification)
self._callback(request.headers['x-m2m-origin'], **notification)
return Response(
headers={

View File

@ -547,7 +547,7 @@ class XAE(LoggerMixin):
"""
return self._get_content_from_cin(
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
def _handle_new_sensor(self, sensor_path):
latest = self.get_resource(sensor_path + '/latest')
latest = self.get_resource(sensor_path + '/la')
if latest:
spawn(self._handle_sensor_data, sensor_path, self._get_content_from_cin(latest))

View File

@ -13,6 +13,12 @@ from openmtc_server.exc import ConfigurationError
from openmtc_server.util import log_error
container_virtual_mapping = {
'la': 'latest',
'ol': 'oldest'
}
class OneM2MMethodDomain(Component):
def __init__(self, config, *args, **kw):
super(OneM2MMethodDomain, self).__init__(*args, **kw)
@ -209,11 +215,11 @@ class OneM2MMethodDomain(Component):
# oldest, latest -> Container
# TODO(rst): fanOutPoint -> group
# TODO(rst): pollingChannelURI -> pollingChannel
if path.endswith(('latest', 'oldest')):
if path.endswith(tuple(container_virtual_mapping.keys())):
parent_path, virtual = path.rsplit('/', 1)
parent = get_resource(parent_path)
if isinstance(parent, model.Container):
resource = getattr(parent, virtual)
resource = getattr(parent, container_virtual_mapping[virtual])
if resource is None:
raise CSENotFound()
return resource

View File

@ -22,14 +22,16 @@ from openmtc_onem2m.exc import (CSEOperationNotAllowed, STATUS_OK, CSETypeError,
CSEMissingValue, CSEValueError, STATUS_CREATED,
CSEError, CSESyntaxError, CSEBadRequest,
CSEPermissionDenied, STATUS_NOT_FOUND, CSEConflict,
CSEContentsUnacceptable, CSETargetNotReachable)
CSEContentsUnacceptable, CSETargetNotReachable,
STATUS_UPDATED, STATUS_DELETED)
from openmtc_onem2m.model import (ExpiringResource, Notification,
AccessControlOperationE, ResourceTypeE,
NotificationContentTypeE, FilterUsageE,
get_short_resource_name, URIList,
DiscResTypeE, Container, AccessControlPolicy,
AccessControlPolicyIDHolder, AccessControlRuleC,
DynAuthDasRequestC, SecurityInfo, SecurityInfoTypeE, AE)
DynAuthDasRequestC, SecurityInfo, SecurityInfoTypeE,
AE, ResultContentE, ContentInstance)
from openmtc_onem2m.transport import (OneM2MResponse, OneM2MRequest,
OneM2MOperation, OneM2MErrorResponse)
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):
super(OneM2MDefaultController, self).__init__()
self.resource_type = resource_type
self.db_session = db_session
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):
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_poa = dynamic_authorization.get('poa', [])
# release version indicator
if not self.request.rvi:
self.request.rvi = '2a'
return self._handle_request()
def _handle_request(self):
@ -200,7 +219,7 @@ class OneM2MDefaultController(LoggerMixin):
self._check_privileges(parent)
def _get_parent_of_resource(self, resource):
return self.db_session.get(resource.parentID)
return self._get(resource.parentID)
def _check_privileges(self, resource):
# get all ACPs
@ -374,7 +393,7 @@ class OneM2MDefaultController(LoggerMixin):
try:
for dac_id in resource.dynamicAuthorizationConsultationIDs:
try:
dac = self.db_session.get(dac_id)
dac = self._get(dac_id)
if dac.dynamicAuthorizationEnabled:
return dac
except DBNotFound:
@ -384,7 +403,7 @@ class OneM2MDefaultController(LoggerMixin):
except AttributeError:
return None
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):
acp = AccessControlPolicy(
@ -407,7 +426,7 @@ class OneM2MDefaultController(LoggerMixin):
resp = self.api.handle_onem2m_request(req).get()
dyn_acp_id = resp.content.resourceID
resource.accessControlPolicyIDs.append(dyn_acp_id)
self.db_session.update(resource, ['accessControlPolicyIDs'])
self._update(resource, ['accessControlPolicyIDs'])
def _perform_evaluation(self, policies, privilege_type):
@ -725,7 +744,7 @@ class OneM2MDefaultController(LoggerMixin):
self.resource = resource
return self.db_session.store(resource)
return self._create(resource)
def _set_resource_id(self, values):
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
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:
fu = self.request.filter_criteria.filterUsage
except AttributeError:
@ -857,7 +882,7 @@ class OneM2MDefaultController(LoggerMixin):
self.logger.debug("is resource '%s' virtual? -> %s", s.name,
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)
def _prepare_resource(self):
@ -872,17 +897,22 @@ class OneM2MDefaultController(LoggerMixin):
if self.fields and isinstance(self.fields, list):
res.set_values({k: v if k in self.fields else None for
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):
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):
return self._retrieve_children_for_resource(self.resource)
def _retrieve_children_for_resource(self, 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
# UPDATE
@ -988,8 +1018,8 @@ class OneM2MDefaultController(LoggerMixin):
# self.resource = resource
return self.db_session.update(self.resource)
# return self.db_session.update(resource, values.keys())
return self._update(self.resource)
# return self._update(resource, values.keys())
def _set_mandatory_update_attributes(self, values):
values["lastModifiedTime"] = self.now
@ -1000,7 +1030,7 @@ class OneM2MDefaultController(LoggerMixin):
self.request)
def _send_update_response(self):
return OneM2MResponse(STATUS_OK, pc=self.resource,
return OneM2MResponse(STATUS_UPDATED, pc=self.resource,
request=self.request)
# DELETE
@ -1014,14 +1044,14 @@ class OneM2MDefaultController(LoggerMixin):
return self._send_delete_response()
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):
self._delete_children()
self._do_delete_resource()
def _do_delete_resource(self):
return self.db_session.delete(self.resource)
return self._delete(self.resource)
def _delete_children(self):
self._retrieve_children()
@ -1045,7 +1075,7 @@ class OneM2MDefaultController(LoggerMixin):
self.events.resource_deleted.fire(self.resource, self.request)
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
@ -1115,7 +1145,7 @@ class AEController(OneM2MDefaultController):
ae_id = get_generic_ae_id()
try:
self.db_session.get(ae_id)
self._get(ae_id)
except DBNotFound:
pass
else:
@ -1283,17 +1313,14 @@ class ContentInstanceController(OneM2MDefaultController):
def _create_resource(self):
super(ContentInstanceController, self)._create_resource()
# handle_old_instances
max_nr_of_instances = self.parent.maxNrOfInstances
current_nr_of_instances = self.parent.currentNrOfInstances
if 0 < max_nr_of_instances <= current_nr_of_instances:
def remove_oldest_child():
self.parent.currentNrOfInstances -= 1
self.parent.currentByteSize -= self.parent.oldest.contentSize
self.db_session.delete(self.parent.oldest)
self._delete(self.parent.oldest)
if self.parent.currentNrOfInstances >= 1:
oldest = self.db_session.get_oldest_content_instance(
oldest = self._get_oldest_content_instance(
self.parent)
self.logger.debug("Setting new oldest: %s", oldest)
self.parent.oldest = oldest
@ -1301,6 +1328,14 @@ class ContentInstanceController(OneM2MDefaultController):
self.logger.debug("Setting oldest to 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
self.parent.currentNrOfInstances += 1
self.parent.currentByteSize += self.resource.contentSize
@ -1309,7 +1344,13 @@ class ContentInstanceController(OneM2MDefaultController):
self.resource)
self.parent.oldest = 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):
self.request.name = None
@ -1323,21 +1364,23 @@ class ContentInstanceController(OneM2MDefaultController):
def _delete_resource(self):
super(ContentInstanceController, self)._delete_resource()
cnt = self.db_session.get(self.resource.parentID)
cnt = self._get(self.resource.parentID)
# TODO(rst): handle byte size
try:
ci_l = self.db_session.get_latest_content_instance(cnt)
ci_o = self.db_session.get_oldest_content_instance(cnt)
ci_l = self._get_latest_content_instance(cnt)
ci_o = self._get_oldest_content_instance(cnt)
except (DBError, KeyError):
cnt.latest = None
cnt.oldest = None
cnt.currentNrOfInstances = 0
cnt.currentByteSize = 0
else:
cnt.latest = ci_l
cnt.oldest = ci_o
cnt.currentNrOfInstances -= 1
cnt.currentByteSize -= self.resource.contentSize
return self.db_session.update(cnt)
return self._update(cnt)
class AccessControlPolicyController(OneM2MDefaultController):

View File

@ -249,11 +249,21 @@ class OpenMTCWSGIApplication(LoggerMixin):
# request and response primitives, and vice versa, if applicable.
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,
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')
if http_request.query_string:
@ -315,9 +325,18 @@ class OpenMTCWSGIApplication(LoggerMixin):
headers = {
"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:
headers['Content-Location'] = (resource_id_pre + response.content.resourceID)
except (AttributeError, TypeError):
@ -339,7 +358,8 @@ class OpenMTCWSGIApplication(LoggerMixin):
try:
content_type, payload = encode_onem2m_content(response.content,
accept, pretty,
path=resource_id_pre)
path=resource_id_pre,
fields=response.fields)
except CSEContentsUnacceptable as e:
status_code = e.status_code
content_type = "text/plain"
@ -369,7 +389,8 @@ class OpenMTCWSGIApplication(LoggerMixin):
headers = {
"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:
status_code = STATUS_INTERNAL_SERVER_ERROR.http_status_code

View File

@ -13,7 +13,7 @@ from utils import (get_packages, OpenMTCSdist, OpenMTCBuildPy,
# name and version
SETUP_NAME = "openmtc-all"
SETUP_VERSION = "1.1.0"
SETUP_VERSION = "1.2.0"
SETUP_DESCRIPTION = "The OpenMTC Backend and Gateway (GEvent version)"
# meta

View File

@ -7,7 +7,7 @@ from utils import get_packages, OpenMTCSdist
# name and version
NAME = "sdk"
SETUP_NAME = "openmtc-" + NAME
SETUP_VERSION = "1.1.0"
SETUP_VERSION = "1.2.0"
SETUP_DESCRIPTION = "The OpenMTC Python SDK"
# meta

View 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!
```

View 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'}