mirror of
https://github.com/OpenMTC/OpenMTC.git
synced 2025-02-02 16:50:38 +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>
|
||||
</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.
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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",
|
||||
|
@ -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 = {
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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
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.
|
||||
"""
|
||||
|
||||
__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
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
|
||||
|
||||
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={
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
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