/******************************************************************************* * 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) - replace close() with destroy() *******************************************************************************/ package org.eclipse.leshan.integration.tests; import static org.eclipse.leshan.integration.tests.IntegrationTestHelper.LIFETIME; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.*; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.californium.core.coap.CoAP.Code; import org.eclipse.californium.core.coap.Request; import org.eclipse.californium.core.coap.Response; import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.core.network.Endpoint; import org.eclipse.californium.core.network.config.NetworkConfig; import org.eclipse.leshan.Link; import org.eclipse.leshan.ResponseCode; import org.eclipse.leshan.client.californium.LeshanClient; import org.eclipse.leshan.client.californium.impl.CaliforniumLwM2mRequestSender; import org.eclipse.leshan.client.resource.LwM2mInstanceEnabler; import org.eclipse.leshan.client.resource.LwM2mObjectEnabler; import org.eclipse.leshan.client.resource.ObjectEnabler; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.ObserveRequest; import org.eclipse.leshan.core.request.ReadRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.response.ObserveResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.RegisterResponse; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.junit.After; import org.junit.Before; import org.junit.Test; public class RegistrationTest { protected IntegrationTestHelper helper = new IntegrationTestHelper(); @Before public void start() { helper.initialize(); helper.createServer(); helper.server.start(); helper.createClient(); } @After public void stop() throws InterruptedException { helper.client.destroy(true); helper.server.destroy(); helper.dispose(); } @Test public void register_update_deregister() { // Check client is not registered helper.assertClientNotRegisterered(); // Start it and wait for registration helper.client.start(); helper.waitForRegistration(1); // Check client is well registered helper.assertClientRegisterered(); assertArrayEquals(Link.parse("</>;rt=\"oma.lwm2m\",</1/0>,</2>,</3/0>,</2000/0>".getBytes()), helper.getCurrentRegistration().getObjectLinks()); // Check for update helper.waitForUpdate(LIFETIME); helper.assertClientRegisterered(); // Check deregistration helper.client.stop(true); helper.waitForDeregistration(1); helper.assertClientNotRegisterered(); } @Test public void deregister_cancel_multiple_pending_request() throws InterruptedException { // Check client is not registered helper.assertClientNotRegisterered(); // Start it and wait for registration helper.client.start(); helper.waitForRegistration(1); // Check client is well registered helper.assertClientRegisterered(); assertArrayEquals(Link.parse("</>;rt=\"oma.lwm2m\",</1/0>,</2>,</3/0>,</2000/0>".getBytes()), helper.getCurrentRegistration().getObjectLinks()); // Stop client with out de-registration helper.client.stop(false); // Send multiple reads which should be retransmitted. List<Callback<ReadResponse>> callbacks = new ArrayList<>(); for (int index = 0; index < 4; ++index) { Callback<ReadResponse> callback = new Callback<>(); helper.server.send(helper.getCurrentRegistration(), new ReadRequest(3, 0, 1), callback, callback); callbacks.add(callback); } // Restart client (de-registration/re-registration) helper.client.start(); // Check the request was cancelled. int index = 0; for (Callback<ReadResponse> callback : callbacks) { boolean timedout = !callback.waitForResponse(1000); assertFalse("Response or Error expected, no timeout, call " + index, timedout); assertTrue("Response or Error expected, call " + index, callback.isCalled().get()); assertNull("No response expected, call " + index, callback.getResponse()); assertNotNull("Exception expected, call " + index, callback.getException()); ++index; } } @Test public void register_update_deregister_reregister() throws NonUniqueSecurityInfoException, InterruptedException { // Check client is not registered helper.assertClientNotRegisterered(); // Start it and wait for registration helper.client.start(); helper.waitForRegistration(1); // Check client is well registered helper.assertClientRegisterered(); // Check for update helper.waitForUpdate(LIFETIME); helper.assertClientRegisterered(); // Check de-registration helper.client.stop(true); helper.waitForDeregistration(1); helper.assertClientNotRegisterered(); // Check new registration helper.resetLatch(); helper.client.start(); helper.waitForRegistration(1); helper.assertClientRegisterered(); } @Test public void register_update_reregister() throws NonUniqueSecurityInfoException, InterruptedException { // Check client is not registered helper.assertClientNotRegisterered(); // Start it and wait for registration helper.client.start(); helper.waitForRegistration(1); // Check client is well registered helper.assertClientRegisterered(); // Check for update helper.waitForUpdate(LIFETIME); helper.assertClientRegisterered(); // check stop do not de-register helper.client.stop(false); helper.ensureNoDeregistration(1); helper.assertClientRegisterered(); // check new registration helper.resetLatch(); helper.client.start(); helper.waitForRegistration(1); helper.assertClientRegisterered(); } @Test public void register_observe_deregister_observe() throws NonUniqueSecurityInfoException, InterruptedException { // Check client is not registered helper.assertClientNotRegisterered(); // Start it and wait for registration helper.client.start(); helper.waitForRegistration(1); // Check client is well registered helper.assertClientRegisterered(); // observe device timezone ObserveResponse observeResponse = helper.server.send(helper.getCurrentRegistration(), new ObserveRequest(3, 0)); assertEquals(ResponseCode.CONTENT, observeResponse.getCode()); assertNotNull(observeResponse.getCoapResponse()); assertThat(observeResponse.getCoapResponse(), is(instanceOf(Response.class))); // check observation registry is not null Registration currentRegistration = helper.getCurrentRegistration(); Set<Observation> observations = helper.server.getObservationService().getObservations(currentRegistration); assertEquals(1, observations.size()); Observation obs = observations.iterator().next(); assertEquals(currentRegistration.getId(), obs.getRegistrationId()); assertEquals(new LwM2mPath(3, 0), obs.getPath()); // Check de-registration helper.client.stop(true); helper.waitForDeregistration(1); helper.assertClientNotRegisterered(); observations = helper.server.getObservationService().getObservations(currentRegistration); assertTrue(observations.isEmpty()); // try to send a new observation observeResponse = helper.server.send(currentRegistration, new ObserveRequest(3, 0), 50); assertNull(observeResponse); // check observationStore is empty observations = helper.server.getObservationService().getObservations(currentRegistration); assertTrue(observations.isEmpty()); } // TODO not really a registration test @Test(expected = IllegalArgumentException.class) public void fail_to_create_client_with_same_object_twice() { ObjectEnabler objectEnabler = new ObjectEnabler(1, null, new HashMap<Integer, LwM2mInstanceEnabler>(), null); ObjectEnabler objectEnabler2 = new ObjectEnabler(1, null, new HashMap<Integer, LwM2mInstanceEnabler>(), null); ArrayList<LwM2mObjectEnabler> objects = new ArrayList<>(); objects.add(objectEnabler); objects.add(objectEnabler2); helper.client = new LeshanClient("test", new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), objects, new NetworkConfig()); } @Test public void register_with_additional_attributes() throws InterruptedException { // Check registration helper.assertClientNotRegisterered(); // HACK to be able to send a Registration request with additional attributes LeshanClient lclient = (LeshanClient) helper.client; lclient.getCoapServer().start(); Endpoint secureEndpoint = lclient.getCoapServer().getEndpoint(lclient.getSecureAddress()); Endpoint nonSecureEndpoint = lclient.getCoapServer().getEndpoint(lclient.getNonSecureAddress()); CaliforniumLwM2mRequestSender sender = new CaliforniumLwM2mRequestSender(secureEndpoint, nonSecureEndpoint); // Create Request with additional attributes Map<String, String> additionalAttributes = new HashMap<>(); additionalAttributes.put("key1", "value1"); additionalAttributes.put("imei", "2136872368"); Link[] objectLinks = Link.parse("</>;rt=\"oma.lwm2m\",</1/0>,</2>,</3/0>".getBytes()); RegisterRequest registerRequest = new RegisterRequest(helper.getCurrentEndpoint(), null, null, null, null, objectLinks, additionalAttributes); // Send request RegisterResponse resp = sender.send(helper.server.getNonSecureAddress(), false, registerRequest, 5000l); helper.waitForRegistration(1); // Check we are registered with the expected attributes helper.assertClientRegisterered(); assertNotNull(helper.last_registration); assertEquals(additionalAttributes, helper.last_registration.getAdditionalRegistrationAttributes()); assertArrayEquals(Link.parse("</>;rt=\"oma.lwm2m\",</1/0>,</2>,</3/0>".getBytes()), helper.getCurrentRegistration().getObjectLinks()); sender.send(helper.server.getNonSecureAddress(), false, new DeregisterRequest(resp.getRegistrationID()), 5000l); lclient.getCoapServer().stop(); } @Test public void register_with_invalid_request() throws InterruptedException, IOException { // Check registration helper.assertClientNotRegisterered(); // create a register request without the list of supported object Request coapRequest = new Request(Code.POST); coapRequest.setDestination(helper.server.getNonSecureAddress().getAddress()); coapRequest.setDestinationPort(helper.server.getNonSecureAddress().getPort()); coapRequest.getOptions().setContentFormat(ContentFormat.LINK.getCode()); coapRequest.getOptions().addUriPath("rd"); coapRequest.getOptions().addUriQuery("ep=" + helper.currentEndpointIdentifier); // send request CoapEndpoint coapEndpoint = new CoapEndpoint(new InetSocketAddress(0)); coapEndpoint.start(); coapEndpoint.sendRequest(coapRequest); // check response Response response = coapRequest.waitForResponse(1000); assertEquals(response.getCode(), org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST); coapEndpoint.stop(); } }