/******************************************************************************* * 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 *******************************************************************************/ package org.eclipse.leshan.integration.tests; import static org.junit.Assert.*; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Collection; import java.util.List; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.eclipse.leshan.LwM2mId; import org.eclipse.leshan.client.LwM2mClient; import org.eclipse.leshan.client.californium.LeshanClientBuilder; import org.eclipse.leshan.client.object.Device; import org.eclipse.leshan.client.object.Security; import org.eclipse.leshan.client.object.Server; import org.eclipse.leshan.client.resource.LwM2mObjectEnabler; import org.eclipse.leshan.client.resource.ObjectsInitializer; import org.eclipse.leshan.core.model.LwM2mModel; import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.model.ResourceModel.Operations; import org.eclipse.leshan.core.model.ResourceModel.Type; import org.eclipse.leshan.core.observation.Observation; import org.eclipse.leshan.core.request.BindingMode; import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.californium.impl.LeshanServer; import org.eclipse.leshan.server.impl.InMemorySecurityStore; import org.eclipse.leshan.server.impl.RegistrationServiceImpl; import org.eclipse.leshan.server.model.StaticModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.RegistrationListener; import org.eclipse.leshan.server.registration.RegistrationUpdate; /** * Helper for running a server and executing a client against it. * */ public class IntegrationTestHelper { public static final Random r = new Random(); static final String MODEL_NUMBER = "IT-TEST-123"; public static final long LIFETIME = 2; public static final int TEST_OBJECT_ID = 2000; public static final int STRING_RESOURCE_ID = 0; public static final int BOOLEAN_RESOURCE_ID = 1; public static final int INTEGER_RESOURCE_ID = 2; public static final int FLOAT_RESOURCE_ID = 3; public static final int TIME_RESOURCE_ID = 4; public static final int OPAQUE_RESOURCE_ID = 5; public static final int OBJLNK_MULTI_INSTANCE_RESOURCE_ID = 6; public static final int OBJLNK_SINGLE_INSTANCE_RESOURCE_ID = 7; LeshanServer server; LwM2mClient client; String currentEndpointIdentifier; CountDownLatch registerLatch; Registration last_registration; CountDownLatch deregisterLatch; CountDownLatch updateLatch; protected List<ObjectModel> createObjectModels() { // load default object from the spec List<ObjectModel> objectModels = ObjectLoader.loadDefault(); // define custom model for testing purpose ResourceModel stringfield = new ResourceModel(STRING_RESOURCE_ID, "stringres", Operations.RW, false, false, Type.STRING, null, null, null); ResourceModel booleanfield = new ResourceModel(BOOLEAN_RESOURCE_ID, "booleanres", Operations.RW, false, false, Type.BOOLEAN, null, null, null); ResourceModel integerfield = new ResourceModel(INTEGER_RESOURCE_ID, "integerres", Operations.RW, false, false, Type.INTEGER, null, null, null); ResourceModel floatfield = new ResourceModel(FLOAT_RESOURCE_ID, "floatres", Operations.RW, false, false, Type.FLOAT, null, null, null); ResourceModel timefield = new ResourceModel(TIME_RESOURCE_ID, "timeres", Operations.RW, false, false, Type.TIME, null, null, null); ResourceModel opaquefield = new ResourceModel(OPAQUE_RESOURCE_ID, "opaque", Operations.RW, false, false, Type.OPAQUE, null, null, null); ResourceModel objlnkfield = new ResourceModel(OBJLNK_MULTI_INSTANCE_RESOURCE_ID, "objlnk", Operations.RW, true, false, Type.OBJLNK, null, null, null); ResourceModel objlnkSinglefield = new ResourceModel(OBJLNK_SINGLE_INSTANCE_RESOURCE_ID, "objlnk", Operations.RW, false, false, Type.OBJLNK, null, null, null); objectModels.add(new ObjectModel(TEST_OBJECT_ID, "testobject", null, false, false, stringfield, booleanfield, integerfield, floatfield, timefield, opaquefield, objlnkfield, objlnkSinglefield)); return objectModels; } public void initialize() { currentEndpointIdentifier = "leshan_integration_test_" + r.nextInt(); } public String getCurrentEndpoint() { return currentEndpointIdentifier; } public void createClient() { // Create objects Enabler ObjectsInitializer initializer = new ObjectsInitializer(new LwM2mModel(createObjectModels())); initializer.setInstancesForObject(LwM2mId.SECURITY, Security.noSec( "coap://" + server.getNonSecureAddress().getHostString() + ":" + server.getNonSecureAddress().getPort(), 12345)); initializer.setInstancesForObject(LwM2mId.SERVER, new Server(12345, LIFETIME, BindingMode.U, false)); initializer.setInstancesForObject(LwM2mId.DEVICE, new Device("Eclipse Leshan", MODEL_NUMBER, "12345", "U") { @Override public ExecuteResponse execute(int resourceid, String params) { if (resourceid == 4) { return ExecuteResponse.success(); } else { return super.execute(resourceid, params); } } }); List<LwM2mObjectEnabler> objects = initializer.createMandatory(); objects.addAll(initializer.create(2, 2000)); // Build Client LeshanClientBuilder builder = new LeshanClientBuilder(currentEndpointIdentifier); builder.setObjects(objects); client = builder.build(); } public void createServer() { LeshanServerBuilder builder = new LeshanServerBuilder(); builder.setObjectModelProvider(new StaticModelProvider(createObjectModels())); builder.setLocalAddress(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); builder.setLocalSecureAddress(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); builder.setSecurityStore(new InMemorySecurityStore()); server = builder.build(); // monitor client registration setupRegistrationMonitoring(); } protected void setupRegistrationMonitoring() { resetLatch(); server.getRegistrationService().addListener(new RegistrationListener() { @Override public void updated(RegistrationUpdate update, Registration updatedRegistration, Registration previousRegistration) { if (updatedRegistration.getEndpoint().equals(currentEndpointIdentifier)) { updateLatch.countDown(); } } @Override public void unregistered(Registration registration, Collection<Observation> observations, boolean expired) { if (registration.getEndpoint().equals(currentEndpointIdentifier)) { deregisterLatch.countDown(); } } @Override public void registered(Registration registration) { if (registration.getEndpoint().equals(currentEndpointIdentifier)) { last_registration = registration; registerLatch.countDown(); } } }); } public void resetLatch() { registerLatch = new CountDownLatch(1); deregisterLatch = new CountDownLatch(1); updateLatch = new CountDownLatch(1); } public void waitForRegistration(long timeInSeconds) { try { assertTrue(registerLatch.await(timeInSeconds, TimeUnit.SECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } public void ensureNoRegistration(long timeInSeconds) { try { assertFalse(registerLatch.await(timeInSeconds, TimeUnit.SECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } public void waitForUpdate(long timeInSeconds) { try { assertTrue(updateLatch.await(timeInSeconds, TimeUnit.SECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } public void ensureNoUpdate(long timeInSeconds) { try { assertFalse(updateLatch.await(timeInSeconds, TimeUnit.SECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } public void waitForDeregistration(long timeInSeconds) { try { assertTrue(deregisterLatch.await(timeInSeconds, TimeUnit.SECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } public void ensureNoDeregistration(long timeInSeconds) { try { assertFalse(deregisterLatch.await(timeInSeconds, TimeUnit.SECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } public Registration getCurrentRegistration() { return server.getRegistrationService().getByEndpoint(currentEndpointIdentifier); } public void deregisterClient() { Registration r = getCurrentRegistration(); if (r != null) ((RegistrationServiceImpl) server.getRegistrationService()).getStore().removeRegistration(r.getId()); } public void dispose() { deregisterClient(); currentEndpointIdentifier = null; } public void assertClientRegisterered() { assertNotNull(getCurrentRegistration()); } public void assertClientNotRegisterered() { assertNull(getCurrentRegistration()); } }