org.openhab.io.mqttembeddedbroker.internal.MqttEmbeddedBrokerServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.openhab.io.mqttembeddedbroker.internal.MqttEmbeddedBrokerServiceTest.java

Source

/**
 * Copyright (c) 2010-2019 Contributors to the openHAB project
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package org.openhab.io.mqttembeddedbroker.internal;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.verify;

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import javax.naming.ConfigurationException;

import org.apache.commons.io.FileUtils;
import org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnection;
import org.eclipse.smarthome.io.transport.mqtt.MqttBrokerConnection.Protocol;
import org.eclipse.smarthome.io.transport.mqtt.MqttConnectionObserver;
import org.eclipse.smarthome.io.transport.mqtt.MqttConnectionState;
import org.eclipse.smarthome.io.transport.mqtt.MqttException;
import org.eclipse.smarthome.io.transport.mqtt.MqttService;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.moquette.broker.RetainedMessage;
import io.moquette.broker.subscriptions.Topic;

/**
 * Tests connections with the embedded broker. Checks for credential based login,
 * check for SSL connections.
 *
 * @author David Graeff - Initial contribution
 */
public class MqttEmbeddedBrokerServiceTest {
    private final Logger logger = LoggerFactory.getLogger(MqttEmbeddedBrokerServiceTest.class);

    private EmbeddedBrokerService subject;
    private ServiceConfiguration config = new ServiceConfiguration();
    private @Mock MqttService service;

    @Before
    public void setUp() throws ConfigurationException, MqttException, GeneralSecurityException, IOException {
        MockitoAnnotations.initMocks(this);
        subject = new EmbeddedBrokerService();
        subject.setMqttService(service);

        config.username = "username";
        config.password = "password";
        config.port = 12345;
        config.secure = false;
        config.persistenceFile = "";

    }

    @After
    public void cleanUp() {
        subject.deactivate();
    }

    public void waitForConnectionChange(MqttBrokerConnection c, MqttConnectionState expectedState)
            throws InterruptedException {
        Semaphore semaphore = new Semaphore(1);
        semaphore.acquire();

        MqttConnectionObserver mqttConnectionObserver = (state, error) -> {
            if (state == expectedState) {
                semaphore.release();
            }
        };
        c.addConnectionObserver(mqttConnectionObserver);
        if (c.connectionState() == expectedState) {
            semaphore.release();
        }

        // Start the connection and wait until timeout or connected callback returns.
        semaphore.tryAcquire(3000, TimeUnit.MILLISECONDS);

        c.removeConnectionObserver(mqttConnectionObserver);

    }

    @Test
    public void connectUnsecureAndTestCredentials() throws InterruptedException, IOException, ExecutionException {
        subject.initialize(config);

        MqttBrokerConnection c = subject.getConnection();
        assertNotNull(c);
        waitForConnectionChange(c, MqttConnectionState.CONNECTED);

        assertThat(c.getUser(), is("username"));
        assertThat(c.getPassword(), is("password"));

        assertThat(c.connectionState(), is(MqttConnectionState.CONNECTED));
        verify(service).addBrokerConnection(anyString(), eq(c));

        // Connect with a second connection but wrong credentials
        MqttBrokerConnection wrongCredentials = new MqttBrokerConnection(Protocol.TCP, c.getHost(), c.getPort(),
                false, "wrongCred");
        wrongCredentials.setCredentials("someUser", "somePassword");
        try {
            if (wrongCredentials.start().get()) {
                fail("Wrong credentials accepted!");
            }
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        wrongCredentials.stop().get();

        // Connect with a second connection but correct credentials
        MqttBrokerConnection correctCredentials = new MqttBrokerConnection(Protocol.TCP, c.getHost(), c.getPort(),
                false, "correctCred");
        correctCredentials.setCredentials(c.getUser(), c.getPassword());
        try {
            if (!correctCredentials.start().get()) {
                fail("Couldn't connect although correct credentials");
            }
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        correctCredentials.stop().get();
    }

    @Test
    public void connectSecure() throws InterruptedException, IOException {
        config.secure = true;
        subject.initialize(config);

        MqttBrokerConnection c = subject.getConnection();
        assertNotNull(c);

        waitForConnectionChange(c, MqttConnectionState.CONNECTED);

        assertThat(c.getUser(), is("username"));
        assertThat(c.getPassword(), is("password"));

        assertThat(c.connectionState(), is(MqttConnectionState.CONNECTED));
        verify(service).addBrokerConnection(anyString(), eq(c));
    }

    @Test
    public void testPersistence() throws InterruptedException, IOException, ExecutionException {
        config.persistenceFile = "persist.mqtt";
        subject.initialize(config);

        MqttBrokerConnection c = subject.getConnection();
        assertNotNull(c);

        waitForConnectionChange(c, MqttConnectionState.CONNECTED);

        c.publish("demotopic", "testtest".getBytes(), 2, true).get();

        // Stop server -> close persistence storage and sync it to disk
        subject.deactivate();

        File jksFile = new File(subject.getPersistenceFilename());
        assertTrue(jksFile.exists());

        // The original file is still open, create a temp file for examination
        File temp = File.createTempFile("abc", ".tmp");
        temp.deleteOnExit();
        FileUtils.copyFile(jksFile, temp);

        MVStore mvStore = new MVStore.Builder().fileName(temp.getAbsolutePath()).autoCommitDisabled().open();
        MVMap<Topic, RetainedMessage> openMap = mvStore.openMap("retained_store");

        assertThat(openMap.size(), is(1));
        for (Map.Entry<Topic, RetainedMessage> entry : openMap.entrySet()) {
            assertThat(entry.getKey().toString(), is("demotopic"));
            assertThat(new String(entry.getValue().getPayload()), is("testtest"));
        }
    }
}