/*******************************************************************************
* Copyright (c) 2013-2015 Sierra Wireless and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Zebra Technologies - initial API and implementation
* Achim Kraus (Bosch Software Innovations GmbH) - add test for write security object
* Achim Kraus (Bosch Software Innovations GmbH) - add test for update and replace instances
*******************************************************************************/
package org.eclipse.leshan.integration.tests;
import static org.eclipse.leshan.integration.tests.IntegrationTestHelper.*;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.leshan.ResponseCode;
import org.eclipse.leshan.core.model.ResourceModel.Type;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mObjectInstance;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.request.ContentFormat;
import org.eclipse.leshan.core.request.ReadRequest;
import org.eclipse.leshan.core.request.WriteRequest;
import org.eclipse.leshan.core.request.WriteRequest.Mode;
import org.eclipse.leshan.core.response.ErrorCallback;
import org.eclipse.leshan.core.response.ReadResponse;
import org.eclipse.leshan.core.response.ResponseCallback;
import org.eclipse.leshan.core.response.WriteResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class WriteTest {
private IntegrationTestHelper helper = new IntegrationTestHelper();
@Before
public void start() {
helper.initialize();
helper.createServer();
helper.server.start();
helper.createClient();
helper.client.start();
helper.waitForRegistration(1);
}
@After
public void stop() {
helper.client.destroy(false);
helper.server.destroy();
helper.dispose();
}
@Test
public void can_write_string_resource_in_text() throws InterruptedException {
write_string_resource(ContentFormat.TEXT);
}
@Test
public void can_write_string_resource_in_tlv() throws InterruptedException {
write_string_resource(ContentFormat.TLV);
}
@Test
public void can_write_string_resource_in__old_tlv() throws InterruptedException {
write_string_resource(ContentFormat.fromCode(ContentFormat.OLD_TLV_CODE));
}
@Test
public void can_write_string_resource_in_json() throws InterruptedException {
write_string_resource(ContentFormat.JSON);
}
@Test
public void can_write_string_resource_in__old_json() throws InterruptedException {
write_string_resource(ContentFormat.fromCode(ContentFormat.OLD_JSON_CODE));
}
private void write_string_resource(ContentFormat format) throws InterruptedException {
// write resource
String expectedvalue = "stringvalue";
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(format, TEST_OBJECT_ID, 0, STRING_RESOURCE_ID, expectedvalue));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read resource to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(),
new ReadRequest(TEST_OBJECT_ID, 0, STRING_RESOURCE_ID));
LwM2mResource resource = (LwM2mResource) readResponse.getContent();
assertEquals(expectedvalue, resource.getValue());
}
@Test
public void can_write_boolean_resource_in_text() throws InterruptedException {
write_boolean_resource(ContentFormat.TEXT);
}
@Test
public void can_write_boolean_resource_in_tlv() throws InterruptedException {
write_boolean_resource(ContentFormat.TLV);
}
@Test
public void can_write_boolean_resource_in_old_tlv() throws InterruptedException {
write_boolean_resource(ContentFormat.fromCode(ContentFormat.OLD_TLV_CODE));
}
@Test
public void can_write_boolean_resource_in_json() throws InterruptedException {
write_boolean_resource(ContentFormat.JSON);
}
@Test
public void can_write_boolean_resource_in_old_json() throws InterruptedException {
write_boolean_resource(ContentFormat.fromCode(ContentFormat.OLD_JSON_CODE));
}
private void write_boolean_resource(ContentFormat format) throws InterruptedException {
// write resource
boolean expectedvalue = true;
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(format, TEST_OBJECT_ID, 0, BOOLEAN_RESOURCE_ID, expectedvalue));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read resource to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(),
new ReadRequest(TEST_OBJECT_ID, 0, BOOLEAN_RESOURCE_ID));
LwM2mResource resource = (LwM2mResource) readResponse.getContent();
assertEquals(expectedvalue, resource.getValue());
}
@Test
public void can_write_integer_resource_in_text() throws InterruptedException {
write_integer_resource(ContentFormat.TEXT);
}
@Test
public void can_write_integer_resource_in_tlv() throws InterruptedException {
write_integer_resource(ContentFormat.TLV);
}
@Test
public void can_write_integer_resource_in_old_tlv() throws InterruptedException {
write_integer_resource(ContentFormat.fromCode(ContentFormat.OLD_TLV_CODE));
}
@Test
public void can_write_integer_resource_in_json() throws InterruptedException {
write_integer_resource(ContentFormat.JSON);
}
@Test
public void can_write_integer_resource_in_old_json() throws InterruptedException {
write_integer_resource(ContentFormat.fromCode(ContentFormat.OLD_JSON_CODE));
}
private void write_integer_resource(ContentFormat format) throws InterruptedException {
// write resource
long expectedvalue = 999l;
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(format, TEST_OBJECT_ID, 0, INTEGER_RESOURCE_ID, expectedvalue));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read resource to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(),
new ReadRequest(TEST_OBJECT_ID, 0, INTEGER_RESOURCE_ID));
LwM2mResource resource = (LwM2mResource) readResponse.getContent();
assertEquals(expectedvalue, resource.getValue());
}
@Test
public void can_write_float_resource_in_text() throws InterruptedException {
write_float_resource(ContentFormat.TEXT);
}
@Test
public void can_write_float_resource_in_tlv() throws InterruptedException {
write_float_resource(ContentFormat.TLV);
}
@Test
public void can_write_float_resource_in_old_tlv() throws InterruptedException {
write_float_resource(ContentFormat.fromCode(ContentFormat.OLD_TLV_CODE));
}
@Test
public void can_write_float_resource_in_json() throws InterruptedException {
write_float_resource(ContentFormat.JSON);
}
@Test
public void can_write_float_resource_in_old_json() throws InterruptedException {
write_float_resource(ContentFormat.fromCode(ContentFormat.OLD_JSON_CODE));
}
private void write_float_resource(ContentFormat format) throws InterruptedException {
// write resource
double expectedvalue = 999.99;
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(format, TEST_OBJECT_ID, 0, FLOAT_RESOURCE_ID, expectedvalue));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read resource to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(),
new ReadRequest(TEST_OBJECT_ID, 0, FLOAT_RESOURCE_ID));
LwM2mResource resource = (LwM2mResource) readResponse.getContent();
assertEquals(expectedvalue, resource.getValue());
}
@Test
public void can_write_time_resource_in_text() throws InterruptedException {
write_time_resource(ContentFormat.TEXT);
}
@Test
public void can_write_time_resource_in_tlv() throws InterruptedException {
write_time_resource(ContentFormat.TLV);
}
@Test
public void can_write_time_resource_in_old_tlv() throws InterruptedException {
write_time_resource(ContentFormat.fromCode(ContentFormat.OLD_TLV_CODE));
}
@Test
public void can_write_time_resource_in_json() throws InterruptedException {
write_time_resource(ContentFormat.JSON);
}
@Test
public void can_write_time_resource_in_old_json() throws InterruptedException {
write_time_resource(ContentFormat.fromCode(ContentFormat.OLD_JSON_CODE));
}
private void write_time_resource(ContentFormat format) throws InterruptedException {
// write resource
Date expectedvalue = new Date(946681000l); // second accuracy
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(format, TEST_OBJECT_ID, 0, TIME_RESOURCE_ID, expectedvalue));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read resource to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(),
new ReadRequest(TEST_OBJECT_ID, 0, TIME_RESOURCE_ID));
LwM2mResource resource = (LwM2mResource) readResponse.getContent();
assertEquals(expectedvalue, resource.getValue());
}
@Test
public void can_write_opaque_resource_in_opaque() throws InterruptedException {
write_opaque_resource(ContentFormat.OPAQUE);
}
@Test
public void can_write_opaque_resource_in_tlv() throws InterruptedException {
write_opaque_resource(ContentFormat.TLV);
}
@Test
public void can_write_opaque_resource_in_old_tlv() throws InterruptedException {
write_opaque_resource(ContentFormat.fromCode(ContentFormat.OLD_TLV_CODE));
}
@Test
public void can_write_opaque_resource_in_json() throws InterruptedException {
write_opaque_resource(ContentFormat.JSON);
}
@Test
public void can_write_opaque_resource_in_old_json() throws InterruptedException {
write_opaque_resource(ContentFormat.fromCode(ContentFormat.OLD_JSON_CODE));
}
private void write_opaque_resource(ContentFormat format) throws InterruptedException {
// write resource
byte[] expectedvalue = new byte[] { 1, 2, 3 };
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(format, TEST_OBJECT_ID, 0, OPAQUE_RESOURCE_ID, expectedvalue));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read resource to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(),
new ReadRequest(TEST_OBJECT_ID, 0, OPAQUE_RESOURCE_ID));
LwM2mResource resource = (LwM2mResource) readResponse.getContent();
assertArrayEquals(expectedvalue, (byte[]) resource.getValue());
}
@Test
public void cannot_write_non_writable_resource() throws InterruptedException {
// try to write unwritable resource like manufacturer on device
String manufacturer = "new manufacturer";
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(3, 0, 0, manufacturer));
// verify result
assertEquals(ResponseCode.METHOD_NOT_ALLOWED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
}
@Test
public void cannot_write_security_resource() throws InterruptedException {
// try to write unwritable resource like manufacturer on device
String uri = "new.dest.server";
WriteResponse response = helper.server.send(helper.getCurrentRegistration(), new WriteRequest(0, 0, 0, uri));
// verify result
assertEquals(ResponseCode.NOT_FOUND, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
}
@Test
public void can_write_object_instance_in_tlv() throws InterruptedException {
can_write_object_instance(ContentFormat.TLV);
}
@Test
public void can_write_object_instance_in_old_tlv() throws InterruptedException {
can_write_object_instance(ContentFormat.fromCode(ContentFormat.OLD_TLV_CODE));
}
@Test
public void can_write_object_instance_in_json() throws InterruptedException {
can_write_object_instance(ContentFormat.JSON);
}
@Test
public void can_write_object_instance_in_old_json() throws InterruptedException {
can_write_object_instance(ContentFormat.fromCode(ContentFormat.OLD_JSON_CODE));
}
public void can_write_object_instance(ContentFormat format) throws InterruptedException {
// write device timezone and offset
LwM2mResource utcOffset = LwM2mSingleResource.newStringResource(14, "+02");
LwM2mResource timeZone = LwM2mSingleResource.newStringResource(15, "Europe/Paris");
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(Mode.REPLACE, format, 3, 0, utcOffset, timeZone));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read the timezone to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(), new ReadRequest(3, 0));
LwM2mObjectInstance instance = (LwM2mObjectInstance) readResponse.getContent();
assertEquals(utcOffset, instance.getResource(14));
assertEquals(timeZone, instance.getResource(15));
}
@Test
public void can_write_replacing_object_instance() throws InterruptedException {
// setup server object
WriteResponse response = helper.server.send(helper.getCurrentRegistration(), new WriteRequest(1, 0, 3, 60));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// write server object
LwM2mResource lifetime = LwM2mSingleResource.newIntegerResource(1, 120);
LwM2mResource defaultMinPeriod = LwM2mSingleResource.newIntegerResource(2, 10);
LwM2mResource notificationStoring = LwM2mSingleResource.newBooleanResource(6, false);
LwM2mResource binding = LwM2mSingleResource.newStringResource(7, "U");
response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(Mode.REPLACE, 1, 0, lifetime, defaultMinPeriod, notificationStoring, binding));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read the values to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(), new ReadRequest(1, 0));
LwM2mObjectInstance instance = (LwM2mObjectInstance) readResponse.getContent();
assertEquals(lifetime, instance.getResource(1));
assertEquals(defaultMinPeriod, instance.getResource(2));
assertEquals(notificationStoring, instance.getResource(6));
assertEquals(binding, instance.getResource(7));
assertNull(instance.getResource(3)); // removed not contained optional writable resource
}
@Test
public void cannot_write_replacing_incomplete_object_instance() throws InterruptedException {
// write server object
LwM2mResource lifetime = LwM2mSingleResource.newIntegerResource(1, 120);
LwM2mResource defaultMinPeriod = LwM2mSingleResource.newIntegerResource(2, 10);
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(Mode.REPLACE, 1, 0, lifetime, defaultMinPeriod));
// verify result
assertEquals(ResponseCode.BAD_REQUEST, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
}
@Test
public void can_write_updating_object_instance() throws InterruptedException {
// setup server object
WriteResponse response = helper.server.send(helper.getCurrentRegistration(), new WriteRequest(1, 0, 3, 60));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// write server object
LwM2mResource lifetime = LwM2mSingleResource.newIntegerResource(1, 120);
LwM2mResource defaultMinPeriod = LwM2mSingleResource.newIntegerResource(2, 10);
response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(Mode.UPDATE, 1, 0, lifetime, defaultMinPeriod));
// verify result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// read the values to check the value changed
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(), new ReadRequest(1, 0));
LwM2mObjectInstance instance = (LwM2mObjectInstance) readResponse.getContent();
assertEquals(lifetime, instance.getResource(1));
assertEquals(defaultMinPeriod, instance.getResource(2));
// no resources are removed when updating
assertNotNull(instance.getResource(3));
assertNotNull(instance.getResource(6));
assertNotNull(instance.getResource(7));
}
@Test
public void can_write_multi_instance_objlnk_resource_in_tlv() throws InterruptedException {
Map<Integer, ObjectLink> neighbourCellReport = new HashMap<>();
neighbourCellReport.put(0, new ObjectLink(10245, 1));
neighbourCellReport.put(1, new ObjectLink(10242, 2));
neighbourCellReport.put(2, new ObjectLink(10244, 3));
// Write objlnk resource in TLV format
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(ContentFormat.TLV, IntegrationTestHelper.TEST_OBJECT_ID, 0,
IntegrationTestHelper.OBJLNK_MULTI_INSTANCE_RESOURCE_ID, neighbourCellReport, Type.OBJLNK));
// Verify Write result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// Reading back the written OBJLNK value
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(), new ReadRequest(
IntegrationTestHelper.TEST_OBJECT_ID, 0, IntegrationTestHelper.OBJLNK_MULTI_INSTANCE_RESOURCE_ID));
LwM2mMultipleResource resource = (LwM2mMultipleResource) readResponse.getContent();
// verify read value
assertEquals(((ObjectLink) resource.getValue(0)).getObjectId(), 10245);
assertEquals(((ObjectLink) resource.getValue(0)).getObjectInstanceId(), 1);
assertEquals(((ObjectLink) resource.getValue(1)).getObjectId(), 10242);
assertEquals(((ObjectLink) resource.getValue(1)).getObjectInstanceId(), 2);
assertEquals(((ObjectLink) resource.getValue(2)).getObjectId(), 10244);
assertEquals(((ObjectLink) resource.getValue(2)).getObjectInstanceId(), 3);
}
@Test
public void can_write_single_instance_objlnk_resource_in_tlv() throws InterruptedException {
ObjectLink data = new ObjectLink(10245, 1);
// Write objlnk resource in TLV format
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(ContentFormat.TLV, IntegrationTestHelper.TEST_OBJECT_ID, 0,
IntegrationTestHelper.OBJLNK_SINGLE_INSTANCE_RESOURCE_ID, data));
// Verify Write result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// Reading back the written OBJLNK value
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(), new ReadRequest(
IntegrationTestHelper.TEST_OBJECT_ID, 0, IntegrationTestHelper.OBJLNK_SINGLE_INSTANCE_RESOURCE_ID));
LwM2mSingleResource resource = (LwM2mSingleResource) readResponse.getContent();
// verify read value
assertEquals(((ObjectLink) resource.getValue()).getObjectId(), 10245);
assertEquals(((ObjectLink) resource.getValue()).getObjectInstanceId(), 1);
}
@Test
public void can_write_single_instance_objlnk_resource_in_text() throws InterruptedException {
// Write objlnk resource in TEXT format
WriteResponse response = helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(ContentFormat.TEXT, IntegrationTestHelper.TEST_OBJECT_ID, 0,
IntegrationTestHelper.OBJLNK_SINGLE_INSTANCE_RESOURCE_ID, new ObjectLink(10245, 0)));
// Verify Write result
assertEquals(ResponseCode.CHANGED, response.getCode());
assertNotNull(response.getCoapResponse());
assertThat(response.getCoapResponse(), is(instanceOf(Response.class)));
// Reading back the written OBJLNK value
ReadResponse readResponse = helper.server.send(helper.getCurrentRegistration(),
new ReadRequest(ContentFormat.TEXT, IntegrationTestHelper.TEST_OBJECT_ID, 0,
IntegrationTestHelper.OBJLNK_SINGLE_INSTANCE_RESOURCE_ID));
LwM2mSingleResource resource = (LwM2mSingleResource) readResponse.getContent();
// verify read value
assertEquals(((ObjectLink) resource.getValue()).getObjectId(), 10245);
assertEquals(((ObjectLink) resource.getValue()).getObjectInstanceId(), 0);
}
@Test(expected = CodecException.class)
public void send_writerequest_synchronously_with_bad_payload_raises_codeexception() throws InterruptedException {
helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(3, 0, 13, "a string instead of timestamp for currenttime resource"));
}
@Test(expected = CodecException.class)
public void send_writerequest_asynchronously_with_bad_payload_raises_codeexception() throws InterruptedException {
helper.server.send(helper.getCurrentRegistration(),
new WriteRequest(3, 0, 13, "a string instead of timestamp for currenttime resource"),
new ResponseCallback<WriteResponse>() {
@Override
public void onResponse(WriteResponse response) {
}
}, new ErrorCallback() {
@Override
public void onError(Exception e) {
}
});
}
}