""" Various LwM2M interoperability tests #################################### Copyright (c) 2023 Nordic Semiconductor ASA SPDX-License-Identifier: Apache-2.0 Test specification: =================== https://www.openmobilealliance.org/release/LightweightM2M/ETS/OMA-ETS-LightweightM2M-V1_1-20190912-D.pdf This module contains testcases for * Registration Interface [100-199] * Device management & Service Enablement Interface [200-299] * Information Reporting Interface [300-399] """ import time import logging from datetime import datetime import pytest from leshan import Leshan from twister_harness import Shell from twister_harness import DeviceAdapter logger = logging.getLogger(__name__) def test_LightweightM2M_1_1_int_102(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-102 - Registration Update""" lines = shell.get_filtered_output(shell.exec_command('lwm2m read 1/0/1 -u32')) lifetime = int(lines[0]) lifetime = lifetime + 10 start_time = time.time() * 1000 leshan.write(endpoint, '1/0/1', lifetime) dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) latest = leshan.get(f'/clients/{endpoint}') assert latest["lastUpdate"] > start_time assert latest["lastUpdate"] <= time.time()*1000 assert latest["lifetime"] == lifetime shell.exec_command('lwm2m write 1/0/1 -u32 86400') def test_LightweightM2M_1_1_int_103(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-103 - Deregistration""" leshan.execute(endpoint, '1/0/4') dut.readlines_until(regex='LwM2M server disabled', timeout=5.0) dut.readlines_until(regex='Deregistration success', timeout=5.0) # Reset timers by restarting the client shell.exec_command('lwm2m stop') time.sleep(1) shell.exec_command(f'lwm2m start {endpoint}') dut.readlines_until(regex='.*Registration Done', timeout=5.0) def test_LightweightM2M_1_1_int_104(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-104 - Registration Update Trigger""" shell.exec_command('lwm2m update') dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) leshan.execute(endpoint, '1/0/8') dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) @pytest.mark.slow def test_LightweightM2M_1_1_int_107(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-107 - Extending the lifetime of a registration""" leshan.write(endpoint, '1/0/1', 120) dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) lines = shell.get_filtered_output(shell.exec_command('lwm2m read 1/0/1 -u32')) lifetime = int(lines[0]) assert lifetime == 120 logger.debug(f'Wait for update, max {lifetime} s') dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=lifetime) assert leshan.get(f'/clients/{endpoint}') def test_LightweightM2M_1_1_int_108(leshan, endpoint): """LightweightM2M-1.1-int-108 - Turn on Queue Mode""" assert leshan.get(f'/clients/{endpoint}')["queuemode"] @pytest.mark.slow def test_LightweightM2M_1_1_int_109(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-109 - Behavior in Queue Mode""" logger.debug('Wait for Queue RX OFF') dut.readlines_until(regex='.*Queue mode RX window closed', timeout=120) # Restore previous value shell.exec_command('lwm2m write 1/0/1 -u32 86400') dut.readlines_until(regex='.*Registration update complete', timeout=10) def test_LightweightM2M_1_1_int_201(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-201 - Querying basic information in Plain Text format""" fmt = leshan.format leshan.format = 'TEXT' assert leshan.read(endpoint, '3/0/0') == 'Zephyr' assert leshan.read(endpoint, '3/0/1') == 'client-1' assert leshan.read(endpoint, '3/0/2') == 'serial-1' leshan.format = fmt def verify_device_object(resp): ''' Verify that Device object match Configuration 3 ''' assert resp[0][0] == 'Zephyr' assert resp[0][1] == 'client-1' assert resp[0][2] == 'serial-1' assert resp[0][3] == '1.2.3' assert resp[0][11][0] == 0 assert resp[0][16] == 'U' def verify_server_object(obj): ''' Verify that server object match Configuration 3 ''' assert obj[0][0] == 1 assert obj[0][1] == 86400 assert obj[0][2] == 1 assert obj[0][3] == 10 assert obj[0][5] == 86400 assert obj[0][6] is False assert obj[0][7] == 'U' def test_LightweightM2M_1_1_int_203(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-203 - Querying basic information in TLV format""" fmt = leshan.format leshan.format = 'TLV' resp = leshan.read(endpoint,'3/0') verify_device_object(resp) leshan.format = fmt def test_LightweightM2M_1_1_int_204(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-204 - Querying basic information in JSON format""" fmt = leshan.format leshan.format = 'JSON' resp = leshan.read(endpoint, '3/0') verify_device_object(resp) leshan.format = fmt def test_LightweightM2M_1_1_int_205(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-205 - Setting basic information in Plain Text format""" fmt = leshan.format leshan.format = 'TEXT' leshan.write(endpoint, '1/0/2', 101) leshan.write(endpoint, '1/0/3', 1010) leshan.write(endpoint, '1/0/5', 2000) assert leshan.read(endpoint, '1/0/2') == 101 assert leshan.read(endpoint, '1/0/3') == 1010 assert leshan.read(endpoint, '1/0/5') == 2000 leshan.write(endpoint, '1/0/2', 1) leshan.write(endpoint, '1/0/3', 10) leshan.write(endpoint, '1/0/5', 86400) assert leshan.read(endpoint, '1/0/2') == 1 assert leshan.read(endpoint, '1/0/3') == 10 assert leshan.read(endpoint, '1/0/5') == 86400 leshan.format = fmt def test_LightweightM2M_1_1_int_211(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-211 - Querying basic information in CBOR format""" fmt = leshan.format leshan.format = 'CBOR' lines = shell.get_filtered_output(shell.exec_command('lwm2m read 1/0/0 -u16')) short_id = int(lines[0]) assert leshan.read(endpoint, '1/0/0') == short_id assert leshan.read(endpoint, '1/0/6') is False assert leshan.read(endpoint, '1/0/7') == 'U' leshan.format = fmt def test_LightweightM2M_1_1_int_212(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-212 - Setting basic information in CBOR format""" fmt = leshan.format leshan.format = 'CBOR' leshan.write(endpoint, '1/0/2', 101) leshan.write(endpoint, '1/0/3', 1010) leshan.write(endpoint, '1/0/6', True) assert leshan.read(endpoint, '1/0/2') == 101 assert leshan.read(endpoint, '1/0/3') == 1010 assert leshan.read(endpoint, '1/0/6') is True leshan.write(endpoint, '1/0/2', 1) leshan.write(endpoint, '1/0/3', 10) leshan.write(endpoint, '1/0/6', False) leshan.format = fmt def verify_setting_basic_in_format(shell, leshan, endpoint, format): fmt = leshan.format leshan.format = format server_obj = leshan.read(endpoint, '1/0') verify_server_object(server_obj) # Remove Read-Only resources, so we don't end up writing those del server_obj[0][0] del server_obj[0][13] data = { 2: 101, 3: 1010, 5: 2000, 6: True, 7: 'U' } assert leshan.update_obj_instance(endpoint, '1/0', data)['status'] == 'CHANGED(204)' resp = leshan.read(endpoint, '1/0') assert resp[0][2] == 101 assert resp[0][3] == 1010 assert resp[0][5] == 2000 assert resp[0][6] is True assert resp[0][7] == 'U' assert leshan.replace_obj_instance(endpoint, '1/0', server_obj[0])['status'] == 'CHANGED(204)' server_obj = leshan.read(endpoint, '1/0') verify_server_object(server_obj) leshan.format = fmt def test_LightweightM2M_1_1_int_215(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-215 - Setting basic information in TLV format""" verify_setting_basic_in_format(shell, leshan, endpoint, 'TLV') def test_LightweightM2M_1_1_int_220(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-220 - Setting basic information in JSON format""" verify_setting_basic_in_format(shell, leshan, endpoint, 'JSON') def test_LightweightM2M_1_1_int_221(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-221 - Attempt to perform operations on Security""" assert leshan.read(endpoint, '0/0')['status'] == 'UNAUTHORIZED(401)' assert leshan.write(endpoint, '0/0/0', 'coap://localhost')['status'] == 'UNAUTHORIZED(401)' assert leshan.write_attributes(endpoint, '0', {'pmin':10})['status'] == 'UNAUTHORIZED(401)' def test_LightweightM2M_1_1_int_222(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-222 - Read on Object""" resp = leshan.read(endpoint, '1') assert len(resp) == 1 assert len(resp[1][0]) == 11 resp = leshan.read(endpoint, '3') assert len(resp) == 1 assert len(resp[3]) == 1 assert len(resp[3][0]) == 15 assert resp[3][0][0] == 'Zephyr' def test_LightweightM2M_1_1_int_223(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-223 - Read on Object Instance""" resp = leshan.read(endpoint, '1/0') assert len(resp[0]) == 11 resp = leshan.read(endpoint, '3/0') assert len(resp[0]) == 15 assert resp[0][0] == 'Zephyr' def test_LightweightM2M_1_1_int_224(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-224 - Read on Resource""" assert leshan.read(endpoint, '1/0/0') == 1 assert leshan.read(endpoint, '1/0/1') == 86400 assert leshan.read(endpoint, '1/0/6') is False assert leshan.read(endpoint, '1/0/7') == 'U' def test_LightweightM2M_1_1_int_225(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-225 - Read on Resource Instance""" assert leshan.read(endpoint, '3/0/11/0') == 0 def test_LightweightM2M_1_1_int_226(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-226 - Write (Partial Update) on Object Instance""" lines = shell.get_filtered_output(shell.exec_command('lwm2m read 1/0/1 -u32')) lifetime = int(lines[0]) resources = { 1: 60, 6: True } assert leshan.update_obj_instance(endpoint, '1/0', resources)['status'] == 'CHANGED(204)' assert leshan.read(endpoint, '1/0/1') == 60 assert leshan.read(endpoint, '1/0/6') is True resources = { 1: lifetime, 6: False } assert leshan.update_obj_instance(endpoint, '1/0', resources)['status'] == 'CHANGED(204)' def test_LightweightM2M_1_1_int_227(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-227 - Write (replace) on Resource""" lines = shell.get_filtered_output(shell.exec_command('lwm2m read 1/0/1 -u32')) lifetime = int(lines[0]) assert leshan.write(endpoint, '1/0/1', int(63))['status'] == 'CHANGED(204)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) latest = leshan.get(f'/clients/{endpoint}') assert latest["lifetime"] == 63 assert leshan.read(endpoint, '1/0/1') == 63 assert leshan.write(endpoint, '1/0/1', lifetime)['status'] == 'CHANGED(204)' def test_LightweightM2M_1_1_int_228(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-228 - Write on Resource Instance""" resources = { 0: {0: 'a', 1: 'b'} } assert leshan.create_obj_instance(endpoint, '16/0', resources)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) assert leshan.write(endpoint, '16/0/0/0', 'test')['status'] == 'CHANGED(204)' assert leshan.read(endpoint, '16/0/0/0') == 'test' def test_LightweightM2M_1_1_int_229(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-229 - Read-Composite Operation""" old_fmt = leshan.format for fmt in ['SENML_JSON', 'SENML_CBOR']: leshan.format = fmt resp = leshan.composite_read(endpoint, ['/3', '1/0']) assert len(resp.keys()) == 2 assert resp[3] is not None assert resp[1][0] is not None assert len(resp[3][0]) == 15 assert len(resp[1][0]) == 11 resp = leshan.composite_read(endpoint, ['1/0/1', '/3/0/11/0']) logger.debug(resp) assert len(resp.keys()) == 2 assert resp[1][0][1] is not None assert resp[3][0][11][0] is not None leshan.format = old_fmt def test_LightweightM2M_1_1_int_230(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-230 - Write-Composite Operation""" resources = { "/1/0/1": 60, "/1/0/6": True, "/16/0/0": { "0": "aa", "1": "bb", "2": "cc", "3": "dd" } } old_fmt = leshan.format for fmt in ['SENML_JSON', 'SENML_CBOR']: leshan.format = fmt assert leshan.composite_write(endpoint, resources)['status'] == 'CHANGED(204)' resp = leshan.read(endpoint, '1/0') assert resp[0][1] == 60 assert resp[0][6] is True resp = leshan.read(endpoint, '16/0/0') assert resp[0][0] == "aa" assert resp[0][1] == "bb" assert resp[0][2] == "cc" assert resp[0][3] == "dd" # Return to default shell.exec_command('lwm2m write /1/0/1 -u32 86400') shell.exec_command('lwm2m write /1/0/6 -u8 0') leshan.format = old_fmt def query_basic_in_senml(leshan: Leshan, endpoint: str, fmt: str): """Querying basic information in one of the SenML formats""" old_fmt = leshan.format leshan.format = fmt verify_server_object(leshan.read(endpoint, '1')[1]) verify_device_object(leshan.read(endpoint, '3/0')) assert leshan.read(endpoint, '3/0/16') == 'U' assert leshan.read(endpoint, '3/0/11/0') == 0 leshan.format = old_fmt def test_LightweightM2M_1_1_int_231(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-231 - Querying basic information in SenML JSON format""" query_basic_in_senml(leshan, endpoint, 'SENML_JSON') def test_LightweightM2M_1_1_int_232(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-232 - Querying basic information in SenML CBOR format""" query_basic_in_senml(leshan, endpoint, 'SENML_CBOR') def setting_basic_senml(shell: Shell, leshan: Leshan, endpoint: str, fmt: str): """Setting basic information in one of the SenML formats""" old_fmt = leshan.format leshan.format = fmt resources = { 1: 61, 6: True, } assert leshan.update_obj_instance(endpoint, '1/0', resources)['status'] == 'CHANGED(204)' srv_obj = leshan.read(endpoint, '1/0') assert srv_obj[0][1] == 61 assert srv_obj[0][6] is True assert leshan.write(endpoint, '16/0/0/0', 'test_value')['status'] == 'CHANGED(204)' portfolio = leshan.read(endpoint, '16') assert portfolio[16][0][0][0] == 'test_value' assert leshan.write(endpoint, '1/0/1', 63)['status'] == 'CHANGED(204)' assert leshan.read(endpoint, '1/0/1') == 63 shell.exec_command('lwm2m write /1/0/1 -u32 86400') shell.exec_command('lwm2m write /1/0/6 -u8 0') leshan.format = old_fmt def test_LightweightM2M_1_1_int_233(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-233 - Setting basic information in SenML CBOR format""" setting_basic_senml(shell, leshan, endpoint, 'SENML_CBOR') def test_LightweightM2M_1_1_int_234(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-234 - Setting basic information in SenML JSON format""" setting_basic_senml(shell, leshan, endpoint, 'SENML_JSON') def test_LightweightM2M_1_1_int_235(leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-235 - Read-Composite Operation on root path""" resp = leshan.composite_read(endpoint, ['/']) expected_keys = [1, 3, 5] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 def test_LightweightM2M_1_1_int_236(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-236 - Read-Composite - Partial Presence""" resp = leshan.composite_read(endpoint, ['1/0', '/3/0/11/0', '/3339/0/5522', '/3353/0/6030']) assert resp[1][0][1] is not None assert resp[3][0][11][0] is not None assert len(resp) == 2 def test_LightweightM2M_1_1_int_237(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-237 - Read on Object without specifying Content-Type""" old_fmt = leshan.format leshan.format = None assert leshan.read(endpoint, '1')[1][0][1] is not None assert leshan.read(endpoint, '3')[3][0][0] == 'Zephyr' leshan.format = old_fmt def test_LightweightM2M_1_1_int_241(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-241 - Executable Resource: Rebooting the device""" leshan.execute(endpoint, '3/0/4') dut.readlines_until(regex='.*DEVICE: REBOOT', timeout=5.0) dut.readlines_until(regex='.*rd_client_event: Disconnected', timeout=5.0) shell.exec_command(f'lwm2m start {endpoint} -b 0') dut.readlines_until(regex='.*Registration Done', timeout=5.0) assert leshan.get(f'/clients/{endpoint}') def test_LightweightM2M_1_1_int_256(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-256 - Write Operation Failure""" lines = shell.get_filtered_output(shell.exec_command('lwm2m read 1/0/0 -u16')) short_id = int(lines[0]) assert leshan.write(endpoint, '1/0/0', 123)['status'] == 'METHOD_NOT_ALLOWED(405)' assert leshan.read(endpoint, '1/0/0') == short_id def test_LightweightM2M_1_1_int_257(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-257 - Write-Composite Operation""" resources = { "/1/0/2": 102, "/1/0/6": True, "/3/0/13": datetime.fromtimestamp(0) } old_fmt = leshan.format for fmt in ['SENML_JSON', 'SENML_CBOR']: leshan.format = fmt assert leshan.composite_write(endpoint, resources)['status'] == 'CHANGED(204)' assert leshan.read(endpoint, '1/0/2') == 102 assert leshan.read(endpoint, '1/0/6') is True # Cannot verify the /3/0/13, it is a timestamp that moves forward. # Return to default shell.exec_command(f'lwm2m write /3/0/13 -u32 {int(datetime.now().timestamp())}') shell.exec_command('lwm2m write /1/0/6 -u8 0') shell.exec_command('lwm2m write /1/0/2 -u32 1') leshan.format = old_fmt def test_LightweightM2M_1_1_int_260(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-260 - Discover Command""" resp = leshan.discover(endpoint, '3') expected_keys = ['/3', '/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 assert leshan.write_attributes(endpoint, '3', {'pmin': 10, 'pmax': 200})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') assert int(resp['/3/0/6']['dim']) == 2 assert int(resp['/3/0/7']['dim']) == 2 assert int(resp['/3/0/8']['dim']) == 2 assert leshan.write_attributes(endpoint, '3/0/7', {'lt': 1, 'gt': 6, 'st': 1})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0') expected_keys = ['/3/0', '/3/0/1', '/3/0/2', '/3/0/3', '/3/0/4', '/3/0/6', '/3/0/7', '/3/0/8', '/3/0/9', '/3/0/11', '/3/0/16'] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 assert int(resp['/3/0/7']['dim']) == 2 assert float(resp['/3/0/7']['lt']) == 1.0 assert float(resp['/3/0/7']['gt']) == 6.0 assert float(resp['/3/0/7']['st']) == 1.0 resp = leshan.discover(endpoint, '3/0/7') expected_keys = ['/3/0/7', '/3/0/7/0', '/3/0/7/1'] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) # restore leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) def test_LightweightM2M_1_1_int_261(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-261 - Write-Attribute Operation on a multiple resource""" resp = leshan.discover(endpoint, '3/0/11') logger.debug(resp) expected_keys = ['/3/0/11', '/3/0/11/0'] missing_keys = [key for key in expected_keys if key not in resp.keys()] assert len(missing_keys) == 0 assert len(resp) == len(expected_keys) assert int(resp['/3/0/11']['dim']) == 1 assert leshan.write_attributes(endpoint, '3', {'pmin':10, 'pmax':200})['status'] == 'CHANGED(204)' assert leshan.write_attributes(endpoint, '3/0', {'pmax':320})['status'] == 'CHANGED(204)' assert leshan.write_attributes(endpoint, '3/0/11/0', {'pmax':100, 'epmin':1, 'epmax':20})['status'] == 'CHANGED(204)' resp = leshan.discover(endpoint, '3/0/11') logger.debug(resp) assert int(resp['/3/0/11']['pmin']) == 10 assert int(resp['/3/0/11']['pmax']) == 320 assert int(resp['/3/0/11/0']['pmax']) == 100 # Note: Zephyr does not support epmin&epmax. # Restore leshan.remove_attributes(endpoint, '3', ['pmin', 'pmax']) leshan.remove_attributes(endpoint, '3/0', ['pmax']) leshan.remove_attributes(endpoint, '3/0/11/0', ['pmax']) def test_LightweightM2M_1_1_int_280(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-280 - Successful Read-Composite Operation""" resp = leshan.composite_read(endpoint, ['/3/0/16', '/3/0/11/0', '/1/0']) logger.debug(resp) assert len(resp) == 2 assert len(resp[3]) == 1 assert len(resp[3][0]) == 2 # No extra resources assert resp[3][0][11][0] == 0 assert resp[3][0][16] == 'U' assert resp[1][0][0] == 1 assert resp[1][0][1] == 86400 assert resp[1][0][6] is False assert resp[1][0][7] == 'U' def test_LightweightM2M_1_1_int_281(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-281 - Partially Successful Read-Composite Operation""" resp = leshan.composite_read(endpoint, ['/1/0/1', '/1/0/7', '/1/0/8']) assert len(resp) == 1 assert len(resp[1][0]) == 2 # /1/0/8 should not be there assert resp[1][0][1] == 86400 assert resp[1][0][7] == 'U' # # Information Reporting Interface [300-399] # @pytest.mark.slow def test_LightweightM2M_1_1_int_301(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-301 - Observation and Notification of parameter values""" pwr_src = leshan.read(endpoint, '3/0/6') logger.debug(pwr_src) assert pwr_src[6][0] == 1 assert pwr_src[6][1] == 5 assert leshan.write_attributes(endpoint, '3/0/7', {'pmin': 5, 'pmax': 10})['status'] == 'CHANGED(204)' leshan.observe(endpoint, '3/0/7') with leshan.get_event_stream(endpoint, timeout=30) as events: shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') data = events.next_event('NOTIFICATION') assert data is not None assert data[3][0][7][0] == 3000 # Ensure that we don't get new data before pMin start = time.time() shell.exec_command('lwm2m write /3/0/7/0 -u32 3500') data = events.next_event('NOTIFICATION') assert data[3][0][7][0] == 3500 assert (start + 5) < time.time() + 0.5 # Allow 0.5 second diff assert (start + 5) > time.time() - 0.5 # Ensure that we get update when pMax expires data = events.next_event('NOTIFICATION') assert data[3][0][7][0] == 3500 assert (start + 15) <= time.time() + 1 # Allow 1 second slack. (pMinx + pMax=15) leshan.cancel_observe(endpoint, '3/0/7') leshan.remove_attributes(endpoint, '3/0/7', ['pmin', 'pmax']) def test_LightweightM2M_1_1_int_302(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-302 - Cancel Observations using Reset Operation""" leshan.observe(endpoint, '3/0/7') leshan.observe(endpoint, '3/0/8') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') data = events.next_event('NOTIFICATION') assert data[3][0][7][0] == 4000 leshan.passive_cancel_observe(endpoint, '3/0/7') shell.exec_command('lwm2m write /3/0/7/0 -u32 3000') dut.readlines_until(regex=r'.*Observer removed for 3/0/7') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/8/0 -u32 100') data = events.next_event('NOTIFICATION') assert data[3][0][8][0] == 100 leshan.passive_cancel_observe(endpoint, '3/0/8') shell.exec_command('lwm2m write /3/0/8/0 -u32 50') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') def test_LightweightM2M_1_1_int_303(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-303 - Cancel observations using Observe with Cancel parameter""" leshan.observe(endpoint, '3/0/7') leshan.observe(endpoint, '3/0/8') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/7/0 -u32 4000') data = events.next_event('NOTIFICATION') assert data[3][0][7][0] == 4000 leshan.cancel_observe(endpoint, '3/0/7') dut.readlines_until(regex=r'.*Observer removed for 3/0/7') with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m write /3/0/8/0 -u32 100') data = events.next_event('NOTIFICATION') assert data[3][0][8][0] == 100 leshan.cancel_observe(endpoint, '3/0/8') dut.readlines_until(regex=r'.*Observer removed for 3/0/8') @pytest.mark.slow def test_LightweightM2M_1_1_int_304(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-304 - Observe-Composite Operation""" # Need to use Configuration C.1 shell.exec_command('lwm2m write 1/0/2 -u32 0') shell.exec_command('lwm2m write 1/0/3 -u32 0') assert leshan.write_attributes(endpoint, '1/0/1', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) assert data[1][0][1] is not None assert data[3][0][11][0] is not None assert data[3][0][16] == 'U' assert len(data) == 2 assert len(data[1]) == 1 assert len(data[3][0]) == 2 start = time.time() with leshan.get_event_stream(endpoint, timeout=50) as events: data = events.next_event('NOTIFICATION') logger.debug(data) assert data[1][0][1] is not None assert data[3][0][11][0] is not None assert data[3][0][16] == 'U' assert len(data) == 2 assert len(data[1]) == 1 assert len(data[3][0]) == 2 assert (start + 30) < time.time() assert (start + 45) > time.time() - 1 leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') leshan.remove_attributes(endpoint, '1/0/1', ['pmin', 'pmax']) def test_LightweightM2M_1_1_int_305(dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-305 - Cancel Observation-Composite Operation""" leshan.composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0/11/0', '/3/0/16']) dut.readlines_until(regex=r'.*Observer removed for 1/0/1') dut.readlines_until(regex=r'.*Observer removed for 3/0/11/0') dut.readlines_until(regex=r'.*Observer removed for 3/0/16') def test_LightweightM2M_1_1_int_306(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-306 - Send Operation""" with leshan.get_event_stream(endpoint) as events: shell.exec_command('lwm2m send /1 /3') dut.readlines_until(regex=r'.*SEND status: 0', timeout=5.0) data = events.next_event('SEND') assert data is not None verify_server_object(data[1]) verify_device_object(data[3]) def test_LightweightM2M_1_1_int_307(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-307 - Muting Send""" leshan.write(endpoint, '1/0/23', True) lines = shell.get_filtered_output(shell.exec_command('lwm2m send /3/0')) assert any("can't do send operation" in line for line in lines) leshan.write(endpoint, '1/0/23', False) shell.exec_command('lwm2m send /3/0') dut.readlines_until(regex=r'.*SEND status: 0', timeout=5.0) @pytest.mark.slow def test_LightweightM2M_1_1_int_308(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-308 - Observe-Composite and Creating Object Instance""" shell.exec_command('lwm2m delete /16/0') shell.exec_command('lwm2m delete /16/1') # Need to use Configuration C.1 shell.exec_command('lwm2m write 1/0/2 -u32 0') shell.exec_command('lwm2m write 1/0/3 -u32 0') resources_a = { 0: {0: 'aa', 1: 'bb', 2: 'cc', 3: 'dd'} } content_one = {16: {0: resources_a}} resources_b = { 0: {0: '11', 1: '22', 2: '33', 3: '44'} } content_both = {16: {0: resources_a, 1: resources_b}} assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_one with leshan.get_event_stream(endpoint, timeout=50) as events: data = events.next_event('NOTIFICATION') start = time.time() assert data == content_one assert leshan.create_obj_instance(endpoint, '16/1', resources_b)['status'] == 'CREATED(201)' data = events.next_event('NOTIFICATION') assert (start + 30) < time.time() + 2 assert (start + 45) > time.time() - 2 assert data == content_both leshan.cancel_composite_observe(endpoint, ['/16/0', '/16/1']) # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') leshan.remove_attributes(endpoint, '16/0', ['pmin','pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_309(shell: Shell, dut: DeviceAdapter, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-309 - Observe-Composite and Deleting Object Instance""" shell.exec_command('lwm2m delete /16/0') shell.exec_command('lwm2m delete /16/1') # Need to use Configuration C.1 shell.exec_command('lwm2m write 1/0/2 -u32 0') shell.exec_command('lwm2m write 1/0/3 -u32 0') resources_a = { 0: {0: 'aa', 1: 'bb', 2: 'cc', 3: 'dd'} } content_one = {16: {0: resources_a}} resources_b = { 0: {0: '11', 1: '22', 2: '33', 3: '44'} } content_both = {16: {0: resources_a, 1: resources_b}} assert leshan.create_obj_instance(endpoint, '16/0', resources_a)['status'] == 'CREATED(201)' assert leshan.create_obj_instance(endpoint, '16/1', resources_b)['status'] == 'CREATED(201)' dut.readlines_until(regex='.*net_lwm2m_rd_client: Update Done', timeout=5.0) assert leshan.write_attributes(endpoint, '16/0', {'pmin': 30, 'pmax': 45})['status'] == 'CHANGED(204)' data = leshan.composite_observe(endpoint, ['/16/0', '/16/1']) assert data == content_both with leshan.get_event_stream(endpoint, timeout=50) as events: data = events.next_event('NOTIFICATION') start = time.time() assert data == content_both assert leshan.delete(endpoint, '16/1')['status'] == 'DELETED(202)' data = events.next_event('NOTIFICATION') assert (start + 30) < time.time() + 2 assert (start + 45) > time.time() - 2 assert data == content_one leshan.cancel_composite_observe(endpoint, ['/16/0', '/16/1']) # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') leshan.remove_attributes(endpoint, '16/0', ['pmin', 'pmax']) @pytest.mark.slow def test_LightweightM2M_1_1_int_310(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-310 - Observe-Composite and modification of parameter values""" # Need to use Configuration C.1 shell.exec_command('lwm2m write 1/0/2 -u32 0') shell.exec_command('lwm2m write 1/0/3 -u32 0') leshan.composite_observe(endpoint, ['/1/0/1', '/3/0']) with leshan.get_event_stream(endpoint, timeout=50) as events: assert leshan.write_attributes(endpoint, '3', {'pmax': 5})['status'] == 'CHANGED(204)' start = time.time() data = events.next_event('NOTIFICATION') assert data[3][0][0] == 'Zephyr' assert data[1] == {0: {1: 86400}} assert (start + 5) > time.time() - 1 start = time.time() data = events.next_event('NOTIFICATION') assert (start + 5) > time.time() - 1 leshan.cancel_composite_observe(endpoint, ['/1/0/1', '/3/0']) # Restore configuration C.3 shell.exec_command('lwm2m write 1/0/2 -u32 1') shell.exec_command('lwm2m write 1/0/3 -u32 10') leshan.remove_attributes(endpoint, '3', ['pmax']) def test_LightweightM2M_1_1_int_311(shell: Shell, leshan: Leshan, endpoint: str): """LightweightM2M-1.1-int-311 - Send command""" with leshan.get_event_stream(endpoint, timeout=50) as events: shell.exec_command('lwm2m send /1/0/1 /3/0/11') data = events.next_event('SEND') assert data == {3: {0: {11: {0: 0}}}, 1: {0: {1: 86400}}}